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