Livqeno Docs

RTC Events

Every event a Room emits, with its payload and when it fires. Identical across Web, React and React Native.

Room is a typed event emitter. These 17 events are its whole surface — from RoomEventMap in @ravenkash/rtc, and the same set on @ravenkash/react-native, because it is the same class.

function onJoin(participant: RemoteParticipant) {
  console.log(`${participant.identity} joined`);
}
 
room.on('participantJoined', onJoin);
room.off('participantJoined', onJoin);      // keep the reference to unsubscribe

room.on() returns the room, so calls chain:

room.on('connected', render).on('participantJoined', render).on('participantLeft', render);

@ravenkash/chat differs here. chat.on() returns an unsubscribe function rather than the client, because chat handlers are almost always registered inside a component effect where cleanup is the common path. room.on() chains; chat.on() hands you the teardown. See Chat events.

Connection

EventPayloadFires when
connectionStateChangedstate: ConnectionStateThe state changes. The one to drive UI from
connectedThe room finished joining
disconnectedThe connection ended, deliberately or not
reconnectingA dropped connection is being re-established
reconnectedRecovery succeeded. Your tracks are already republished

reconnected carries no payload because there is nothing to reattach — that is the guarantee, not an omission. See Reconnection.

Participants

EventPayloadFires when
participantJoinedparticipant: RemoteParticipantSomeone else joins
participantLeftparticipant: RemoteParticipantSomeone else leaves

Only remote participants. You already know when you joined.

Remote tracks

EventPayloadFires when
trackPublishedkind: TrackKind, participant: RemoteParticipantA remote participant starts publishing
trackUnpublishedkind: TrackKind, participant: RemoteParticipantThey stop publishing
trackSubscribedtrack: RemoteTrack, participant: RemoteParticipantThe track is available to render
trackUnsubscribedtrack: RemoteTrack, participant: RemoteParticipantIt is no longer available
trackMutedkind: TrackKind, participant: RemoteParticipantThey muted a track they are still publishing
trackUnmutedkind: TrackKind, participant: RemoteParticipantThey unmuted it

Render on trackSubscribed, not trackPublished. Published means the track exists; subscribed means media has arrived. Attaching on the first gives you an empty element.

trackMuted is not trackUnpublished. A muted track stays published, so keep the participant's tile and show a muted badge — tearing the tile down and rebuilding it on unmute is the visible difference.

Your own tracks

EventPayloadFires when
localTrackPublishedtrack: LocalTrackenableCamera(), enableMicrophone(), enableScreenShare() or publish() finished
localTrackUnpublishedtrack: LocalTrackYour track stopped publishing

Data and errors

EventPayloadFires when
dataReceivedpayload: Uint8Array, participant?: RemoteParticipantA data-channel message arrived
errorerror: RTCErrorSomething failed, as a typed error rather than an unhandled rejection

participant on dataReceived is optional because a message can arrive without an attributable sender. Handle the undefined case.

import { isRTCError } from '@ravenkash/rtc';
 
room.on('error', (error) => {
  if (isRTCError(error) && error.code === 'CAMERA_PERMISSION_DENIED') {
    showPermissionHelp();
  }
});

Not events

Two things you might reach for, which the SDK deliberately does not emit:

  • Per-participant connection quality. Poll room.getConnectionStats() instead.
  • Reconnect attempt count. Read getDiagnostics().reconnectCount.

There is also no active-speaker event — see Known limitations.

Other platforms

The hooks subscribe for you and re-render on the same events:

const state = useConnectionState();
const participants = useParticipants();
const remote = useRemoteParticipants();
const local = useLocalParticipant();
const error = useRavenError();

useRaven() exposes the underlying Room if you need on() directly.

Next steps