From 04bdb70d4726158088aedf06f6ddbe63377669e4 Mon Sep 17 00:00:00 2001 From: Talon Date: Tue, 23 Jun 2026 23:44:00 +0200 Subject: [PATCH] fix(codec): scale DRED duration to frame size instead of hardcoding 2 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 --- core/src/codec/opus_codec.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/src/codec/opus_codec.cpp b/core/src/codec/opus_codec.cpp index abdfd2a..a2e85cc 100644 --- a/core/src/codec/opus_codec.cpp +++ b/core/src/codec/opus_codec.cpp @@ -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_PACKET_LOSS_PERC( static_cast(p.expected_packet_loss))); - // DRED: 2 × 10ms frames of redundancy covers one 20ms frame loss with ML reconstruction. - opus_encoder_ctl(enc_, OPUS_SET_DRED_DURATION(p.dred ? 2 : 0)); + // DRED: embed enough redundancy to cover one full previous frame at any frame size. + // 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(dred_units) : 0)); return true; }