Skip to main content
Version: 3.x.x

Room Class Methods - Android

info
  • Call each method shown as suspend fun from a coroutine. The examples use lifecycleScope, which comes from androidx.lifecycle:lifecycle-runtime-ktx.
  • A suspend method returns when the call has finished. If the call is refused or fails, it throws VideoSDKException, which carries a code and a name. The exception is unchecked, so an exception you don't catch crashes the app.
  • Every suspend method is safe to call from the main thread. Room events reach your listeners on the main thread.
  • Called before the room is joined, or while it is reconnecting, most methods report 3035 or 3065 on onError and return without throwing. A call refused while reconnecting is not retried after the room reconnects. The sections below say which methods throw in that case.

join()​

suspend fun join()
  • Joins the room and turns on the mic and camera you asked for in VideoSDK.createRoom(). createRoom() returns a new Room but does not join it.
  • Before you call it, add your RoomEventListener with addEventListener(), or you can miss the first events.
  • Get CAMERA and RECORD_AUDIO granted first, with VideoSDK.checkPermissions(). A device whose permission is missing stays off for the whole session.
  • You are in the room once onRoomJoined fires. That event can arrive before join() returns.
  • The same Room can be joined again after leave().

Events associated with join():​

  • The local participant receives onRoomStateChanged with CONNECTING when the join starts.
  • The local participant receives onRoomJoined once joined, then onRoomStateChanged with CONNECTED. If the join fails, it receives onError and onRoomStateChanged with FAILED.
  • The local participant receives onStreamEnabled for each stream turned on by the join.
  • Remote participants receive onParticipantJoined with the new Participant.

Token with ask_join​

  • join() doesn't let the participant in directly. Participants whose token has allow_join receive onEntryRequested.
  • The waiting participant receives onEntryResponded with the decision.

Token with allow_join​

  • join() lets the participant in directly.

Returns​

  • Unit

Throws​

VideoSDKException with:

  • 3055 (ERROR_OPERATION_IN_PROGRESS) if a join is already running.
  • 3054 (ERROR_ALREADY_IN_REQUESTED_STATE) if this room is already joined.
  • 3056 (ERROR_OPERATION_ABORTED) if leave() cancelled the join.
  • 3047 (ERROR_UNABLE_TO_JOIN_ROOM), or the server's error code, such as 4002 (INVALID_TOKEN) for a token the server rejects. The code reported on onError can differ from the thrown one.

Example​

room.addEventListener(roomEventListener)
lifecycleScope.launch {
try {
room.join()
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Join failed: ${e.code} ${e.name} ${e.message}")
}
}

leave()​

suspend fun leave()
  • Leaves the room.
  • It also works while the room is reconnecting. Called while a join is still running, it cancels that join. Call it after a failed join too, so the room is released; then create a new room to try again.
  • The camera and microphone are released before onRoomLeft fires.

Events associated with leave():​

Returns​

  • Unit

Throws​

VideoSDKException with:

  • 3035 (ERROR_ACTION_PERFORMED_BEFORE_ROOM_JOINED) if join() was never called.
  • 3054 (ERROR_ALREADY_IN_REQUESTED_STATE) if the room has already been left.

Neither is reported on onError.

caution

lifecycleScope is already cancelled when onDestroy() runs, so a leave() launched there never runs. Leave the room before the screen is destroyed, for example from your leave button.

Example​

fun onLeaveClicked() {
lifecycleScope.launch {
try {
room.leave()
} catch (e: VideoSDKException) {
// 3035: never joined, 3054: already left
Log.w("VideoSDK", "Leave refused: ${e.code} ${e.name}")
}
finish()
}
}

end()​

suspend fun end()
  • Ends the room for every participant, you included.
  • The server decides whether your token may end the room. If it refuses, you stay in the room.

Events associated with end():​

Returns​

  • Unit

Throws​

VideoSDKException with:

  • 3035 (ERROR_ACTION_PERFORMED_BEFORE_ROOM_JOINED) when you are not in the room, and 3065 (ERROR_ROOM_RECONNECTING) while it is reconnecting.
  • 3057 (ERROR_END_ROOM_FAILED) when the server refuses. You stay in the room.
  • 3079 (ERROR_OPERATION_TIMED_OUT) when the server doesn't answer.

Example​

lifecycleScope.launch {
try {
room.end()
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "End failed: ${e.code} ${e.name}")
}
}

enableCam()​

suspend fun enableCam(customCameraTrack: CustomStreamTrack? = null)
  • Turns on your camera and sends it to the room.
  • Every participant receives onStreamEnabled with the new RTCStream.
  • Without a customCameraTrack, the camera opens with the settings the room already has: those of the last custom track, or the default profile.
  • If the call is refused, customCameraTrack is released, so the camera doesn't stay open.

Parameters​

Returns​

  • Unit

Throws​

VideoSDKException with 3054 (ERROR_ALREADY_IN_REQUESTED_STATE) when the camera is already on, 3055 (ERROR_OPERATION_IN_PROGRESS) while another camera call is running, 3066 (ERROR_ACTION_NOT_SUPPORTED_IN_MODE) in RECV_ONLY or SIGNALLING_ONLY mode, or the camera error, also reported on onError, when the camera can't be opened.

Example​

lifecycleScope.launch {
try {
room.enableCam()
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Camera failed: ${e.code} ${e.name}")
}
}

disableCam()​

suspend fun disableCam()
  • Turns off your camera. The camera is closed, so the system camera indicator goes off.
  • Every participant receives onStreamDisabled with the RTCStream that stopped.

Returns​

  • Unit

Throws​

