Fixes the two P2 efficacy findings from the Codex audit of the W12 profiles feature. FEC was enabled on the encoder but never used: the jitter buffer's loss path did pure PLC, so the redundancy was wasted bitrate. Now the gap path reconstructs the lost frame from the next buffered packet via Opus in-band FEC (new `AudioDecoder::decode_fec`, libopus decode with fec=true into a one-frame buffer), keeping that packet for its own normal decode and falling back to PLC if FEC decode fails. This is the documented libopus FEC pattern; receiver-side only, no wire change. DTX was enabled on BadNetwork but provided no benefit — the capture noise gate already suppresses silence transmission, and the broadcast DTX silence packets only created seq gaps that grew the jitter cushion. All profiles now set dtx=false (plumbing kept for a future revisit). Adds a jitter-buffer test proving FEC reconstruction beats pure PLC (RMS error < 0.75x) and that the FEC source packet stays buffered. 500 lib tests, clippy + fmt clean, release build clean. Co-Authored-By: Codex (gpt-5.5) <noreply@openai.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
29 lines
923 B
Rust
29 lines
923 B
Rust
use thiserror::Error;
|
|
|
|
#[derive(Error, Debug)]
|
|
pub enum CodecError {
|
|
#[error("Failed to initialize codec: {0}")]
|
|
Init(String),
|
|
#[error("Encoding failed: {0}")]
|
|
Encode(String),
|
|
#[error("Decoding failed: {0}")]
|
|
Decode(String),
|
|
}
|
|
|
|
pub trait AudioEncoder: Send {
|
|
/// Encodes raw PCM samples into compressed bytes.
|
|
fn encode(&mut self, pcm: &[i16]) -> Result<Vec<u8>, CodecError>;
|
|
}
|
|
|
|
pub trait AudioDecoder: Send {
|
|
/// Decodes compressed bytes back into raw PCM samples.
|
|
/// If `compressed` is `None` (or `Some(&[])`), it indicates packet loss,
|
|
/// enabling the decoder to perform packet loss concealment (PLC).
|
|
fn decode(&mut self, compressed: Option<&[u8]>) -> Result<Vec<i16>, CodecError>;
|
|
|
|
/// Reconstructs the previous lost frame from the next packet's in-band FEC.
|
|
fn decode_fec(&mut self, next_payload: &[u8]) -> Result<Vec<i16>, CodecError>;
|
|
}
|
|
|
|
pub mod opus_impl;
|