Skip to main content
Version: 3.x.x

RoomEventListener Class - Android


implementation​

  • RoomEventListener is an open class, and every method has an empty body. Override only the events you need, and add the listener to the Room class using the addEventListener() method. Add it before you call join(), or you can miss the first events.
  • Callbacks run on the main thread, except onError, which can arrive on another thread.
  • If your callback throws an exception, the SDK catches and logs it, and the other listeners still run.

Example​

private val roomEventListener = object : RoomEventListener() {
override fun onRoomJoined(switchRoomId: String?) {
Log.d("#room", "onRoomJoined()")
}
}

onRoomJoined()​

  • Called when the localParticipant successfully joined the room. From here you can enable media, subscribe to PubSub topics and call the other room methods.
  • It fires again on the same Room after a reconnect that needed a fresh join, and after switchTo(). Don't use it for one-time setup.
  • After a reconnect or a room switch, the SDK turns your mic and camera back on as they were before. You don't need to call unmuteMic() or enableCam() again.

Event callback parameters​

  • switchRoomId: String?
    • The ID of the room you switched to with switchTo(). It is null on a first join and on a rejoin after reconnecting.

Example​

override fun onRoomJoined(switchRoomId: String?) {
if (switchRoomId == null) {
Log.d("#room", "onRoomJoined()")
} else {
Log.d("#room", "Switched to room $switchRoomId")
}
}

onRoomLeft()​

  • Called when the localParticipant left the room.
  • It fires on every way out: leave(), end(), being removed, the same participant ID joining from another device, or reconnection giving up.
  • onRoomStateChanged with DISCONNECTED always fires just before it.
  • The camera and microphone are released before it fires, so you can join again from inside it.

Event callback parameters​

  • reason: LeaveReason - The reason why you left. It is MANUAL_LEAVE_CALLED after leave(), MEETING_END_API after your own end(), and ROOM_CLOSE when another participant ended the room. See LeaveReason Enum for all possible values.

Example​

override fun onRoomLeft(reason: LeaveReason) {
Log.d("#room", "onRoomLeft() :: reason: ${reason.code} ${reason.message}")
}

onParticipantJoined()​

  • Called when a new participant joined the room. AI agents arrive here too. The local participant never does.
  • Add a ParticipantEventListener to the participant here. This event always fires before that participant's first onStreamEnabled.

Event callback parameters​

Example​

override fun onParticipantJoined(participant: Participant) {
Log.d("#room", participant.displayName + " joined")
}

onParticipantLeft()​

Event callback parameters​

  • participant: Participant
    • If this device never saw the participant, it is a stand-in with the right id and an empty displayName.
  • reason: LeaveReason - The reason why the participant left. It is UNKNOWN when the server sent no reason. See LeaveReason Enum for all possible values.

Example​

override fun onParticipantLeft(participant: Participant, reason: LeaveReason) {
Log.d("#room", "${participant.displayName} left :: reason: ${reason.message}")
}

onSpeakerChanged()​

  • Called when the active speaker changes. There is one active speaker at a time; this is not a volume level for each participant.
  • getActiveSpeakerId() returns the same value later.

Event callback parameters​

  • activeSpeakerId: String? - The participant now speaking, or null when nobody is speaking.

Example​

override fun onSpeakerChanged(activeSpeakerId: String?) {
Log.d("#room", "Active speaker: $activeSpeakerId")
}

onPresenterChanged()​

Event callback parameters​

  • presenterId: String? - The participant now presenting, or null once sharing has stopped. A changeMode() that ends an active share also passes null.

Example​

override fun onPresenterChanged(presenterId: String?) {
Log.d("#room", "Presenter: $presenterId")
}

onEntryRequested()​

  • Called when a new participant who is trying to join the room has the permission ask_join in their token.
  • It is only emitted to the participants in the room who have the permission allow_join in their token.
  • Nothing happens until you answer. Call allow() or deny(), or use respondEntry(). If you don't answer, the participant keeps waiting until the server times out the request.
  • An answer given after the room was left, or while it is reconnecting, is not sent. The reason arrives on onError.

Event callback parameters​

  • participantId: String - The waiting participant's ID.
  • name: String - Their display name. It is empty if they joined without one.
  • allow: () -> Unit - Lets them in.
  • deny: () -> Unit - Turns them away.

