1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(all(not(feature = "std"), feature = "opus"))]
6extern crate alloc;
7
8pub use error::CodecError;
9
10pub mod error;
11pub mod g722;
12#[cfg(feature = "g729")]
13pub mod g729;
14#[cfg(feature = "opus")]
15pub mod opus;
16pub mod pcma;
17pub mod pcmu;
18pub mod resampler;
20pub mod resampler_fixed;
23pub mod telephone_event;
24
25#[cfg(feature = "std")]
26pub use resampler::Resampler;
27#[cfg(feature = "std")]
28pub use resampler::{BoxedResampler, resample};
29
30pub type Sample = i16;
31
32#[cfg(feature = "std")]
33pub type PcmBuf = Vec<Sample>;
34
35#[derive(Debug, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
36pub enum CodecType {
37 PCMU,
38 PCMA,
39 G722,
40 #[cfg(feature = "g729")]
41 G729,
42 #[cfg(feature = "opus")]
43 Opus,
44 TelephoneEvent,
45}
46
47pub trait Decoder: Send + Sync {
54 fn decode_into(&mut self, data: &[u8], out: &mut [Sample]) -> Result<usize, CodecError>;
59
60 fn max_decode_samples(&self, n_bytes: usize) -> usize;
63
64 fn sample_rate(&self) -> u32;
66
67 fn channels(&self) -> u16;
69
70 #[cfg(feature = "std")]
72 fn decode(&mut self, data: &[u8]) -> PcmBuf {
73 let max = self.max_decode_samples(data.len());
74 let mut buf = vec![0i16; max];
75 match self.decode_into(data, &mut buf) {
76 Ok(n) => {
77 buf.truncate(n);
78 buf
79 }
80 Err(_) => Vec::new(),
81 }
82 }
83}
84
85pub trait Encoder: Send + Sync {
92 fn encode_into(&mut self, samples: &[Sample], out: &mut [u8]) -> Result<usize, CodecError>;
97
98 fn max_encode_bytes(&self, n_samples: usize) -> usize;
101
102 fn sample_rate(&self) -> u32;
104
105 fn channels(&self) -> u16;
107
108 #[cfg(feature = "std")]
110 fn encode(&mut self, samples: &[Sample]) -> Vec<u8> {
111 let max = self.max_encode_bytes(samples.len());
112 let mut buf = vec![0u8; max];
113 match self.encode_into(samples, &mut buf) {
114 Ok(n) => {
115 buf.truncate(n);
116 buf
117 }
118 Err(_) => Vec::new(),
119 }
120 }
121}
122
123#[cfg(feature = "std")]
124pub fn create_decoder(codec: CodecType) -> Box<dyn Decoder> {
125 match codec {
126 CodecType::PCMU => Box::new(pcmu::PcmuDecoder::new()),
127 CodecType::PCMA => Box::new(pcma::PcmaDecoder::new()),
128 CodecType::G722 => Box::new(g722::G722Decoder::new()),
129 #[cfg(feature = "g729")]
130 CodecType::G729 => Box::new(g729::G729Decoder::new()),
131 #[cfg(feature = "opus")]
132 CodecType::Opus => Box::new(opus::OpusDecoder::new_default()),
133 CodecType::TelephoneEvent => Box::new(telephone_event::TelephoneEventDecoder::new()),
134 }
135}
136
137#[cfg(feature = "std")]
138pub fn create_encoder(codec: CodecType) -> Box<dyn Encoder> {
139 match codec {
140 CodecType::PCMU => Box::new(pcmu::PcmuEncoder::new()),
141 CodecType::PCMA => Box::new(pcma::PcmaEncoder::new()),
142 CodecType::G722 => Box::new(g722::G722Encoder::new()),
143 #[cfg(feature = "g729")]
144 CodecType::G729 => Box::new(g729::G729Encoder::new()),
145 #[cfg(feature = "opus")]
146 CodecType::Opus => Box::new(opus::OpusEncoder::new_default()),
147 CodecType::TelephoneEvent => Box::new(telephone_event::TelephoneEventEncoder::new()),
148 }
149}
150
151#[cfg(all(feature = "std", feature = "opus"))]
152pub fn create_opus_encoder(
153 sample_rate: u32,
154 channels: u16,
155 application: opus::OpusApplication,
156) -> Box<dyn Encoder> {
157 Box::new(opus::OpusEncoder::new_with_application(
158 sample_rate,
159 channels,
160 application,
161 ))
162}
163
164#[cfg(all(feature = "std", feature = "opus"))]
165pub fn create_opus_decoder(sample_rate: u32, channels: u16) -> Box<dyn Decoder> {
166 Box::new(opus::OpusDecoder::new(sample_rate, channels))
167}
168
169impl CodecType {
170 pub fn mime_type(&self) -> &str {
171 match self {
172 CodecType::PCMU => "audio/PCMU",
173 CodecType::PCMA => "audio/PCMA",
174 CodecType::G722 => "audio/G722",
175 #[cfg(feature = "g729")]
176 CodecType::G729 => "audio/G729",
177 #[cfg(feature = "opus")]
178 CodecType::Opus => "audio/opus",
179 CodecType::TelephoneEvent => "audio/telephone-event",
180 }
181 }
182 pub fn rtpmap(&self) -> &str {
183 match self {
184 CodecType::PCMU => "PCMU/8000",
185 CodecType::PCMA => "PCMA/8000",
186 CodecType::G722 => "G722/8000",
187 #[cfg(feature = "g729")]
188 CodecType::G729 => "G729/8000",
189 #[cfg(feature = "opus")]
190 CodecType::Opus => "opus/48000/2",
191 CodecType::TelephoneEvent => "telephone-event/8000",
192 }
193 }
194 pub fn fmtp(&self) -> Option<&str> {
195 match self {
196 CodecType::PCMU => None,
197 CodecType::PCMA => None,
198 CodecType::G722 => None,
199 #[cfg(feature = "g729")]
200 CodecType::G729 => None,
201 #[cfg(feature = "opus")]
202 CodecType::Opus => Some("minptime=10;useinbandfec=1;stereo=1;sprop-stereo=1"),
203 CodecType::TelephoneEvent => Some("0-16"),
204 }
205 }
206
207 pub fn clock_rate(&self) -> u32 {
208 match self {
209 CodecType::PCMU => 8000,
210 CodecType::PCMA => 8000,
211 CodecType::G722 => 8000,
212 #[cfg(feature = "g729")]
213 CodecType::G729 => 8000,
214 #[cfg(feature = "opus")]
215 CodecType::Opus => 48000,
216 CodecType::TelephoneEvent => 8000,
217 }
218 }
219
220 pub fn channels(&self) -> u16 {
221 match self {
222 #[cfg(feature = "opus")]
223 CodecType::Opus => 2,
224 _ => 1,
225 }
226 }
227
228 pub fn payload_type(&self) -> u8 {
229 match self {
230 CodecType::PCMU => 0,
231 CodecType::PCMA => 8,
232 CodecType::G722 => 9,
233 #[cfg(feature = "g729")]
234 CodecType::G729 => 18,
235 #[cfg(feature = "opus")]
236 CodecType::Opus => 111,
237 CodecType::TelephoneEvent => 101,
238 }
239 }
240 pub fn samplerate(&self) -> u32 {
241 match self {
242 CodecType::PCMU => 8000,
243 CodecType::PCMA => 8000,
244 CodecType::G722 => 16000,
245 #[cfg(feature = "g729")]
246 CodecType::G729 => 8000,
247 #[cfg(feature = "opus")]
248 CodecType::Opus => 48000,
249 CodecType::TelephoneEvent => 8000,
250 }
251 }
252 pub fn is_audio(&self) -> bool {
253 match self {
254 CodecType::PCMU | CodecType::PCMA | CodecType::G722 => true,
255 #[cfg(feature = "g729")]
256 CodecType::G729 => true,
257 #[cfg(feature = "opus")]
258 CodecType::Opus => true,
259 _ => false,
260 }
261 }
262
263 pub fn is_dynamic(&self) -> bool {
264 match self {
265 #[cfg(feature = "opus")]
266 CodecType::Opus => true,
267 CodecType::TelephoneEvent => true,
268 _ => false,
269 }
270 }
271}
272
273impl TryFrom<u8> for CodecType {
274 type Error = CodecError;
275
276 fn try_from(value: u8) -> Result<Self, Self::Error> {
277 match value {
278 0 => Ok(CodecType::PCMU),
279 8 => Ok(CodecType::PCMA),
280 9 => Ok(CodecType::G722),
281 #[cfg(feature = "g729")]
282 18 => Ok(CodecType::G729), 101 => Ok(CodecType::TelephoneEvent),
285 #[cfg(feature = "opus")]
286 111 => Ok(CodecType::Opus), _ => Err(CodecError::InvalidCodecType),
288 }
289 }
290}
291
292impl TryFrom<&str> for CodecType {
293 type Error = CodecError;
294
295 fn try_from(name: &str) -> Result<Self, Self::Error> {
296 let b = name.as_bytes();
297 if b.eq_ignore_ascii_case(b"pcmu") || b.eq_ignore_ascii_case(b"ulaw") {
298 Ok(CodecType::PCMU)
299 } else if b.eq_ignore_ascii_case(b"pcma") || b.eq_ignore_ascii_case(b"alaw") {
300 Ok(CodecType::PCMA)
301 } else if b.eq_ignore_ascii_case(b"g722") {
302 Ok(CodecType::G722)
303 } else if cfg!(feature = "g729") && b.eq_ignore_ascii_case(b"g729") {
304 #[cfg(feature = "g729")]
305 {
306 Ok(CodecType::G729)
307 }
308 #[cfg(not(feature = "g729"))]
309 {
310 Err(CodecError::InvalidCodecName)
311 }
312 } else if cfg!(feature = "opus") && b.eq_ignore_ascii_case(b"opus") {
313 #[cfg(feature = "opus")]
314 {
315 Ok(CodecType::Opus)
316 }
317 #[cfg(not(feature = "opus"))]
318 {
319 Err(CodecError::InvalidCodecName)
320 }
321 } else if b.eq_ignore_ascii_case(b"telephone-event") {
322 Ok(CodecType::TelephoneEvent)
323 } else {
324 Err(CodecError::InvalidCodecName)
325 }
326 }
327}
328
329pub fn samples_to_bytes_into(samples: &[Sample], out: &mut [u8]) -> Result<usize, CodecError> {
338 let needed = core::mem::size_of_val(samples);
339 if out.len() < needed {
340 return Err(CodecError::BufferTooSmall);
341 }
342 if samples.is_empty() {
343 return Ok(0);
344 }
345 let dst_aligned = out
350 .as_mut_ptr()
351 .addr()
352 .is_multiple_of(core::mem::align_of::<Sample>());
353 #[cfg(target_endian = "little")]
354 if dst_aligned {
355 let dst = unsafe {
359 core::slice::from_raw_parts_mut(out.as_mut_ptr() as *mut Sample, samples.len())
360 };
361 dst.copy_from_slice(samples);
362 return Ok(needed);
363 }
364 for (i, s) in samples.iter().enumerate() {
365 let b = s.to_le_bytes();
366 out[2 * i] = b[0];
367 out[2 * i + 1] = b[1];
368 }
369 Ok(needed)
370}
371
372pub fn bytes_to_samples_into(u8_data: &[u8], out: &mut [Sample]) -> Result<usize, CodecError> {
377 let n = u8_data.len() / core::mem::size_of::<Sample>();
378 if out.len() < n {
379 return Err(CodecError::BufferTooSmall);
380 }
381 if n == 0 {
382 return Ok(0);
383 }
384 let src_aligned = u8_data
387 .as_ptr()
388 .addr()
389 .is_multiple_of(core::mem::align_of::<Sample>());
390 #[cfg(target_endian = "little")]
391 if src_aligned {
392 let src = unsafe { core::slice::from_raw_parts(u8_data.as_ptr() as *const Sample, n) };
394 out[..n].copy_from_slice(src);
395 return Ok(n);
396 }
397 for (i, chunk) in u8_data.chunks_exact(2).enumerate() {
398 out[i] = (chunk[0] as i16) | ((chunk[1] as i16) << 8);
399 }
400 Ok(n)
401}
402
403#[cfg(feature = "std")]
404pub fn samples_to_bytes(samples: &[Sample]) -> Vec<u8> {
405 let mut out = vec![0u8; core::mem::size_of_val(samples)];
406 let _ = samples_to_bytes_into(samples, &mut out);
407 out
408}
409
410#[cfg(feature = "std")]
411pub fn bytes_to_samples(u8_data: &[u8]) -> PcmBuf {
412 let n = u8_data.len() / core::mem::size_of::<Sample>();
413 let mut out = vec![0i16; n];
414 let _ = bytes_to_samples_into(u8_data, &mut out);
415 out
416}