iOS dosen't call didActivateAudioSession

PLATFORM AND VERSION

iOS Development environment: Xcode 15.0, macOS 14.4.1, Objective-C

Run-time configuration: iOS 17.2.1,

DESCRIPTION OF PROBLEM

I am developing an application that uses NetworkExtension (VoIP local push function). But iOS sometimes doesn't call didActivateAudioSession after following sequence. Would you tell me why iOS doesn't call didActivateAudioSession ? (I said "sometimes", but once it occurs, it will occur repeatedly)

  1. myApp --- CXStartCallAction --->iOS
  2. myApp <-- performStartCallAction callback --- iOS
  3. myApp --- AVAudioSession setCategory: AVAudioSessionCategoryPlayAndRecord --->iOS
  4. myApp --- AVAudioSession setMode: AVAudioSessionModeVoiceChat --->iOS
  5. myApp <-- didActivateAudioSession callback ----iOS

I suspect that myApp cannot acquire an AVAudioSession if another app is already using AVAudioSession.

[QUESTION1]

Is my guess correct? Should I consider another cause?

[QUESTION2]

If my guess is correct, how can I prove if another app is already using an AVAudioSession? This issue is based on a customer complaint, but the customer said they don't use any other apps.

Best Regards,

Answered by DTS Engineer in 793622022

I am developing an application that uses NetworkExtension (VoIP local push function). But iOS sometimes doesn't call didActivateAudioSession after following sequence. Would you tell me why iOS doesn't call didActivateAudioSession ? (I said "sometimes", but once it occurs, it will occur repeatedly)

So, first and foremost, please review the "VoIP calling with CallKit". CallKit is closely entangled with the audio system and must be configured and controlled in exactly the way that sample shows. Incorrect usage will cause a variety of failures, including the one you're seeing.

Moving to your specific issue, the problem with this sequence here:

1. myApp --- CXStartCallAction --->iOS
2. myApp <-- performStartCallAction callback --- iOS
3. myApp --- AVAudioSession setCategory: AVAudioSessionCategoryPlayAndRecord --->iOS
4. myApp --- AVAudioSession setMode: AVAudioSessionModeVoiceChat --->iOS
5. myApp <-- didActivateAudioSession callback ----iOS

...is that you were trying to configure the AudioSession "to late". CallKit modifies your audio session as well as activating it and attempting to modify it after the call sequence has already started won't work (See below).

I suspect that myApp cannot acquire an AVAudioSession if another app is already using AVAudioSession.

Is my guess correct? Should I consider another cause?

No, or at least not in the way you mean.

The audio session category CallKit activates is NOT a "standard" AVAudioSessionCategoryPlayAndRecord category, but a "special" phone specific session. As an aside here, you can confirm this by listening closely to the maximum volume of a CallKit session vs. a standard AVAudioSessionCategoryPlayAndRecord. The CallKit session will be noticeably louder than the standard session.

In any case, that specific session type what CallKit uses to activate a recording session in the background, something which a standard session cannot. When you attempt to modify the category at the wrong time, one of two failures occur:

  1. IF the session is not active, you can disrupt CallKit's session activation process, causing the session to fail.

  2. IF the session IS active, then the category change will simply fail, since you cannot change the category configuration of an active session.

One other point to understand here is that not only is incorrect:

I suspect that myApp cannot acquire an AVAudioSession if another app is already using AVAudioSession.

...but the actual behavior is in fact the OPPOSITE of that. That is, NONE of the standard audio session types can interfere with the CallKit AudioSession. That is, it has higher activation priority than EVERY other audio session type on the system and CANNOT be interrupted by any of the public session categories. Audio issues inside CallKit apps are caused by how the app has configured "itself" because nothing else on the system has a high enough priority to interfere with the CallKit session. This is also why CallKit has its own system for switching between calls- CallKit has to coordinate between CallKit apps because the audio system itself won't let them directly interrupt each other.

Finally, keep in mind that Phone.app and Facetime are also CallKit apps. In terms of the audio layer, they're using the same API and have the same capabilities you have. If you're seeing very different audio behavior than they are, it's because of how you're using the API, not because they have additional abilities.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

I am developing an application that uses NetworkExtension (VoIP local push function). But iOS sometimes doesn't call didActivateAudioSession after following sequence. Would you tell me why iOS doesn't call didActivateAudioSession ? (I said "sometimes", but once it occurs, it will occur repeatedly)

So, first and foremost, please review the "VoIP calling with CallKit". CallKit is closely entangled with the audio system and must be configured and controlled in exactly the way that sample shows. Incorrect usage will cause a variety of failures, including the one you're seeing.

Moving to your specific issue, the problem with this sequence here:

1. myApp --- CXStartCallAction --->iOS
2. myApp <-- performStartCallAction callback --- iOS
3. myApp --- AVAudioSession setCategory: AVAudioSessionCategoryPlayAndRecord --->iOS
4. myApp --- AVAudioSession setMode: AVAudioSessionModeVoiceChat --->iOS
5. myApp <-- didActivateAudioSession callback ----iOS