Example​

override fun onEntryRequested(
participantId: String,
name: String,
allow: () -> Unit,
deny: () -> Unit,
) {
Log.d("#room", "$name wants to join")
// let them in, or call deny() to turn them away
allow()
}

onEntryResponded()​

  • Called when the server has processed an entry decision.
  • It is emitted to the participants in the room who have the permission allow_join in their token.
  • It is also emitted to the participant who requested to join the room.

Event callback parameters​

  • participantId: String - The participant the decision was about.
  • decision: EntryDecision? - EntryDecision.ALLOWED or EntryDecision.DENIED. It is null if the server sent neither.

Example​

override fun onEntryResponded(participantId: String, decision: EntryDecision?) {
Log.d("#room", "Entry for $participantId: $decision")
}

onWebcamRequested()​

  • Called when another participant asks you to turn your camera on. Nothing changes until you answer.
  • accept() turns your camera on. It is live once your local participant's onStreamEnabled fires, not when accept() returns.
  • reject() sends nothing back. The other participant's request times out.

Event callback parameters​

  • participantId: String - The participant who asked.
  • listener: WebcamRequestListener - Call accept() or reject() on it. It is valid for this one request only.

Example​

override fun onWebcamRequested(participantId: String, listener: WebcamRequestListener) {
// turn the camera on, or call listener.reject() to decline
listener.accept()
}

onMicRequested()​

  • Called when another participant asks you to turn your microphone on. Nothing changes until you answer.
  • accept() turns your microphone on. It is live once your local participant's onStreamEnabled fires, not when accept() returns.
  • reject() sends nothing back. The other participant's request times out.

Event callback parameters​

  • participantId: String - The participant who asked.
  • listener: MicRequestListener - Call accept() or reject() on it. It is valid for this one request only.

Example​

override fun onMicRequested(participantId: String, listener: MicRequestListener) {
// turn the microphone on, or call listener.reject() to decline
listener.accept()
}

onRecordingStateChanged()​

  • Called at every step of the room's cloud recording, the intermediate ones included.
  • recordingState holds the latest state.

Event callback parameters​

  • state: RecordingState

state has the following values. A state this SDK version does not know is not delivered.

  • RECORDING_STARTING - Recording is in starting phase and hasn't started yet.
  • RECORDING_STARTED - Recording has started successfully.
  • RECORDING_STOPPING - Recording is in stopping phase and hasn't stopped yet.
  • RECORDING_STOPPED - Recording has stopped successfully.

Example​

override fun onRecordingStateChanged(state: RecordingState) {
when (state) {
RecordingState.RECORDING_STARTING -> Log.d("onRecordingStateChanged", "Room recording is starting")
RecordingState.RECORDING_STARTED -> Log.d("onRecordingStateChanged", "Room recording is started")
RecordingState.RECORDING_STOPPING -> Log.d("onRecordingStateChanged", "Room recording is stopping")
RecordingState.RECORDING_STOPPED -> Log.d("onRecordingStateChanged", "Room recording is stopped")
}
}

onRecordingStarted()​

  • Called when the server confirms that recording of the room has started.

Example​

override fun onRecordingStarted() {
//
}

onRecordingStopped()​

  • Called when the server confirms that recording of the room has stopped.

Example​

override fun onRecordingStopped() {
//
}

onLivestreamStateChanged()​

  • Called at every step of the room's livestream, the intermediate ones included.
  • liveStreamState holds the latest state.

Event callback parameters​

  • state: LiveStreamState

state has the following values. A state this SDK version does not know is not delivered.

  • LIVESTREAM_STARTING - Livestream is in starting phase and hasn't started yet. After onError reports 4013 (START_LIVESTREAM_FAILED), a LIVESTREAM_STARTING doesn't mean a start is still in progress.
  • LIVESTREAM_STARTED - Livestream has started successfully.
  • LIVESTREAM_STOPPING - Livestream is in stopping phase and hasn't stopped yet.
  • LIVESTREAM_STOPPED - Livestream has stopped successfully.

Example​

