feat: DRED (Deep REDundancy) per-channel toggle
Adds Opus 1.6 DRED support end-to-end: encoder embeds 20 ms of ML redundancy in every packet when enabled; decoder recovers lost frames from the next buffered packet's DRED extension rather than falling back to PLC comfort noise. Protocol: bool dred = 11 added to AudioConfig (backward-compatible, defaults false). C ABI: int dred added to vc_audio_config. Encoder: OPUS_SET_DRED_DURATION(2) when dred=true. Decoder: OpusDREDDecoder + per-stream OpusDRED scratch pre-allocated off the RT thread; JitterBuffer::try_copy_front_payload peeks at the next packet without popping on every PLC step; opus_decoder_dred_decode reconstructs the lost frame if DRED data is present, otherwise falls back to PLC. New test: test_dred_toggle (22/22 ctest green). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,8 @@ 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<opus_int32>(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));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -70,6 +72,14 @@ int OpusDecoder::decode(const uint8_t* opus_data, int len, int16_t* out_pcm, int
|
||||
return n;
|
||||
}
|
||||
|
||||
int OpusDecoder::decode_dred(::OpusDRED* dred, int32_t dred_offset,
|
||||
int16_t* out_pcm, int max_samples) {
|
||||
if (!dec_ || !dred) return -1;
|
||||
int n = opus_decoder_dred_decode(dec_, dred, dred_offset, out_pcm, max_samples);
|
||||
if (n < 0) { err_ = opus_strerror(n); return -1; }
|
||||
return n;
|
||||
}
|
||||
|
||||
void OpusDecoder::destroy() {
|
||||
if (dec_) { opus_decoder_destroy(dec_); dec_ = nullptr; }
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ struct OpusParams {
|
||||
uint32_t complexity = 10;
|
||||
uint32_t expected_packet_loss = 0; // % 0..100
|
||||
OpusApplication application = OpusApplication::Voip;
|
||||
bool dred = false;
|
||||
};
|
||||
|
||||
// Returns frame_samples for a given sample_rate + frame_ms.
|
||||
@@ -95,6 +96,14 @@ class OpusDecoder {
|
||||
int decode(const uint8_t* opus_data, int len, int16_t* out_pcm, int max_samples,
|
||||
bool fec = false);
|
||||
|
||||
// Decode a lost frame using pre-parsed DRED state from the next received packet.
|
||||
// dred_offset=0 means the frame immediately before the next packet.
|
||||
// Returns frame_samples on success, -1 if DRED unavailable or decode failed.
|
||||
#ifdef VOICECAT_HAS_OPUS
|
||||
int decode_dred(::OpusDRED* dred, int32_t dred_offset, int16_t* out_pcm, int max_samples);
|
||||
::OpusDecoder* raw() const { return dec_; }
|
||||
#endif
|
||||
|
||||
void destroy();
|
||||
|
||||
bool valid() const { return dec_ != nullptr; }
|
||||
|
||||
Reference in New Issue
Block a user