Duvet DOCS
GitHub

Voice Events

VOICE_STATE_UPDATE

EVENT VOICE_STATE_UPDATE

Sent when a user's voice state changes (join, leave, mute, deafen, screen share), with the whole state. Broadcast to all members of the space, or of the conversation for calls. A VOICE_SYNC that changes nothing sends none. Updates can arrive out of order: apply one only if its version is greater than the last one applied for that user and room, counting the versions in SPACE_CREATE voice_states and READY active_calls.

FieldTypeDescription
room_id stringVoice room ID
user_id stringUser whose voice state changed
joined booleanWhether the user is in the voice room
muted booleanWhether the user is muted: what their client last sent in VOICE_SYNC, but always true without SpeakInVoice (false when joined is false)
deafened booleanWhether the user is deafened (false when joined is false)
screen_sharing booleanWhether the user is screen sharing (false when joined is false)
version integerGrows with every voice change, across rooms and gateway restarts; a safe JavaScript integer
{
  "type": "VOICE_STATE_UPDATE",
  "data": {
    "room_id": "019cf96a-be82-72c5-830f-75e85355d800",
    "user_id": "019cf96a-3d5b-72c5-830f-75e85355d078",
    "joined": true,
    "muted": false,
    "deafened": false,
    "screen_sharing": false,
    "version": 1792181390951042
  }
}

VOICE_SESSION_REPLACED

EVENT VOICE_SESSION_REPLACED

Sent to a user when their voice session ends server-side: it was replaced by a new connection (e.g., connecting from another device), or they lost ViewChannels or JoinVoice in that room, left the space, or the room was deleted or is no longer a voice room. If the session that joined is gone (the client reconnected), it is sent to all of the user's sessions; only one that is in that room should act on it. The client should clean up its local voice state. Losing SpeakInVoice does not end the session; the gateway stops forwarding the user's audio and shows them as muted (VOICE_STATE_UPDATE). When they get it back, it shows the mute state their client last sent in VOICE_SYNC again. Clients mute themselves when they lose it, and should send that VOICE_SYNC too.

FieldTypeDescription
room_id stringVoice room ID where the session ended
reason ?string"permissions" when the user lost access to the room; absent when the session was replaced
{
  "type": "VOICE_SESSION_REPLACED",
  "data": {
    "room_id": "019cf96a-be82-72c5-830f-75e85355d800",
    "reason": "permissions"
  }
}

VOICE_JOINED

EVENT VOICE_JOINED

Sent to the user after they successfully join a voice room. Contains the SDP answer from the server to complete the WebRTC handshake.

FieldTypeDescription
room_id stringVoice room ID
answer RTCSessionDescription?SDP answer from the server (always set)
{
  "type": "VOICE_JOINED",
  "data": {
    "room_id": "019cf96a-be82-72c5-830f-75e85355d800",
    "answer": {
      "type": "answer",
      "sdp": "v=0\r\no=- 1234567890 2 IN IP4 127.0.0.1..."
    }
  }
}

WEBRTC_ICE_CANDIDATE

EVENT WEBRTC_ICE_CANDIDATE

Sent when the server discovers a new ICE candidate for the WebRTC connection. The client should add this candidate to its peer connection.

FieldTypeDescription
candidate stringICE candidate string
room_id stringVoice room ID
{
  "type": "WEBRTC_ICE_CANDIDATE",
  "data": {
    "candidate": "candidate:1 1 UDP 2130706431 192.168.1.1 12345 typ host",
    "room_id": "019cf96a-be82-72c5-830f-75e85355d800"
  }
}

WEBRTC_RENEGOTIATE

EVENT WEBRTC_RENEGOTIATE

Sent by the server when the WebRTC connection needs to be renegotiated (e.g., when another user joins or leaves the voice room). Contains a new SDP offer that the client must respond to with an answer.

FieldTypeDescription
offer RTCSessionDescriptionNew SDP offer from the server
room_id stringVoice room ID
{
  "type": "WEBRTC_RENEGOTIATE",
  "data": {
    "offer": {
      "type": "offer",
      "sdp": "v=0\r\no=- 1234567890 3 IN IP4 127.0.0.1..."
    },
    "room_id": "019cf96a-be82-72c5-830f-75e85355d800"
  }
}

WEBRTC_RENEGOTIATE_ANSWER

EVENT WEBRTC_RENEGOTIATE_ANSWER

Sent by the server as a confirmation after processing the client's renegotiation answer.

FieldTypeDescription
room_id stringVoice room ID
answer RTCSessionDescription?SDP answer from the server (always set)
{
  "type": "WEBRTC_RENEGOTIATE_ANSWER",
  "data": {
    "room_id": "019cf96a-be82-72c5-830f-75e85355d800",
    "answer": {
      "type": "answer",
      "sdp": "v=0\r\no=- 1234567890 4 IN IP4 127.0.0.1..."
    }
  }
}