override fun onLivestreamStateChanged(state: LiveStreamState) {
when (state) {
LiveStreamState.LIVESTREAM_STARTING -> Log.d("LivestreamStateChanged", "Room livestream is starting")
LiveStreamState.LIVESTREAM_STARTED -> Log.d("LivestreamStateChanged", "Room livestream is started")
LiveStreamState.LIVESTREAM_STOPPING -> Log.d("LivestreamStateChanged", "Room livestream is stopping")
LiveStreamState.LIVESTREAM_STOPPED -> Log.d("LivestreamStateChanged", "Room livestream is stopped")
}
}

onLivestreamStarted()​

  • Called when the server confirms that the RTMP live stream of the room has started.

Example​

override fun onLivestreamStarted() {
//
}

onLivestreamStopped()​

  • Called when the server confirms that the RTMP live stream of the room has stopped.

Example​

override fun onLivestreamStopped() {
//
}

onHlsStateChanged()​

  • Called at every step of the room's HLS (HTTP Live Streaming), once per state.
  • hlsState holds the latest state.

Event callback parameters​

  • state: HLSState
    • HLS_STARTING - HLS is in starting phase and hasn't started yet.
    • HLS_STARTED - The server accepted the request. The stream can't be played yet.
    • HLS_PLAYABLE - The stream can be played now. The URLs arrive with this state.
    • HLS_STOPPING - HLS is in stopping phase and hasn't stopped yet.
    • HLS_STOPPED - HLS has stopped successfully.
  • hlsUrl: HLSUrl? - The playback URLs. It is set only with HLS_PLAYABLE, so start your player then. It is null with every other state, and with HLS_PLAYABLE only if the server sent no URL.
    • playbackHlsUrl: String? - The playlist for viewers.
    • livestreamUrl: String? - The playlist that follows the live edge.

Example​

override fun onHlsStateChanged(state: HLSState, hlsUrl: HLSUrl?) {
when (state) {
HLSState.HLS_STARTING -> Log.d("onHlsStateChanged", "Room HLS is starting")
HLSState.HLS_STARTED -> Log.d("onHlsStateChanged", "Room HLS is started")
HLSState.HLS_PLAYABLE -> {
Log.d("onHlsStateChanged", "Room HLS is playable now")
val playbackHlsUrl = hlsUrl?.playbackHlsUrl
val livestreamUrl = hlsUrl?.livestreamUrl
}
HLSState.HLS_STOPPING -> Log.d("onHlsStateChanged", "Room HLS is stopping")
HLSState.HLS_STOPPED -> Log.d("onHlsStateChanged", "Room HLS is stopped")
}
}

onTranscriptionStateChanged()​

  • This event will be triggered at every step of realtime transcription.
  • One transcription runs for the whole room, so every participant gets these events.
  • transcriptionState holds the latest state.

Event callback parameters​

  • state: TranscriptionState

state has the following values. A state this SDK version does not know is not delivered.

  • TRANSCRIPTION_STARTING - Realtime Transcription is in starting phase and no text is arriving yet.
  • TRANSCRIPTION_STARTED - Realtime Transcription has started, and text arrives on onTranscriptionText.
  • TRANSCRIPTION_STOPPING - Realtime Transcription is in stopping phase. The last lines may still arrive.
  • TRANSCRIPTION_STOPPED - Realtime Transcription has stopped.

Example​

override fun onTranscriptionStateChanged(state: TranscriptionState) {
when (state) {
TranscriptionState.TRANSCRIPTION_STARTING -> Log.d("#room", "Transcription is starting")
TranscriptionState.TRANSCRIPTION_STARTED -> Log.d("#room", "Transcription is started")
TranscriptionState.TRANSCRIPTION_STOPPING -> Log.d("#room", "Transcription is stopping")
TranscriptionState.TRANSCRIPTION_STOPPED -> Log.d("#room", "Transcription is stopped")
}
}

onTranscriptionText()​

  • Called when text arrives from a running realtime transcription. Every participant receives every speaker's text.
  • The same utterance can arrive more than once as the service refines it: first as TranscriptionType.REALTIME lines, then once as TranscriptionType.FULL_SENTENCE. Add a line to a transcript only when getType() is FULL_SENTENCE.

