Integração com o CallKit
Neste documento, veremos como integrar o CallKit ao seu aplicativo iOS.
Pré-requisitos
- Uma conta do Azure com uma assinatura ativa. Crie uma conta gratuitamente.
- Um recurso dos Serviços de Comunicação implantado. Crie um recurso dos Serviços de Comunicação.
- Um token de acesso de usuário para habilitar o cliente de chamada. Para saber mais, confira Criar e gerenciar token de acesso.
- Opcional: conclua o guia de início rápido para adicionar uma chamada de voz ao seu aplicativo
Integração do CallKit (dentro do SDK)
A integração do CallKit no SDK do iOS dos Serviços de Comunicação do Azure lida com a interação com o CallKit para nós. Para executar quaisquer operações de chamada como silenciar/desativar o som, reter/retomar, só precisamos chamar a API no SDK dos Serviços de Comunicação do Azure.
Inicializar agente de chamada com CallKitOptions
Com a instância configurada do , podemos criar o CallAgent
tratamento com do .CallKitOptions
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 informações do destinatário da chamada para chamadas de saída
Primeiro, precisamos criar uma instância de para chamadas de saída ou JoinCallOptions()
para chamadas em StartCallOptions()
grupo:
let options = StartCallOptions()
ou
let options = JoinCallOptions()
Em seguida, crie uma instância de CallKitRemoteInfo
options.callKitRemoteInfo = CallKitRemoteInfo()
- Atribua valor para personalizar o nome de exibição para
callKitRemoteInfo.displayNameForCallKit
destinatários de chamada e configureCXHandle
o valor. Esse valor especificado emdisplayNameForCallKit
é exatamente como ele aparece no último log de chamadas discadas. no último registro de chamadas discado.
options.callKitRemoteInfo.displayNameForCallKit = "DISPLAY_NAME"
- Atribuir o valor é o que o aplicativo recebe quando o
cxHandle
usuário chama de volta esse contato
options.callKitRemoteInfo.cxHandle = CXHandle(type: .generic, value: "VALUE_TO_CXHANDLE")
Especificar informações do destinatário da chamada para chamadas recebidas
Primeiro precisamos criar uma instância de CallKitOptions
:
let callKitOptions = CallKitOptions(with: createProviderConfig())
Configure as propriedades da CallKitOptions
instância:
O bloco que é passado para variável provideRemoteInfo
será chamado pelo SDK quando recebermos uma chamada de entrada e precisamos obter um nome de exibição para o chamador de entrada, que precisamos passar para o 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
}
Configurar sessão de áudio
Configurar sessão de áudio será chamado antes de fazer ou aceitar chamada de entrada e antes de retomar a chamada depois de ter sido colocada em 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
}
Observação : nos casos em que a Contoso já configurou sessões de áudio NÃO fornecer nil
, mas retornar nil
erro no bloco
callKitOptions.configureAudioSession = self.configureAudioSession
public func configureAudioSession() -> Error? {
return nil
}
se nil
for fornecido configureAudioSession
, o SDK chama a implementação padrão no SDK.
Lidar com a carga de notificação por push recebida
Quando o aplicativo recebe a carga de notificação por push recebida, precisamos ligar handlePush
para processá-la. O SDK de Chamada dos Serviços de Comunicação do Azure gerará o 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 lidar com notificações push quando o aplicativo é fechado ou de outra forma.
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)
}
}
}
Integração do CallKit (dentro do aplicativo)
Se você deseja integrar o CallKit no aplicativo e não usar a implementação do CallKit no SDK, consulte o exemplo de início rápido aqui. Mas uma das coisas importantes a se cuidar é iniciar o áudio no momento certo. Curta a seguir
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)
O silenciamento do alto-falante e do microfone garante que os dispositivos de áudio físicos não sejam usados até que o CallKit ligue o didActivateAudioSession
CXProviderDelegate
. Caso contrário, a chamada pode ser descartada ou o áudio não funcionará.
Quando didActivateAudioSession
é quando os fluxos de áudio devem ser iniciados.
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()
}
É importante também silenciar o áudio de saída antes de parar o áudio nos casos em que o CallKit não invoca didActivateAudioSession
o . O usuário pode então desativar manualmente o som do microfone.
Observação
Em alguns casos, o CallKit não chama didActivateAudioSession
mesmo que o aplicativo tenha permissões de áudio elevadas, nesse caso o áudio permanecerá mudo até que a chamada de volta seja recebida. E a interface do usuário precisa refletir o estado do alto-falante e do microfone. O(s) participante(s) remoto(s) na chamada verá que o usuário também silenciou o áudio. O usuário terá que desativar manualmente o som nesses casos.