1-to-1 audio call
This page provides a code example for making a 1-to-1 audio call.
Prerequisites
Before you begin, you must do the following:
- Initialize PlanetKit.
- Get a proper access token.
- Check the overall API usage flow in 1-to-1 call flow.
Considerations for implementing a 1-to-1 audio call
To receive call notifications on the callee side, you must implement a notification system or integrate an external push notification system such as Firebase Cloud Messaging (FCM).
You also need to know what information must be delivered to the callee. Refer to Role of the app server, which describes cc_param
, the data that must be delivered by your application.
After calling makeCall()
or verifyCall()
, you must check the reason
property of the returned PlanetKitCallResult
.
- If the
reason
isPlanetKitStartFailReason.NONE
, it means success. - Otherwise, it means failure and you must take an appropriate action based on the
reason
.
Request permissions
An application must acquire the following runtime permissions before making calls.
Manifest.permission.READ_PHONE_STATE
Manifest.permission.RECORD_AUDIO
Manifest.permission.BLUETOOTH_CONNECT
(FortargetSdkVersion
31 or higher only)
Prepare variables
Prepare variables for key properties and an event listener.
PlanetKitMyMediaStatusListener
is used to handle the local user's media status change events. You can update the local user's UI based on these events, such as when the mic becomes muted or unmuted, or when the audio description is updated.
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.
}
}
Make an outgoing call (caller side)
To make a call, call PlanetKit.makeCall()
with a proper PlanetKitMakeCallParam
. To build a PlanetKitMakeCallParam
, use 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.
}
}
Respond to an incoming call (callee side)
Android apps typically use Firebase Cloud Messaging (FCM) for the push notification. Android provides a base class called FirebaseMessagingService
for receiving messages from FCM.
When you receive a push message, you must parse the cc_param
from the message and create a cCParam
. This data is a required argument that must be passed when responding to a call.
To respond to a call, build PlanetKitVerifyCallParam
and then call 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.
}
}
}
Accept an incoming call (callee side)
In general, the recipient needs time to decide whether to accept a new call after responding to the call. To accept a call, call acceptCall()
.
The call
variable is the PlanetKitCall
instance that has been verified by verifyCall()
.
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
}
Set the media status listener for the local user (Optional)
Once the call is connected, add the media status listener for the local user depending on your needs.
fun setMyMediaStatusListenerExample(instanceId: Int): Boolean
{
var call = PlanetKit.getCall(instanceId) ?: return false
call.getMyMediaStatus()?.addHandler(myMediaStatusListener, null) {
}
return true
}
End a call
To end a call, call endCall()
.
fun endCallExample(instanceId: Int): Boolean
{
var call = PlanetKit.getCall(instanceId) ?: return false
call.endCall()
return true
}