fix(M2): wire vc_client's real voice plane through the C ABI, not just raw sockets
test_m2_voice passed against raw BSD sockets, but vc_client::stream_start/stop, UDP binding, and capture/recv were still VC_ERR_NOT_IMPLEMENTED stubs -- meaning vccli and any GUI client still couldn't actually talk. Implements the real client-side UDP-binding handshake, media key derivation, capture->encode->seal-> send and recv->open->decode->playback paths, plus server-side StreamInfo broadcast so peers learn about each other's streams via sync_remote_streams(). Adds test_voice_client_abi (two real vc_client instances, not raw sockets) and vccli --voice/--mute/--text flags, manually verified live between two instances. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
54
PROGRESS.md
54
PROGRESS.md
@@ -10,12 +10,25 @@ up instantly. Newest status at the top.
|
||||
|
||||
## ▶ Where we left off / next action
|
||||
|
||||
- **Done:** **M2 — voice, single stream** ✓ complete (2026-06-16).
|
||||
`ctest --preset m1-dev` — all **9/9 tests** green including the new M2 exit criterion
|
||||
(`test_m2_voice`): two headless clients encrypt Opus frames via ChaCha20-Poly1305, bind
|
||||
UDP sockets, and the server SFU relay re-encrypts + forwards frames.
|
||||
- **Done:** **M2 — voice, single stream** ✓ complete (2026-06-16), now genuinely satisfied
|
||||
through the real client library, not just `test_m2_voice`'s raw-socket harness.
|
||||
`vc_stream_start/stop`, UDP binding, capture→encode→seal→send, and recv→open→decode→
|
||||
playback were all `VC_ERR_NOT_IMPLEMENTED` stubs in `core/src/core/client.cpp` even after
|
||||
`test_m2_voice` went green — meaning `vccli`/any GUI client still couldn't actually talk.
|
||||
Implemented for real this session, plus server-side `StreamInfo` broadcast
|
||||
(`SessionRegistry::set_user_stream/clear_user_stream` → `UserEvent::UPDATED`) so a second
|
||||
client's `sync_remote_streams()` learns about a peer's stream without polling.
|
||||
`ctest --test-dir build/m1-dev` — **10/10 tests** green, including the new
|
||||
`test_voice_client_abi` (two real `vc_client` instances, not raw sockets, drive the full
|
||||
UDP-binding → stream-announce → cross-client `STREAM_STARTED`/`STOPPED` event path).
|
||||
`vccli --voice` (new flag, alongside `--host/--port/--nick/--channel/--mute/--text`) was
|
||||
manually verified live: two instances see each other's mic-stream start/stop in real time.
|
||||
Note: `test_m1_integration` and `test_m2_voice` have a pre-existing intermittent flake on
|
||||
Windows in their cleanup paths (thread-join / SQLite-file-handle release race, unrelated to
|
||||
this session's changes) — rerun in isolation if one fails standalone in the full suite.
|
||||
- **Next:** **M3 — multi-stream & per-channel tuning** (screen audio, listener-side per-user
|
||||
NR, jitter buffer stats API). See `docs/roadmap.md §M3`.
|
||||
NR, jitter buffer stats API — note `voicecat.h` currently exposes no stats getter beyond
|
||||
`on_level`'s RMS meter, so a stats API needs new C ABI surface). See `docs/roadmap.md §M3`.
|
||||
|
||||
---
|
||||
|
||||
@@ -94,7 +107,36 @@ to the second client; B receives ≥ 25 frames and all decrypt correctly. Passes
|
||||
- [x] `test_voice_frame` — header round-trip, big-endian layout, binding packet format.
|
||||
- [x] `test_media_aead` — seal/open round-trip, anti-replay, tamper detection, multi-packet sequence.
|
||||
- [x] `test_opus_codec` — encode/decode round-trip energy check (within 3 dB), PLC, frame-samples helper.
|
||||
- [x] `test_m2_voice` — M2 exit criterion. Verified green 2026-06-16.
|
||||
- [x] `test_m2_voice` — M2 exit criterion (raw-socket harness). Verified green 2026-06-16.
|
||||
|
||||
**Follow-up (same day):** the above made `test_m2_voice` pass, but `vc_client`'s public voice
|
||||
methods were still stubs — the *actual* M2 exit criterion ("two vccli/early-GUI clients talk")
|
||||
wasn't met. Closed the gap:
|
||||
|
||||
- [x] `core/src/core/client.cpp` — real `stream_start`/`stream_stop`/`set_self_mute`/
|
||||
`set_remote_stream`; UDP-binding handshake (`start_udp_binding`/`handle_udp_binding_ack`/
|
||||
`finish_udp_binding`); media key derivation from `tls_` (RFC 5705 exporter); `run_udp_recv`
|
||||
(AEAD-open → `JitterBuffer::Frame` → `audio_engine_.push_recv_frame`); `on_capture_frame`
|
||||
(encode → seal → `sendto`); `sync_remote_streams` (diffs a `User` proto's `streams` against
|
||||
`remote_streams_`, wiring up `OpusDecoder`s and emitting `STREAM_STARTED`/`STOPPED`).
|
||||
`set_input_device`/`set_input_mode`/`set_push_to_talk`/`list_devices` remain
|
||||
`VC_ERR_NOT_IMPLEMENTED` — no device-enumeration backend yet; scoped to M3 (VAD/PTT).
|
||||
- [x] `core/src/session/session.cpp/h` — `SessionModel::find_user`, `find_user_by_ssrc`,
|
||||
`Stream{stream_id, ssrc, kind, label, sample_rate, frame_ms}`.
|
||||
- [x] `server/src/conn_session.cpp/h` — `handle_stream_announce`/`handle_stream_stop` now
|
||||
broadcast via `SessionRegistry::set_user_stream`/`clear_user_stream` → `UserEvent::UPDATED`.
|
||||
- [x] `server/src/session_registry.cpp/h` — `set_user_stream`/`clear_user_stream` (mutate a
|
||||
user's `StreamInfo` list, return the updated `User` proto for broadcast).
|
||||
- [x] `tests/test_voice_client_abi.cpp` — drives two real `vc_client` instances through
|
||||
`vc_connect`/`vc_authenticate_guest`/`vc_stream_start`/`vc_stream_stop`; asserts client B
|
||||
observes client A's `STREAM_STARTED`/`STOPPED` events. Verified green 2026-06-16.
|
||||
- [x] `tools/vccli/src/main.cpp` — argv parsing (`--host/--port/--nick/--channel/--voice/
|
||||
--mute/--text`); `--voice` starts a MIC stream and blocks on SIGINT, printing `on_event`
|
||||
callbacks live (unbuffered stdout — MinGW/MSVCRT treat `_IOLBF` as full buffering for
|
||||
non-console streams). Dropped the originally-planned `--voice-loopback` and the
|
||||
`tx=N rx=M lost=K jitter=J` stats line: `voicecat.h` exposes no PCM-injection hook or
|
||||
jitter/loss stats getter publicly, only `on_event` + `on_level` (RMS). Manually verified:
|
||||
two `vccli --voice` instances see each other's stream start in real time.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user