In attempt to pause my signal chain when a user puts the app into the background, or is interrupted by a phone call, I am trying to handle the interruption by stopping all playing nodes and setting the AVAudioSession().setActive(false)
as per convention.
It seems fine to call stop()
on all nodes except CallbackInstrument
, which crashes at line 231 of DSPBase.cpp in *CAudioKitEX from the AudioKitEX
repo :
void DSPBase::processOrBypass(AUAudioFrameCount frameCount, AUAudioFrameCount bufferOffset) {
if (isStarted) {
process(FrameRange{bufferOffset, frameCount});
} else {
// Advance all ramps.
stepRampsBy(frameCount);
// Copy input to output.
if (inputBufferLists.size() and !bCanProcessInPlace) {
for (int channel=0; channel< channelCount; ++channel) {
auto input = (const float *)inputBufferLists[0]->mBuffers[channel].mData + bufferOffset;
auto output = (float *)outputBufferList->mBuffers[channel].mData + bufferOffset;
std::copy(input, input+frameCount, output);
}
}
// Generators should be silent.
if (inputBufferLists.empty()) {
zeroOutput(frameCount, bufferOffset);
}
}
}
My CallbackInstrument
is attached to a Sequencer
as a discrete track. The crash occurs when the sequencer is playing and the app goes into the background, which I then call a method to stop all current sequencers, stop all active nodes prior to calling AVAudioSession.setSession(false)
.
I would simply ignore this and/or not stop CallbackInstrument
however, by not attempting to stop or reset the CallbackInstrument
node, AVAudioSession
catches an error:
AVAudioSession_iOS.mm:1271 Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session.
Error seting audio session false:Error Domain=NSOSStatusErrorDomain Code=560030580 "(null)"
Error code=560030580 refers to AVAudioSessionErrorCodeIsBusy
as stated here
Question:
If stopping a Sequencer
with a CallbackInstrument
does not in fact stop rendering audio/midi from the callback, how do we safely stop a signal chain with a CallbackInstrument
in order to prepare for AVAudioSession.setActive(false)
?
I have an example repo of the issue which can be found here.
Nicely presented question by the way :)
Seems like doing it this way does not guarantee that the audioBufferList
in process or bypass is populated, while it does report that the size() == 1, its pointer to audioBuferList[0]
is nill
...
Possibly there should be an additional check for this?
However, if instead of calling stop()
on every node in your AudioManager.sleep()
if you call engine.stop()
and conversely self.start()
in your AudioManager.wake()
instead of start on all your nodes... This avoids your error and should stop/start all nodes in the process.