fix(codec): scale DRED duration to frame size instead of hardcoding 2
Some checks failed
Build Linux Binaries / linux/amd64 (push) Has been cancelled
Build Linux Binaries / linux/arm64 (push) Has been cancelled

OPUS_SET_DRED_DURATION was hardcoded to 2 (20 ms), meaning DRED only
covered 1/3 of a lost 60 ms frame and was useless above 20 ms channels.
Now computed as max(2, ceil(frame_ms/10)) so DRED always embeds enough
redundancy to reconstruct one full previous frame regardless of frame size.
The floor of 2 preserves two-frame burst-loss coverage at 10 ms channels.
Decoder side and server are unaffected (server relays payloads verbatim).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 23:44:00 +02:00
parent b44a200b95
commit 04bdb70d47

View File

@@ -46,8 +46,13 @@ bool OpusEncoder::init(const OpusParams& p) {
opus_encoder_ctl(enc_, OPUS_SET_DTX(p.dtx ? 1 : 0)); opus_encoder_ctl(enc_, OPUS_SET_DTX(p.dtx ? 1 : 0));
opus_encoder_ctl(enc_, OPUS_SET_PACKET_LOSS_PERC( opus_encoder_ctl(enc_, OPUS_SET_PACKET_LOSS_PERC(
static_cast<opus_int32>(p.expected_packet_loss))); static_cast<opus_int32>(p.expected_packet_loss)));
// DRED: 2 × 10ms frames of redundancy covers one 20ms frame loss with ML reconstruction. // DRED: embed enough redundancy to cover one full previous frame at any frame size.
opus_encoder_ctl(enc_, OPUS_SET_DRED_DURATION(p.dred ? 2 : 0)); // OPUS_SET_DRED_DURATION takes units of 10ms; ceil(frame_ms/10) ensures one complete frame
// of ML-reconstructed redundancy regardless of whether the channel runs at 10/20/40/60 ms.
// At 10ms frames this yields 1 unit (one frame back); a burst-loss floor of 2 ensures
// two consecutive 10ms frames can be recovered. Cost: ~800 bps per 10ms unit.
uint32_t dred_units = std::max(2u, (p.frame_ms + 9u) / 10u);
opus_encoder_ctl(enc_, OPUS_SET_DRED_DURATION(p.dred ? static_cast<opus_int32>(dred_units) : 0));
return true; return true;
} }