Skip to main content
Version: 3.x.x

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 the onRoomJoined() event is triggered. This ensures that messages are reliably received by participants. Called before the join completes, subscribe() throws a VideoSDKException with code 3035. subscribe() is a suspend function, 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 joined
      room.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 throws 3073, which the catch above handles.

    • Device Management: If you need users to use specific audio or video devices when the room is first joined, use the setAudioDevice() method of Room for audio; it works before join() too. For the camera, create a track for the selected camera with createCameraVideoTrack() and pass it as customCameraTrack to createRoom(), or call changeCam() 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 the autoStartConfig in 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:

  1. 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() throws IllegalStateException.
    • Clear the preview with removeTrack(). Call releaseSurfaceViewRenderer() 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:
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:

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

  2. Errors associated with Token: For errors related to authentication tokens, ensure the token is valid and hasn’t expired, then try the request again.

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

  4. 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_FAILED error event occurs, attempt to call the startRecording() method again. If you're using webhooks, you can also retry on recording-failed hook.

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

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

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

  8. Errors associated with Participant and Room: The server refused a request that targets a remote participant or changes the room, such as remove() or changeMode(). Nothing changed, so you can try the action again.

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

  10. 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. onError can 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 suspend functions that throw a VideoSDKException when they are refused or fail, and some of these errors never reach onError. 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