VideoSDKException with 3054 (ERROR_ALREADY_IN_REQUESTED_STATE) when the camera is already off, 3055 (ERROR_OPERATION_IN_PROGRESS) while another camera call is running, or 3066 (ERROR_ACTION_NOT_SUPPORTED_IN_MODE) in RECV_ONLY or SIGNALLING_ONLY mode.

Example​

lifecycleScope.launch {
try {
if (room.isCamEnabled) room.disableCam() else room.enableCam()
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Camera toggle failed: ${e.code} ${e.name}")
}
}

unmuteMic()​

suspend fun unmuteMic(customMicrophoneTrack: CustomStreamTrack? = null)
  • Turns on your microphone and sends it to the room.
  • Every participant receives onStreamEnabled with the new RTCStream.
  • Without a customMicrophoneTrack, the microphone opens with the audio settings the room already has.
  • If the call is refused, customMicrophoneTrack is released, so the microphone doesn't stay open.

Parameters​

Returns​

  • Unit

Throws​

VideoSDKException with 3054 (ERROR_ALREADY_IN_REQUESTED_STATE) when the mic is already on, 3055 (ERROR_OPERATION_IN_PROGRESS) while another mic call is running, or 3066 (ERROR_ACTION_NOT_SUPPORTED_IN_MODE) in RECV_ONLY or SIGNALLING_ONLY mode.


muteMic()​

suspend fun muteMic()
  • Turns off your microphone. The microphone is released, so the system microphone indicator goes off.
  • Every participant receives onStreamDisabled with the RTCStream that stopped.

Returns​

  • Unit

Throws​

VideoSDKException with 3054 (ERROR_ALREADY_IN_REQUESTED_STATE) when the mic is already muted, 3055 (ERROR_OPERATION_IN_PROGRESS) while another mic call is running, or 3066 (ERROR_ACTION_NOT_SUPPORTED_IN_MODE) in RECV_ONLY or SIGNALLING_ONLY mode.

Example​

lifecycleScope.launch {
try {
if (room.isMicEnabled) room.muteMic() else room.unmuteMic()
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Mic toggle failed: ${e.code} ${e.name}")
}
}

enableScreenShare()​

suspend fun enableScreenShare(data: Intent, enableAudio: Boolean = false)

suspend fun enableScreenShare(customTrack: CustomStreamTrack? = null)
  • Starts sharing your screen.
  • Pass the Intent from the screen-capture consent dialog, or a screen-share track.
  • The SDK starts the foreground service that Android 14 and newer require for screen capture, so the call takes a moment to return. The SDK declares the permission that service needs.
  • Every participant receives onStreamEnabled with the new RTCStream.
  • Every participant receives onPresenterChanged() with your participant ID.

Parameters​

  • data: Intent
    • The result Intent of the consent dialog. Use it only when the result code is RESULT_OK. The share uses the h720p_15fps profile.
  • enableAudio: Boolean
    • true also captures the device's audio and mixes it into your microphone track, so muting the mic silences both.
    • OPTIONAL, default false
  • customTrack: CustomStreamTrack?
    • A screen-share track from VideoSDK.createScreenShareVideoTrack(). It carries the consent, the profile and whether to capture audio. null uses the track from the most recent createScreenShareVideoTrack() call.
    • OPTIONAL, default null

Returns​

  • Unit

Throws​

VideoSDKException with:

  • 3054 (ERROR_ALREADY_IN_REQUESTED_STATE) when a share is already running, or 3055 (ERROR_OPERATION_IN_PROGRESS) while another screen-share call is running.
  • 3066 (ERROR_ACTION_NOT_SUPPORTED_IN_MODE) in RECV_ONLY or SIGNALLING_ONLY mode.
  • 3016 (ERROR_GET_DISPLAY_MEDIA_PERMISSION_DENIED) when the user declined the consent, or it can't be used.
  • 3048 (ERROR_MEDIA_NOT_READY) when you pass null and no screen-share track was created.
  • 3071 (ERROR_INVALID_CUSTOM_TRACK_CONFIG) when customTrack is not a screen-share track.

Example​

private val screenShareLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
val data = result.data
if (result.resultCode == Activity.RESULT_OK && data != null) {
lifecycleScope.launch {
try {
room.enableScreenShare(data)
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Screen share failed: ${e.code} ${e.name}")
}
}
}
}

fun startScreenShare() {
val manager = getSystemService(MediaProjectionManager::class.java)
screenShareLauncher.launch(manager.createScreenCaptureIntent())
}

disableScreenShare()​

suspend fun disableScreenShare()

Returns​

  • Unit

Throws​

VideoSDKException with 3054 (ERROR_ALREADY_IN_REQUESTED_STATE) when nothing is being shared, 3055 (ERROR_OPERATION_IN_PROGRESS) while another screen-share call is running, or 3066 (ERROR_ACTION_NOT_SUPPORTED_IN_MODE) in RECV_ONLY or SIGNALLING_ONLY mode.


uploadBase64File()​

suspend fun uploadBase64File(base64Data: String, token: String, fileName: String): String
  • Uploads a file to VideoSDK's temporary storage and returns its URL. Pass that URL to fetchBase64File() to get the file back.
  • The room must be joined.

Parameters​

  • base64Data: String
    • Your file, converted to base64.
  • token: String
  • fileName: String
    • The file name, with its extension.

Returns​

  • String - The URL of the uploaded file.

Throws​

VideoSDKException with:

  • 3073 (ERROR_INVALID_PARAMETER) if any argument is empty.
  • 3035 or 3065 if the room is not joined or is reconnecting. These are also reported on onError.
  • 3074 (ERROR_FILE_UPLOAD_FAILED) if the upload fails. The same error is also reported on onError.

