Group video call
This page provides a code example for implementing a group video call.
Prerequisites
Before you begin, you must do the following:
- Initialize PlanetKit.
- Get a proper access token.
- Check the overall API usage flow in Group call flow.
Considerations for implementing a group video call
After calling joinConference()
, you must check the reason
property of the returned PlanetKitConferenceResult
.
- If the
reason
isPlanetKitStartFailReason.NONE
, it means success. - Otherwise, it means failure and you must take an appropriate action based on the
reason
.
Request device permissions
An application must acquire the following runtime permissions before starting a group call.
Manifest.permission.READ_PHONE_STATE
Manifest.permission.RECORD_AUDIO
Manifest.permission.BLUETOOTH_CONNECT
(FortargetSdkVersion
31 or higher only)Manifest.permission.CAMERA
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, when the audio description is updated, or when the video status 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.
}
override fun onVideoStatusUpdated(videoStatus: PlanetKitVideoStatus) {
// This is called when the local user's video status is updated.
// Write your own code here.
}
}
Preview the local user's video
The preview feature allows the local user to preview their own video regardless of the group call session.
To starting previewing the local user's video, call startPreview()
of PlanetKitCameraManager
.
fun startPreviewExample(preview: PlanetKitVideoView)
{
PlanetKit.getCameraManager().startPreview(preview)
}
To stop previewing the local user's video, call stopPreview()
of PlanetKitCameraManager
.
fun stopPreviewExample(preview: PlanetKitVideoView)
{
PlanetKit.getCameraManager().stopPreview(preview)
}
Join a group call
To join a group call, call PlanetKit.joinConference()
with a proper PlanetKitConferenceParam
. To build a PlanetKitConferenceParam
, use PlanetKitConferenceParam.Builder()
.
- To join a group video call, call
mediaType()
ofPlanetKitConferenceParam.Builder
withPlanetKitMediaType.AUDIOVIDEO
. - The local user's initial video state can be set with
setInitialMyVideoState()
ofPlanetKitConferenceParam.Builder
.- The default value of the
initialMyVideoState
property isPlanetKitInitialMyVideoState.RESUME
. - If the local user's initial video state is set to paused by calling
setInitialMyVideoState()
withPlanetKitInitialMyVideoState.PAUSE
, the local user's video is not transmitted. The local user's video can be transmitted by callingresumeMyVideo()
after the call is connected.
- The default value of the
fun joinConferenceExample(roomId: String, accessToken: String, initialMyVideoState: PlanetKitInitialMyVideoState)
{
val param = PlanetKitConferenceParam.Builder()
.myId(myUserId)
.roomId(roomId)
.myServiceId(serviceId)
.roomServiceId(serviceId)
.accessToken(accessToken)
.mediaType(PlanetKitMediaType.AUDIOVIDEO)
.setInitialMyVideoState(initialMyVideoState)
.build()
val result = PlanetKit.joinConference(param, conferenceListener = object : ConferenceListener {
override fun onConnected(conference: PlanetKitConference,
isVideoHwCodecEnabled: Boolean,
isVideoShareModeSupported: Boolean) {
// This is called when the call is connected.
// Write your own code here.
}
override fun onDisconnected(conference: PlanetKitConference,
param: PlanetKitDisconnectedParam) {
// This is called when the call is disconnected.
// Write your own code here.
}
override fun onPeerListUpdated(param: PlanetKitConferencePeerListUpdatedParam) {
// This is called when the list of peers is updated.
// The following is an example function. For more information, see the "Manage peers using PlanetKitPeerControl" section.
handlePeerListUpdate(param)
}
override fun onPeersVideoUpdated(conference: PlanetKitConference, param: PlanetKitConferenceVideoUpdateParam) {
// This is called when the video of one or more peers is updated.
// Write your own code here.
}
})
if (result.reason == PlanetKitStartFailReason.NONE) {
// The "result.conference" instance is the main instance to call APIs from now on.
// You must keep it to control this call.
}
else {
// Handle an error by referring to result.reason.
}
}
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(): Boolean
{
var conference = PlanetKit.getConference() ?: return false
conference.getMyMediaStatus()?.addHandler(myMediaStatusListener, null) {
}
return true
}
Add a video view for the local user
Call addMyVideoView()
to add a video view where the local user's video will be rendered. The rendering of the video starts or stops according to the local user's video status.
fun addMyVideoViewExample(myVideoView: PlanetKitVideoView): Boolean
{
var conference = PlanetKit.getConference() ?: return false
conference.addMyVideoView(myVideoView)
return true
}
Add a video view for a peer
Call addPeerVideoView()
to add a video view where the peer's video will be rendered.
fun addPeerVideoViewExample(peer: PlanetKitConferencePeer, peerVideoView: PlanetKitVideoView): Boolean
{
var conference = PlanetKit.getConference() ?: return false
conference.addPeerVideoView(peer, peerVideoView)
return true
}
Create peer control for each peer
When the peer list is updated, create PlanetKitPeerControl
for newly added peers and register a PeerControlListener
object. You can handle the status change of each peer using the PeerControlListener
.
class PeerContainer internal constructor(
peer: PlanetKitConferencePeer
) {
val peerControl: PlanetKitPeerControl = peer.createPeerControl()
?: throw IllegalStateException("Failed to create peer control.")
init {
val peerControlListener = object : PlanetKitPeerControl.PeerControlListener {
override fun onMicMuted(peer: PlanetKitConferencePeer) {
// This is called when the peer's audio is muted.
// Write your own code here.
}
override fun onMicUnmuted(peer: PlanetKitConferencePeer) {
// This is called when the peer's audio is unmuted.
// Write your own code here.
}
override fun onAudioDescriptionUpdated(
peer: PlanetKitConferencePeer,
audioDescription: PlanetKitAudioDescription
) {
// This is called when the peer's audio description is updated.
// Write your own code here. The following is an example of implementation.
val yourOwnThresholdTalkingVolumeLevel = 10
val isPeerTalking =
audioDescription.averageVolumeLevel >= yourOwnThresholdTalkingVolumeLevel
}
override fun onVideoUpdated(
peer: PlanetKitConferencePeer,
videoStatus: PlanetKitVideoStatus,
subgroupName: String?
) {
// This is called when the peer's video is updated.
// Write your own code here. The following is an example of implementation.
when (videoStatus.videoState) {
PlanetKitVideoStatus.VideoState.DISABLED -> {
// The peer's video is disabled.
// The video stops even if you don't call peerControl.stopVideo().
}
PlanetKitVideoStatus.VideoState.ENABLED -> {
// The peer's video is enabled.
// If you call peerControl.startVideo(), the peer's video is received and rendered.
peerControl.startVideo(
PlanetKitVideoResolution.RECOMMENDED,
subgroupName
)
}
PlanetKitVideoStatus.VideoState.PAUSED -> {
// Write your own code for paused video.
}
}
}
override fun onDisconnected(peer: PlanetKitConferencePeer) {
// This is called when the peer is disconnected from the call.
// Write your own code here.
}
}
peerControl.register(peerControlListener)
}
}
// Example function called in the onPeerListUpdated callback.
private val peerContainerList = mutableListOf<PeerContainer>()
fun handlePeerListUpdate(param: PlanetKitConferencePeerListUpdatedParam) {
// Process added peers.
for (addedPeer in param.addedPeers) {
// Create peer control for your class.
peerContainerList.add(PeerContainer(addedPeer))
}
// Process removed peers.
for (removedPeer in param.removedPeers) {
peerContainerList.removeIf {
it.peerControl.peer.isSameMember(removedPeer)
}
}
}
Leave a group call
To leave a group call, call leaveConference()
.
fun leaveConferenceExample(): Boolean
{
var conference = PlanetKit.getConference() ?: return false
conference.leaveConference()
return true
}