CallKit with AWS chime.

Report for developing ios application with callkit and aws chime, only incoming call.

I have been developing ios application with CallKit and AWS Chime these days. It has only incoming call feature, no outgoing call.

I encountered some problems and I found the causes of them. I report one of them for future me and someone else. The problem is

When I called start(callKitEnabled: true), the result would be error with code .audioFailedToStart only when CallKit UI were being displayed.

The important thing is AudioSession can get interrupted by system for many reasons. Receiving a phone call is also included. When you receive a voip push, you must display CallKit UI calling reportNewIncomingCall method. This is a CallKit way.

Let's begin with pseudo-code looks like swift.

1: Add observer to check whether the current audio session is interrupted at somewhere.

1NotificationCenter.default.addObserver(self, selector: #selector(handle), name: AVAudioSession.interruptionNotification, object: AVAudioSession.sharedInstance())
3@objc func handle(_ notification: Notification) {
4 let info = notification.userInfo
5 let interruptionType = info?["AVAudioSessionInterruptionTypeKey"]
6 let interruptionReason = info?["AVAudioSessionInterruptionReasonKey"]
7 print("CallKit+AWSChime: \(interruptionType!) \(AVAudioSession.InterruptionType.began) \(AVAudioSession.InterruptionType.ended)")
8 print("CallKit+AWSChime: \(interruptionReason!) \(AVAudioSession.InterruptionReason.default)")

2: Prepare voip push handling method.

1func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
2 // assuming type is voip
4 print("CallKit+AWSChime: received voip payload and call reportNewIncomingCall")
5 configureAudioSession() // configure audio session here to check the interruption.
6 reportNewIncomingCall()

3: Prepare delegate method for answering/accepting call.

1func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
2 print("CallKit+AWSChime: CXProvider answerCallAction")
3 action.fulfill()

4: Prepare delegate method for checking audio session is activated.

1func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
2 print("CallKit+AWSChime: audio session didActivate")

Check logs on console running this application.

The result was the following.

1CallKit+AWSChime: received voip payload and call reportNewIncomingCall
2CallKit+AWSChime: 1 AVAudioSessionInterruptionType(rawValue: 1) AVAudioSessionInterruptionType(rawValue: 0)
3CallKit+AWSChime: 0 AVAudioSessionInterruptionReason(rawValue: 0)
4CallKit+AWSChime: CXProvider answerCallAction
5CallKit+AWSChime: audio session didActivate

When calling reportNewIncomingCall, the current audio session is interrupted by system. The second line shows that. The value 1 means audio session interruption began. Accepting the call, CallKit system seems to make audio session activated.

The interruption seems to be end pulling up CallKit UI.

The figure on left shows CallKit UI is displaying. In this case, audio session is interrupted. Swiping the bar up, CallKit UI is minimized. In this case, audio session interruption is ended.

My consideration.

As described above, CallKit system can interrupt current audio session. The interruption continues until the call terminate. In other words, while CallKit UI is displaying we cannot control audio session.

I thought this is why the chime method, start(callKitEnabled: true), failed to start. I tried just start() or start(callKitEnabled: false) but the result was same.

If you found any mistake, please contact me

Thank you.