Example​

private fun uploadFile() {
val base64Data = "<Your File's base64>" // Convert your file to base64 and pass here
val token = "<VIDEOSDK_TOKEN>"
val fileName = "myImage.jpeg" // Provide name with extension here
lifecycleScope.launch {
try {
val fileUrl = room.uploadBase64File(base64Data, token, fileName)
Log.d("VideoSDK", "Uploaded file url: $fileUrl")
} catch (e: VideoSDKException) {
Log.d("VideoSDK", "Error in upload file: ${e.code} ${e.message}")
}
}
}

fetchBase64File()​

suspend fun fetchBase64File(url: String, token: String): String
  • Downloads a file from VideoSDK's temporary storage and returns it as base64.
  • The room must be joined.

Parameters​

Returns​

  • String - The file in base64 format.

Throws​

VideoSDKException with:

  • 3073 (ERROR_INVALID_PARAMETER) if any argument is empty.
  • 3035 or 3065 if the room is not joined or is reconnecting. These are also reported on onError.
  • 3075 (ERROR_FILE_FETCH_FAILED) if the fetch fails. The same error is also reported on onError.

Example​

private fun fetchFile() {
val url = "<Your FileUrl>" // Provide fileUrl which is returned by uploadBase64File()
val token = "<VIDEOSDK_TOKEN>"
lifecycleScope.launch {
try {
val base64 = room.fetchBase64File(url, token)
Log.d("VideoSDK", "Fetched file in base64: $base64")
} catch (e: VideoSDKException) {
Log.d("VideoSDK", "Error in fetch file: ${e.code} ${e.message}")
}
}
}

startRecording()​

suspend fun startRecording(
webhookUrl: String? = null,
awsDirPath: String? = null,
config: RecordingConfig? = null,
transcription: PostTranscriptionConfig? = null,
)
  • Starts recording the room.
  • It returns once the request is sent, before anything is recorded. onRecordingStarted() confirms that the recording is running.

Parameters​

  • webhookUrl: String?

    • A URL the server calls back about this recording, for example when it starts, stops or fails. See Webhooks and Events. null for none.
    • OPTIONAL, default null
  • awsDirPath: String?

    • The folder in the storage bucket configured for your account. See Configure Recording Storage. null stores the recording with VideoSDK.
    • OPTIONAL, default null
  • config: RecordingConfig? (package live.videosdk.rtc.android.model)

    • Leave config, or any of its fields, null to use the defaults. mode defaults to video and audio, and quality applies only to video and audio.
    • layout: ConfigLayout?
      • type: ConfigLayoutGrid? — GRID | SPOTLIGHT | SIDEBAR
      • priority: ConfigLayoutPriority? — SPEAKER | PIN
      • gridSize: Int? max 4
    • theme: ConfigTheme? — DARK | LIGHT | DEFAULT
    • mode: ConfigMode? — VIDEO_AND_AUDIO | AUDIO
    • quality: ConfigQuality? — LOW | MED | HIGH
    • orientation: ConfigOrientation? — LANDSCAPE | PORTRAIT
    • OPTIONAL, default null
  • transcription: PostTranscriptionConfig?

    • Transcribes the recording after the call, with an optional summary. null skips it.
    • enabled: Boolean
    • summary: SummaryConfig?, default null
      • enabled: Boolean
      • prompt: String?, default null
    • modelId: String?, default null
    • OPTIONAL, default null

Returns​

  • Unit

Throws​

VideoSDKException with 4011 (START_RECORDING_FAILED) when the server refuses the start, for example while a recording is already starting or running. The exception carries the server's reason, and the same error is reported on onError.

Events associated with startRecording():​

Example​

val webhookUrl = "https://webhook.your-api-server.com"
val config = RecordingConfig(
layout = ConfigLayout(
type = ConfigLayoutGrid.SPOTLIGHT,
priority = ConfigLayoutPriority.PIN,
gridSize = 4,
),
theme = ConfigTheme.DARK,
)

val prompt = "Write summary in sections like Title, Agenda, Speakers, Action Items, Outlines, Notes and Summary"
val transcription = PostTranscriptionConfig(
enabled = true,
summary = SummaryConfig(enabled = true, prompt = prompt),
modelId = "raman_v1",
)

lifecycleScope.launch {
try {
room.startRecording(webhookUrl = webhookUrl, config = config, transcription = transcription)
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Recording failed: ${e.code} ${e.name}")
}
}

stopRecording()​

suspend fun stopRecording()
  • Stops recording the room.
  • It returns once the request is sent. onRecordingStopped() confirms that the recording has stopped.

Returns​

  • Unit

Throws​

VideoSDKException with 4012 (STOP_RECORDING_FAILED) when the server refuses the stop, for example when no recording is running or one is still starting. The exception carries the server's reason, and the same error is reported on onError.

Events associated with stopRecording():​

Example​

lifecycleScope.launch {
try {
room.stopRecording()
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Stop recording failed: ${e.code} ${e.name}")
}
}

startLivestream()​

suspend fun startLivestream(outputs: List<LivestreamOutput>, config: LivestreamConfig? = null)
  • Streams the room to one or more RTMP destinations, such as YouTube Live, Facebook or your own RTMP server.
  • It returns once the request is sent. onLivestreamStarted() confirms that the livestream is running.