Event callback parameters​

  • data: TranscriptionText
    • TranscriptionText.getParticipantId(): String - The speaker's participant ID, or "" when the server sent none.
    • TranscriptionText.getParticipantName(): String - The speaker's display name.
    • TranscriptionText.getText(): String - The transcribed text.
    • TranscriptionText.getTimestamp(): Long - The service's timestamp for the utterance. It is 0 when the service sent none.
    • TranscriptionText.getType(): TranscriptionType? - REALTIME for a partial result that can still change, FULL_SENTENCE for the settled sentence, or null for an unknown value.

Example​

override fun onTranscriptionText(data: TranscriptionText) {
// a REALTIME line is a preview that a later line replaces
if (data.getType() != TranscriptionType.FULL_SENTENCE) return

val participantName = data.getParticipantName()
val text = data.getText()
val timestamp = data.getTimestamp()

Log.d("#room", "$participantName: $text $timestamp")
}

onTranslationStateChanged()​

  • This event will be triggered at every step of realtime translation.
  • One translation runs for the whole room. A participant who joins while translation is already running receives TRANSLATION_STARTED too, before its own onRoomJoined. Add your RoomEventListener before you call join(), or you miss it.
  • translationState holds the latest state.

Event callback parameters​

  • state: TranslationState

state has the following values. A state this SDK version does not know is not delivered.

  • TRANSLATION_STARTING - Translation is in starting phase and no text is arriving yet.
  • TRANSLATION_STARTED - Translation has started, and text arrives on onTranslationText.
  • TRANSLATION_STOPPING - Translation is in stopping phase. The last lines may still arrive.
  • TRANSLATION_STOPPED - Translation has stopped.

Example​

override fun onTranslationStateChanged(state: TranslationState) {
if (state == TranslationState.TRANSLATION_STARTED) {
Log.d("#room", "Translation is running")
}
}

onTranslationText()​

Event callback parameters​

  • data: TranslationText
    • TranslationText.getParticipantId(): String - The speaker's participant ID.
    • TranslationText.getParticipantName(): String - The speaker's display name.
    • TranslationText.getParticipantLanguage(): String - The language the speaker spoke, such as "en".
    • TranslationText.getLanguage(): String - The language of this text, such as "hi".
    • TranslationText.getText(): String - The translated text.
    • TranslationText.getTimestamp(): Double - It is 0.0 when the service sent none.
    • TranslationText.getType(): TranslationType? - PARTIAL while the utterance is still being revised, FULL once it is final, or null for an unknown value. A new PARTIAL line replaces the previous one, so add text to a transcript only on FULL.

Example​

override fun onTranslationText(data: TranslationText) {
if (data.getType() == TranslationType.FULL) {
Log.d("#room", "${data.getParticipantName()} (${data.getLanguage()}): ${data.getText()}")
}
}

onTranslationLanguageChanged()​

  • Called when any participant, including the local one, changes the language they receive translations in.
  • After you call changeTranslationLanguage(), the new language applies once this event arrives for your participant ID. Until then, onTranslationText keeps delivering the old language.
  • If the server refuses the change, for example because translation has not started, changeTranslationLanguage() throws VideoSDKException with 4044 (CHANGE_TRANSLATION_LANGUAGE_FAILED).

Event callback parameters​

  • participantId: String - The participant whose language changed.
  • language: String - The new language code.

Example​

override fun onTranslationLanguageChanged(participantId: String, language: String) {
Log.d("#room", "$participantId now receives translations in $language")
}

onWhiteboardStarted()​

  • This event will be triggered when the whiteboard is successfully started.

Event callback parameters​

  • url: String - Load it in a WebView. It is empty when the server sent no URL, which means there is nothing to show.

Example​

override fun onWhiteboardStarted(url: String) {
super.onWhiteboardStarted(url)
//...
}

onWhiteboardStopped()​

  • This event will be triggered when the whiteboard session is successfully terminated.

Example​

override fun onWhiteboardStopped() {
super.onWhiteboardStopped()
//...
}

onError()​

  • Called when the SDK detects an error or the server reports one for this room.
  • Most errors that a suspend method throws are also reported here.
  • Unlike the other callbacks, it can arrive off the main thread. Post to the main thread before you touch the UI.

