-
Notifications
You must be signed in to change notification settings - Fork 5
Audio session fixes #61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Hi @mikaelwills
Here is fragment of code from Apple CallKit documentation In contains very usable comment, explaining usage pattern: Stage 'configure audio' should be first and it's done internally by webrtc; Here is updated source code of plugin, which we testing and going to publish.
|
e08727b to
e4854d3
Compare
|
@siprix awesome, Justed tested the new file and it seems to be good so far after repeated calls! |
|
@siprix Well it worked when i first built with the new file, 20 calls in a row were fine. Came back to it latter and now the audio session wont connect at all when receiving and incoming call. Whats stands out to me is this Config is invalid: min_bitrate_bps=-1; max_bitrate_bps=-1; both expected greater or equal to 0. Inside the audio_send_stream.cc |
|
Reason of issue is interruption: provided log doesn't contain details when interruption started/ended. Most probably app was in background and move it to foreground would trigger log like: Checking how to handle this automatically. |
|
Published updated version 1.0.33 which includes previously provided impl and also addresses handling interruption. |
|
@siprix the v1.0.33 fixes look good Regarding Apple's pattern: configure → fulfill → activate → start audio. The issue is that WebRTC's internal configureAudioSession() doesn't always set .playAndRecord. My logs show it configured .playback: When didActivate fires, iOS has activated that session - the one with no microphone. Calling _siprixModule.activate() at that point can't fix a session that's already activated with the wrong category. Apple's docs say "configure the audio session" - but WebRTC configured it for playback-only. We need to verify/correct the category before accepting the call. Either:
Option 2 is what my original PR's ensureAudioSessionConfigured() does - it's not starting audio, it's correcting a misconfigured session before starting audio. Would it be worth being a bit more aggresive with the category setting, ensuring the audio session is properly configured regardless of what state WebRTC left it in. |
|
@siprix Happy new year! With testing prior to the break and this morning im seeing this issue a lot less after the recent changes. |
|
Here is fragment from last provided log: Something went wrong when app accepts call in background. Internal webrtc impl can't split 'configure' and 'start audio' actions. It has 2 separate methods for manual enable audio and activate session. Here is one more update (binary + plugin sources). siprix_ios_20251230.zip (the same build provided in the 'onTerminated callback..' topic) |
|
@siprix Yea this issue has started to come back for me now. Over the past couple days i cannot get audio connected with an app killed push first call. I downloaded the new binary and .swift file you gave me, Call acceptance now works (200 OK sent), but audio still fails. The category gets overwritten from PlayAndRecord to Playback right after didActivate: 141123.748 Set category to: AVAudioSessionCategoryPlayAndRecord Result: inputNumberOfChannels: 0, VPAU start fails with 561145187. I also deleted my app and did an entire fresh install when the push came in i got the pop up to accept microphone permissions, granted that but the call still had no audio. |
iOS CallKit Audio Session Race Condition Fix - PR Description
Incoming calls on iOS with CallKit were failing because of a race condition between WebRTC (used internally by Siprix) and CallKit competing for audio session control. WebRTC needs to initialize audio immediately when the SIP INVITE arrives (to generate the SDP answer), but CallKit expects to control when the audio session activates. When WebRTC wins the race, iOS doesn't call the
didActivatecallback, which means we never actually accept the call even though the UI shows "connected".Changes
1. Defer SIP Accept Until didActivate
Instead of accepting the SIP call immediately in
CXAnswerCallAction, we now:_callPendingAnswerdidActivateto fireWhy it's critical: Accepting the call before the audio session is ready leads to no audio routing. iOS needs to know the audio path exists before the SIP connection completes.
2. Fulfill CXAnswerCallAction Immediately
Fulfill the action right away to tell CallKit we're ready to proceed:
Why it's critical: If we don't fulfill, CallKit won't proceed with audio activation, so
didActivatenever fires and we're stuck waiting forever.3. Force Reset Interrupted Audio Sessions
In
didActivate, detect when WebRTC has already activated the audio session:Why it's critical: WebRTC activating audio before CallKit leaves the session in an "interrupted" state. Resetting clears this and lets us reconfigure for VoIP properly.
4. Audio Configuration in didActivate (Not onSipConnected)
Added
ensureAudioSessionConfigured()method that sets up VoIP audio settings:Called from
didActivate(before SIP accept), notonSipConnected(after connection).Why it's critical: Configuring audio AFTER the SIP connection is too late - iOS has already determined there's no audio path. Must happen in
didActivatewhich fires BEFORE we send the SIP accept.Why This Approach
We can't prevent WebRTC from initializing early - it's required for SIP to work (needs to check hardware capabilities to generate the SDP answer). So instead, we work around it:
The deferred answer pattern ensures everything happens in the right order: fulfill action → activate session → configure audio → accept call. Doing it any other way leaves the audio routing broken.
@siprix let me know your thoughts on whether this is all appropriate or not. After these changes ive personally noticed a dramatic increase in call reliability when receiving a call from the foreground/background and from an app killed state.