...is that you were trying to configure the AudioSession "to late". CallKit modifies your audio session as well as activating it and attempting to modify it after the call sequence has already started won't work (See below).

I suspect that myApp cannot acquire an AVAudioSession if another app is already using AVAudioSession.

Is my guess correct? Should I consider another cause?

No, or at least not in the way you mean.

The audio session category CallKit activates is NOT a "standard" AVAudioSessionCategoryPlayAndRecord category, but a "special" phone specific session. As an aside here, you can confirm this by listening closely to the maximum volume of a CallKit session vs. a standard AVAudioSessionCategoryPlayAndRecord. The CallKit session will be noticeably louder than the standard session.

In any case, that specific session type what CallKit uses to activate a recording session in the background, something which a standard session cannot. When you attempt to modify the category at the wrong time, one of two failures occur:

  1. IF the session is not active, you can disrupt CallKit's session activation process, causing the session to fail.

  2. IF the session IS active, then the category change will simply fail, since you cannot change the category configuration of an active session.

One other point to understand here is that not only is incorrect:

I suspect that myApp cannot acquire an AVAudioSession if another app is already using AVAudioSession.

...but the actual behavior is in fact the OPPOSITE of that. That is, NONE of the standard audio session types can interfere with the CallKit AudioSession. That is, it has higher activation priority than EVERY other audio session type on the system and CANNOT be interrupted by any of the public session categories. Audio issues inside CallKit apps are caused by how the app has configured "itself" because nothing else on the system has a high enough priority to interfere with the CallKit session. This is also why CallKit has its own system for switching between calls- CallKit has to coordinate between CallKit apps because the audio system itself won't let them directly interrupt each other.

Finally, keep in mind that Phone.app and Facetime are also CallKit apps. In terms of the audio layer, they're using the same API and have the same capabilities you have. If you're seeing very different audio behavior than they are, it's because of how you're using the API, not because they have additional abilities.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi

Thank you for your response. I am sorry. my before descrption was incorrect. myApp is executing following sequence.

But iPhone sometimes doesn't call didActivateAudioSession of step6 after this sequence. (I said "sometimes", but once it occurs, it will occur repeatedly)

How about this sequence? If you have some notice about it, could you tell me it?

  1. myApp --- AVAudioSession setCategory: AVAudioSessionCategoryPlayAndRecord --->iOS myApp <-- return YES ---- iOS

  2. myApp --- AVAudioSession setMode: AVAudioSessionModeVoiceChat --->iOS myApp <-- return YES ---- iOS

  3. myApp --- AVAudioSession setActive:YES --->iOS myApp <-- return YES ---- iOS

  4. myApp --- CXStartCallAction --->iOS

  5. myApp <-- performStartCallAction callback --- iOS

  6. myApp <-- didActivateAudioSession callback ----iOS

Hi

////////

I'll correct the line breaks and repost it.

////////

Thank you for your response. I am sorry. my before descrption was incorrect. myApp is executing following sequence.

But iPhone sometimes doesn't call didActivateAudioSession of step6 after this sequence. (I said "sometimes", but once it occurs, it will occur repeatedly)

How about this sequence? If you have some notice about it, could you tell me it?

  1. myApp --- AVAudioSession setCategory: AVAudioSessionCategoryPlayAndRecord --->iOS

    myApp <-- return YES ---- iOS

  2. myApp --- AVAudioSession setMode: AVAudioSessionModeVoiceChat --->iOS

    myApp <-- return YES ---- iOS

  3. myApp --- AVAudioSession setActive:YES --->iOS

    myApp <-- return YES ---- iOS

  4. myApp --- CXStartCallAction --->iOS

  5. myApp <-- performStartCallAction callback --- iOS

  6. myApp <-- didActivateAudioSession callback ----iOS

Hi DTS Engineer,

What about my last comment?

Do you need some additinal infomation?

FYI, I took a few days off at the end of the week and just got back to work today.

What about my last comment? Do you need some additinal infomation?

No, the problem is here:

  1. myApp --- AVAudioSession setActive:YES --->iOS

Don't do that.

CallKit apps should NOT attempt to activate their own audio sessions, as doing so can prevent CallKit from doing the necessary modifications and activations. If you review "VoIP calling with CallKit" as I suggested, you'll find that it does NOT activate it own session, except for a single "setActive" call inside it's interruption handler.

Note that what you said here is what I'd generally expect:

But iPhone sometimes doesn't call didActivateAudioSession of step6 after this sequence. (I said "sometimes", but once it occurs, it will occur repeatedly)

Once you've activated the session incorrectly, CallKit can then get "stuck" in the broken cycle, keeping you locked in that cycle.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

iOS dosen't call didActivateAudioSession
 
 
Q