Event callback parameters​

  • error: VideoSDKError
    • code: Int - The error code. See Error Codes.
    • name: String - The error name, such as ERROR_ROOM_RECONNECTING. It is empty only for a code this SDK version does not know that arrived without a name.
    • message: String - A readable reason. It carries the server's message when the server sent one.
  • Compare error with a VideoSDKError constant using == or when. Two errors are equal when their codes are equal.

Example​

override fun onError(error: VideoSDKError) {
when (error) {
VideoSDKError.ERROR_ROOM_RECONNECTING -> Log.w("#room", "Reconnecting…")
else -> Log.e("#room", "Error ${error.code} (${error.name}): ${error.message}")
}
// onError can arrive off the main thread
runOnUiThread {
Toast.makeText(this@MainActivity, error.message, Toast.LENGTH_SHORT).show()
}
}

onRoomStateChanged()​

  • Called when the connection state of the room changes. roomState holds the latest state.
  • All available states are:
    • CONNECTING - The join has started.
    • CONNECTED - Fires together with onRoomJoined, and again when a connection problem is fixed without rejoining.
    • RECONNECTING - The connection dropped and the SDK is retrying. Until it recovers, most methods are refused with 3065. While the phone is offline, the SDK waits up to 2 minutes for the network; then the room ends with onRoomLeft(LeaveReason.WEBSOCKET_CONNECTION_ATTEMPTS_EXHAUSTED). See Room Connection Events.
    • DISCONNECTED - The room is over. It fires once, just before onRoomLeft.
    • FAILED - The join failed, or reconnecting gave up. It is not retried. After a join fails, call leave(): it releases the room and fires onRoomLeft with LeaveReason.MANUAL_LEAVE_CALLED. To try again, create a new room with VideoSDK.createRoom() and join that.

Event callback parameters​

  • roomState: RoomState

Example​

override fun onRoomStateChanged(roomState: RoomState) {
when (roomState) {
RoomState.CONNECTING -> Log.d("#room", "Joining…")
RoomState.RECONNECTING -> Log.d("#room", "Reconnecting…")
RoomState.CONNECTED -> Log.d("#room", "Connected")
RoomState.FAILED -> Log.d("#room", "Could not connect")
RoomState.DISCONNECTED -> Unit
}
}

onExternalCallRinging()​

  • Called when an incoming phone call starts ringing on the user's device.
  • The external-call events only report the call. The SDK does not mute, pause or leave anything on its own.
  • They are delivered to the room that was joined most recently.
note

The four external-call events need the READ_PHONE_STATE permission. Declare it in AndroidManifest.xml and request it at runtime. Without it, they never fire. See External call detection.

Event callback parameters​

  • callType: CallType - Always CallType.INCOMING. Android reports no ringing for a call the user dials.

Example​

override fun onExternalCallRinging(callType: CallType) {
Log.d("#room", "onExternalCallRinging: User phone is ringing ($callType)")
}

onExternalCallAnswered()​

  • Called when a phone call starts on the user's device: the user answers an incoming call or dials out.

Event callback parameters​

Example​

override fun onExternalCallAnswered(callType: CallType) {
Log.d("#room", "onExternalCallAnswered: $callType call started")
}

onExternalCallRejected()​

  • Called when a ringing call ends without being answered. Android cannot tell a declined call from a missed one, so both arrive here.

Event callback parameters​

  • callType: CallType - Always CallType.INCOMING.

Example​

override fun onExternalCallRejected(callType: CallType) {
Log.d("#room", "onExternalCallRejected: call was declined or missed")
}

onExternalCallHangup()​

  • Called when an answered or dialled phone call ends.

Event callback parameters​

Example​

override fun onExternalCallHangup(callType: CallType) {
Log.d("#room", "onExternalCallHangup: $callType call ended")
}

onPausedAllStreams()​

  • Called when the remote streams of one kind stop being delivered to you, after pauseAllStreams().
  • pauseAllStreams() with no kind pauses audio, video and share, so this callback fires once for each kind.
  • A single stream paused with RTCStream.pause() reports on the participant's onStreamPaused instead.

