ParticipantEventListener Class - Android
Implementation
-
You can extend the
ParticipantEventListenerclass, override only the callbacks you need, and add the listener toParticipantclass using theaddEventListener()method ofParticipantClass. Every callback has an empty default body. -
Callbacks arrive on the main thread. The exception is the
onStreamEnabled()replay thataddEventListener()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.streamsto render them, or each stream is handled twice.
Event callback parameters
-
stream: RTCStream - use
stream.kindto tell the streams apart:MediaType.AUDIO,MediaType.VIDEO,MediaType.SHAREorMediaType.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()
-
onMediaStatusChanged()is called when the participant turns their microphone, camera or screen share on or off, whether or not this device receives it. -
In a room joined with
createRoom(autoConsume = false), use it as the cue to callconsumeMicStreams()orconsumeWebcamStreams().onStreamEnabled()fires only for media this device receives.
Event callback parameters
- participantId:
String- The participant whose media changed. - kind:
MediaType-AUDIO,VIDEO,SHAREorSHARE_AUDIO. - newStatus:
Boolean-truewhen it was turned on.
onStreamPaused()
onStreamPaused()is called when this device stops receiving one of the participant's streams, because you calledpause()on it or the server paused it. The participant still sends it.
Event callback parameters
- kind:
StreamKind?-AUDIO,VIDEOorSHARE;nullfor 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,VIDEOorSHARE;nullfor 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:EncryptionSuccessorDecryptionSuccesswhen 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:
| Value | Meaning |
|---|---|
EncryptionSuccess | A stream this device sends is being encrypted. |
DecryptionSuccess | A stream from a remote participant is being decrypted. |
EncryptionFailed | A frame could not be encrypted, so it was not sent. |
DecryptionFailed | A frame from a remote participant could not be decrypted. Not reported. |
InternalError | Encryption 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 onkindrather thanidhere.
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 whoseisAgent()returnstrue.
Event callback parameters
- agentState:
AgentState-IDLE,LISTENING,THINKINGorSPEAKING.
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
participantto see who spoke.
Event callback parameters
- transcription:
TranscriptionSegment-textis the segment andtimestampis when the agent produced it, in epoch milliseconds, or0when 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- containslatency,providers,speechandsystemInstructions. Read it withoptmethods, 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

