Handling AVAudioEngine Configuration Change

Hi all,

I have been quite stumped on this behavior for a little bit now, so thought it best to share here and see if someone more experience with AVAudioEngine / AVAudioSession can weigh in.

Right now I have a AVAudioEngine that I am using to perform some voice chat with and give buffers to play. This works perfectly until route changes start to occur, which causes the AVAudioEngine to reset itself, which then causes all players attached to this engine to be stopped.

Once a AVPlayerNode gets stopped due to this (but also any other time), all samples that were scheduled to be played then get purged. Where this becomes confusing for me is the completion handler gets called every time regardless of the sound actually being played.

Is there a reliable way to know if a sample needs to be rescheduled after a player has been reset?

I am not quite sure in my case what my observer of AVAudioEngineConfigurationChange needs to be doing, as this engine only handles output. All input is through a separate engine for simplicity.

Currently I am storing a queue of samples as they get sent to the AVPlayerNode for playback, and after that completion checking if the player isPlaying or not. If it's playing I assume that the sound actually was played- and if not then I leave it in the queue and assume that an observer on the route change or the configuration change will realize there are samples in the queue and reset them

Thanks for any feedback!

Hello @draff27, thank you for your post.

Where this becomes confusing for me is the completion handler gets called every time regardless of the sound actually being played.

When you schedule a file or buffer, you can also specify a callback type. Please see AVAudioPlayerNodeCompletionCallbackType. This callback type allows you to differentiate between the player having consumed the data, rendered, or finished playing it back.

I struggled with this for a long time and finally gave up and switched to using AVAudioSourceNode and playing my own audio.

In my opinion the callbacks on AVPlayerNode are too coarse to give you the information you need to handle all the complex cases that can arise with interruptions, route changes etc.

@milesegan

Were there any memory management issues switching from AVAudioPlayerNode to AVAudioSourceNode?

I'm using the player node now and am having issues when the audio engine goes through a configuration change. When this happens I stop the engine, remove the player node(s), re-attach and re-connect the player nodes, and then restart the engine.

I wrote this code before realizing source nodes were a thing. I'm hoping that using a source mode makes things simpler and require less dynamic coordination. My thinking is that I can have the requisite number of source nodes connected to a mixer and just leave that configuration around for the duration of my app. Then, when one of my two or three dedicated inputs comes online, I can feed buffers into the source nodes and not worry about adding and removing player nodes. From your experience, does this sound like it would work? Would you be willing to share some code showing how you configure your engine with the source node?

Handling AVAudioEngine Configuration Change
 
 
Q