1#![deny(missing_docs)]
2use std::ffi::c_void;
5
6#[allow(non_camel_case_types)]
7type int16_t = i16;
8#[allow(non_camel_case_types)]
9type uint8_t = u8;
10
11#[allow(non_camel_case_types)]
12#[repr(C)]
13struct bcg729EncoderChannelContextStruct(c_void);
14#[allow(non_camel_case_types)]
15#[repr(C)]
16struct bcg729DecoderChannelContextStruct(c_void);
17
18#[link(name = "bcg729", kind = "static")]
19unsafe extern "C" {
20 fn initBcg729EncoderChannel(enable_vad: uint8_t) -> *mut bcg729EncoderChannelContextStruct;
21 fn closeBcg729EncoderChannel(ctx: *mut bcg729EncoderChannelContextStruct);
22 fn bcg729Encoder(
23 ctx: *mut bcg729EncoderChannelContextStruct,
24 input_frame: *const int16_t,
25 bit_stream: *mut uint8_t,
26 bit_stream_length: *mut uint8_t,
27 );
28 fn bcg729GetRFC3389Payload(ctx: *mut bcg729EncoderChannelContextStruct, payload: *mut uint8_t);
29
30 fn initBcg729DecoderChannel() -> *mut bcg729DecoderChannelContextStruct;
31 fn closeBcg729DecoderChannel(ctx: *mut bcg729DecoderChannelContextStruct);
32 fn bcg729Decoder(
33 ctx: *mut bcg729DecoderChannelContextStruct,
34 bit_stream: *const uint8_t,
35 bit_stream_length: uint8_t,
36 frame_erasure_flag: uint8_t,
37 sid_frame_flag: uint8_t,
38 rfc3389_payload_flag: uint8_t,
39 signal: *mut int16_t,
40 );
41}
42
43pub const FRAME_SAMPLES: usize = 80;
45pub const VOICE_FRAME_BYTES: usize = 10;
47
48pub struct Encoder {
50 ctx: *mut bcg729EncoderChannelContextStruct,
51}
52
53impl Encoder {
54 pub fn new(enable_vad: bool) -> anyhow::Result<Self> {
56 let ctx = unsafe { initBcg729EncoderChannel(if enable_vad { 1 } else { 0 }) };
57 if ctx.is_null() {
58 anyhow::bail!("initBcg729EncoderChannel returned null");
59 }
60 Ok(Self { ctx })
61 }
62
63 pub fn encode(&mut self, input_80_samples: &[i16; FRAME_SAMPLES]) -> Vec<u8> {
66 let mut out = [0u8; VOICE_FRAME_BYTES];
67 let mut len: u8 = 0;
68 unsafe {
69 bcg729Encoder(
70 self.ctx,
71 input_80_samples.as_ptr(),
72 out.as_mut_ptr(),
73 &mut len,
74 );
75 }
76 out[..len as usize].to_vec()
77 }
78
79 pub fn rfc3389_payload(&mut self) -> [u8; 11] {
81 let mut p = [0u8; 11];
82 unsafe { bcg729GetRFC3389Payload(self.ctx, p.as_mut_ptr()) };
83 p
84 }
85}
86
87impl Drop for Encoder {
88 fn drop(&mut self) {
89 if !self.ctx.is_null() {
90 unsafe { closeBcg729EncoderChannel(self.ctx) };
91 self.ctx = std::ptr::null_mut();
92 }
93 }
94}
95
96pub struct Decoder {
98 ctx: *mut bcg729DecoderChannelContextStruct,
99}
100
101impl Decoder {
102 pub fn new() -> anyhow::Result<Self> {
104 let ctx = unsafe { initBcg729DecoderChannel() };
105 if ctx.is_null() {
106 anyhow::bail!("initBcg729DecoderChannel returned null");
107 }
108 Ok(Self { ctx })
109 }
110
111 pub fn decode(
114 &mut self,
115 payload: &[u8],
116 frame_erased: bool,
117 is_sid: bool,
118 rfc3389: bool,
119 ) -> [i16; FRAME_SAMPLES] {
120 let mut out = [0i16; FRAME_SAMPLES];
121 let len = payload.len() as u8;
122 unsafe {
123 bcg729Decoder(
124 self.ctx,
125 payload.as_ptr(),
126 len,
127 frame_erased as u8,
128 is_sid as u8,
129 rfc3389 as u8,
130 out.as_mut_ptr(),
131 );
132 }
133 out
134 }
135}
136
137impl Drop for Decoder {
138 fn drop(&mut self) {
139 if !self.ctx.is_null() {
140 unsafe { closeBcg729DecoderChannel(self.ctx) };
141 self.ctx = std::ptr::null_mut();
142 }
143 }
144}