Udostępnij za pośrednictwem


Integracja z zestawem CallKit

W tym dokumencie omówimy sposób integracji biblioteki CallKit z aplikacją systemu iOS.

Wymagania wstępne

Integracja zestawu CallKit (w zestawie SDK)

Integracja zestawu CallKit w zestawie SDK usług Azure Communication Services dla systemu iOS obsługuje interakcję z zestawem CallKit dla nas. Aby wykonać wszystkie operacje wywołania, takie jak wyciszenie/wyciszenie, blokada/wznawianie, musimy wywołać interfejs API tylko w zestawie SDK usług Azure Communication Services.

Inicjowanie agenta wywołania za pomocą elementu CallKitOptions

Za pomocą skonfigurowanego CallKitOptionswystąpienia programu możemy utworzyć element CallAgent z obsługą elementu 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
})

Określanie informacji adresata połączenia dla połączeń wychodzących

Najpierw musimy utworzyć wystąpienie dla połączeń wychodzących StartCallOptions() lub JoinCallOptions() wywołania grupy:

let options = StartCallOptions()

lub

let options = JoinCallOptions()

Następnie utwórz wystąpienie klasy CallKitRemoteInfo

options.callKitRemoteInfo = CallKitRemoteInfo()
  1. Przypisz wartość , callKitRemoteInfo.displayNameForCallKit aby dostosować nazwę wyświetlaną adresatów wywołań i skonfigurować CXHandle wartość. Ta wartość określona w parametrze displayNameForCallKit jest dokładnie taka, jak jest wyświetlana w ostatnim dzienniku połączeń telefonicznych. w ostatnim dzienniku połączeń telefonicznych.
options.callKitRemoteInfo.displayNameForCallKit = "DISPLAY_NAME"
  1. Przypisz wartość odbieraną przez aplikację cxHandle , gdy użytkownik odwołuje się do tego kontaktu
options.callKitRemoteInfo.cxHandle = CXHandle(type: .generic, value: "VALUE_TO_CXHANDLE")

Określanie informacji adresata połączenia dla połączeń przychodzących

Najpierw musimy utworzyć wystąpienie klasy CallKitOptions:

let callKitOptions = CallKitOptions(with: createProviderConfig())

Skonfiguruj właściwości CallKitOptions wystąpienia:

Blok przekazywany do zmiennej provideRemoteInfo będzie wywoływany przez zestaw SDK podczas odbierania wywołania przychodzącego i musimy uzyskać nazwę wyświetlaną dla elementu wywołującego przychodzącego, który musimy przekazać do zestawu 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
}

Konfigurowanie sesji audio

Konfiguracja sesji audio zostanie wywołana przed umieszczeniem lub zaakceptowaniem połączenia przychodzącego i przed wznowieniem połączenia po jego wstrzymaniu.

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
}

UWAGA: W przypadkach, gdy firma Contoso skonfigurowała już sesje audio, nie udostępniaj nil , ale zwraca nil błąd w bloku

callKitOptions.configureAudioSession = self.configureAudioSession

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

jeśli nil zostanie podany dla configureAudioSession zestawu SDK, zestaw SDK wywołuje domyślną implementację w zestawie SDK.

Obsługa przychodzącego ładunku powiadomień wypychanych

Gdy aplikacja odbiera przychodzący ładunek powiadomień wypychanych, musimy wywołać handlePush metodę , aby ją przetworzyć. Wywołanie zestawu SDK usług Azure Communication Services spowoduje wywołanie IncomingCall zdarzenia.

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) {
}

Możemy użyć reportIncomingCall metody do obsługi powiadomień wypychanych, gdy aplikacja jest zamknięta lub w inny sposób.

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)
      }
  }
}

Integracja z zestawem CallKit (w aplikacji)

Jeśli chcesz zintegrować zestaw CallKit w aplikacji i nie używać implementacji CallKit w zestawie SDK, zapoznaj się z przykładowym przewodnikiem Szybki start tutaj. Ale jedną z ważnych rzeczy, które należy wziąć pod uwagę, jest rozpoczęcie dźwięku w odpowiednim czasie. Podobnie jak poniżej

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)

Wyciszanie głośnika i mikrofonu gwarantuje, że fizyczne urządzenia audio nie będą używane, dopóki zestaw CallKit nie wywoła elementu didActivateAudioSession w obiekcie CXProviderDelegate. W przeciwnym razie połączenie może zostać porzucone lub dźwięk nie będzie działać. Kiedy didActivateAudioSession należy uruchomić strumienie 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()
}
    

Ważne jest również wyciszenie wychodzącego dźwięku przed zatrzymaniem dźwięku w przypadkach, gdy zestaw CallKit nie wywołuje elementu didActivateAudioSession. Następnie użytkownik może ręcznie cofnąć wyciszenie mikrofonu.

Uwaga

W niektórych przypadkach zestaw CallKit nie wywołuje wywołania didActivateAudioSession , mimo że aplikacja ma podwyższony poziom uprawnień dźwięku, w takim przypadku dźwięk pozostanie wyciszony do momentu odebrania wywołania zwrotnego. Interfejs użytkownika musi odzwierciedlać stan głośnika i mikrofonu. Zdalny uczestnik/s w wywołaniu zobaczy, że użytkownik również wyciszył dźwięk. W takich przypadkach użytkownik będzie musiał ręcznie cofnąć wyciszenie.

Następne kroki