This is a common requirement for iOS apps that use IceLink. Apple has some documentation on getting started with CallKit that will show you how to receive push notifications, handle incoming calls, make outgoing calls, etc. Once you have finished reading through that you will probably be left wondering how to wire all of this CallKit functionality into the IceLink API. Here, we provide some advice on how to integrate your IceLink app with CallKit based on our own experience working with the CallKit API.
Be sure you set the proper audio session category so you can hear audio!
Callkit integration is an application level concern. The IceLink API can be integrated successfully with CallKit, but this is done entirely in application code. That said, it is recommended that you implement your CallKit integration using the most recently released version of IceLink to ensure you have any improvements to the
CocoaAudioUnitSource, and the other necessary Cocoa APIs.
- In a CallKit integrated app you do not configure the
RemoteMedia(as our examples do). Instead you configure the
AVAudioSessionwhen you answer the call. CallKit then takes the
AVAudioSessionover, and finally returns it to your app when the call is activated. We demonstrate this in a code snippet below.
- You should only start LocalMedia after CallKit activates the call and gives you the
- You should properly handle the case where the user has first installed the app and needs to provide permissions for the mic and camera. You do not want the app to be asking for camera and mic permissions while the user is trying to answer their first call with CallKit. The recommended way to achieve this is to create and start a "throw away"
LocalMediaon your app's first screen the first time the user opens the app. This way you uncouple acquiring permissions from receipt of an incoming call.
- When a user answers a call with your app when the phone is not locked, then the local view will appear black until the call connects and
LocalMediais started. Recall that with CallKit we cannot start
LocalMediauntil after the connection is established, so this is expected behaviour. It is recommended that you show something else to your users ... some UI telling them that a call is connecting.
- We have provided abstractions of a
Call, and a
CallManager, for your convenience. These classes are based heavily off of Apple's CallKit integration examples and you are welcome to use them.
CallManager.swiftprovides a collection of calls and functions to manage them, and
Call.swiftis a convenience class for maintaining the state of a call.
Now, let's take a look at how to answer a CallKit call. We recommend using a provider class to manage all of the CallKit related events. This
ProviderDelegate can be used in conjunction with the provided
CallManager classes to encapsulate all CallKit related code integrations. There are a few things our CallKit
ProviderDelegate will need to do. Obviously, it needs to answer calls and end calls. As discussed in point three above it also needs to start
LocalMedia after CallKit has activated the
AVAudioSession. It should also handle the case where the CallKit
CXProvider, your telephony provider, is externally reset. Let's handle the reset first because it is nice and simple:
Easy enough. Now let's look at something more complex - answering an incoming CallKit call. One of the key pieces in this snippet is the event handler for
onConnected. This event handler is set here where the
CXAnswerCallAction is performed, but fired from the connection handling logic when your connection transitions to the
When you have answered a call CallKit takes control of the (shared)
AVAudioSession that you configured and makes use of it. It then passes it back to your app letting you know that the
AVAudioSession has been activated for the given provider. It is at this point, and not before, that you should start your
LocalMedia as shown here. At this point you must also make sure that you tell iOS you want to get notified of audio interruptions being ended. This is necessary so that when an audio interruption ends, iOS will let your application know the interruption has ended, and the
CocoaAudioSource will then resume raising frames:
Also take care of any non-call related audio:
Next lets take care of a call that gets muted:
Now lets take care of a call Held:
So, that takes care of answering a call, IceLink connection management, and activating the call, but you'll also need to handle the user ending a call via CallKit. This involves tearing down your connection(s) and LocalMedia, and generally cleaning up, and then of course letting CallKit know that you are done.