You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Keep the user's audio route when the session configuration is unchanged - #1166
AudioSessionEngineObserver.configureAudioSession calls setCategory(_:mode:options:) and setPreferredIOBufferDuration(_:) on every requirement change: muting or unmuting the mic, enabling or disabling it, engine restarts and reconnects. It also calls them on every isSpeakerOutputPreferred or voice processing change.
Setting the category again makes iOS re-evaluate the route, even when the category, mode and options are the same as before. So an output the user picked with AVRoutePickerView or Control Center (receiver, speaker, a Bluetooth device) gets dropped the next time the requirements change. For example, the user switches to the receiver during a call, mutes the mic, and the audio goes back to the speaker. The speaker presets include .defaultToSpeaker, so it is most visible there.
client-sdk-flutter#1227 describes a similar conflict between a user-selected route and the engine re-applying its session configuration.
Changes
Only call setCategory when the session's current category, mode or options differ from the selected configuration (needsCategoryUpdate).
Voice Processing I/O can switch the speaker preset's .videoChat to .voiceChat by itself (noted in AudioSessionConfiguration), so the two chat modes count as the same mode in that check. A speaker preference change still differs in .defaultToSpeaker, and a voice processing path change still differs in mode (.default vs the chat modes), so both are still applied.
Only call setPreferredIOBufferDuration when the preferred duration differs from WebRTC's value.
The selected configuration, requirement tracking, activation and deactivation are unchanged, and there is no public API change. If iOS reports the options differently from how they were set, the check sees a difference and the category is set again, which is the current behaviour.
Test
AudioSessionCategorySelectionTests and the new AudioSessionCategoryUpdateTests pass on the iOS Simulator.
Steps to verify on a device (iPhone 17 Pro, iOS 27.0.1), in a room with the mic published:
Pick the receiver (or a Bluetooth headset) in AVRoutePickerView.
Mute and unmute the mic a few times.
Expected: the output stays on the picked route instead of going back to the speaker.
Tested on an iPhone 17 Pro running iOS 27.0.1, using the default audio processing options and an AirPods Pro route selected through AVRoutePickerView. Across three repetitions, main logged a category configuration for each mute/unmute in .restart mode and each microphone unpublish/republish; this branch skipped those redundant writes. .voiceProcessing and .inputMixer mute/unmute did not reconfigure the session on either version. Changing isSpeakerOutputPreferred still applied the new mode/options on this branch. Three brief Wi-Fi interruptions recovered through quick reconnect without additional category writes or changing the Bluetooth route on either version. I did not reproduce a switch back to the speaker on main, and the mode stayed .videoChat until I explicitly changed the speaker preference. The route picker did not expose a separate receiver option with the default configuration. This confirms the reduction in redundant writes, but does not establish the full route-reset reproduction on this device.
Closing this for now. On a device the redundant writes go away, but I couldn't reproduce the route actually being reset on main, so there's no user-facing problem to point at yet. I'll reopen with a reproduction if I find one.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
AudioSessionEngineObserver.configureAudioSessioncallssetCategory(_:mode:options:)andsetPreferredIOBufferDuration(_:)on every requirement change: muting or unmuting the mic, enabling or disabling it, engine restarts and reconnects. It also calls them on everyisSpeakerOutputPreferredor voice processing change.Setting the category again makes iOS re-evaluate the route, even when the category, mode and options are the same as before. So an output the user picked with
AVRoutePickerViewor Control Center (receiver, speaker, a Bluetooth device) gets dropped the next time the requirements change. For example, the user switches to the receiver during a call, mutes the mic, and the audio goes back to the speaker. The speaker presets include.defaultToSpeaker, so it is most visible there.client-sdk-flutter#1227 describes a similar conflict between a user-selected route and the engine re-applying its session configuration.
Changes
setCategorywhen the session's current category, mode or options differ from the selected configuration (needsCategoryUpdate)..videoChatto.voiceChatby itself (noted inAudioSessionConfiguration), so the two chat modes count as the same mode in that check. A speaker preference change still differs in.defaultToSpeaker, and a voice processing path change still differs in mode (.defaultvs the chat modes), so both are still applied.setPreferredIOBufferDurationwhen the preferred duration differs from WebRTC's value.The selected configuration, requirement tracking, activation and deactivation are unchanged, and there is no public API change. If iOS reports the options differently from how they were set, the check sees a difference and the category is set again, which is the current behaviour.
Test
AudioSessionCategorySelectionTestsand the newAudioSessionCategoryUpdateTestspass on the iOS Simulator.AVRoutePickerView.