refactor(voice): remove the unused voice state ack (#2716)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-12 01:37:45 +02:00
1 parent 3e79530389
commit e1bc6c2f7e
16 files changed
+21 -581

No files matched your search

@@ -15,7 +15,7 @@ Except for [Heartbeat](#heartbeat), [Identify](#identify), and [Resume](#resume)
| 1 | Heartbeat | Opcode `11` Heartbeat ACK |
| 2 | Identify | [Ready](/gateway/events/#ready), a close frame, or silence when the payload is held or discarded |
| 3 | Presence Update | No direct response |
| 4 | Voice State Update | [Voice State Ack](/gateway/events/#voice-state-ack), [Voice State Update](/gateway/events/#voice-state-update), and [Voice Server Update](/gateway/events/#voice-server-update) when state changes |
| 4 | Voice State Update | [Voice State Update](/gateway/events/#voice-state-update) and [Voice Server Update](/gateway/events/#voice-server-update) when state changes |
| 6 | Resume | Replayed Dispatches followed by [Resumed](/gateway/events/#resumed), Invalid Session, or a close frame |
| 8 | Request Guild Members | One or more [Guild Members Chunk](/gateway/events/#guild-members-chunk) events |
| 14 | Lazy Request | [Guild Sync](/gateway/events/#guild-sync) and [Guild Member List Update](/gateway/events/#guild-member-list-update) |
@@ -265,9 +265,6 @@ Opcode `4` joins, moves, updates, or leaves the voice membership associated with
| viewer_stream_keys?<sup>3</sup> | ?array[string] | The stream keys this connection is watching, where an omitted key keeps the current list and null clears it |
| latitude? | number or string | The client latitude, used to pick a voice region |
| longitude? | number or string | The client longitude, used to pick a voice region |
| mutation_id? | string | A client-generated identity echoed in [Voice State Ack](/gateway/events/#voice-state-ack) |
| runtime_epoch? | string | The client runtime generation echoed in Voice State Ack |
| base_version?<sup>4</sup> | integer | The voice state version this update was computed against |
<sup>1</sup> A `channel_id` with no `connection_id` opens a new connection, and a `channel_id` with one updates or moves that connection. An update that leaves one guild, meaning a non-null `guild_id` with `channel_id: null`, requires a `connection_id`, and one that omits it is refused with `VOICE_MISSING_CONNECTION_ID`
@@ -288,9 +285,7 @@ Opcode `4` joins, moves, updates, or leaves the voice membership associated with
"self_mute": false,
"self_deaf": false,
"self_video": false,
"self_stream": false,
"mutation_id": "e0a1c2",
"base_version": 7
"self_stream": false
}
}
```
@@ -305,10 +300,6 @@ The command has no `session_id` field. The current Gateway session is the member
Joining or replacing a grant produces [Voice Server Update](/gateway/events/#voice-server-update) with the token and endpoint for the media connection, and [Voice State Update](/gateway/events/#voice-state-update) for every session that can see the channel.
When a guild update has `mutation_id`, Fluxer also reports the outcome to the requesting session as [Voice State Ack](/gateway/events/#voice-state-ack), whose `status` is `applied` or `rejected` and whose `error_code` names the exact refusal. Without `mutation_id` a refusal produces no event at all, and the DM and group DM call context never acks.
`base_version` is a staleness check for an update that names an existing guild connection. An update whose `base_version` is more than one behind that connection's current voice state version is rejected with `stale_base_version`. The check runs after the member, channel, and connection lookups and before the permission checks. It does not apply to opening a new connection, to leaving a channel, or to the DM and group DM call context.
The first two updates in a rolling one-second window are processed immediately. Later updates enter a [per-session queue](/gateway/limits-and-rate-limits/#connection-and-command-rate-limits) that holds at most 64 commands and drains one command every 500 ms. A newer update replaces an older queued update for the same `guild_id` and `connection_id` pair, and a full queue discards its oldest entry before accepting the new one.
## Request Guild Members
@@ -105,7 +105,6 @@ A Dispatch is buffered for [Resume](/gateway/commands/#resume) replay unless it
| [Channel Pins Update](#channel-pins-update) | A channel's most recent pin time changes | Channel visibility |
| [Channel Pins ACK](#channel-pins-ack) | The current user acknowledges a channel's pins | Current user |
| [Voice State Update](#voice-state-update) | A guild or call participant's voice state changes | Channel visibility |
| [Voice State Ack](#voice-state-ack) | The session's own voice mutation is applied or rejected | Current session |
| [Voice Server Update](#voice-server-update) | The session receives or replaces its own voice grant | Current session |
| [Entrance Sound Play](#entrance-sound-play) | A participant's entrance sound plays in a voice channel | Voice channel |
| [Call Create](#call-create) | A private channel call begins or becomes visible | Call recipient |
@@ -942,71 +941,6 @@ A `channel_id` of null means the participant left.
The broadcast form has no `region_id`, `server_id`, `latitude`, or `longitude`.
### <span id="voice-state-ack"></span>VOICE_STATE_ACK
Reports the outcome of the session's own [Voice State Update](/gateway/commands/#voice-state-update). Sent only when that command supplied `mutation_id`, and delivered to the requesting session alone.
| Field | Type | Description |
| --- | --- | --- |
| mutation_id | string | The `mutation_id` the command supplied |
| runtime_epoch<sup>1</sup> | string | The `runtime_epoch` the command supplied |
| connection_id | ?string | Voice connection the mutation applied to |
| guild_id | ?snowflake | Guild the mutation applied to |
| channel_id | ?snowflake | Channel the mutation applied to |
| status | string | `applied` or `rejected` |
| server_version | integer | The voice state version after the mutation |
| canonical_state<sup>2</sup> | [voice state object](#voice-state-object) | The authoritative voice state, an empty object when none exists |
| error_code? | string | Stable rejection code, present only when `status` is `rejected` |
| error_message? | string | Human-readable rejection message |
<sup>1</sup> Echoed back unchanged. A command that omitted the field produces the literal string `undefined` here, so a client MUST compare the value against the epoch it sent
<sup>2</sup> Also has the `region_id` and `server_id` fields a [Voice State Update](#voice-state-update) omits, and never has coordinates. Both extra fields are internal routing identity, and a client MUST NOT depend on them
A mutation whose `base_version` is more than one behind the server's current version is rejected after the connection lookup and before the permission checks, with `error_code` and `error_message` both set to `stale_base_version`.
Every other rejection has one of these codes, with `error_message` set to the registry text for the same code.
#### `VOICE_CONNECTION_NOT_FOUND`
The named voice connection does not exist and no matching pending connection could be restored.
#### `VOICE_PENDING_EXPIRED`
The pending voice connection expired before the mutation arrived.
#### `VOICE_INVALID_STATE`
A `viewer_stream_keys` entry is malformed, names another channel, or names a connection that is not in the channel.
#### `VOICE_MEMBER_TIMED_OUT`<sup>1</sup>
The member is timed out.
#### `VOICE_PERMISSION_DENIED`<sup>1</sup>
The user lacks `VIEW_CHANNEL` or `CONNECT` on the target channel.
#### `VOICE_CHANNEL_FULL`<sup>1</sup>
The channel is at its `user_limit`.
#### `VOICE_CONNECTION_LIMIT_REACHED`<sup>1</sup>
The user holds too many voice connections.
#### `VOICE_CAMERA_USER_LIMIT`
The channel already has 25 users with cameras enabled.
#### `VOICE_E2EE_REQUIRED`<sup>1</sup>
The channel is end-to-end encrypted and the client does not support it.
<sup>1</sup> Checked only when the mutation moves the connection to a different channel. A mutation that keeps the connection in its current channel skips these checks and is applied
Only a command that supplies `connection_id` can produce an ack. A command that omits it opens a new connection, and a `connection_id` that belongs to another user is rejected before any other check. A refusal of either kind produces no Dispatch. Without `mutation_id`, a refused voice state update also produces no Dispatch at all.
### <span id="voice-server-update"></span>VOICE_SERVER_UPDATE
The session received or replaced its own voice grant. Delivered to the requesting session alone.
@@ -110,7 +110,7 @@ Identify accepts at most 256 `ignored_events` entries. A longer array closes wit
## Voice admission
Voice admission follows the enclosing guild, DM, group DM, channel, and permission rules. A refusal is reported as [Voice State Ack](/gateway/events/#voice-state-ack) with an `error_code` and closes nothing. A Voice State Update that has no `mutation_id` produces no event when it is refused.
Voice admission follows the enclosing guild, DM, group DM, channel, and permission rules. A refusal produces no event and closes nothing.
A guild voice channel admits at most `user_limit` users, where `0` means unlimited. A channel in which any participant has a camera enabled also admits at most 25 users in total, whatever its `user_limit`. A channel that already holds 25 users with cameras enabled refuses a further camera with `VOICE_CAMERA_USER_LIMIT`. [Capacity](/voice/#capacity) states these bounds in full.
+1 -3
View File
@@ -71,9 +71,7 @@ A grant is issued when a connection opens, when it moves to another channel, and
The grant `token` is issued for the media server and consumed by the media connection alone. No route on this API accepts it.
Fluxer reports a guild refusal as [Voice State Ack](/gateway/events/#voice-state-ack) with a `status` of `rejected` and an `error_code` naming the exact reason, and only a command with a `mutation_id` receives one. A refused placement without it produces no Dispatch, so a client that needs to observe a guild refusal MUST send `mutation_id`.
A call never acks. A refused placement into a direct message or group direct message call produces no Dispatch whether or not the command had `mutation_id`. A client observes that refusal only as the absence of a grant.
Fluxer reports a refusal by sending no Dispatch. A client observes a refused placement only as the absence of a grant.
## Guild voice channels