Parameters​

  • outputs: List<LivestreamOutput>
    • Each LivestreamOutput(url, streamKey) is an RTMP ingest URL and its stream key. Pass at least one.
  • config: LivestreamConfig? (package live.videosdk.rtc.android.model)
    • layout: ConfigLayout?
      • type: ConfigLayoutGrid? — GRID | SPOTLIGHT | SIDEBAR
      • priority: ConfigLayoutPriority? — SPEAKER | PIN
      • gridSize: Int? max 25
    • theme: ConfigTheme? — DARK | LIGHT | DEFAULT
    • recording: LivestreamRecordingConfig? — LivestreamRecordingConfig(enabled = true) also records the livestream.
    • OPTIONAL, default null. A field left null uses the default.

Returns​

  • Unit

Events associated with startLivestream():​

Example​

val YOUTUBE_RTMP_URL = "rtmp://a.rtmp.youtube.com/live2"
val YOUTUBE_RTMP_STREAM_KEY = "<STREAM_KEY>"

val outputs = listOf(LivestreamOutput(YOUTUBE_RTMP_URL, YOUTUBE_RTMP_STREAM_KEY))

val config = LivestreamConfig(
layout = ConfigLayout(
type = ConfigLayoutGrid.SPOTLIGHT,
priority = ConfigLayoutPriority.PIN,
gridSize = 9,
),
theme = ConfigTheme.DARK,
)

lifecycleScope.launch {
try {
room.startLivestream(outputs, config)
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Livestream failed: ${e.code} ${e.name}")
}
}

stopLivestream()​

suspend fun stopLivestream()
  • Stops the livestream.
  • It returns once the request is sent. onLivestreamStopped() confirms that the livestream has stopped.

Returns​

  • Unit

Events associated with stopLivestream():​

Example​

lifecycleScope.launch {
try {
room.stopLivestream()
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Stop livestream failed: ${e.code} ${e.name}")
}
}

startHLS()​

suspend fun startHLS(config: HLSConfig? = null, transcription: PostTranscriptionConfig? = null)
  • Publishes the room as an HLS stream, for viewers who only watch and never join the room, such as a webinar audience.
  • It returns once the request is sent. Don't start your player on HLS_STARTED: wait until onHlsStateChanged() reports HLSState.HLS_PLAYABLE, then play its hlsUrl.playbackHlsUrl.

Parameters​

  • config: HLSConfig? (package live.videosdk.rtc.android.model)

    • Leave config, or any of its fields, null to use the defaults. mode defaults to video and audio, and quality applies only to video and audio.
    • layout: ConfigLayout?
      • type: ConfigLayoutGrid? — GRID | SPOTLIGHT | SIDEBAR
      • priority: ConfigLayoutPriority? — SPEAKER | PIN
      • gridSize: Int? max 25
    • theme: ConfigTheme? — DARK | LIGHT | DEFAULT
    • mode: ConfigMode? — VIDEO_AND_AUDIO | AUDIO
    • quality: ConfigQuality? — LOW | MED | HIGH
    • orientation: ConfigOrientation? — LANDSCAPE | PORTRAIT
    • OPTIONAL, default null
  • transcription: PostTranscriptionConfig?

    • Transcribes the HLS stream after it ends, with an optional summary. null skips it.
    • enabled: Boolean
    • summary: SummaryConfig?, default null
      • enabled: Boolean
      • prompt: String?, default null
    • modelId: String?, default null
    • OPTIONAL, default null

Returns​

  • Unit

Events associated with startHLS():​

  • Every participant receives onHlsStateChanged() for each step: HLS_STARTING, HLS_STARTED, then HLS_PLAYABLE.

Example​

val config = HLSConfig(
layout = ConfigLayout(
type = ConfigLayoutGrid.SPOTLIGHT,
priority = ConfigLayoutPriority.PIN,
gridSize = 9,
),
orientation = ConfigOrientation.PORTRAIT,
theme = ConfigTheme.DARK,
)

val prompt = "Write summary in sections like Title, Agenda, Speakers, Action Items, Outlines, Notes and Summary"
val transcription = PostTranscriptionConfig(
enabled = true,
summary = SummaryConfig(enabled = true, prompt = prompt),
modelId = "raman_v1",
)

lifecycleScope.launch {
try {
room.startHLS(config, transcription)
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "HLS failed: ${e.code} ${e.name}")
}
}

stopHLS()​

suspend fun stopHLS()
  • Stops the HLS stream.
  • It returns once the request is sent. onHlsStateChanged() reports HLSState.HLS_STOPPED once HLS has stopped.

Returns​

  • Unit

Events associated with stopHLS():​

Example​

lifecycleScope.launch {
try {
room.stopHLS()
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Stop HLS failed: ${e.code} ${e.name}")
}
}

startTranscription()​

suspend fun startTranscription(config: TranscriptionConfig? = null)
  • Starts realtime transcription of everyone in the room, not just you.
  • Text arrives on onTranscriptionText(). The same sentence can arrive more than once as the service refines it.

Parameters​

  • config: TranscriptionConfig?
    • null uses the service's defaults. Every property is optional:
      • webhookURL: String? — a URL the service sends the finished transcript to. Live text arrives on onTranscriptionText() either way.
      • summary: SummaryConfig? — SummaryConfig(enabled, prompt). With enabled = true, a summary is produced after transcription stops. prompt tells it how to write the summary.
      • modelConfig: JSONObject? — settings for the transcription model, sent to the service unchanged.
    • OPTIONAL, default null

Returns​

  • Unit

Events associated with startTranscription():​

Example​

// Realtime Transcription Configuration
val webhookUrl = "https://www.example.com"

val summaryConfig = SummaryConfig(
enabled = true,
prompt = "Write summary in sections like Title, Agenda, Speakers, Action Items, Outlines, Notes and Summary"
)
val transcriptionConfig = TranscriptionConfig(
webhookURL = webhookUrl,
summary = summaryConfig
)

