Voice
FiveCord runs voice over LiveKit. The main Gateway places a session into a voice channel and hands it one credential. The client presents that credential to a media server, and every track goes over the connection it opens there. Microphone, camera, and screen share are track sources on that one connection, so going live opens nothing new.
Client commands and Gateway events define the placement protocol.
Voice surfaces
Section titled “Voice surfaces”| Surface | What it is | Reference |
|---|---|---|
| Guild voice channel | A channel of type 2, which also has messages, pins, and slowmode | Channels |
| Private call | The direct message and group direct message counterpart of a voice channel | Calls |
| Go Live stream1 | Screen share published as an extra track on a voice connection the member already holds | Streams |
| Entrance sound2 | A short clip announced to everyone already connected to a voice channel | Entrance sounds |
| Voice activity sharing | Whether a friend is told which voice channel the account is in | User settings |
1 Going live opens no second connection and issues no second credential
2 The one surface that publishes no media track
Media transport
Section titled “Media transport”Media never crosses the HTTP API. No route returns an audio or video track, the credential a media connection presents, or the key material an end-to-end encrypted channel uses.
FiveCord runs media over LiveKit and publishes no signalling protocol of its own. There is no voice websocket, no voice opcode set, no UDP discovery step, and no separate encryption handshake. A client connects to the endpoint the Voice Server Update grant names, presents the grant token, and speaks the LiveKit protocol from there.
| Concept | Value |
|---|---|
| Room name, guild voice channel | guild_{guild_id}_channel_{channel_id} |
| Room name, private call | dm_channel_{channel_id} |
| Participant identity | user_{user_id}_{connection_id} |
The grant lives for 600 seconds.
One room is one voice channel, and one participant is one voice connection. A member holding several connections in the same channel is several participants in the same room, which is how one account is present from more than one device.
The grant also names the track sources the connection may publish. SPEAK allows the microphone source, and STREAM allows the camera source together with the screen share sources. A server-deafened connection may neither publish nor subscribe.
Deployment feature state
Section titled “Deployment feature state”A deployment can be configured without voice. The instance discovery document reports that state as features.voice_enabled. No other surface warns a client in advance.
Where features.voice_enabled is false, FiveCord issues no media credential, so a placement request is refused with VOICE_TOKEN_FAILED. List RTC regions answers 200 with an empty array before it resolves the channel, and Modify call region accepts any region string.
Placement
Section titled “Placement”Voice State Update declares where a session wants to be. It has the target guild_id, channel_id, and connection_id together with self_mute, self_deaf, self_video, and self_stream. A null channel_id leaves, and a call placement always has a null guild_id.
channel_id and connection_id together select the operation.
| Command shape | Result |
|---|---|
channel_id and no connection_id | Opens a new connection |
channel_id and a connection_id | Updates or moves that connection |
Null channel_id and a connection_id, in a guild | Drops that connection |
Null channel_id and no connection_id, in a guild | Refused with VOICE_MISSING_CONNECTION_ID |
Null channel_id and no connection_id, in a call | Drops every voice membership the session holds |
Null channel_id with a non-string, non-null connection_id | Refused with VALIDATION_INVALID_PARAMS |
The server answers with Voice State Update for the resulting membership, delivered to every session that can view the channel, and with Voice Server Update for the requesting session alone. That grant has the token, endpoint, channel_id, and connection_id of the media server the deployment selected. guild_id is present for a guild voice channel and omitted for a call, so a client reads the scope of the grant from that field. It also has an e2ee_key when the channel is end-to-end encrypted.
A grant is issued when a connection opens, when it moves to another channel, and when the region changes. An update that stays in the same channel reissues nothing, so toggling self_mute, self_video, or self_stream produces one Voice State Update and no new grant.
The grant token is issued for the media server and consumed by the media connection alone. No route on this API accepts it.
FiveCord reports a refusal by sending no Dispatch. A client observes a refused placement only as the absence of a grant.
Guild voice channels
Section titled “Guild voice channels”A guild voice channel stores its bitrate, user_limit, voice_connection_limit, and rtc_region on the channel object. It also has ordinary messages, pins, and slowmode, so its text history is read and written through the Messages resource.
A new voice channel stores a bitrate of 64000. The ceiling is 96000, and the AUDIO_BITRATE_128_KBPS, AUDIO_BITRATE_256_KBPS, and AUDIO_BITRATE_384_KBPS guild features raise it to 128000, 256000, and 384000. A direct message and a group direct message call carry no bitrate and always run at 64000.
Permissions
Section titled “Permissions”| Permission | Effect on voice |
|---|---|
| VIEW_CHANNEL and CONNECT1 | Both are required to hold a voice connection in the channel |
| SPEAK2 | Publish audio |
| STREAM3 | Publish camera video and Go Live media |
| MUTE_MEMBERS4 | Apply and clear a moderator mute |
| DEAFEN_MEMBERS4 | Apply and clear a moderator deafen |
| MOVE_MEMBERS | Move a member to another guild voice channel, or disconnect it |
| UPDATE_RTC_REGION | Change the channel’s rtc_region |
1 A member missing either bit is refused with VOICE_PERMISSION_DENIED
2 A member without it is admitted, and its voice state is published with suppress true
3 One bit gates both, so there is no separate camera permission
4 MUTE_MEMBERS covers the mute field and DEAFEN_MEMBERS the deaf field of the guild member update object. PRIORITY_SPEAKER and USE_VAD are defined and assignable permission bits that no HTTP route and no Gateway command evaluates
ADMINISTRATOR resolves to the complete mask before any channel overwrite is applied, so it satisfies every row of that table. Two cases skip the VIEW_CHANNEL and CONNECT check. A member the guild is already moving is admitted. So is a member holding virtual access to the channel. The guild grants virtual access to a connected member that loses VIEW_CHANNEL or that a moderator moves into a channel it cannot see. Virtual access also grants SPEAK and STREAM in that channel on its own.
FiveCord checks the permissions in the table above when it issues a grant, and the guild checks them again for a connection that is already open. Joining, moving, a region change, a role edit, an overwrite edit, and a member role change each recompute SPEAK and STREAM.
The guild applies the new result to a live connection and issues no new Voice Server Update. The media server mutes a published microphone, camera, or screen share track the member may no longer publish, and drops a connection that fails the VIEW_CHANNEL and CONNECT check.
Moderation is an HTTP operation on the guild membership. Modify guild member and Modify current guild member share one request body. Each applies a moderator mute and a moderator deafen, moves a member between guild voice channels, and forces a disconnect. Both require the caller to hold MUTE_MEMBERS, DEAFEN_MEMBERS, and MOVE_MEMBERS for those changes, including when the target is the caller itself. No other HTTP route and no Gateway command does any of it.
That mute and that deafen reach the media server without a new credential. The change applies to every connection the account holds in that channel, and no Voice Server Update follows.
Capacity
Section titled “Capacity”| Bound | Refusal |
|---|---|
user_limit1 | VOICE_CHANNEL_FULL |
voice_connection_limit2 | VOICE_CONNECTION_LIMIT_REACHED |
| 25 members with a camera on3 | VOICE_CAMERA_USER_LIMIT |
1 A stored 0 means no limit. While any member in the channel has a camera on, the effective occupancy limit becomes the lower of user_limit and 25, and a channel with no limit is capped at 25 for as long as that holds
2 The ceiling on simultaneous connections one member may hold in the channel. A channel that stores no usable value is evaluated at 5, and a stored value above 100 is evaluated at 100
3 One member with several connections counts once, and the requesting member is counted before the comparison
A private call reads no voice_connection_limit and applies a fixed ceiling of 5 connections for each member.
A member whose communication_disabled_until is still in the future is refused with VOICE_MEMBER_TIMED_OUT before any permission or capacity check runs. An unclaimed account is refused with VOICE_UNCLAIMED_ACCOUNT for a one-on-one direct message call and for any guild voice channel whose guild it does not own. A group direct message call is not refused. A session that did not identify with e2ee_capable is refused with VOICE_E2EE_REQUIRED while the guild has voice encryption enabled and every connection already in the channel is capable. A bot is exempt from that one.
Regions
Section titled “Regions”List RTC regions returns the RTC region objects the caller MAY select for one guild voice channel. A region is returned only when the caller passes every restriction configured for it and at least one voice server accessible to the caller is active in it. The array can be empty.
rtc_region is written by Modify channel and requires UPDATE_RTC_REGION. A null value selects automatic routing, and so does a stored value the placing account cannot reach.
Automatic routing selects an available server, using the supplied latitude and longitude when possible. Participants in the same channel share a server. Always use the endpoint returned in Voice Server Update.
The literal automatic is not a channel region. Only the region field of Modify call region accepts it, as a synonym for null.
An operator manages the regions and the voice servers registered inside them through the Admin voice resource.
Private calls
Section titled “Private calls”A private call has no moderator, no permission overwrites, and no moderator mute, deafen, or disconnect.
The Calls resource owns its HTTP surface, which reads whether the caller may ring, changes the region of an active call, rings recipients, and stops ringing them. End call session ends no call. Call Create, Call Update, and Call Delete publish the call state, and both joining and leaving are the same Voice State Update a guild voice channel uses.
A recipient’s incoming call flags decide whether it is rung. The flags can admit nobody, friends only, friends of friends, guild members, or everyone, and they can admit everyone silently.
Get call eligibility checks two conditions on the caller before it reads that policy. A caller already connected to the channel’s call is reported as not ringable. So is an unclaimed account in a direct message. The operation applies no recipient policy to a group direct message, and reports one as ringable unless the caller is already connected to its call.
Ring call recipients applies neither of those conditions and evaluates the policy once per targeted recipient, in a group direct message as well as in a direct message. The result selects who is rung, so a recipient the policy excludes and a recipient it admits silently are both left out of the ringing set while the request still answers 204.
Go Live streams
Section titled “Go Live streams”Going live publishes a screen share track, and its screen share audio track, on the LiveKit participant the member already holds in the channel. There is no second connection, no second participant, and no second connection_id. A member that held STREAM at placement already has both screen share sources in its grant, so no new credential is issued and no Voice Server Update follows.
The publisher advertises the stream by setting self_stream on that connection with Voice State Update, naming the connection’s own connection_id. The server increments the voice state version and rebroadcasts the state as one Voice State Update.
The voice state of a connection without STREAM in its channel has self_stream and self_video false, whatever the client sent. The guild clears both when a live connection loses STREAM, and rebroadcasts the state.
A viewer declares which streams it watches with viewer_stream_keys on its own voice state, and a channel move resets that list to empty.
That connection’s connection_id is the last segment of the stream key, which is {guild_id}:{channel_id}:{connection_id} for a guild voice channel and dm:{channel_id}:{connection_id} for a private call.
The Streams resource owns the operations addressed by that key, which record a region preference and read, upload, and delete a JPEG preview image. Reading a preview takes the same access that lets a member join the channel, so any member holding CONNECT there MAY read it without owning the connection. Mutating one also requires STREAM on a guild channel and a voice state matching exactly the channel and the connection the key names.
Losing screen share permission also stops its audio. Other permitted track sources remain available.
Entrance sounds
Section titled “Entrance sounds”An entrance sound is a short clip an account plays for everyone already connected to a voice channel. An account keeps a personal library of at most eight clips, each 100 through 5200 milliseconds and at most 1048576 decoded bytes, stored as mp3, ogg, m4a, or wav. It then assigns one clip per scope: global, guilds, dms, and guild:{guild_id}.
FiveCord records which clip belongs to which scope and nothing more. Play entrance sound names the clip explicitly, so the client decides which selection applies to a given channel.
Playback requires a voice state in the target channel and no channel permission. A caller that holds none is refused at the channel_id path with the validation code ENTRANCE_SOUND_INVALID_SCOPE, and a channel ID naming no channel is refused the same way. A successful call sends one ENTRANCE_SOUND_PLAY Dispatch to every other account with a voice state in the channel, at most once per account and never back to the caller. That Dispatch has the clip’s CDN URL, and each recipient fetches and plays it locally, so no audio track is published for it.
Every session the account holds receives the Dispatch, including sessions that are not in the channel. A client filters on channel_id.
Voice activity sharing
Section titled “Voice activity sharing”An account chooses whether a friend is told which voice channel it is in. Modify voice activity sharing writes the account’s default and rewrites the caller’s side of every existing friendship to the same value in one operation. It then holds a 24 hour cooldown, and a second attempt inside that window is refused at the share_voice_activity path with the validation code VOICE_ACTIVITY_SHARING_ON_COOLDOWN and a retry_after in seconds.
The stored result is share_voice_activity on the caller’s own relationship object, and friend_shares_voice_activity reports the reciprocal record. List relationships reads friend_shares_voice_activity from that reciprocal record. So do the Relationship Update Dispatches this operation emits for each rewritten friendship, one to the caller and one to the friend. Every other operation that returns a relationship object reports friend_shares_voice_activity as true.