Deactivating audio error on iOS device

I had an iOS app that used to work fine two months ago. I made a small change unrelated change (size of a button), recompiled and now it fails to work on my test device (iPhone SE), when it used to work fine. It also works fine on the emulator. I get the following error:

**[avas] AVAudioSession.mm:1142:-[AVAudioSession setActive:withOptions:error:]: Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session.**

**JUCE Assertion failure in juce_ios_Audio.cpp:207**

This is the offending code:

static void setAudioSessionActive (bool enabled)
{
JUCE_NSERROR_CHECK ([[AVAudioSession sharedInstance] setActive: enabled
error: &error]);
}

The offending section of code is called (several layers deep) from this my code:

setAudioChannels (0, 2); // no inputs, two outputs
AudioDeviceManager::AudioDeviceSetup setup;
deviceManager.getAudioDeviceSetup(setup);
setup.sampleRate = 44100;
deviceManager.initialise(0, 2, nullptr, true, “”, &setup);

Any ideas of what to do?

I think this call starts the audio device already, but I don’t think you need that line at all.
Can you try without the setAudioChannels()? It is done when you call deviceManager.initialise()…

Can you post the stack trace when you see the error?

There was a fairly recent change the the audio session handling on the develop branch. Do you see the same behaviour if you pull the latest changes from there?

Thank you for the suggestion. If I comment out the setAudioChannels(…) line, the program does not crash and seems to work. But I get no sounds at all in both the emulator and the device.

Below is the stack trace. I haven’t tried the development branch but will do soon.