lifecycleScope.launch {
try {
room.startTranscription(transcriptionConfig)
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Transcription failed: ${e.code} ${e.name}")
}
}

stopTranscription()​

suspend fun stopTranscription()
  • Stops realtime transcription for the room.

Returns​

  • Unit

Events associated with stopTranscription():​

Example​

lifecycleScope.launch {
try {
room.stopTranscription()
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Stop transcription failed: ${e.code} ${e.name}")
}
}

startTranslation()​

suspend fun startTranslation(config: JSONObject? = null)
  • Starts realtime translation for the room.
  • Each participant receives only the language they asked for, set in createRoom() with translationLanguage or with changeTranslationLanguage(). One device never receives two languages at once.

Parameters​

  • config: JSONObject?
    • Translation settings, sent to the server unchanged. null uses the defaults.
    • OPTIONAL

Returns​

  • Unit

Events associated with startTranslation():​

Example​

lifecycleScope.launch {
try {
room.startTranslation()
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Translation failed: ${e.code} ${e.name}")
}
}

stopTranslation()​

suspend fun stopTranslation()
  • Stops realtime translation for every participant in the room, not just you.

Returns​

  • Unit

Events associated with stopTranslation():​


changeTranslationLanguage()​

suspend fun changeTranslationLanguage(language: String)
  • Changes the language you receive translations in. Other participants keep their own language.
  • Translation must already be running: call startTranslation() first.
  • The new language takes effect when onTranslationLanguageChanged() reports the change. Until then, onTranslationText() keeps the old language.

Parameters​

  • language: String
    • The language code, such as "hi".

Returns​

  • Unit

Throws​

VideoSDKException with 4044 (CHANGE_TRANSLATION_LANGUAGE_FAILED) when the server refuses the change, for example before translation has started.

Example​

lifecycleScope.launch {
try {
room.changeTranslationLanguage("hi")
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Language change failed: ${e.code} ${e.name}")
}
}

startWhiteboard()​

suspend fun startWhiteboard()
  • Opens a shared whiteboard for the room.
  • Every participant receives onWhiteboardStarted() with the URL to load in a WebView.

Returns​

  • Unit

Throws​

VideoSDKException with:

  • 4056 (WHITEBOARD_OPERATION_IN_PROGRESS) while another startWhiteboard() or stopWhiteboard() call is running.
  • 4054 (START_WHITEBOARD_FAILED) when the server refuses, for example when the whiteboard is already open. It is also reported on onError.

stopWhiteboard()​

suspend fun stopWhiteboard()

Returns​

  • Unit

Throws​

VideoSDKException with:

  • 4056 (WHITEBOARD_OPERATION_IN_PROGRESS) while another startWhiteboard() or stopWhiteboard() call is running.
  • 4055 (STOP_WHITEBOARD_FAILED) when the server refuses, for example when no whiteboard is open. It is also reported on onError.

changeMode()​

suspend fun changeMode(mode: Mode)
  • Changes your mode in the room.

  • Pass one of these Mode values:

    • Mode.SEND_AND_RECV: Audio and video are both sent and received.

    • Mode.SIGNALLING_ONLY: Audio and video are neither sent nor received, but the participant stays in the room.

    • Mode.RECV_ONLY: Audio and video are received but not sent.

  • After a change to SEND_AND_RECV, the mic and camera come back as they were just before the mode change: a device that was on turns back on, and one you had turned off stays off. For a participant who joined in RECV_ONLY or SIGNALLING_ONLY, micEnabled and camEnabled from createRoom() decide. Don't call unmuteMic() or enableCam() for a device that comes back on by itself: the call can throw 3054.

Parameters​

  • mode: Mode

Returns​

  • Unit

Throws​

VideoSDKException with 3054 (ERROR_ALREADY_IN_REQUESTED_STATE) when you are already in that mode, or 3055 (ERROR_OPERATION_IN_PROGRESS) while another changeMode() is running. Neither is reported on onError. A change that is refused also throws, with the refusal's code. A refusal from the server is reported on onError too, with 4065 (CHANGE_MODE_FAILED) or the server's code.

Events associated with changeMode():​

  • Every participant receives onParticipantModeChanged().
  • The local participant receives onStreamEnabled or onStreamDisabled for each stream the new mode adds or removes.
  • If the mode change ends your screen share, every participant receives onPresenterChanged() with null.

Example​

lifecycleScope.launch {
try {
room.changeMode(Mode.SIGNALLING_ONLY)
} catch (e: VideoSDKException) {
// 3054: already in this mode, 3055: another change is running
Log.e("VideoSDK", "Mode change failed: ${e.code} ${e.name}")
}
}

respondEntry()​

suspend fun respondEntry(participantId: String, decision: EntryDecision)
  • Lets a waiting participant in, or turns them away.
  • It answers a request delivered on onEntryRequested. onEntryResponded reports the decision.
  • You can also answer with the allow() and deny() callbacks that onEntryRequested passes.

Parameters​

  • participantId: String
    • The participantId from onEntryRequested.
  • decision: EntryDecision
    • EntryDecision.ALLOWED or EntryDecision.DENIED.

Returns​

  • Unit

Example​

val participantId = "<participantId from onEntryRequested>"
lifecycleScope.launch {
try {
room.respondEntry(participantId, EntryDecision.ALLOWED)
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "respondEntry failed: ${e.code} ${e.name}")
}
}

changeMic()​

suspend fun changeMic(deviceId: String? = null)

