1use super::{AudioDecoder, AudioEncoder, CodecType};
7
8#[derive(Debug, Default)]
12pub struct PcmuEncoder;
13
14impl PcmuEncoder {
15 pub fn new() -> Self {
17 Self
18 }
19}
20
21impl AudioEncoder for PcmuEncoder {
22 fn encode(&mut self, pcm: &[i16], output: &mut Vec<u8>) -> usize {
23 output.reserve(pcm.len());
24 for &sample in pcm {
25 output.push(linear_to_ulaw(sample));
26 }
27 pcm.len()
28 }
29
30 fn payload_type(&self) -> u8 {
31 0
32 }
33
34 fn codec_type(&self) -> CodecType {
35 CodecType::Pcmu
36 }
37}
38
39#[derive(Debug, Default)]
43pub struct PcmuDecoder;
44
45impl PcmuDecoder {
46 pub fn new() -> Self {
48 Self
49 }
50}
51
52impl AudioDecoder for PcmuDecoder {
53 fn decode(&mut self, encoded: &[u8], output: &mut Vec<i16>) {
54 output.reserve(encoded.len());
55 for &b in encoded {
56 output.push(ulaw_to_linear(b));
57 }
58 }
59
60 fn codec_type(&self) -> CodecType {
61 CodecType::Pcmu
62 }
63}
64
65#[derive(Debug, Default)]
69pub struct PcmaEncoder;
70
71impl PcmaEncoder {
72 pub fn new() -> Self {
74 Self
75 }
76}
77
78impl AudioEncoder for PcmaEncoder {
79 fn encode(&mut self, pcm: &[i16], output: &mut Vec<u8>) -> usize {
80 output.reserve(pcm.len());
81 for &sample in pcm {
82 output.push(linear_to_alaw(sample));
83 }
84 pcm.len()
85 }
86
87 fn payload_type(&self) -> u8 {
88 8
89 }
90
91 fn codec_type(&self) -> CodecType {
92 CodecType::Pcma
93 }
94}
95
96#[derive(Debug, Default)]
100pub struct PcmaDecoder;
101
102impl PcmaDecoder {
103 pub fn new() -> Self {
105 Self
106 }
107}
108
109impl AudioDecoder for PcmaDecoder {
110 fn decode(&mut self, encoded: &[u8], output: &mut Vec<i16>) {
111 output.reserve(encoded.len());
112 for &b in encoded {
113 output.push(alaw_to_linear(b));
114 }
115 }
116
117 fn codec_type(&self) -> CodecType {
118 CodecType::Pcma
119 }
120}
121
122const ULAW_BIAS: i16 = 0x84;
125const ULAW_MAX: i16 = 0x7FFF;
126
127fn linear_to_ulaw(sample: i16) -> u8 {
129 let sign: u8;
130 let mut pcm = sample;
131
132 if pcm < 0 {
133 sign = 0x80;
134 pcm = if pcm == i16::MIN { ULAW_MAX } else { -pcm };
135 } else {
136 sign = 0;
137 }
138
139 pcm = pcm.saturating_add(ULAW_BIAS);
140
141 let mut exponent = 7u8;
142 let mut mask = 0x4000i16;
143 while exponent > 0 && (pcm & mask) == 0 {
144 exponent -= 1;
145 mask >>= 1;
146 }
147
148 let mantissa = ((pcm >> (exponent + 3)) & 0x0F) as u8;
149 !(sign | (exponent << 4) | mantissa)
150}
151
152fn ulaw_to_linear(ulaw: u8) -> i16 {
154 let ulaw = !ulaw;
155 let sign = ulaw & 0x80;
156 let exponent = ((ulaw >> 4) & 0x07) as i32;
157 let mantissa = (ulaw & 0x0F) as i32;
158 let mut sample = ((mantissa << 3) + ULAW_BIAS as i32) << exponent;
159 sample -= ULAW_BIAS as i32;
160 if sign != 0 {
161 -sample as i16
162 } else {
163 sample as i16
164 }
165}
166
167const ALAW_SEG_END: [i16; 8] = [0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF];
170
171fn linear_to_alaw(sample: i16) -> u8 {
173 let sign: u8;
174 let abs_sample: i16;
175
176 if sample >= 0 {
177 sign = 0xD5;
178 abs_sample = sample;
179 } else {
180 sign = 0x55;
181 abs_sample = if sample == i16::MIN {
182 i16::MAX
183 } else {
184 -sample
185 };
186 }
187
188 let sample = abs_sample >> 3;
189
190 let mut seg = 0usize;
191 while seg < 8 && sample > ALAW_SEG_END[seg] {
192 seg += 1;
193 }
194
195 let aval = if seg >= 8 {
196 0x7F
197 } else if seg < 2 {
198 (sample >> 1) as u8
199 } else {
200 ((seg as u8) << 4) | ((sample >> seg) & 0x0F) as u8
201 };
202
203 aval ^ sign
204}
205
206fn alaw_to_linear(alaw: u8) -> i16 {
208 let alaw = alaw ^ 0x55;
209 let seg = ((alaw & 0x70) >> 4) as i32;
210 let value = ((alaw & 0x0F) << 1) | 1;
211
212 let sample = if seg == 0 {
213 (value as i32) << 3
214 } else {
215 ((value as i32) | 0x20) << (seg + 2)
216 };
217
218 if (alaw & 0x80) != 0 {
219 sample as i16
220 } else {
221 -(sample as i16)
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 #[test]
230 fn test_ulaw_roundtrip() {
231 for sample in [
233 -32768i16, -16384, -8192, -1024, -128, 0, 128, 1024, 8192, 16384, 32767,
234 ] {
235 let encoded = linear_to_ulaw(sample);
236 let decoded = ulaw_to_linear(encoded);
237 let diff = (sample as i32 - decoded as i32).abs();
239 assert!(
240 diff < 2048,
241 "μ-law roundtrip too lossy: {} -> {} (diff {})",
242 sample,
243 decoded,
244 diff
245 );
246 }
247 }
248
249 #[test]
250 fn test_alaw_roundtrip() {
251 for sample in [
252 -32768i16, -16384, -8192, -1024, -128, 0, 128, 1024, 8192, 16384, 32767,
253 ] {
254 let encoded = linear_to_alaw(sample);
255 let decoded = alaw_to_linear(encoded);
256 let diff = (sample as i32 - decoded as i32).abs();
257 assert!(
258 diff < 2048,
259 "A-law roundtrip too lossy: {} -> {} (diff {})",
260 sample,
261 decoded,
262 diff
263 );
264 }
265 }
266
267 #[test]
268 fn test_ulaw_encoder_decoder() {
269 let mut encoder = PcmuEncoder::new();
270 let mut decoder = PcmuDecoder::new();
271
272 let input: Vec<i16> = (0..160)
273 .map(|i| ((i as f32 / 160.0) * 16000.0) as i16)
274 .collect();
275 let mut encoded = Vec::new();
276 let consumed = encoder.encode(&input, &mut encoded);
277
278 assert_eq!(consumed, 160);
279 assert_eq!(encoded.len(), 160);
280
281 let mut decoded = Vec::new();
282 decoder.decode(&encoded, &mut decoded);
283 assert_eq!(decoded.len(), 160);
284 }
285
286 #[test]
287 fn test_alaw_encoder_decoder() {
288 let mut encoder = PcmaEncoder::new();
289 let mut decoder = PcmaDecoder::new();
290
291 let input: Vec<i16> = (0..160)
292 .map(|i| ((i as f32 / 160.0) * 16000.0) as i16)
293 .collect();
294 let mut encoded = Vec::new();
295 let consumed = encoder.encode(&input, &mut encoded);
296
297 assert_eq!(consumed, 160);
298 assert_eq!(encoded.len(), 160);
299
300 let mut decoded = Vec::new();
301 decoder.decode(&encoded, &mut decoded);
302 assert_eq!(decoded.len(), 160);
303 }
304
305 #[test]
306 fn test_silence_encoding() {
307 let mut encoder = PcmuEncoder::new();
308 let silence: Vec<i16> = vec![0; 160];
309 let mut encoded = Vec::new();
310 encoder.encode(&silence, &mut encoded);
311
312 assert!(encoded.iter().all(|&b| b == 0xFF || b == 0x7F));
314 }
315
316 #[test]
317 fn test_ulaw_extreme_values() {
318 let max_encoded = linear_to_ulaw(i16::MAX);
320 let min_encoded = linear_to_ulaw(i16::MIN);
321
322 assert_ne!(max_encoded, min_encoded);
324
325 let max_decoded = ulaw_to_linear(max_encoded);
327 let min_decoded = ulaw_to_linear(min_encoded);
328
329 assert!(max_decoded > 0);
330 assert!(min_decoded < 0);
331 }
332
333 #[test]
334 fn test_alaw_extreme_values() {
335 let max_encoded = linear_to_alaw(i16::MAX);
336 let min_encoded = linear_to_alaw(i16::MIN);
337
338 assert_ne!(max_encoded, min_encoded);
339
340 let max_decoded = alaw_to_linear(max_encoded);
341 let min_decoded = alaw_to_linear(min_encoded);
342
343 assert!(max_decoded > 0);
344 assert!(min_decoded < 0);
345 }
346
347 #[test]
348 fn test_ulaw_monotonicity() {
349 let mut last_encoded = linear_to_ulaw(0);
351 for sample in (0..32768i32).step_by(256) {
352 let encoded = linear_to_ulaw(sample as i16);
353 assert!(
356 encoded <= last_encoded || sample < 256,
357 "μ-law not monotonic at {}: {} > {}",
358 sample,
359 encoded,
360 last_encoded
361 );
362 last_encoded = encoded;
363 }
364 }
365
366 #[test]
367 fn test_pcmu_encoder_properties() {
368 let encoder = PcmuEncoder::new();
369
370 assert_eq!(encoder.codec_type(), CodecType::Pcmu);
371 assert_eq!(encoder.payload_type(), 0);
372 }
373
374 #[test]
375 fn test_pcma_encoder_properties() {
376 let encoder = PcmaEncoder::new();
377
378 assert_eq!(encoder.codec_type(), CodecType::Pcma);
379 assert_eq!(encoder.payload_type(), 8);
380 }
381
382 #[test]
383 fn test_pcmu_decoder_properties() {
384 let decoder = PcmuDecoder::new();
385
386 assert_eq!(decoder.codec_type(), CodecType::Pcmu);
387 }
388
389 #[test]
390 fn test_pcma_decoder_properties() {
391 let decoder = PcmaDecoder::new();
392
393 assert_eq!(decoder.codec_type(), CodecType::Pcma);
394 }
395
396 #[test]
397 fn test_encoder_partial_frame() {
398 let mut encoder = PcmuEncoder::new();
399
400 let input: Vec<i16> = vec![1000; 80];
402 let mut encoded = Vec::new();
403 let consumed = encoder.encode(&input, &mut encoded);
404
405 assert_eq!(consumed, 80);
406 assert_eq!(encoded.len(), 80);
407 }
408
409 #[test]
410 fn test_encoder_multiple_frames() {
411 let mut encoder = PcmuEncoder::new();
412
413 let input: Vec<i16> = vec![1000; 480];
415 let mut encoded = Vec::new();
416 let consumed = encoder.encode(&input, &mut encoded);
417
418 assert_eq!(consumed, 480);
419 assert_eq!(encoded.len(), 480);
420 }
421
422 #[test]
423 fn test_ulaw_all_codewords() {
424 for codeword in 0u8..=255 {
426 let _decoded = ulaw_to_linear(codeword);
427 }
429 }
430
431 #[test]
432 fn test_alaw_all_codewords() {
433 for codeword in 0u8..=255 {
435 let _decoded = alaw_to_linear(codeword);
436 }
438 }
439
440 #[test]
441 fn test_sine_wave_encoding() {
442 let mut encoder = PcmuEncoder::new();
443 let mut decoder = PcmuDecoder::new();
444
445 let samples: Vec<i16> = (0..160)
447 .map(|i| {
448 let t = i as f32 / 8000.0;
449 (1000.0 * (2.0 * std::f32::consts::PI * t).sin() * 16000.0) as i16
450 })
451 .collect();
452
453 let mut encoded = Vec::new();
454 encoder.encode(&samples, &mut encoded);
455
456 let mut decoded = Vec::new();
457 decoder.decode(&encoded, &mut decoded);
458
459 assert_eq!(decoded.len(), samples.len());
461
462 let correlation: f64 = samples
464 .iter()
465 .zip(decoded.iter())
466 .map(|(&a, &b)| (a as f64) * (b as f64))
467 .sum();
468
469 assert!(
471 correlation > 0.0,
472 "Decoded signal not correlated with original"
473 );
474 }
475}