Integración con CallKit
En este documento, veremos cómo integrar CallKit con la aplicación iOS.
Requisitos previos
- Una cuenta de Azure con una suscripción activa. Cree una cuenta gratuita.
- Un recurso de Communication Services implementado. Cree un recurso de Communication Services.
- Un token de acceso de usuario para habilitar el cliente de llamada. Para más información, consulte Inicio rápido: Creación y administración de tokens de acceso.
- Opcional: Realice el inicio rápido para agregar llamadas de voz a la aplicación
Integración de CallKit (dentro del SDK)
La integración de CallKit en el SDK de iOS de Azure Communication Services controla la interacción con CallKit para nosotros. Para realizar operaciones de llamada como silenciar o desactivar, mantener o reanudar, solo es necesario llamar a la API en el SDK de Azure Communication Services.
Inicialización del agente de llamadas con CallKitOptions
Con la instancia configurada de CallKitOptions
, podemos crear con el CallAgent
control 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
})
Especificar la información del destinatario de la llamada para las llamadas salientes
En primer lugar, es necesario crear una instancia de StartCallOptions()
para las llamadas salientes o JoinCallOptions()
para la llamada de grupo:
let options = StartCallOptions()
o
let options = JoinCallOptions()
A continuación, cree una instancia de CallKitRemoteInfo
options.callKitRemoteInfo = CallKitRemoteInfo()
- Asigne valor para que personalice el nombre para
callKitRemoteInfo.displayNameForCallKit
mostrar de los destinatarios de la llamada y configureCXHandle
el valor. Este valor especificado endisplayNameForCallKit
es exactamente cómo se muestra en el último registro de llamadas marcados. en el último registro de llamadas marcado.
options.callKitRemoteInfo.displayNameForCallKit = "DISPLAY_NAME"
- Asignar el
cxHandle
valor es lo que recibe la aplicación cuando el usuario vuelve a llamar a ese contacto.
options.callKitRemoteInfo.cxHandle = CXHandle(type: .generic, value: "VALUE_TO_CXHANDLE")
Especificar la información del destinatario de la llamada para las llamadas entrantes
En primer lugar, es necesario crear una instancia de CallKitOptions
:
let callKitOptions = CallKitOptions(with: createProviderConfig())
Configure las propiedades de CallKitOptions
la instancia:
El SDK llamará al bloque que se pasa a la variable provideRemoteInfo
cuando recibamos una llamada entrante y necesitamos obtener un nombre para mostrar para el autor de la llamada entrante, que necesitamos pasar al 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
}
Configuración de la sesión de audio
Se llamará a la sesión de audio antes de colocar o aceptar la llamada entrante y antes de reanudar la llamada después de que se haya puesto en espera.
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
}
NOTA: En los casos en los que Contoso ya ha configurado sesiones de audio NO proporcione nil
pero devuelva nil
el error en el bloque.
callKitOptions.configureAudioSession = self.configureAudioSession
public func configureAudioSession() -> Error? {
return nil
}
si nil
se proporciona para configureAudioSession
, el SDK llama a la implementación predeterminada en el SDK.
Control de la carga de notificaciones de inserción entrantes
Cuando la aplicación recibe la carga de notificación de inserción entrante, es necesario llamar handlePush
a para procesarla. El SDK de llamadas de Azure Communication Services generará el IncomingCall
evento.
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) {
}
Podemos usar reportIncomingCall
para controlar las notificaciones push cuando la aplicación está cerrada o de lo contrario.
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)
}
}
}
Integración de CallKit (dentro de la aplicación)
Si desea integrar CallKit en la aplicación y no usar la implementación de CallKit en el SDK, consulte el ejemplo de inicio rápido aquí. Pero una de las cosas importantes que se deben cuidar es iniciar el audio en el momento adecuado. Al igual que a continuación
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)
Silenciar el altavoz y el micrófono garantizan que los dispositivos de audio físicos no se usen hasta que CallKit llame a didActivateAudioSession
en CXProviderDelegate
. De lo contrario, la llamada puede quitarse o el audio no funcionará.
Cuando didActivateAudioSession
es cuando se deben iniciar las secuencias de audio.
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()
}
Es importante silenciar también el audio saliente antes de detener el audio en casos en los que CallKit no invoca didActivateAudioSession
. A continuación, el usuario puede desactivar manualmente el micrófono.
Nota:
En algunos casos CallKit no llama didActivateAudioSession
a aunque la aplicación tenga permisos de audio elevados, en ese caso el audio permanecerá silenciado hasta que se reciba la devolución de llamada. Y la interfaz de usuario tiene que reflejar el estado del altavoz y el micrófono. Los participantes remotos de la llamada verán que el usuario también ha silenciado el audio. El usuario tendrá que desactivar manualmente en esos casos.