suspend fun changeMic(customMicrophoneTrack: CustomStreamTrack)
  • Moves your call audio to another device from VideoSDK.getMics(): SPEAKER_PHONE, EARPIECE, WIRED_HEADSET or BLUETOOTH.
  • Playback and recording move together. A wired or Bluetooth headset records from its own microphone; the speaker and earpiece use the phone's microphone.
  • If the mic is on, it is turned off and on again on the new device, so onStreamDisabled and then onStreamEnabled fire for every participant. A muted mic stays muted, and the next unmuteMic() uses the new device.
  • changeMic(customMicrophoneTrack) sends a different microphone track instead. It turns the mic on if it was off. Later unmuteMic() calls keep the track's audio settings.

Parameters​

  • deviceId: String?
    • The deviceId of a MicrophoneDeviceInfo from VideoSDK.getMics(). With no deviceId, it moves to the next device in that list, wrapping around.
    • OPTIONAL
  • customMicrophoneTrack: CustomStreamTrack

Returns​

  • Unit

Throws​

VideoSDKException with:

  • 3059 (ERROR_NO_MICROPHONE_DEVICE_FOUND) when deviceId is not in VideoSDK.getMics(). It is also reported on onError.
  • 3034 (ERROR_MICROPHONE_ACCESS_UNAVAILABLE) when the device list can't be read.
  • 3035 or 3065 when the room is not joined or is reconnecting. These are also reported on onError.

If switching to a deviceId fails, the previous device stays selected.

Example​

lifecycleScope.launch {
try {
val bluetooth = VideoSDK.getMics().firstOrNull { it.deviceId == "BLUETOOTH" }
if (bluetooth != null) {
room.changeMic(bluetooth.deviceId)
}
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Mic change failed: ${e.code} ${e.name}")
}
}

changeCam()​

suspend fun changeCam(deviceId: String? = null)

suspend fun changeCam(customCameraTrack: CustomStreamTrack)
  • Switches your camera to another one from VideoSDK.getCameras().
  • If the camera is on, it is turned off and on again on the new camera, so onStreamDisabled and then onStreamEnabled fire for every participant. A camera that is off stays off, and the next enableCam() uses the new camera.
  • changeCam(customCameraTrack) sends a different camera track instead. It turns the camera on if it was off. Later enableCam() calls keep the track's settings.

Parameters​

  • deviceId: String?
    • The deviceId of a camera from VideoSDK.getCameras(). With no deviceId, it moves to the next camera in that list, wrapping around. To pick the front or back camera, pass the deviceId of the camera with that facingMode.
    • OPTIONAL
  • customCameraTrack: CustomStreamTrack

Returns​

  • Unit

Throws​

VideoSDKException with:

  • 3051 (ERROR_NO_WEBCAM_DEVICE_FOUND) when no camera has that deviceId. It is also reported on onError.
  • 3033 (ERROR_CAMERA_ACCESS_UNAVAILABLE) when the camera list can't be read.
  • 3035 or 3065 when the room is not joined or is reconnecting. These are also reported on onError.

If the camera you pick with deviceId can't be opened, the previous camera stays selected.

Example​

lifecycleScope.launch {
try {
val backCamera = VideoSDK.getCameras().firstOrNull { it.facingMode == FacingMode.back }
if (backCamera != null) {
room.changeCam(backCamera.deviceId)
}
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Camera change failed: ${e.code} ${e.name}")
}
}

setWebcamQuality()​

suspend fun setWebcamQuality(quality: VideoQuality)
  • Caps the quality of the camera video you send. Remote participants receive at most this quality.
  • VideoQuality.HIGH sends every layer, VideoQuality.MEDIUM stops the largest one and VideoQuality.LOW sends only the smallest. A camera that sends a single layer is not affected.
  • The cap stays in force after the camera is turned off and on again.
  • When the room was created with dynaCast on, the stream may also drop lower while no remote participant is watching the larger layers, but never goes above this cap.

Parameters​

  • quality: VideoQuality
    • VideoQuality.LOW, VideoQuality.MEDIUM or VideoQuality.HIGH.

Returns​

  • Unit

Throws​

VideoSDKException with 3062 (ERROR_WEBCAM_NOT_ENABLED) when the camera is off, or 3063 (ERROR_SET_WEBCAM_QUALITY_FAILED) when the cap can't be applied.

Example​

lifecycleScope.launch {
try {
room.setWebcamQuality(VideoQuality.LOW)
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Quality change failed: ${e.code} ${e.name}")
}
}

getAppliedVideoConfig()​

fun getAppliedVideoConfig(): JSONObject?
  • It returns the camera settings in force: width, height, frameRate, facingMode, codec and applied.
  • It is null until the camera has been opened once. applied is false when the camera is set up but not running, for example after disableCam().
  • codec is the codec actually in use, which can differ from the one you asked for.

Returns​

  • JSONObject?

Example​

val video: JSONObject? = room.getAppliedVideoConfig()
Log.d("VideoSDK", "Camera: $video")

setVideoEffects()​

fun setVideoEffects(config: VideoEffectsConfig): JSONObject
  • Changes the camera effects while you are in the room: auto-framing, low-light correction, a style and a colour filter. To set them before joining, use VideoSDK.setVideoEffects().
  • Effects work only with VideoEffectsConfig.Pipeline.GRAPH. A pipeline change takes effect the next time the camera starts, so turn the camera off and on, or switch cameras, to apply it now. Changes to the effects themselves apply at once.
  • If the graph can't start on the device, onError reports 3080 (ERROR_VIDEO_EFFECTS_GRAPH_UNAVAILABLE) once, and the camera stays on Pipeline.LEGACY: the call keeps going, but the video is sent without effects. A GRAPH request made before any camera has started is not an error. Check applied and reason in the result. A GRAPH request made before the graph has ever run returns applied false with a reason that starts with pending:, and starts with the next camera.

Parameters​

  • config: VideoEffectsConfig

