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