Intégrer à CallKit

Dans ce document, nous allons découvrir comment intégrer CallKit à votre application iOS.

Prérequis

Intégration de CallKit (dans le SDK)

L’intégration de CallKit dans le Kit de développement logiciel (SDK) iOS Azure Communication Services gère l’interaction avec CallKit pour nous. Pour effectuer des opérations d’appel telles que le son/le son, la conservation/la reprise, nous devons uniquement appeler l’API sur le Kit de développement logiciel (SDK) Azure Communication Services.

Initialiser l’agent d’appel avec CallKitOptions

Avec l’instance configurée de CallKitOptions, nous pouvons créer l’instance CallAgent avec la gestion de CallKit.

let options = CallAgentOptions()
let callKitOptions = CallKitOptions(with: createProviderConfig())
options.callKitOptions = callKitOptions

// Configure the properties of `CallKitOptions` instance here

self.callClient!.createCallAgent(userCredential: userCredential,
    options: options,
    completionHandler: { (callAgent, error) in
    // Initialization
})

Spécifier les informations du destinataire d’appel pour les appels sortants

Tout d’abord, nous devons créer une instance d’appels StartCallOptions() sortants ou JoinCallOptions() d’appel de groupe :

let options = StartCallOptions()

or

let options = JoinCallOptions()

Ensuite, créez une instance de CallKitRemoteInfo

options.callKitRemoteInfo = CallKitRemoteInfo()
  1. Attribuez une valeur pour callKitRemoteInfo.displayNameForCallKit personnaliser le nom complet des destinataires d’appel et configurez CXHandle la valeur. Cette valeur spécifiée est displayNameForCallKit exactement la façon dont elle s’affiche dans le dernier journal des appels composés. dans le dernier journal des appels composés.
options.callKitRemoteInfo.displayNameForCallKit = "DISPLAY_NAME"
  1. Affecter la cxHandle valeur est ce que l’application reçoit lorsque l’utilisateur revient sur ce contact
options.callKitRemoteInfo.cxHandle = CXHandle(type: .generic, value: "VALUE_TO_CXHANDLE")

Spécifier les informations du destinataire d’appel pour les appels entrants

Tout d’abord, nous devons créer une instance de CallKitOptions:

let callKitOptions = CallKitOptions(with: createProviderConfig())

Configurez les propriétés de l’instance CallKitOptions :

Le bloc passé à la variable provideRemoteInfo sera appelé par le Kit de développement logiciel (SDK) lorsque nous recevons un appel entrant et que nous devons obtenir un nom complet pour l’appelant entrant, que nous devons passer au CallKit.

callKitOptions.provideRemoteInfo = self.provideCallKitRemoteInfo

func provideCallKitRemoteInfo(callerInfo: CallerInfo) -> CallKitRemoteInfo
{
    let callKitRemoteInfo = CallKitRemoteInfo()
    callKitRemoteInfo.displayName = "CALL_TO_PHONENUMBER_BY_APP"      
    callKitRemoteInfo.cxHandle = CXHandle(type: .generic, value: "VALUE_TO_CXHANDLE")
    return callKitRemoteInfo
}

Configurer la session audio

Configurez la session audio avant de placer ou d’accepter l’appel entrant et avant de reprendre l’appel une fois qu’il a été mis en attente.

callKitOptions.configureAudioSession = self.configureAudioSession

public func configureAudioSession() -> Error? {
    let audioSession: AVAudioSession = AVAudioSession.sharedInstance()
    var configError: Error?
    do {
        try audioSession.setCategory(.playAndRecord)
    } catch {
        configError = error
    }
    return configError
}

REMARQUE : Dans les cas où Contoso a déjà configuré des sessions audio ne fournissent pas mais ne retournent nil nil pas d’erreur dans le bloc

callKitOptions.configureAudioSession = self.configureAudioSession

public func configureAudioSession() -> Error? {
    return nil
}

s’il nil est fourni pour configureAudioSession le kit SDK appelle l’implémentation par défaut dans le Kit de développement logiciel (SDK).

Gérer la charge utile de notification Push entrante

Lorsque l’application reçoit une charge utile de notification Push entrante, nous devons l’appeler handlePush pour le traiter. Le Kit de développement logiciel (SDK) d’appel Azure Communication Services déclenche l’événement IncomingCall .

public func handlePushNotification(_ pushPayload: PKPushPayload)
{
    let callNotification = PushNotificationInfo.fromDictionary(pushPayload.dictionaryPayload)
    if let agent = self.callAgent {
        agent.handlePush(notification: callNotification) { (error) in }
    }
}