Returns​

  • JSONObject - The configuration in force, with applied and reason.

Example​

val result: JSONObject = room.setVideoEffects(
VideoEffectsConfig(
pipeline = VideoEffectsConfig.Pipeline.GRAPH,
lighting = VideoEffectsConfig.Lighting(enabled = true),
filter = VideoEffectsConfig.Filter(lut = VideoEffectsConfig.Lut.WARM),
)
)
val reason = result.optString("reason")
if (!result.optBoolean("applied") && !reason.startsWith("pending:")) {
Log.w("VideoSDK", "Effects not applied: $reason")
}

getAppliedVideoEffectsConfig()​

fun getAppliedVideoEffectsConfig(): JSONObject
  • It returns the video effects configuration in force, with applied and reason.

Returns​

  • JSONObject

setVideoProcessor()​

fun setVideoProcessor(processor: VideoFrameProcessor)
  • It installs a processor that sees every captured camera frame before it is encoded, for an effect or overlay the SDK does not provide.
  • It works before join() too, so a pre-join preview is processed.
  • onFrameCaptured() runs on the camera capture thread, so keep it under one frame interval or frames are dropped.
  • A new processor replaces the one already installed. removeVideoProcessor() takes it out, and leaving the room removes it.

Parameters​

  • processor: VideoFrameProcessor
    • VideoFrameProcessor is a fun interface. onFrameCaptured(videoFrame) returns the frame unchanged, or a new one.

Returns​

  • Unit

Example​

room.setVideoProcessor { videoFrame ->
// Return the frame unchanged, or a new one.
videoFrame
}

removeVideoProcessor()​

fun removeVideoProcessor()
  • It removes the processor set with setVideoProcessor(). Camera frames are sent unprocessed again.
  • Calling it with no processor installed does nothing.

Returns​

  • Unit

pauseAllStreams()​

suspend fun pauseAllStreams(kind: StreamKind? = null)
  • Stops the server sending you remote media of one kind. Unlike hiding the tiles, this saves bandwidth as well as rendering.
  • Other participants are not affected. Call resumeAllStreams() to get the media back.

Parameters​

  • kind: StreamKind?
    • StreamKind.AUDIO, StreamKind.VIDEO or StreamKind.SHARE (screen share). null pauses all three.
    • OPTIONAL, default null

Returns​

  • Unit

Events associated with pauseAllStreams():​

Example​

lifecycleScope.launch {
try {
room.pauseAllStreams()
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Pause failed: ${e.code} ${e.name}")
}
}

resumeAllStreams()​

suspend fun resumeAllStreams(kind: StreamKind? = null)

Parameters​

  • kind: StreamKind?
    • StreamKind.AUDIO, StreamKind.VIDEO or StreamKind.SHARE (screen share). null resumes all three.
    • OPTIONAL, default null

Returns​

  • Unit

Events associated with resumeAllStreams():​

Example​

lifecycleScope.launch {
try {
room.resumeAllStreams()
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Resume failed: ${e.code} ${e.name}")
}
}

enableAdaptiveSubscription()​

suspend fun enableAdaptiveSubscription()
  • Turns on adaptive subscription. Each video you receive then follows the size you report with setViewPort() on that participant.
  • Calling it while adaptive subscription is already on reports 4048 (ADAPTIVE_SUBSCRIPTION_ENABLE_FAILED) on onError.

Returns​

  • Unit

disableAdaptiveSubscription()​

suspend fun disableAdaptiveSubscription()
  • Turns off adaptive subscription. Each video you receive goes back to the quality its sender sends.
  • Calling it while adaptive subscription is already off reports an error on onError. Today that error is 4048 (ADAPTIVE_SUBSCRIPTION_ENABLE_FAILED), not 4049, so don't match on 4049 for it.

Returns​

  • Unit

requestMediaRelay()​

suspend fun requestMediaRelay(
destinationRoomId: String,
token: String? = null,
kinds: List<StreamKind>? = null,
)

Parameters​

  • destinationRoomId: String
    • The ID of the room to relay into.
  • token: String?
    • A token valid for the destination room. null uses this room's token.
    • OPTIONAL, default null
  • kinds: List<StreamKind>?
    • The kinds to relay: StreamKind.AUDIO, StreamKind.VIDEO and StreamKind.SHARE (screen share). null relays all three. An empty list relays none.
    • OPTIONAL, default null

Returns​

  • Unit

Throws​

VideoSDKException with 3073 (ERROR_INVALID_PARAMETER) when destinationRoomId is empty.

Example​

lifecycleScope.launch {
try {
room.requestMediaRelay("<room-id>")
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Relay request failed: ${e.code} ${e.name}")
}
}

stopMediaRelay()​

suspend fun stopMediaRelay(destinationRoomId: String)
  • Stops relaying your media to one room, for every kind at once.

Parameters​

  • destinationRoomId: String
    • The ID of the room you are relaying into.

Returns​

  • Unit

Throws​

VideoSDKException with 3073 (ERROR_INVALID_PARAMETER) when destinationRoomId is empty.

Events associated with stopMediaRelay():​

Example​

lifecycleScope.launch {
try {
room.stopMediaRelay("<room-id>")
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Stop relay failed: ${e.code} ${e.name}")
}
}

switchTo()​

suspend fun switchTo(roomId: String, token: String? = null)
  • Moves you into another room, such as a breakout room, without calling leave() and join(). The same Room object keeps working.
  • onRoomJoined fires again for the new room, with switchRoomId set to its ID.
  • You always enter the new room in Mode.SEND_AND_RECV, whatever mode you were in.
  • Your mic and camera come back on in the new room as they were before the switch. You don't need to call unmuteMic() or enableCam() again.

