CallKit과 통합
이 문서에서 CallKit을 iOS 애플리케이션과 통합하는 방법을 살펴보겠습니다.
필수 조건
- 활성 구독이 있는 Azure 계정. 체험 계정을 만듭니다.
- 배포된 Communication Services 리소스. Communication Services 리소스 만들기
- 호출 클라이언트를 사용하도록 설정하는 사용자 액세스 토큰입니다. 자세한 내용은 액세스 토큰 만들기 및 관리를 참조하세요.
- 선택 사항: 빠른 시작을 완료하여 애플리케이션에 음성 통화를 추가합니다.
CallKit 통합(SDK 내)
Azure Communication Services iOS SDK의 CallKit 통합은 CallKit과의 상호 작용을 처리합니다. 음소거/음소거 해제, 대기/다시 시작과 같은 통화 작업을 수행하려면 Azure Communication Services SDK에서 API를 호출하기만 하면 됩니다.
CallKitOptions로 통화 에이전트 초기화
CallKitOptions
의 구성된 인스턴스를 사용하여 CallKit
을 처리하여 CallAgent
를 만들 수 있습니다.
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()
또는
let options = JoinCallOptions()
그런 다음 CallKitRemoteInfo
의 인스턴스를 만듭니다.
options.callKitRemoteInfo = CallKitRemoteInfo()
- 통화 수신자의 표시 이름을 사용자 지정하고
CXHandle
값을 구성하려면callKitRemoteInfo.displayNameForCallKit
에 대한 값을 할당합니다.displayNameForCallKit
에 지정된 이 값은 마지막으로 전화를 건 호출 기록에 정확하게 표시되는 방식입니다. 마지막으로 전화를 거는 통화 로그에 있습니다.
options.callKitRemoteInfo.displayNameForCallKit = "DISPLAY_NAME"
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
}
configureAudioSession
에 대해 nil
이 제공되면 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, didRecieveIncomingCall 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 구현을 사용하지 않으려면 여기에서 빠른 시작 샘플을 참조하세요. 그러나 주의해야 할 중요한 사항 중 하나는 적시에 오디오를 시작하는 것입니다. 다음과 같습니다.
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이 CXProviderDelegate
에서 didActivateAudioSession
을 호출할 때까지 실제 오디오 디바이스가 사용되지 않습니다. 그렇지 않으면 통화가 끊기거나 오디오가 작동하지 않습니다.
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는 스피커와 마이크의 상태를 반영해야 합니다. 통화 중인 원격 참가자는 사용자가 음소거한 오디오도 볼 수 있습니다. 이러한 경우 사용자는 수동으로 음소거를 해제해야 합니다.