Skip to main content
Version: 3.x.x

ParticipantEventListener Class - Android

Implementation​

  • You can extend the ParticipantEventListener class, override only the callbacks you need, and add the listener to Participant class using the addEventListener() method of Participant Class. Every callback has an empty default body.

  • Callbacks arrive on the main thread. The exception is the onStreamEnabled() replay that addEventListener() runs on the calling thread.

  • Catch and log exceptions inside your callbacks yourself.


onStreamEnabled()​

  • onStreamEnabled() is called when the participant starts sending their microphone, camera or screen share. This is where you render it.

  • It also fires for the local participant, for example when you turn on your own camera.

  • When you add a listener, it fires straight away for every stream the participant already has. Don't also loop over participant.streams to render them, or each stream is handled twice.

Event callback parameters​

  • stream: RTCStream - use stream.kind to tell the streams apart: MediaType.AUDIO, MediaType.VIDEO, MediaType.SHARE or MediaType.SHARE_AUDIO.

  • To follow the health of a video stream, set setOnStreamStateChangedListener() on it here.


onStreamDisabled()​

  • onStreamDisabled() is called when the participant stops sending their microphone, camera or screen share. Remove any view that shows it.

Event callback parameters​

  • stream: RTCStream - the stream that ended. Its track is already gone, so don't read from it.

onMediaStatusChanged()​

Event callback parameters​

  • participantId: String - The participant whose media changed.
  • kind: MediaType - AUDIO, VIDEO, SHARE or SHARE_AUDIO.
  • newStatus: Boolean - true when it was turned on.

onStreamPaused()​

  • onStreamPaused() is called when this device stops receiving one of the participant's streams, because you called pause() on it or the server paused it. The participant still sends it.

Event callback parameters​

  • kind: StreamKind? - AUDIO, VIDEO or SHARE; null for screen-share audio.
  • reason: String - the reason the server gave, or empty.

onStreamResumed()​

  • onStreamResumed() is called when a paused stream of the participant is received again.

Event callback parameters​

  • kind: StreamKind? - AUDIO, VIDEO or SHARE; null for screen-share audio.
  • reason: String - the reason the server gave, or empty.

onE2EEStateChanged()​

  • onE2EEStateChanged() is called when end-to-end encryption starts working or fails on one of the participant's streams: EncryptionSuccess or DecryptionSuccess when it starts working. A success state is reported once per stream, not per frame.

  • Decryption failures are not reported. A wrong or removed key shows only as the stream going dark.

  • Encryption states are reported on the local participant, and decryption states on the remote participant who sent the media.

  • It is reported only while a key provider is set with VideoSDK.setKeyProvider().

Event callback parameters​

  • state: E2EEState - the encryption state of the stream:
ValueMeaning
EncryptionSuccessA stream this device sends is being encrypted.
DecryptionSuccessA stream from a remote participant is being decrypted.
EncryptionFailedA frame could not be encrypted, so it was not sent.
DecryptionFailedA frame from a remote participant could not be decrypted. Not reported.
InternalErrorEncryption failed inside the SDK.
  • stream: RTCStream - the stream concerned. When the stream ID cannot be matched, it is another stream of the same kind, so rely on kind rather than id here.

Example​

participant.addEventListener(object : ParticipantEventListener() {
override fun onE2EEStateChanged(state: E2EEState, stream: RTCStream) {
if (state == E2EEState.DecryptionSuccess) {
Log.d("VideoSDK", "Decrypting ${stream.kind} from ${participant.displayName}")
}
}
})

onAgentStateChanged()​

  • onAgentStateChanged() is called when an AI agent moves between listening, thinking and speaking. It fires on agent participants, the ones whose isAgent() returns true.

Event callback parameters​

  • agentState: AgentState - IDLE, LISTENING, THINKING or SPEAKING.

onAgentTranscriptionReceived()​

  • onAgentTranscriptionReceived() is called for each transcript segment while an AI agent is in the room. It covers what the agent heard and what it said.

  • It fires on the agent participant, not on the participant who spoke. Add the listener to the agent, and read participant to see who spoke.

Event callback parameters​

  • transcription: TranscriptionSegment - text is the segment and timestamp is when the agent produced it, in epoch milliseconds, or 0 when the agent sent no time or one that can't be read. Order by arrival if you need a stable order.
  • participant: Participant - the participant who spoke. It can be the local participant.

onAgentMetrics()​

  • onAgentMetrics() is called on an agent participant after each turn of the conversation, with the agent's timings, the models it used and the text of the turn.

Event callback parameters​

  • metrics: JSONObject - contains latency, providers, speech and systemInstructions. Read it with opt methods, because a key can be missing.

Example​

participant.addEventListener(object : ParticipantEventListener() {
override fun onStreamEnabled(stream: RTCStream) {
//
}

override fun onStreamDisabled(stream: RTCStream) {
//
}

override fun onMediaStatusChanged(participantId: String, kind: MediaType, newStatus: Boolean) {
//
}

override fun onStreamPaused(kind: StreamKind?, reason: String) {
//
}

override fun onStreamResumed(kind: StreamKind?, reason: String) {
//
}

override fun onE2EEStateChanged(state: E2EEState, stream: RTCStream) {
//
}
})

For an AI agent, add the listener when the agent joins:

override fun onParticipantJoined(participant: Participant) {
if (!participant.isAgent()) return
participant.addEventListener(object : ParticipantEventListener() {
override fun onAgentStateChanged(agentState: AgentState) {
//
}

override fun onAgentTranscriptionReceived(transcription: TranscriptionSegment, participant: Participant) {
//
}

override fun onAgentMetrics(metrics: JSONObject) {
//
}
})
}

Got a Question? Ask us on discord