Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este documento, veremos cómo integrar CallKit con la aplicación iOS.
Prerrequisitos
- Una cuenta de Azure con una suscripción activa. Cree una cuenta gratuita.
- Un recurso de Communication Services implementado. Creación de 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: Complete 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 el CallAgent con el manejo 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()
or
let options = JoinCallOptions()
A continuación, cree una instancia de CallKitRemoteInfo
options.callKitRemoteInfo = CallKitRemoteInfo()
- Asigne un valor para
callKitRemoteInfo.displayNameForCallKita fin de personalizar el nombre para mostrar de los destinatarios de la llamada y configure el valorCXHandle. El valor especificado endisplayNameForCallKites exactamente tal como aparece en el último registro de llamadas marcadas. en el registro de la última llamada realizada.
options.callKitRemoteInfo.displayNameForCallKit = "DISPLAY_NAME"
- Asignar el valor
cxHandlees lo que recibe la aplicación cuando el usuario vuelve a llamar en 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 la instancia CallKitOptions.
El bloque que se pasa a la variable provideRemoteInfo será llamado por el SDK cuando recibamos una llamada entrante y necesitemos obtener un nombre para mostrar del llamante entrante, el cual deberemos 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 configurará la sesión de audio antes de realizar o aceptar una 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 sino que devuelva el error nil en el bloque.
callKitOptions.configureAudioSession = self.configureAudioSession
public func configureAudioSession() -> Error? {
return nil
}
si se proporciona nil para configureAudioSession, entonces el SDK llama a la implementación predeterminada en el SDK.
Gestionar la carga útil de notificaciones push entrantes
Cuando la aplicación recibe la carga de notificaciones push entrantes, es necesario llamar a handlePush para procesarla. El SDK de llamadas de Azure Communication Services generará el evento 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, didReceiveIncomingCall 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. Como se indica 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 garantiza que los dispositivos de audio físicos no se usen hasta que CallKit invoque 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 a didActivateAudioSession aunque la aplicación tenga permisos de audio elevados, en ese caso el audio permanecerá silenciado hasta que se reciba la llamada de retorno. 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 reactivar el audio manualmente en esos casos.