Developer Experience Guidelines - Android
This section provides best practices for working with VideoSDK, from handling errors to managing resources and event subscriptions. Following them simplifies troubleshooting and prevents common pitfalls.
Initiate Key Features After Room Join Event
Start specific features only after the onRoomJoined() event has been triggered.
-
Trigger Key Actions After Joining the Room : Initiating crucial actions after the
onRoomJoined()event helps avoid errors. If your application utilizes any of the following features or you want to perform any action as soon as the room is joined, it's recommended to call them only after the room has been joined:-
Chat Subscription: To enable in-room chat functionality, subscribe to the chat topic after theonRoomJoined()event is triggered. This ensures that messages are reliably received by participants. Called before the join completes,subscribe()throws aVideoSDKExceptionwith code3035.subscribe()is asuspendfunction, so launch a coroutine for it.private val chatListener = object : PubSubMessageListener {override fun onMessageReceived(message: PubSubMessage) {Log.d("VideoSDK", "${message.senderName} says: ${message.message}")}}private val roomEventListener = object : RoomEventListener() {override fun onRoomJoined(switchRoomId: String?) {lifecycleScope.launch {try {// Subscribe once the room is joinedroom.pubSub.subscribe("CHAT", chatListener)} catch (e: VideoSDKException) {Log.e("VideoSDK", "subscribe failed: ${e.code} ${e.name}")}}}}onRoomJoined()also fires after a reconnect that needed a fresh join. Your subscription is kept, so subscribing again with the same listener throws3073, which thecatchabove handles. -
Device Management: If you need users to use specific audio or video devices when the room is first joined, use thesetAudioDevice()method ofRoomfor audio; it works beforejoin()too. For the camera, create a track for the selected camera withcreateCameraVideoTrack()and pass it ascustomCameraTracktocreateRoom(), or callchangeCam()once the room is joined.setSelectedVideoDevice()only records the selection and does not switch the camera. -
Recording and Transcription: To automatically start recording or transcription as soon as the room starts, configure theautoStartConfigin the Create Room API. For detailed information, refer to the documentation here.
-
Dispose Custom Tracks When Necessary
Dispose of custom tracks to free the camera and other system resources. In most scenarios, the SDK disposes of tracks for you. However, in specific cases outlined below, you will need to dispose of custom tracks explicitly:
- When Enabling/Disabling the Camera on a Precall Screen:
- If your application includes a precall screen and you want to ensure that the device's camera is not used when the camera is disabled, you must call
stop()on the custom video track. Otherwise, the device’s camera will continue to be used even when the camera is off. - Additionally, remember to create a new track when the user enables the camera again.
- Call
VideoSDK.initialize()before you create the track. Before it,createCameraVideoTrack()throwsIllegalStateException. - Clear the preview with
removeTrack(). CallreleaseSurfaceViewRenderer()only when the view is destroyed, because the view can't render again after it. - If you don’t need to manage the camera's usage on the device level (i.e., you’re okay with the camera being used whether it’s enabled or disabled), you can skip this step.
- Here's how you can manage a custom track on a precall screen:
- If your application includes a precall screen and you want to ensure that the device's camera is not used when the camera is disabled, you must call
import live.videosdk.rtc.android.CustomCameraTrackConfig
import live.videosdk.rtc.android.CustomStreamTrack
import live.videosdk.rtc.android.VideoSDK
import live.videosdk.rtc.android.VideoView
import live.videosdk.rtc.android.lib.VideoSDKException
import live.videosdk.rtc.android.mediaDevice.FacingMode
import live.videosdk.rtc.android.mediaDevice.CameraDeviceInfo
import videosdk.org.webrtc.VideoTrack
class JoinActivity : AppCompatActivity() {
private var videoTrack: CustomStreamTrack? = null
private var joinView: VideoView? = null
private var isCamEnabled = false
private suspend fun toggleCam(cameraDevice: CameraDeviceInfo?) {
if (isCamEnabled) {
videoTrack?.stop() // Release the camera
videoTrack = null
joinView!!.removeTrack() // Remove the video track from the view
joinView!!.visibility = View.INVISIBLE
} else {
try {
// Re-enabling the camera by creating a new track
videoTrack = VideoSDK.createCameraVideoTrack(
encoderConfig = CustomCameraTrackConfig.H720P_W960P,
facingMode = FacingMode.front,
multiStream = true,
cameraId = cameraDevice?.deviceId // The deviceId of the user's selected camera
)
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Camera failed: ${e.code} ${e.name}")
return
}
// display in localView
joinView!!.addTrack(videoTrack?.track as? VideoTrack)
joinView!!.visibility = View.VISIBLE
}
isCamEnabled = !isCamEnabled // Toggle camera state
}
}
Listen for Error Events
Listening to error events enables your application to handle unexpected issues efficiently, providing users with clear feedback and potential solutions. Error codes pinpoint specific problems, whether from configuration settings, account restrictions, permission limitations, or device constraints. Here are recommended solutions based on common error categories:
-
Errors associated with Organization: If you encounter errors related to your organization (e.g., account status or participant limits), reach out to support at support@videosdk.live or reach out to us on Discord for assistance.
-
Errors associated with Token: For errors related to authentication tokens, ensure the token is valid and hasn’t expired, then try the request again.
-
Errors associated with Room and Participant: Check that roomId and participantId are correctly passed and valid. Also, ensure each participant has a unique participantId: when the same participantId joins from another device, the earlier session is ended.
-
Errors associated with Add-on Service: If you encounter errors with add-on services (such as recording or streaming), try restarting the service after receiving a failure event. For example, if a
START_RECORDING_FAILEDerror event occurs, attempt to call thestartRecording()method again. If you're using webhooks, you can also retry on recording-failed hook. -
Errors associated with Media: Inform the user about media access issues, such as microphone or camera permissions. Design the UI to clearly indicate what is preventing the mic or camera from enabling, helping the user understand the problem.
-
Errors associated with Track & Codec: Ensure that the track you’ve created and passed to enable the mic or camera methods meets the required specifications.
-
Errors associated with Actions: If you need to perform actions as soon as the room is joined, start them only after the onRoomJoined() event. Called earlier, they fail with
3035(ERROR_ACTION_PERFORMED_BEFORE_ROOM_JOINED). -
Errors associated with Participant and Room: The server refused a request that targets a remote participant or changes the room, such as
remove()orchangeMode(). Nothing changed, so you can try the action again. -
Errors associated with Collaboration: A PubSub, data message, file sharing, realtime store, whiteboard or translation request failed. Check that the room is connected and that what you send is within the size limits, then try again.
-
Other errors: The cause is not known. If the error keeps coming back, reach out to support at support@videosdk.live.
- Here's how to listen for the error event.
onErrorcan be called off the main thread, so post to the main thread before you update the UI.
private val roomEventListener: RoomEventListener = object : RoomEventListener() {
//..
override fun onError(error: VideoSDKError) {
Log.d("#error", "Error is: ${error.code} ${error.name} ${error.message}")
}
}
- Most actions, the PubSub calls included, are
suspendfunctions that throw aVideoSDKExceptionwhen they are refused or fail, and some of these errors never reachonError. An exception you don't catch crashes the app, so catch it where you call the action:
lifecycleScope.launch {
try {
room.unmuteMic()
} catch (e: VideoSDKException) {
Log.d("#error", "Error is: ${e.code} ${e.name} ${e.message}")
}
}
Got a Question? Ask us on discord