Parameters​

  • roomId: String
    • The ID of the room to move to.
  • token: String?
    • A token valid for the new room. null uses this room's token.
    • OPTIONAL, default null

Returns​

  • Unit

Throws​

VideoSDKException with:

  • 3073 (ERROR_INVALID_PARAMETER) when roomId is blank.
  • 4076 (SWITCH_ROOM_FAILED) when the destination room has no live session, for example because nobody has joined it yet. It is not reported on onError, and you stay in the current room, still CONNECTED.

Example​

lifecycleScope.launch {
try {
room.switchTo("<room-id>")
//or
room.switchTo("<room-id>", token)
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Switch failed: ${e.code} ${e.name}")
}
}

send()​

suspend fun send(message: String, reliable: Boolean = true)

suspend fun send(data: ByteArray, reliable: Boolean = true)
  • Sends a text or binary message to everyone else in the room.
  • Messages have no topic and are not saved, so participants who join later don't receive them. Use PubSub for messages that need a topic or history.
  • Other participants receive the message on onDataReceived. You don't receive your own message.

Parameters​

  • message: String or data: ByteArray
    • Up to 15 KiB.
  • reliable: Boolean
    • true resends until the message arrives and keeps the order. false sends it once: faster on a poor network, but it can be lost.
    • OPTIONAL, default true

Returns​

  • Unit

Throws​

VideoSDKException with:

  • 3035 or 3065 when the room is not joined or is reconnecting.
  • 3066 (ERROR_ACTION_NOT_SUPPORTED_IN_MODE) in a mode that can't send.
  • 3072 (ERROR_PAYLOAD_TOO_LARGE) when the message is larger than 15 KiB.
  • 3048 (ERROR_MEDIA_NOT_READY) when there is no connection to send on.
  • 3079 (ERROR_OPERATION_TIMED_OUT) when the connection never opens, and 3070 (ERROR_SEND_FAILED) when sending fails.

3035, 3079 and 3070 are also reported on onError.

Example​

lifecycleScope.launch {
try {
room.send("Hello everyone")
room.send(byteArrayOf(1, 2, 3), reliable = false)
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Send failed: ${e.code} ${e.name}")
}
}

activeRoom()​

companion object {
fun activeRoom(): Room?
}
  • Called as Room.activeRoom(). It returns the room that is joined or joining, or null when there is none.
  • It is set when join() starts and cleared once the room is left.
  • Use it from code that holds no Room reference.

Returns​

  • Room?

getActivePresenterId()​

fun getActivePresenterId(): String?
  • It returns the ID of the participant sharing their screen, or null when nobody is.
  • It follows onPresenterChanged.

Returns​

  • String?

getActiveSpeakerId()​

fun getActiveSpeakerId(): String?
  • It returns the ID of the participant speaking now, or null when the room is quiet.
  • It follows onSpeakerChanged.

Returns​

  • String?

Example​

val presenterId: String? = room.getActivePresenterId()
val speakerId: String? = room.getActiveSpeakerId()
Log.d("VideoSDK", "Presenter: $presenterId, speaker: $speakerId")

setAudioDevice()​

fun setAudioDevice(device: MicrophoneDeviceInfo)

Parameters​

Returns​

  • Unit

Throws​

VideoSDKException with 3059 (ERROR_NO_MICROPHONE_DEVICE_FOUND) when device is not one of the devices VideoSDK.getMics() lists right now. It is also reported on onError. The audio stays routed as it was.

Example​

val speaker = VideoSDK.getMics().firstOrNull { it.deviceId == "SPEAKER_PHONE" }
if (speaker != null) {
try {
room.setAudioDevice(speaker)
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Audio device change failed: ${e.code} ${e.name}")
}
}

setAudioDeviceChangeListener()​

fun setAudioDeviceChangeListener(listener: AudioDeviceChangeEvent?)
  • It sets the listener that is called whenever a headset or Bluetooth device is plugged in or removed, or the selected audio device changes.
  • It is also called once right away with the current device and list.
  • A new listener replaces the previous one, and null removes it. The listener is set for the whole app, not just this room: it stays set after leave().

Parameters​

  • listener: AudioDeviceChangeEvent?
    • AudioDeviceChangeEvent is a fun interface, so a lambda works. onAudioDeviceChanged(selectedAudioDevice: MicrophoneDeviceInfo?, audioDevices: List<MicrophoneDeviceInfo>) receives the device in use and every available device. selectedAudioDevice is null only when no audio device is available, which is always the case before VideoSDK.initialize().

Returns​

  • Unit

Example​

room.setAudioDeviceChangeListener { selectedAudioDevice, audioDevices ->
Toast.makeText(
this@MainActivity,
"Selected AudioDevice: ${selectedAudioDevice?.label} (${audioDevices.size} available)",
Toast.LENGTH_SHORT
).show()
}

addEventListener()​

fun addEventListener(listener: RoomEventListener)
  • Adds a RoomEventListener. Add it before you call join(), or you can miss the join and the first participants.
  • You can add more than one listener, and each one is called. The same listener added twice is called twice.
  • Events reach your listeners on the main thread. Override only the events you need: every method has an empty default.

Parameters​

  • listener: RoomEventListener

Returns​

  • Unit

removeEventListener()​

fun removeEventListener(listener: RoomEventListener)
  • Removes a listener you added. A listener that was never added is ignored.

Parameters​

  • listener: RoomEventListener

Returns​

  • Unit

removeAllEventListeners()​

fun removeAllEventListeners()
  • Removes every RoomEventListener you added.

Returns​

  • Unit

Got a Question? Ask us on discord