feat(audio): channel sample_rate caps Opus bandwidth (narrowband/wideband)
Some checks failed
Build Linux Binaries / linux/amd64 (push) Has been cancelled
Build Linux Binaries / linux/arm64 (push) Has been cancelled

The per-channel sample_rate field was inert after pinning the codec to
48 kHz. Make it meaningful without changing the 48 kHz clock: carry it as
OpusParams::max_bandwidth_hz and apply OPUS_SET_MAX_BANDWIDTH in
OpusEncoder::init (8000->narrowband, 16000->wideband, 24000->super-wideband,
48000->full). A low-bitrate room can now shed out-of-band content while
every endpoint keeps a single 48 kHz clock.

Make sample_rate channel-authoritative on the server: conn_session no
longer overrides effective sample_rate with the client's always-48000
request (it now behaves like frame_ms/mode). vc_get_stream_audio_config
reports the channel's configured rate for own streams too.

New ctest channel_samplerate: a 7 kHz tone is attenuated ~1000x on an
8 kHz (narrowband) channel vs a 48 kHz (full-band) channel, proving the cap
is in effect. ctest --preset dev 26/26.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 16:56:49 +02:00
parent a460009a2f
commit e155e342f4
9 changed files with 379 additions and 15 deletions

View File

@@ -101,8 +101,13 @@ message AudioConfig {
Guidance baked into defaults / docs:
- **Sample rate: always run Opus at 48 kHz internally.** Opus resamples internally anyway;
48 kHz avoids surprises. The `sample_rate` field mainly constrains capture/narrowband
modes for very low bitrate channels. Default **48000**.
48 kHz avoids surprises, and the whole audio stack (capture, `vc_stream_feed_pcm`, mixing,
playback) runs at 48 kHz. The per-channel `sample_rate` field is **channel-authoritative**
(not a client request) and does *not* change the codec/PCM clock — it caps the encoder's
audio bandwidth via `OPUS_SET_MAX_BANDWIDTH` (8000 → narrowband ~4 kHz, 16000 → wideband
~8 kHz, 24000 → super-wideband ~12 kHz, 48000 → full ~20 kHz). This lets a low-bitrate room
shed out-of-band content while every endpoint keeps a single 48 kHz clock. Default **48000**
(full band). See `OpusEncoder::init` and `vc_client::opus_params_from_audio_config`.
- **Frame size: 20 ms default.** Smaller (10 ms) lowers latency at the cost of more
per-packet overhead and CPU; larger (40/60 ms) improves efficiency and loss resilience at
the cost of latency. Expose it per channel for "low-latency talk" vs "stable music" rooms.