Parameters​

  • kind: Specifies the type of media stream that was paused.
    • Type: StreamKind?
    • Possible values:
      • StreamKind.AUDIO: Indicates that audio streams have been paused.
      • StreamKind.VIDEO: Indicates that video streams have been paused.
      • StreamKind.SHARE: Indicates that screen-sharing video streams have been paused.
      • null: The server named a kind this SDK version does not know.

Example​

override fun onPausedAllStreams(kind: StreamKind?) {
Log.d("TAG", "onPausedAllStreams: $kind")
super.onPausedAllStreams(kind)
}

onResumedAllStreams()​

Parameters​

  • kind: Specifies the type of media stream that was resumed.
    • Type: StreamKind?
    • Possible values:
      • StreamKind.AUDIO: Indicates that audio streams have been resumed.
      • StreamKind.VIDEO: Indicates that video streams have been resumed.
      • StreamKind.SHARE: Indicates that screen-sharing video streams have been resumed.
      • null: The server named a kind this SDK version does not know.

Example​

override fun onResumedAllStreams(kind: StreamKind?) {
Log.d("TAG", "onResumedAllStreams: $kind")
super.onResumedAllStreams(kind)
}

onParticipantModeChanged()​

This event is triggered when any participant's mode changes, including a change the server made.

The new mode is one of the following:

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

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

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

The participant's mode property is already updated when this event fires.

Event Callback Parameters​

  • participantId: String - The participant whose mode changed.
  • mode: Mode - Their new mode.

Example​

override fun onParticipantModeChanged(participantId: String, mode: Mode) {
Log.d("#room", "$participantId is now in $mode mode")
}

onPinStateChanged()​

  • This event will be triggered when any participant is pinned or unpinned by any participant.
  • The participant's pinState property is already updated when this event fires.

Event callback parameters​

  • participantId: String - The participant who was pinned or unpinned.
  • state: ParticipantPinState - Which of their streams are pinned now.
    • cam: Boolean - true while the camera is pinned.
    • share: Boolean - true while the screen share is pinned.
    • Both false means the participant is unpinned.
  • pinnedBy: String? - The participant who made the change, or null when the server did not say.

Example​

override fun onPinStateChanged(participantId: String, state: ParticipantPinState, pinnedBy: String?) {
Log.d("onPinStateChanged", "$participantId cam=${state.cam} share=${state.share} by $pinnedBy")
}

onMediaRelayRequestReceived()​

  • Called when a request is received for media relay in the destination room.
  • Nothing is relayed until you answer with accept() or reject().
  • Both need a joined room. If the room has ended or is reconnecting when you answer, the answer is not sent and the reason arrives on onError.

Event callback parameters​

  • participantId - (String): Specifies the participantId who requested the media relay.

  • roomId - (String): The room the request comes from.

  • displayName - (String): Specifies the display name of the participant who requested the media relay.

  • accept - (() -> Unit): Approves the request. The requesting participant's media then arrives in this room as a participant: you get onParticipantJoined for them. onMediaRelayStarted is not called in this room; only the requester gets it.

  • reject - (() -> Unit): Denies the media relay request. The requesting room is told.

Example​

override fun onMediaRelayRequestReceived(
participantId: String,
roomId: String,
displayName: String,
accept: () -> Unit,
reject: () -> Unit,
) {
Log.d("MediaRelay", "$displayName wants to relay media from $roomId")
// approve the request, or call reject() to deny it
accept()
}

onMediaRelayRequestResponse()​

  • Called when a response is received for media relay request in the source room.
  • An accepted request is followed by onMediaRelayStarted on your side. A rejected one is followed by nothing.

Event callback parameters​

  • decision - (RelayDecision?): RelayDecision.ACCEPTED or RelayDecision.REJECTED. It is null if the server sent neither.

  • decidedBy - (String): Specifies the participantId who responded to the media relay request.

  • roomId - (String): Specifies the room that answered. It is empty when the server did not say.

Example​

override fun onMediaRelayRequestResponse(decision: RelayDecision?, decidedBy: String, roomId: String) {
super.onMediaRelayRequestResponse(decision, decidedBy, roomId)

Log.d("MediaRelay", "Room: $roomId, Decided by: $decidedBy, Decision: $decision")
}

