Skip to main content

audio_codec/
g729.rs

1use super::{CodecError, Decoder, Encoder, Sample};
2
3const L_FRAME: usize = 80; // 10ms frame at 8kHz
4const L_FRAME_COMPRESSED: usize = 10; // G.729 frame size in bytes
5
6/// G.729 audio decoder using g729-sys
7pub struct G729Decoder {
8    decoder: g729_sys::Decoder,
9}
10
11impl Default for G729Decoder {
12    fn default() -> Self {
13        Self::new()
14    }
15}
16
17impl G729Decoder {
18    /// Create a new G.729 decoder instance.
19    pub fn new() -> Self {
20        Self {
21            decoder: g729_sys::Decoder::new(),
22        }
23    }
24}
25
26unsafe impl Send for G729Decoder {}
27unsafe impl Sync for G729Decoder {}
28
29impl Decoder for G729Decoder {
30    fn decode_into(&mut self, data: &[u8], out: &mut [Sample]) -> Result<usize, CodecError> {
31        if data.is_empty() {
32            return Ok(0);
33        }
34
35        // G.729 processes 10-byte frames, each producing 80 samples
36        let mut written = 0usize;
37        let mut pos = 0usize;
38
39        while pos + L_FRAME_COMPRESSED <= data.len() {
40            if out.len() < written + L_FRAME {
41                return Err(CodecError::BufferTooSmall);
42            }
43            let frame_data = &data[pos..pos + L_FRAME_COMPRESSED];
44            // g729-sys: decode(frame, bfi, vad, dtx) -> [i16;80]
45            let decoded_frame = self.decoder.decode(frame_data, false, false, false);
46            out[written..written + L_FRAME].copy_from_slice(&decoded_frame);
47            written += L_FRAME;
48            pos += L_FRAME_COMPRESSED;
49        }
50
51        Ok(written)
52    }
53
54    fn max_decode_samples(&self, n_bytes: usize) -> usize {
55        (n_bytes / L_FRAME_COMPRESSED) * L_FRAME
56    }
57
58    fn sample_rate(&self) -> u32 {
59        8000 // G.729 operates at 8kHz
60    }
61
62    fn channels(&self) -> u16 {
63        1 // G.729 is always mono
64    }
65}
66
67/// G.729 audio encoder using g729-sys
68pub struct G729Encoder {
69    encoder: g729_sys::Encoder,
70}
71
72impl Default for G729Encoder {
73    fn default() -> Self {
74        Self::new()
75    }
76}
77
78impl G729Encoder {
79    /// Create a new G.729 encoder instance.
80    ///
81    /// Annex B (VAD/DTX) is disabled by default.
82    pub fn new() -> Self {
83        Self {
84            encoder: g729_sys::Encoder::new(false),
85        }
86    }
87
88    /// Create a new G.729 encoder with explicit VAD/DTX control.
89    pub fn with_vad(enable_vad: bool) -> Self {
90        Self {
91            encoder: g729_sys::Encoder::new(enable_vad),
92        }
93    }
94}
95
96unsafe impl Send for G729Encoder {}
97unsafe impl Sync for G729Encoder {}
98
99impl Encoder for G729Encoder {
100    fn encode_into(&mut self, samples: &[Sample], out: &mut [u8]) -> Result<usize, CodecError> {
101        if samples.is_empty() {
102            return Ok(0);
103        }
104
105        let mut written = 0usize;
106        let mut pos = 0usize;
107        let mut frame_arr = [0i16; L_FRAME];
108        let mut packet = [0u8; L_FRAME_COMPRESSED];
109
110        while pos + L_FRAME <= samples.len() {
111            frame_arr.copy_from_slice(&samples[pos..pos + L_FRAME]);
112            let n = self.encoder.encode_into(&frame_arr, &mut packet);
113            let n = n as usize;
114            if out.len() < written + n {
115                return Err(CodecError::BufferTooSmall);
116            }
117            out[written..written + n].copy_from_slice(&packet[..n]);
118            written += n;
119            pos += L_FRAME;
120        }
121
122        Ok(written)
123    }
124
125    fn max_encode_bytes(&self, n_samples: usize) -> usize {
126        (n_samples / L_FRAME) * L_FRAME_COMPRESSED
127    }
128
129    fn sample_rate(&self) -> u32 {
130        8000 // G.729 operates at 8kHz
131    }
132
133    fn channels(&self) -> u16 {
134        1 // G.729 is always mono
135    }
136}