次の方法で共有


CallKit との統合

このドキュメントでは、CallKit と iOS アプリケーションを統合する方法について説明します。

[前提条件]

CallKit 統合 (SDK 内)

Azure Communication Services iOS SDK の CallKit 統合は、CallKit との対話を処理します。 ミュート/ミュート解除、保留/再開などの呼び出し操作を実行するには、Azure Communication Services SDK で API を呼び出す必要があります。

CallKitOptions を使用して呼び出しエージェントを初期化する

CallKitOptionsの構成されたインスタンスを使用すると、CallAgentの処理を使用して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
})

発信通話の通話受信者情報を指定する

まず、発信通話用の StartCallOptions() のインスタンスを作成するか、グループ通話用に JoinCallOptions() する必要があります。

let options = StartCallOptions()

or

let options = JoinCallOptions()

次に、次のインスタンスを作成します。 CallKitRemoteInfo

options.callKitRemoteInfo = CallKitRemoteInfo()
  1. callKitRemoteInfo.displayNameForCallKitの値を割り当てて、通話受信者の表示名をカスタマイズし、CXHandle値を構成します。 displayNameForCallKitで指定されたこの値は、最後にダイヤルされた通話ログに正確に表示されます。 最後にダイヤルされた通話ログに記録されます。
options.callKitRemoteInfo.displayNameForCallKit = "DISPLAY_NAME"
  1. cxHandle値を割り当てると、ユーザーがその連絡先に再度電話をかけるときにアプリケーションが受け取ります。
options.callKitRemoteInfo.cxHandle = CXHandle(type: .generic, value: "VALUE_TO_CXHANDLE")

着信通話の通話受信者情報を指定する

まず、 CallKitOptionsのインスタンスを作成する必要があります。

let callKitOptions = CallKitOptions(with: createProviderConfig())

CallKitOptions インスタンスのプロパティを設定します。

変数 provideRemoteInfo に渡されるブロックは、着信呼び出しを受信したときに SDK によって呼び出され、着信呼び出し元の表示名を取得する必要があります。これは 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
}

オーディオ セッションを構成する

音声セッションを構成するのは、着信通話をかけるまたは受け入れる前や、通話を保留後に再開する前です。

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
}

注: Contoso が既にオーディオ セッションを構成している場合は、 nil を提供せず、ブロック nil エラーを返しません

callKitOptions.configureAudioSession = self.configureAudioSession

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

nilconfigureAudioSessionが指定されている場合、SDK は SDK の既定の実装を呼び出します。

受信プッシュ通知ペイロードを処理する

アプリが受信プッシュ通知ペイロードを受け取ったら、それを処理するために handlePush を呼び出す必要があります。 Azure Communication Services Calling SDK によって、 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) {
}

reportIncomingCallを使用して、アプリが閉じられたり、それ以外の場合にプッシュ通知を処理したりできます。

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

CallKit 統合 (アプリ内)

アプリ内に CallKit を統合し、SDK で CallKit 実装を使用しない場合は、 こちらのクイックスタート サンプルを参照してください。 しかし、重要なことの 1 つは、適切なタイミングでオーディオを開始することです。 次のように

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)

スピーカーとマイクをミュートすると、CallKit が didActivateAudioSessionCXProviderDelegateを呼び出すまで、物理オーディオ デバイスが使用されないようにします。 そうしないと、呼び出しがドロップされたり、音声が機能しない可能性があります。 didActivateAudioSessionは、オーディオ ストリームを開始する必要がある場合です。

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

CallKit が didActivateAudioSessionを呼び出さない場合は、音声を停止する前に発信オーディオをミュートすることも重要です。 その後、ユーザーはマイクのミュートを手動で解除できます。

場合によっては、アプリに昇格されたオーディオアクセス許可がある場合でも、CallKit は didActivateAudioSession を呼び出しません。その場合、コールバックが受信されるまでオーディオはミュートされた状態を維持します。 また、UI はスピーカーとマイクの状態を反映する必要があります。 通話中のリモート参加者は、ユーザーも音声をミュートしていることがわかります。 このような場合、ユーザーは手動でミュートを解除する必要があります。

次のステップ