onMediaRelayStarted()​

  • Called on the participant who requested the relay, once the destination room has accepted and the relay is running.
  • The destination room doesn't get it. There, the relayed participant arrives on onParticipantJoined.

Parameters​

  • roomId - (String): The destination room.

Example​

override fun onMediaRelayStarted(roomId: String) {
super.onMediaRelayStarted(roomId)
Log.d("MediaRelay", "Media relay started with room ID: $roomId")
}

onMediaRelayStopped()​

  • Called on the participant who requested the relay when it stops, for any reason.
  • The destination room doesn't get it. There, the relayed participant leaves on onParticipantLeft with LeaveReason.REMOVE_PEER_MEDIA_RELAY_STOP.

Parameters​

  • roomId - (String): The destination room.

  • reason - (String?): The server's reason for the stop, for example "Requested by sdk." after stopMediaRelay(). It is null when the server sent none.

Example​

override fun onMediaRelayStopped(roomId: String, reason: String?) {
super.onMediaRelayStopped(roomId, reason)
Log.d("MediaRelay", "Media relay stopped for room ID: $roomId, Reason: $reason")
}

onMediaRelayError()​

  • Called when the media relay fails.
  • An error is not always followed by onMediaRelayStopped, so clear your relay UI here too.

Parameters​

  • roomId - (String): Specifies the room the media relay connected.

  • error - (String): Specifies the error that occurred. It is empty when the server sent none.

Example​

override fun onMediaRelayError(roomId: String, error: String) {
super.onMediaRelayError(roomId, error)
Log.e("MediaRelay", "Media relay error for room ID: $roomId, Error: $error")
}

onCodecChanged()​

  • Called when the video you send was switched to VP8 because a remote participant could not decode the codec you were using.
  • It fires only while your camera is sending, and only when codecSwitchEnabled in VideoSDK.createRoom() is true, which is the default.
  • A local encoder problem does not fire this event. It is reported on onError with 3045 instead.

Event callback parameters​

  • info: CodecChangeInfo
    • unsupportedRemoteCodec: VideoCodec? - The codec the remote participant could not decode.
    • currentCodec: VideoCodec - The codec you send now. It is always VP8.
    • previousCodec: VideoCodec? - The codec you sent before.
    • kind: String - Always "video".
    • causedBy: Participant? - The participant that could not decode. It is null when the switch happened at join or when that participant is no longer in the room.

Example​

override fun onCodecChanged(info: CodecChangeInfo) {
Log.d("#room", "Video codec changed from ${info.previousCodec} to ${info.currentCodec}")
}

onQualityLimitation()​

  • Called when the media you send has to be reduced to fit the device's CPU or the network, and again when the limit clears.
  • Each type is tracked on its own, so more than one can be active at a time.
  • Quality problems on the media you receive are not reported here.

Event callback parameters​

  • type: QualityLimitationType - CPU, BANDWIDTH or CONGESTION.
  • state: QualityLimitationState - DETECTED when the limit starts, RESOLVED when it clears.
  • timestamp: Long - When the change was detected, in epoch milliseconds.

Example​

override fun onQualityLimitation(
type: QualityLimitationType,
state: QualityLimitationState,
timestamp: Long,
) {
if (state == QualityLimitationState.DETECTED) {
Log.w("#room", "Sending quality is limited by $type at $timestamp")
} else {
Log.d("#room", "$type limitation resolved")
}
}

onDataReceived()​

  • Called for each message another participant sends with send().
  • You don't receive your own messages. Messages have no topic and are not replayed to participants who join later.

Event callback parameters​

  • data: DataMessage
    • senderId: String - The participant who sent the message.
    • isBinary: Boolean - true for bytes, false for text.
    • text: String? - The text, or null when isBinary is true.
    • data: ByteArray? - The bytes, or null when isBinary is false.
    • reliable: Boolean - true when the message was sent reliably, false when it was sent without delivery guarantees.
    • timestamp: Long - When this device received the message, in epoch milliseconds.

Example​

override fun onDataReceived(data: DataMessage) {
if (data.isBinary) {
Log.d("#room", "${data.senderId} sent ${data.data?.size ?: 0} bytes")
} else {
Log.d("#room", "${data.senderId}: ${data.text}")
}
}

Got a Question? Ask us on discord