Skip to content

telemetry/v2: VoiceChunk as Envelope.voice = 4 - #16

Merged
thesprockee merged 3 commits into
mainfrom
telemetry-v2-voice-chunk
Oct 17, 2026
Merged

thesprockee merged 3 commits into
mainfrom
telemetry-v2-voice-chunk

Conversation

@thesprockee

@thesprockee thesprockee commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

Adds per-player voice to telemetry v2, plus the slot generation that ties a voice chunk to its player.

What:

  • telemetry/v2/voice.proto: VoiceChunk { speaker_slot, first_sequence, timestamp_offset_ms, repeated bytes opus, generation }.
  • Envelope.voice = 4.
  • PlayerInfo.generation = 7 and PlayerJoined.generation = 7.
  • README and CHANGELOG updated.

Why its own Envelope member:

  • The source is the game's SR15NetUserVoipEvent: a 6-byte header (slot, generation, sequence), then one 20 ms, 48 kHz mono Opus packet. That layout holds on all 15,486 server-to-client voice records of one 4v4 production match. Mean payload is 46.1 B, about 16 kbit/s per talking speaker.
  • Voice records arrive 1.9x as often as the server's frame records, and about 9x as often as 30 Hz telemetry frames. Inside EchoArenaFrame.events they would bloat every frame and the footer's event index. As their own envelopes, a reader that does not want voice skips them.
  • A chunk holds one speaker's contiguous sequences, so voice is never mixed and loss shows as a gap between chunks.

Why generation: at a slot hand-over, voice must not land on the wrong player when the roster lags. (slot, generation) names one occupant on both sides.

  • It is the same counter. In the 4v4 decode, every slot carrying both an entrant state (genidx at +0x64) and voice has equal values: 6 of 6, with slot 5 at 1, which rules out an always-0 voice generation.
  • The stat updates' [u16 slot][u16 generation] agree on all 9 slots.

Compatibility: additive. ./scripts/breaking-gate.sh --target '.git#branch=main' reports OK. buf format, buf lint and buf build exit 0.

Producer: nevr-spectator (EchoTools/nevr-server-rs, docs/design/nevr-spectator.md §3). Consumer: the local monitor.

thesprockee and others added 3 commits October 17, 2026 05:03
Per-player voice for telemetry v2: one speaker's consecutive Opus packets
per chunk (speaker_slot, first_sequence, timestamp_offset_ms on the
capture's time base, repeated opus). Its own Envelope member, not an
EchoEvent or a Frame field: voice records arrive 1.9x as often as the
server's frame records and about 9x as often as 30 Hz telemetry frames,
so inside frames they would bloat every frame and the footer's event
index. Additive: buf breaking passes against main.

Producer: nevr-spectator (EchoTools/nevr-server-rs, design
docs/design/nevr-spectator.md §3). Consumer: the local monitor.

Co-Authored-By: nevr-spectator <agents@sprock.io>
Co-Authored-By: Andrew Bates <a@sprock.io>
The consumer's ask: voice at a slot hand-over must not land on the wrong
player when the roster lags. The voice header carries the slot's
generation; telemetry v2's roster carried none, so a chunk could only be
matched by slot. Now (slot, generation) names one occupant on both sides.

Same counter, measured: in one 4v4 production match's server-to-client
decode, every slot that has both an entrant state (genidx at +0x64) and
voice has equal values, 6 of 6 (slots 1,2,4,6,8 at 0, slot 5 at 1; slot 5
rules out a voice generation that is always 0); the stat updates'
[u16 slot][u16 generation] agree on all 9 slots. Additive: breaking-gate OK.

Co-Authored-By: nevr-spectator <agents@sprock.io>
Co-Authored-By: Andrew Bates <a@sprock.io>
On a pull_request run the checkout has origin/main but no local
refs/heads/main, and the gate's `.git#branch=main` target is a file://
clone that only sees local heads, so it failed closed with "couldn't find
remote ref main" (run 39023658105) on every PR. Main's own runs never hit
it because there main is the checked-out branch.

Make the local branch from origin/<base_ref> first, and name the target
by base_ref too. scripts/breaking-gate.sh is untouched, so it still fails
closed when the clone or the check cannot run. Reproduced in a clone with
no local main: the gate fails with the CI's exact message, and passes
after `git branch --force main origin/main`.

Co-Authored-By: nevr-spectator <agents@sprock.io>
Co-Authored-By: Andrew Bates <a@sprock.io>
@thesprockee
thesprockee merged commit 7605853 into main Oct 17, 2026
3 checks passed
@thesprockee
thesprockee deleted the telemetry-v2-voice-chunk branch October 17, 2026 10:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant