Different versions of iOS deal with AVAudioSession interruptions sightly differently. This section documents how the Programmable Voice iOS SDK manages audio interruptions and resumes call audio after the interruption ends. There are currently some cases that the SDK cannot resume call audio automatically because iOS does not provide the necessary notifications to indicate that the interruption has ended.
- The
TVOCall
object registers itself as an observer ofAVAudioSessionInterruptionNotification
when it's created. - When the notification is fired and the interruption type is
AVAudioSessionInterruptionTypeBegan
, theTVOCall
object automatically disables both the local and remote audio tracks. - When the SDK receives the notification with
AVAudioSessionInterruptionTypeEnded
, it re-enables the local and remote audio tracks and resumes the audio of active Calls.- We have noticed that on iOS 8 and 9, the interruption notification with
AVAudioSessionInterruptionTypeEnded
is not always fired therefore the SDK is not able to resume call audio automatically. This is a known issue and an alternative way is to use theUIApplicationDidBecomeActiveNotification
and resume audio when the app is active again after the interruption.
- We have noticed that on iOS 8 and 9, the interruption notification with
Below is a table listing the system notifications received with different steps to trigger audio interruptions and resume during an active Voice SDK call. (Assume the app is in an active Voice SDK call)
Scenario | Notification of interruption-begins | Notification of interruption-ends | Call audio resumes? | Note |
---|---|---|---|---|
PSTN Interruption | ||||
A. PSTN interruption Accept the PSTN incoming call Remote party of PSTN call hangs up |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
|
B. PSTN interruption Accept the PSTN incoming call Local party of PSTN call hangs up |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
|
C. PSTN interruption Reject PSTN |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
|
D. PSTN interruption Ignore PSTN |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
|
E. PSTN interruption Remote party of PSTN call hangs up before local party can answer |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
|
Other Types of Audio Interruption (YouTube app as example) |
||||
F. Switch to YouTube app and play video Stop the video Switch back to Voice app |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
❌ iOS 9 ✅ iOS 10 ✅ iOS 11 |
❌ iOS 9 ✅ iOS 10 ✅ iOS 11 |
Interruption-ended notification is not fired on iOS 9. Interruption-ended notification is not fired until few seconds after switching back to the Voice app on iOS 10/11. The AVAudioSessionInterruptionOptionShouldResume flag is false . |
G. Switch to YouTube app and play video Switch back to Voice app without stopping the video |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
❌ iOS 9 ✅ iOS 10 ✅ iOS 11 |
❌ iOS 9 ✅ iOS 10 ✅ iOS 11 |
Interruption-ended notification is not fired on iOS 9. Interruption-ended notification is not fired until few seconds after switching back to the Voice app on iOS 10/11. The AVAudioSessionInterruptionOptionShouldResume flag is false . |
H. Switch to YouTube app and play video Double-press Home button and terminate YouTube app Back to Voice app |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
✅ iOS 9 ✅ iOS 10 ✅ iOS 11 |
Interruption-ended notification is not fired until the Voice app is back to the active state. The AVAudioSessionInterruptionOptionShouldResume flag is false . |
On iOS 10 and later, CallKit (if integrated) takes care of the interruption by providing a set of delegate methods so that the application can respond with proper audio device handling and state transitioning in order to ensure call audio works after the interruption has ended.
By enabling the supportsHolding
flag of the CXCallUpdate
object when reporting a call to the CallKit framework, you will see the "Hold & Accept" option when there is another PSTN or CallKit-enabled call. By pressing the "Hold & Accept" option, a series of things and callbacks will happen:
- The
provider:performSetHeldCallAction:
delegate method is called withCXSetHeldCallAction.isOnHold = YES
. Put the Voice call on-hold here and fulfill the action. - The
AVAudioSessionInterruptionNotification
notification is fired to indicate the AVAudioSession interruption has started. - CallKit will deactivate the AVAudioSession of your app and fire the
provider:didDeactivateAudioSession:
callback. - When the interrupting call ends, instead of getting the
AVAudioSessionInterruptionNotification
notification, the system will notify that you can resume the call audio that was put on-hold when the interruption began by calling theprovider:performSetHeldCallAction:
method again. Note that this callback is not fired if the interrupting call is disconnected by the remote party. - The AVAudioSession of the app will be activated again and you should re-enable the audio device of the SDK
TwilioVoice.audioDevice.enabled = YES
in theprovider:didActivateAudioSession:
method.
Scenario | Audio resumes after interrupion? | Note |
---|---|---|
A. Hold & Accept Hang up PSTN interruption on the local end |
✅ iOS 10 ✅ iOS 11 |
|
B. Hold & Accept Remote party hangs up PSTN interruption |
❌ iOS 10 ❌ iOS 11 |
provider:performSetHeldCallAction: not called after the interruption ends. |
C. Hold & Accept Switch back to the Voice Call on system UI |
✅ iOS 10 ✅ iOS 11 |
|
D. Reject |
✅ iOS 10 ✅ iOS 11 |
No actual audio interruption happened since the interrupting call is not answered |
E. Ignore |
✅ iOS 10 ✅ iOS 11 |
No actual audio interruption happened since the interrupting call is not answered |
In case 2, CallKit does not automatically resume call audio by calling provider:performSetHeldCallAction:
method, but the system UI will show that the Voice call is still on-hold. You can resume the call using the "Hold" button, or use the CXSetHeldCallAction
to lift the on-hold state programmatically. The app is also responsible of updating UI state to indicate the "hold" state of the call to avoid user confusion.
// Resume call audio programmatically after interruption
CXSetHeldCallAction *setHeldCallAction = [[CXSetHeldCallAction alloc] initWithCallUUID:self.call.uuid onHold:holdSwitch.on];
CXTransaction *transaction = [[CXTransaction alloc] initWithAction:setHeldCallAction];
[self.callKitCallController requestTransaction:transaction completion:^(NSError *error) {
if (error) {
NSLog(@"Failed to submit set-call-held transaction request");
} else {
NSLog(@"Set-call-held transaction successfully done");
}
}];