* thread #1, name = 'JUCE Message Thread', queue = 'com.apple.main-thread', stop reason = signal SIGTRAP
  * frame #0: 0x000000018156c890 libsystem_kernel.dylib`__kill + 8
    frame #1: 0x00000001040bd1bc VindorPlayer`juce::logNSError(e=domain: "NSOSStatusErrorDomain" - code: 560030580) at juce_ios_Audio.cpp:207
    frame #2: 0x00000001040bc150 VindorPlayer`juce::iOSAudioIODevice::Pimpl::setAudioSessionActive(enabled=false) at juce_ios_Audio.cpp:290
    frame #3: 0x00000001040bbdb0 VindorPlayer`juce::iOSAudioIODevice::Pimpl::Pimpl(this=0x000000011dd20770, ioDeviceType=0x00000001c00a79e0, ioDevice=0x00000001c022aa80) at juce_ios_Audio.cpp:258
    frame #4: 0x00000001040b7544 VindorPlayer`juce::iOSAudioIODevice::Pimpl::Pimpl(this=0x000000011dd20770, ioDeviceType=0x00000001c00a79e0, ioDevice=0x00000001c022aa80) at juce_ios_Audio.cpp:248
    frame #5: 0x00000001040b7414 VindorPlayer`juce::iOSAudioIODevice::iOSAudioIODevice(this=0x00000001c022aa80, ioDeviceType=0x00000001c00a79e0, (null)=0x000000016bdb74f0, (null)=0x000000016bdb74f8) at juce_ios_Audio.cpp:1332
    frame #6: 0x00000001040b7590 VindorPlayer`juce::iOSAudioIODevice::iOSAudioIODevice(this=0x00000001c022aa80, ioDeviceType=0x00000001c00a79e0, (null)=0x000000016bdb74f0, (null)=0x000000016bdb74f8) at juce_ios_Audio.cpp:1333
    frame #7: 0x00000001040b8b80 VindorPlayer`juce::iOSAudioIODeviceType::createDevice(this=0x00000001c00a79e0, outputDeviceName=0x000000016bdb74f0, inputDeviceName=0x000000016bdb74f8) at juce_ios_Audio.cpp:1404
    frame #8: 0x00000001040ad234 VindorPlayer`juce::AudioDeviceManager::setAudioDeviceSetup(this=0x000000011e039ea0, newSetup=0x000000016bdb7838, treatAsChosenDevice=false) at juce_AudioDeviceManager.cpp:463
    frame #9: 0x00000001040acbb0 VindorPlayer`juce::AudioDeviceManager::initialiseDefault(this=0x000000011e039ea0, preferredDefaultDeviceName=0x000000016bdb7fa0, preferredSetupOptions=0x000000016bdb7fb0) at juce_AudioDeviceManager.cpp:242
    frame #10: 0x00000001040abfa0 VindorPlayer`juce::AudioDeviceManager::initialise(this=0x000000011e039ea0, numInputChannelsNeeded=0, numOutputChannelsNeeded=2, xml=0x0000000000000000, selectDefaultDeviceOnFailure=true, preferredDefaultDeviceName=0x000000016bdb7fa0, preferredSetupOptions=0x000000016bdb7fb0) at juce_AudioDeviceManager.cpp:205
    frame #11: 0x000000010404cb68 VindorPlayer`Player::Player(this=0x000000011e038c00) at Player.cpp:636
    frame #12: 0x000000010404df10 VindorPlayer`Player::Player(this=0x000000011e038c00) at Player.cpp:500
    frame #13: 0x0000000104057ae0 VindorPlayer`splayerApplication::MainWindow::MainWindow(this=0x000000011dd08470, name=String @ 0x000000016bdb93a8) at Main.cpp:72
    frame #14: 0x00000001040579b4 VindorPlayer`splayerApplication::MainWindow::MainWindow(this=0x000000011dd08470, name=<unavailable>) at Main.cpp:70
    frame #15: 0x0000000104057678 VindorPlayer`splayerApplication::initialise(this=0x00000001c046c500, commandLine=0x000000016bdb9418) at Main.cpp:30
    frame #16: 0x0000000104318524 VindorPlayer`juce::JUCEApplicationBase::initialiseApp(this=0x00000001c046c500) at juce_ApplicationBase.cpp:297
    frame #17: 0x0000000104537c4c VindorPlayer`juce::JUCEApplication::initialiseApp(this=0x00000001c046c500) at juce_Application.cpp:93
    frame #18: 0x00000001045479b0 VindorPlayer`::-[JuceAppStartupDelegate applicationDidFinishLaunching:](self=0x00000001c003aa20, _cmd="applicationDidFinishLaunching:", application=0x000000011de04660) at juce_ios_Windowing.mm:110
    frame #19: 0x000000018b6f5e24 UIKit`-[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 512
    frame #20: 0x000000018b6f5914 UIKit`-[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 5356
    frame #21: 0x000000018b6c25e0 UIKit`-[UIApplication _runWithMainScene:transitionContext:completion:] + 1680
    frame #22: 0x000000018bcf2b1c UIKit`__111-[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:]_block_invoke + 784
    frame #23: 0x000000018b6c1dd0 UIKit`+[_UICanvas _enqueuePostSettingUpdateTransactionBlock:] + 160
    frame #24: 0x000000018b6c1c6c UIKit`-[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:] + 240
    frame #25: 0x000000018b6c0afc UIKit`-[__UICanvasLifecycleMonitor_Compatability activateEventsOnly:withContext:completion:] + 724
    frame #26: 0x000000018c35684c UIKit`__82-[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:]_block_invoke + 296
    frame #27: 0x000000018b6c01ec UIKit`-[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:] + 432
    frame #28: 0x000000018c13bac8 UIKit`__125-[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:]_block_invoke + 220
    frame #29: 0x000000018c289bf8 UIKit`_performActionsWithDelayForTransitionContext + 112
    frame #30: 0x000000018b6bfc0c UIKit`-[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:] + 248
    frame #31: 0x000000018b6bf5a8 UIKit`-[_UICanvas scene:didUpdateWithDiff:transitionContext:completion:] + 368
    frame #32: 0x000000018b6bc5e0 UIKit`-[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 540
    frame #33: 0x000000018b6bc330 UIKit`-[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 364
    frame #34: 0x00000001842e8470 FrontBoardServices`-[FBSSceneImpl _didCreateWithTransitionContext:completion:] + 364
    frame #35: 0x00000001842f0d6c FrontBoardServices`__56-[FBSWorkspace client:handleCreateScene:withCompletion:]_block_invoke_2 + 224
    frame #36: 0x00000001074d919c libdispatch.dylib`_dispatch_client_callout + 16
    frame #37: 0x00000001074e57cc libdispatch.dylib`_dispatch_block_invoke_direct + 232
    frame #38: 0x000000018431c878 FrontBoardServices`__FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 36
    frame #39: 0x000000018431c51c FrontBoardServices`-[FBSSerialQueue _performNext] + 404
    frame #40: 0x000000018431cab8 FrontBoardServices`-[FBSSerialQueue _performNextFromRunLoopSource] + 56
    frame #41: 0x0000000181a8f404 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
    frame #42: 0x0000000181a8ec2c CoreFoundation`__CFRunLoopDoSources0 + 276
    frame #43: 0x0000000181a8c79c CoreFoundation`__CFRunLoopRun + 1204
    frame #44: 0x00000001819acda8 CoreFoundation`CFRunLoopRunSpecific + 552
    frame #45: 0x0000000183992020 GraphicsServices`GSEventRunModal + 100
    frame #46: 0x000000018b9cc758 UIKit`UIApplicationMain + 236
    frame #47: 0x0000000104547ed4 VindorPlayer`juce::juce_iOSMain(argc=1, argv=0x000000016bdbb850, customDelegatePtr=0x0000000000000000) at juce_ios_Windowing.mm:422
    frame #48: 0x0000000104317f0c VindorPlayer`juce::JUCEApplicationBase::main(argc=1, argv=0x000000016bdbb850) at juce_ApplicationBase.cpp:237
    frame #49: 0x0000000104057474 VindorPlayer`main(argc=1, argv=0x000000016bdbb850) at Main.cpp:104
    frame #50: 0x000000018143dfc0 libdyld.dylib`start + 4
(lldb) 

Hmm. That’s not particularly enlightening.

  • Did this start happening without changing any JUCE code?
  • If you revert your button size change do things work as they used to?

I did revert the change, with the same results. I also got the developer branch and compiled against it with the same result. In addition, I got an old iPhone 5 (iOS 10.3.3), reset it to factory settings, connected it and got the same results. It will crash if I use the original code. If I comment out the setAudioChannels line then it doesn’t crash but I get no sound.

Does the JUCE DemoRunner application (or any of the JUCE-provided examples) work?

In the end, if I keep the line below and removed the others everything is fine.

I’m not sure how to set the sample rate, but it defaults to what I want so that’s ok.

An unexpected side effect is that IOChannelData::IOChannelConfig::getHardwareChannelNames(...) is hard coded on the emulator to return two channels. This is different than the behavior on the iPhone. The phone returns only one channel “Speaker” when outputting through it’s built-in speaker. It returns two channels if headphones are connected. That confused me until I dug deeper into the code.