1pub type Sample = i16;
2pub type PcmBuf = Vec<Sample>;
3
4pub mod g722;
5pub mod g729;
6#[cfg(feature = "opus")]
7pub mod opus;
8pub mod pcma;
9pub mod pcmu;
10pub mod resampler;
11pub mod telephone_event;
12pub use resampler::{Resampler, resample};
13
14#[derive(Debug, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
15pub enum CodecType {
16 PCMU,
17 PCMA,
18 G722,
19 G729,
20 #[cfg(feature = "opus")]
21 Opus,
22 TelephoneEvent,
23}
24
25pub trait Decoder: Send + Sync {
26 fn decode(&mut self, data: &[u8]) -> PcmBuf;
28
29 fn sample_rate(&self) -> u32;
31
32 fn channels(&self) -> u16;
34}
35
36pub trait Encoder: Send + Sync {
37 fn encode(&mut self, samples: &[Sample]) -> Vec<u8>;
39
40 fn sample_rate(&self) -> u32;
42
43 fn channels(&self) -> u16;
45}
46
47pub fn create_decoder(codec: CodecType) -> Box<dyn Decoder> {
48 match codec {
49 CodecType::PCMU => Box::new(pcmu::PcmuDecoder::new()),
50 CodecType::PCMA => Box::new(pcma::PcmaDecoder::new()),
51 CodecType::G722 => Box::new(g722::G722Decoder::new()),
52 CodecType::G729 => Box::new(g729::G729Decoder::new()),
53 #[cfg(feature = "opus")]
54 CodecType::Opus => Box::new(opus::OpusDecoder::new_default()),
55 CodecType::TelephoneEvent => Box::new(telephone_event::TelephoneEventDecoder::new()),
56 }
57}
58
59pub fn create_encoder(codec: CodecType) -> Box<dyn Encoder> {
60 match codec {
61 CodecType::PCMU => Box::new(pcmu::PcmuEncoder::new()),
62 CodecType::PCMA => Box::new(pcma::PcmaEncoder::new()),
63 CodecType::G722 => Box::new(g722::G722Encoder::new()),
64 CodecType::G729 => Box::new(g729::G729Encoder::new()),
65 #[cfg(feature = "opus")]
66 CodecType::Opus => Box::new(opus::OpusEncoder::new_default()),
67 CodecType::TelephoneEvent => Box::new(telephone_event::TelephoneEventEncoder::new()),
68 }
69}
70
71#[cfg(feature = "opus")]
72pub fn create_opus_encoder(
73 sample_rate: u32,
74 channels: u16,
75 application: opus::OpusApplication,
76) -> Box<dyn Encoder> {
77 Box::new(opus::OpusEncoder::new_with_application(
78 sample_rate,
79 channels,
80 application,
81 ))
82}
83
84#[cfg(feature = "opus")]
85pub fn create_opus_decoder(sample_rate: u32, channels: u16) -> Box<dyn Decoder> {
86 Box::new(opus::OpusDecoder::new(sample_rate, channels))
87}
88
89impl CodecType {
90 pub fn mime_type(&self) -> &str {
91 match self {
92 CodecType::PCMU => "audio/PCMU",
93 CodecType::PCMA => "audio/PCMA",
94 CodecType::G722 => "audio/G722",
95 CodecType::G729 => "audio/G729",
96 #[cfg(feature = "opus")]
97 CodecType::Opus => "audio/opus",
98 CodecType::TelephoneEvent => "audio/telephone-event",
99 }
100 }
101 pub fn rtpmap(&self) -> &str {
102 match self {
103 CodecType::PCMU => "PCMU/8000",
104 CodecType::PCMA => "PCMA/8000",
105 CodecType::G722 => "G722/8000",
106 CodecType::G729 => "G729/8000",
107 #[cfg(feature = "opus")]
108 CodecType::Opus => "opus/48000/2",
109 CodecType::TelephoneEvent => "telephone-event/8000",
110 }
111 }
112 pub fn fmtp(&self) -> Option<&str> {
113 match self {
114 CodecType::PCMU => None,
115 CodecType::PCMA => None,
116 CodecType::G722 => None,
117 CodecType::G729 => None,
118 #[cfg(feature = "opus")]
119 CodecType::Opus => Some("minptime=10;useinbandfec=1;stereo=1;sprop-stereo=1"),
120 CodecType::TelephoneEvent => Some("0-16"),
121 }
122 }
123
124 pub fn clock_rate(&self) -> u32 {
125 match self {
126 CodecType::PCMU => 8000,
127 CodecType::PCMA => 8000,
128 CodecType::G722 => 8000,
129 CodecType::G729 => 8000,
130 #[cfg(feature = "opus")]
131 CodecType::Opus => 48000,
132 CodecType::TelephoneEvent => 8000,
133 }
134 }
135
136 pub fn channels(&self) -> u16 {
137 match self {
138 #[cfg(feature = "opus")]
139 CodecType::Opus => 2,
140 _ => 1,
141 }
142 }
143
144 pub fn payload_type(&self) -> u8 {
145 match self {
146 CodecType::PCMU => 0,
147 CodecType::PCMA => 8,
148 CodecType::G722 => 9,
149 CodecType::G729 => 18,
150 #[cfg(feature = "opus")]
151 CodecType::Opus => 111,
152 CodecType::TelephoneEvent => 101,
153 }
154 }
155 pub fn samplerate(&self) -> u32 {
156 match self {
157 CodecType::PCMU => 8000,
158 CodecType::PCMA => 8000,
159 CodecType::G722 => 16000,
160 CodecType::G729 => 8000,
161 #[cfg(feature = "opus")]
162 CodecType::Opus => 48000,
163 CodecType::TelephoneEvent => 8000,
164 }
165 }
166 pub fn is_audio(&self) -> bool {
167 match self {
168 CodecType::PCMU | CodecType::PCMA | CodecType::G722 => true,
169 CodecType::G729 => true,
170 #[cfg(feature = "opus")]
171 CodecType::Opus => true,
172 _ => false,
173 }
174 }
175
176 pub fn is_dynamic(&self) -> bool {
177 match self {
178 #[cfg(feature = "opus")]
179 CodecType::Opus => true,
180 CodecType::TelephoneEvent => true,
181 _ => false,
182 }
183 }
184}
185
186impl TryFrom<u8> for CodecType {
187 type Error = anyhow::Error;
188
189 fn try_from(value: u8) -> Result<Self, Self::Error> {
190 match value {
191 0 => Ok(CodecType::PCMU),
192 8 => Ok(CodecType::PCMA),
193 9 => Ok(CodecType::G722),
194 18 => Ok(CodecType::G729), 101 => Ok(CodecType::TelephoneEvent),
197 #[cfg(feature = "opus")]
198 111 => Ok(CodecType::Opus), _ => Err(anyhow::anyhow!("Invalid codec type: {}", value)),
200 }
201 }
202}
203
204impl TryFrom<&str> for CodecType {
205 type Error = anyhow::Error;
206
207 fn try_from(name: &str) -> Result<Self, Self::Error> {
208 match name.to_lowercase().as_str() {
209 "pcmu" | "ulaw" => Ok(CodecType::PCMU),
210 "pcma" | "alaw" => Ok(CodecType::PCMA),
211 "g722" => Ok(CodecType::G722),
212 "g729" => Ok(CodecType::G729),
213 #[cfg(feature = "opus")]
214 "opus" => Ok(CodecType::Opus),
215 "telephone-event" => Ok(CodecType::TelephoneEvent),
216 _ => Err(anyhow::anyhow!("Invalid codec name: {}", name)),
217 }
218 }
219}
220
221#[cfg(target_endian = "little")]
222pub fn samples_to_bytes(samples: &[Sample]) -> Vec<u8> {
223 unsafe {
224 std::slice::from_raw_parts(
225 samples.as_ptr() as *const u8,
226 samples.len() * std::mem::size_of::<Sample>(),
227 )
228 .to_vec()
229 }
230}
231
232#[cfg(target_endian = "big")]
233pub fn samples_to_bytes(samples: &[Sample]) -> Vec<u8> {
234 samples.iter().flat_map(|s| s.to_le_bytes()).collect()
235}
236
237#[cfg(target_endian = "little")]
238pub fn bytes_to_samples(u8_data: &[u8]) -> PcmBuf {
239 unsafe {
240 std::slice::from_raw_parts(
241 u8_data.as_ptr() as *const Sample,
242 u8_data.len() / std::mem::size_of::<Sample>(),
243 )
244 .to_vec()
245 }
246}
247#[cfg(target_endian = "big")]
248pub fn bytes_to_samples(u8_data: &[u8]) -> PcmBuf {
249 u8_data
250 .chunks(2)
251 .map(|chunk| (chunk[0] as i16) | ((chunk[1] as i16) << 8))
252 .collect()
253}