// Event raised by the SDK
public func callAgent(_ callAgent: CallAgent, didRecieveIncomingCall incomingcall: IncomingCall) {
}

Nous pouvons utiliser reportIncomingCall pour gérer les notifications Push lorsque l’application est fermée ou autrement.

if let agent = self.callAgent {
  /* App is not in a killed state */
  agent.handlePush(notification: callNotification) { (error) in }
} else {
  /* App is in a killed state */
  CallClient.reportIncomingCall(with: callNotification, callKitOptions: callKitOptions) { (error) in
      if (error == nil) {
          DispatchQueue.global().async {
              self.callClient = CallClient()
              let options = CallAgentOptions()
              let callKitOptions = CallKitOptions(with: createProviderConfig())
              callKitOptions.provideRemoteInfo = self.provideCallKitRemoteInfo
              callKitOptions.configureAudioSession = self.configureAudioSession
              options.callKitOptions = callKitOptions
              self.callClient!.createCallAgent(userCredential: userCredential,
                  options: options,
                  completionHandler: { (callAgent, error) in
                  if (error == nil) {
                      self.callAgent = callAgent
                      self.callAgent!.handlePush(notification: callNotification) { (error) in }
                  }
              })
          }
      } else {
          os_log("SDK couldn't handle push notification", log:self.log)
      }
  }
}

Intégration de CallKit (dans l’application)

Si vous souhaitez intégrer le CallKit dans l’application et ne pas utiliser l’implémentation CallKit dans le Kit de développement logiciel (SDK), reportez-vous à l’exemple de démarrage rapide ici. Mais l’une des choses importantes à prendre en charge est de démarrer l’audio au bon moment. Comme suit

let outgoingAudioOptions = OutgoingAudioOptions()
outgoingAudioOptions.muted = true

let incomingAudioOptions = IncomingAudioOptions()
incomingAudioOptions.muted = true

var copyAcceptCallOptions = AcceptCallOptions()
copyStartCallOptions.outgoingAudioOptions = outgoingAudioOptions
copyStartCallOptions.incomingAudioOptions = incomingAudioOptions

callAgent.startCall(participants: participants,
                    options: copyStartCallOptions,
                    completionHandler: completionBlock)

Désactiver le haut-parleur et le microphone pour garantir que les périphériques audio physiques ne sont pas utilisés tant que le CallKit n’appelle pas le didActivateAudioSession CXProviderDelegatemicro. Sinon, l’appel peut être supprimé ou l’audio ne fonctionnera pas. Quand didActivateAudioSession est le moment où les flux audio doivent être démarrés.

func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
    Task {
        guard let activeCall = await self.callKitHelper.getActiveCall() else {
            print("No active calls found when activating audio session !!")
            return
        }

        try await startAudio(call: activeCall)
    }
}

func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
    Task {
        guard let activeCall = await self.callKitHelper.getActiveCall() else {
            print("No active calls found when deactivating audio session !!")
            return
        }

        try await stopAudio(call: activeCall)
    }
}

private func stopAudio(call: Call) async throws {
    try await self.callKitHelper.muteCall(callId: call.id, isMuted: true)
    try await call.stopAudio(stream: call.activeOutgoingAudioStream)

    try await call.stopAudio(stream: call.activeIncomingAudioStream)
    try await call.muteIncomingAudio()
}

private func startAudio(call: Call) async throws {
    try await call.startAudio(stream: LocalOutgoingAudioStream())
    try await self.callKitHelper.muteCall(callId: call.id, isMuted: false)

    try await call.startAudio(stream: RemoteIncomingAudioStream())
    try await call.unmuteIncomingAudio()
}
    

Il est important de désactiver également l’audio sortant avant d’arrêter l’audio dans les cas où CallKit n’appelle didActivateAudioSessionpas . L’utilisateur peut ensuite activer manuellement le microphone.

Remarque

Dans certains cas, CallKit n’appelle didActivateAudioSession pas même si l’application dispose d’autorisations audio élevées, dans ce cas, l’audio reste muet jusqu’à ce que le rappel soit reçu. Et l’interface utilisateur doit refléter l’état du haut-parleur et du microphone. Le participant/s distant dans l’appel voit également que l’utilisateur a désactivé l’audio. L’utilisateur devra désactiver manuellement le son dans ces cas.

Étapes suivantes