本文にスキップする
Version: 6.0

1対1ビデオ通話

1対1ビデオ通話を実装するサンプルコードです。

前提条件

開始する前に、次の作業が必要です。

1対1ビデオ通話実装時の考慮事項

受信者側で通話の通知を受けるには、通知用システムを実装するか、FCM(Firebase Cloud Messaging)といった外部プッシュ通知システムを連携する必要があります。

また、受信者にどのような情報を渡すべきかを知っておく必要があります。アプリサーバーの役割にて、アプリケーションが渡すべきデータであるcc_paramについて確認できます。

makeCall()またはverifyCall()を呼び出した後は、返却されたPlanetKitCallResultreasonプロパティを確認する必要があります。

  • reasonPlanetKitStartFailReason.NONEの場合、成功を意味します。
  • それ以外は失敗を意味し、reasonに応じて適切に処理する必要があります。

権限申請

通話をする前に、次のランタイム権限を取得してください。

  • Manifest.permission.READ_PHONE_STATE
  • Manifest.permission.RECORD_AUDIO
  • Manifest.permission.BLUETOOTH_CONNECTtargetSdkVersion 31以上)
  • Manifest.permission.CAMERA

変数の用意

主要プロパティとイベントリスナーに対する変数を用意します。

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

override fun onVideoStatusUpdated(videoStatus: PlanetKitVideoStatus) {
// This is called when the local user's video status is updated.
// Write your own code here.
}
}

ローカルユーザーのビデオプレビュー

プレビュー機能を使用すると、ローカルユーザーが1対1通話セッションに関係なく、自分のビデオをプレビューできます。

ローカルユーザーのビデオプレビューを開始するには、PlanetKitCameraManagerのをstartPreview()呼び出します。

fun startPreviewExample(preview: PlanetKitVideoView)
{
PlanetKit.getCameraManager().startPreview(preview)
}

ローカルユーザーのビデオプレビューを中止するには、PlanetKitCameraManagerのをstopPreview()呼び出します。

fun stopPreviewExample(preview: PlanetKitVideoView)
{
PlanetKit.getCameraManager().stopPreview(preview)
}

通話の作成(発信側)

通話を作成するには、適切なPlanetKitMakeCallParamと共にPlanetKit.makeCall()を呼び出します。PlanetKitMakeCallParamを作成するには、PlanetKitMakeCallParam.Builder()を使用してください。

  • ビデオ通話を作成するためにPlanetKitMediaType.AUDIOVIDEOを引数としてPlanetKitMakeCallParam.BuildermediaType()を呼び出します。
  • 発信者のビデオの初期状態は、PlanetKitMakeCallParam.BuildersetInitialMyVideoState()で設定できます。
    • initialMyVideoStateプロパティのデフォルト値は、PlanetKitInitialMyVideoState.RESUMEです。
    • PlanetKitInitialMyVideoState.PAUSEを引数としてsetInitialMyVideoState()を呼び出して発信者のビデオの初期状態が一時停止に設定された場合、発信者のビデオは送信されません。この場合、発信者のビデオは通話が接続された後、resumeMyVideo()を呼び出して送信できます。
fun makeCallExample(peerId: String, accessToken: String, initialMyVideoState: PlanetKitInitialMyVideoState)
{
val makeCallParam = PlanetKitMakeCallParam.Builder()
.myId(myUserId)
.myServiceId(serviceId)
.peerId(peerId)
.peerServiceId(serviceId)
.accessToken(accessToken)
.mediaType(PlanetKitMediaType.AUDIOVIDEO)
.setInitialMyVideoState(initialMyVideoState)
.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}, isRecordOnCloudEnabled=${cCParam.isRecordOnCloudEnabled}}")

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()を呼び出します。

  • 受信者のビデオの初期状態は、acceptCall()initialMyVideoStateパラメーターで設定できます。
    • initialMyVideoStateパラメーターのデフォルト値は、PlanetKitInitialMyVideoState.RESUMEです。
    • PlanetKitInitialMyVideoState.PAUSEを引数として引き渡し、受信者のビデオの初期状態が一時停止に設定された場合、受信者のビデオは送信されません。この場合、受信者のビデオは通話が接続された後、resumeMyVideo()を呼び出して送信できます。
Tip

call変数は、verifyCall()で検証済みのPlanetKitCallインスタンスです。

fun acceptCallExample(instanceId: Int, initialMyVideoState: PlanetKitInitialMyVideoState): 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.
}
}, initialMyVideoState
)

return true
}

ローカルユーザーに対するメディアステータスリスナーの設定(任意)

通話が接続されると、必要に応じてローカルユーザーに対するメディアステータスリスナーを設定します。

fun setMyMediaStatusListenerExample(instanceId: Int): Boolean
{
var call = PlanetKit.getCall(instanceId) ?: return false

call.getMyMediaStatus()?.addHandler(myMediaStatusListener, null) {
}

return true
}

ローカルユーザーのためのビデオビュー追加

addMyVideoView()を呼び出してローカルユーザーのビデオがレンダリングされるビデオビューを追加します。ビデオのレンダリングは、ローカルユーザーのビデオ状態によって、開始または中止されます。

fun addMyVideoViewExample(instanceId: Int, myVideoView: PlanetKitVideoView): Boolean
{
var call = PlanetKit.getCall(instanceId) ?: return false

call.addMyVideoView(myVideoView)

return true
}

ピアのためのビデオビュー追加

addPeerVideoView()を呼び出してピアのビデオがレンダリングされるビデオビューを追加します。ビデオのレンダリングは、ピアのビデオ状態によって、開始または中止されます。

fun addPeerVideoViewExample(instanceId: Int, peerVideoView: PlanetKitVideoView): Boolean
{
var call = PlanetKit.getCall(instanceId) ?: return false

call.addPeerVideoView(peerVideoView)

return true
}

通話の切断

通話を切断するには、endCall()を呼び出します。

fun endCallExample(instanceId: Int): Boolean
{
var call = PlanetKit.getCall(instanceId) ?: return false

call.endCall()

return true
}

関連サンプルコード

関連ドキュメント