1대1 음성 통화
1대1 음성 통화를 구현하는 예제 코드입니다.
필수 조건
시작하기 전에 다음 작업을 수행해야 합니다.
- PlanetKit을 초기화하세요.
- 적절한 액세스 토큰을 획득하세요.
- 1대1 통화 흐름에서 전반적인 API 사용 과정을 확인하세요.
1대1 음성 통화 구현 시 고려 사항
착신자 측에서 통화 알림을 받으려면 알림용 시스템을 구현하거나 FCM(Firebase Cloud Messaging) 같은 외부 푸시 알림 시스템을 연동해야 합니다.
또한 착신자에게 어떤 정보를 전달해야 하는지도 알아야 합니다. 앱 서버의 역할에서 애플리케이션이 전달해야 하는 데이터인 cc_param
에 관해 볼 수 있습니다.
makeCall()
또는 verifyCall()
을 호출한 다음에는 반환된 PlanetKitCallResult
의 reason
속성을 확인해야 합니다.
reason
이PlanetKitStartFailReason.NONE
인 경우 성공을 의미합니다.- 그렇지 않으면 실패를 의미하며
reason
에 따라 적절한 조치를 취해야 합니다.
권한 요청
통화하기 전에 다음의 런타임 권한을 획득하세요.
Manifest.permission.READ_PHONE_STATE
Manifest.permission.RECORD_AUDIO
Manifest.permission.BLUETOOTH_CONNECT
(targetSdkVersion
31 이상)
변수 준비
주요 속성 및 이벤트 리스너에 대한 변수를 준비합니다.
PlanetKitMyMediaStatusListener
는 로컬 사용자의 미디어 상태 변경 이벤트를 처리하는 데 사용됩니다. 마이크가 음소거되거나 음소거 해제되는 경우 또는 오디오 설명이 업데이트되는 경우 등 이벤트를 기반으로 로컬 사용자의 UI를 업데이트할 수 있습니다.
val myUserId = "test user id" // The local user's user ID
val serviceId = "test service id" // Service ID
// PlanetKitMyMediaStatusListener object
val myMediaStatusListener = object : PlanetKitMyMediaStatusListener {
override fun onMyAudioMuted() {
// This is called when the local user's audio is muted.
// Write your own code here.
}
override fun onMyAudioUnmuted() {
// This is called when the local user's audio is unmuted.
// Write your own code here.
}
override fun onMyAudioDescriptionUpdated(audioDescription: PlanetKitAudioDescription) {
// This is called when the local user's audio description is updated.
// Write your own code here.
}
}
통화 생성(발신 측)
통화를 생성하려면 적절한 PlanetKitMakeCallParam
과 함께 PlanetKit.makeCall()
을 호출하세요. PlanetKitMakeCallParam
을 만들려면 PlanetKitMakeCallParam.Builder()
를 사용하세요.
fun makeCallExample(peerId: String, accessToken: String)
{
val makeCallParam = PlanetKitMakeCallParam.Builder()
.myId(myUserId)
.myServiceId(serviceId)
.peerId(peerId)
.peerServiceId(serviceId)
.accessToken(accessToken)
.build()
var result = PlanetKit.makeCall(makeCallParam, makeCallListener = object : MakeCallListener
{
override fun onWaitConnected(call: PlanetKitCall)
{
// This is called after making a call.
// Write your own code here.
}
override fun onConnected(call: PlanetKitCall, param: PlanetKitCallConnectedParam)
{
// This is called after the call is connected.
// Write your own code here.
}
override fun onDisconnected(call: PlanetKitCall, param: PlanetKitDisconnectedParam)
{
// This is called after the call is disconnected.
// Write your own code here.
}
})
if (result.reason == PlanetKitStartFailReason.NONE)
{
// The "result.call" instance is the main instance to call APIs from now on.
// You must keep it to control this call.
// See call.instanceId and PlanetKit.getCall(instanceId).
}
else
{
// result.reason: PlanetKitStartFailReason describes why makeCall failed.
}
}
통화 수신(착신 측)
Android 앱은 보통 푸시 알림용으로 Firebase Cloud Messaging(이하 FCM)을 사용합니다. Android는 FCM으로부터 메시지를 수신할 용도로 FirebaseMessagingService
라는 기본 클래스를 제공합니다.
푸시 메시지를 받으면 메시지로부터 cc_param
을 파싱하여 cCParam
을 생성해야 합니다. 이 데이터는 통화에 응답할 때 전달해야 하는 필수 인자입니다.
통화에 응답하려면 PlanetKitVerifyCallParam
을 만든 다음 PlanetKit.verifyCall()
을 호출하세요.
class YourFirebaseMessagingService : FirebaseMessagingService()
{
override fun onMessageReceived(message: RemoteMessage)
{
val cCParamStr = message.data["cc_param"]
if (cCParamStr.isNullOrBlank())
{
Log.e("Push", "Empty message from application server")
return
}
val cCParam = PlanetKitCCParam.create(cCParamStr)
if (cCParam == null) {
Log.e(TAG, "Can not create PlanetKitCCParam. Check cCParamStr=$cCParamStr")
return
}
Log.d("Push","ccParam{peerId=${cCParam.peerId}, peerServiceId=${cCParam.peerServiceId}, mediaType=${cCParam.mediaType}")
val verifyCallParam = PlanetKitVerifyCallParam.Builder()
.myId(myUserId)
.serviceId(serviceId)
.cCParam(cCParam)
.build()
val result = PlanetKit.verifyCall(verifyCallParam, verifyListener = object : VerifyListener
{
override fun onVerified(call: PlanetKitCall, peerStartMessage: PlanetKitCallStartMessage?, peerUseResponderPreparation: Boolean)
{
// This is called after verifying a call.
// Write your own code here.
// For example, you can show a notification and switch to your ringing screen.
//
// The "call" is the verified call instance.
// If you send an instance of call through 'Intent of Android',
// then you can use the "call.instanceId".
// You can get the instance of call with the API "PlanetKit.getCall(instanceId)".
}
override fun onDisconnected(call: PlanetKitCall, param: PlanetKitDisconnectedParam)
{
// This is called after the call is disconnected.
// Write your own code here.
}
})
// Store result.call or result.call.instanceId for acceptCall().
if (result.reason == PlanetKitStartFailReason.NONE)
{
// The "result.call" instance is the main instance to call APIs from now on.
// You must keep it to control this call.
// See call.instanceId and PlanetKit.getCall(instanceId).
}
else
{
// result.reason: PlanetKitStartFailReason describes why verifyCall failed.
}
}
}
통화 응답(착신 측)
일반적으로 통화를 수신한 후 통화를 받을 것인지 아닌지 결정할 시간이 필요합니다. 통화에 응답하려면 acceptCall()
을 호출하세요.
call
변수는 verifyCall()
에서 검증을 마친 PlanetKitCall
인스턴스입니다.
fun acceptCallExample(instanceId: Int): Boolean
{
var call = PlanetKit.getCall(instanceId) ?: return false
call.acceptCall(listener = object : AcceptCallListener {
override fun onConnected(call: PlanetKitCall, param: PlanetKitCallConnectedParam) {
// This is called after the call is connected.
// Write your own code here.
}
override fun onDisconnected(call: PlanetKitCall, param: PlanetKitDisconnectedParam) {
// This is called after the call is disconnected.
// Write your own code here.
}
}
)
return true
}
로컬 사용자에 대한 미디어 상태 리스너 설정(선택 사항)
통화가 연결되면 필요에 따라 로컬 사용자에 대한 미디어 상태 리스너를 설정하세요.
fun setMyMediaStatusListenerExample(instanceId: Int): Boolean
{
var call = PlanetKit.getCall(instanceId) ?: return false
call.getMyMediaStatus()?.addHandler(myMediaStatusListener, null) {
}
return true
}
통화 종료
통화를 종료하려면 endCall()
을 호출하세요.
fun endCallExample(instanceId: Int): Boolean
{
var call = PlanetKit.getCall(instanceId) ?: return false
call.endCall()
return true
}