1use crate::frames::{MAX_FRAMES_PER_PACKET, MAX_FRAME_BYTES};
33use crate::toc::{FrameCountCode, OpusTocByte};
34use crate::Error;
35
36pub fn encode_length(length: usize, out: &mut Vec<u8>) -> Result<(), Error> {
47 if length > MAX_FRAME_BYTES {
48 return Err(Error::MalformedPacket);
49 }
50 if length < 252 {
51 out.push(length as u8);
52 } else {
53 let first = 252 + ((length - 252) % 4);
54 let second = (length - first) / 4;
55 out.push(first as u8);
56 out.push(second as u8);
57 }
58 Ok(())
59}
60
61fn write_padding_chain(mut padding: usize, out: &mut Vec<u8>) {
65 while padding >= 255 {
66 out.push(255);
67 padding -= 254;
68 }
69 out.push(padding as u8);
70}
71
72fn validate_shape(toc_byte: u8, frames: &[&[u8]]) -> Result<OpusTocByte, Error> {
75 let toc = OpusTocByte::from_byte(toc_byte);
76 for f in frames {
77 if f.len() > MAX_FRAME_BYTES {
78 return Err(Error::MalformedPacket);
79 }
80 }
81 match toc.frame_count_code {
82 FrameCountCode::One => {
83 if frames.len() != 1 {
84 return Err(Error::MalformedPacket);
85 }
86 }
87 FrameCountCode::TwoEqual => {
88 if frames.len() != 2 || frames[0].len() != frames[1].len() {
89 return Err(Error::MalformedPacket);
90 }
91 }
92 FrameCountCode::TwoUnequal => {
93 if frames.len() != 2 {
94 return Err(Error::MalformedPacket);
95 }
96 }
97 FrameCountCode::Arbitrary => {
98 let m = frames.len();
99 if m == 0 || m > MAX_FRAMES_PER_PACKET as usize {
100 return Err(Error::MalformedPacket);
101 }
102 if m as u32 * toc.frame_size_tenths_ms as u32 > 1200 {
104 return Err(Error::MalformedPacket);
105 }
106 }
107 }
108 Ok(toc)
109}
110
111pub fn compose_packet(toc_byte: u8, frames: &[&[u8]]) -> Result<Vec<u8>, Error> {
121 let toc = validate_shape(toc_byte, frames)?;
122 match toc.frame_count_code {
123 FrameCountCode::One => Ok([&[toc_byte], frames[0]].concat()),
124 FrameCountCode::TwoEqual => Ok([&[toc_byte], frames[0], frames[1]].concat()),
125 FrameCountCode::TwoUnequal => {
126 let mut out = Vec::with_capacity(3 + frames[0].len() + frames[1].len());
127 out.push(toc_byte);
128 encode_length(frames[0].len(), &mut out)?;
129 out.extend_from_slice(frames[0]);
130 out.extend_from_slice(frames[1]);
131 Ok(out)
132 }
133 FrameCountCode::Arbitrary => {
134 let cbr = frames.iter().all(|f| f.len() == frames[0].len());
135 compose_packet_code3(toc_byte, frames, !cbr, 0)
136 }
137 }
138}
139
140pub fn compose_packet_code3(
152 toc_byte: u8,
153 frames: &[&[u8]],
154 vbr: bool,
155 padding: usize,
156) -> Result<Vec<u8>, Error> {
157 let toc = validate_shape(toc_byte, frames)?;
158 if toc.frame_count_code != FrameCountCode::Arbitrary {
159 return Err(Error::MalformedPacket);
160 }
161 if !vbr && frames.iter().any(|f| f.len() != frames[0].len()) {
162 return Err(Error::MalformedPacket);
163 }
164 let m = frames.len();
165 let mut out = Vec::new();
166 out.push(toc_byte);
167 out.push(((m as u8) << 2) | (u8::from(padding > 0) << 1) | u8::from(vbr));
168 if padding > 0 {
169 write_padding_chain(padding, &mut out);
170 }
171 if vbr {
172 for f in &frames[..m - 1] {
174 encode_length(f.len(), &mut out)?;
175 }
176 }
177 for f in frames {
178 out.extend_from_slice(f);
179 }
180 out.resize(out.len() + padding, 0);
181 Ok(out)
182}
183
184pub fn compose_self_delimited(
198 toc_byte: u8,
199 frames: &[&[u8]],
200 vbr: bool,
201 padding: usize,
202) -> Result<Vec<u8>, Error> {
203 let toc = validate_shape(toc_byte, frames)?;
204 if toc.frame_count_code != FrameCountCode::Arbitrary && (vbr || padding > 0) {
205 return Err(Error::MalformedPacket);
206 }
207 let mut out = Vec::new();
208 out.push(toc_byte);
209 match toc.frame_count_code {
210 FrameCountCode::One => {
211 encode_length(frames[0].len(), &mut out)?;
213 out.extend_from_slice(frames[0]);
214 }
215 FrameCountCode::TwoEqual => {
216 encode_length(frames[0].len(), &mut out)?;
218 out.extend_from_slice(frames[0]);
219 out.extend_from_slice(frames[1]);
220 }
221 FrameCountCode::TwoUnequal => {
222 encode_length(frames[0].len(), &mut out)?;
224 encode_length(frames[1].len(), &mut out)?;
225 out.extend_from_slice(frames[0]);
226 out.extend_from_slice(frames[1]);
227 }
228 FrameCountCode::Arbitrary => {
229 if !vbr && frames.iter().any(|f| f.len() != frames[0].len()) {
230 return Err(Error::MalformedPacket);
231 }
232 let m = frames.len();
233 out.push(((m as u8) << 2) | (u8::from(padding > 0) << 1) | u8::from(vbr));
234 if padding > 0 {
235 write_padding_chain(padding, &mut out);
236 }
237 if vbr {
238 for f in &frames[..m - 1] {
241 encode_length(f.len(), &mut out)?;
242 }
243 encode_length(frames[m - 1].len(), &mut out)?;
244 } else {
245 encode_length(frames[0].len(), &mut out)?;
247 }
248 for f in frames {
249 out.extend_from_slice(f);
250 }
251 out.resize(out.len() + padding, 0);
252 }
253 }
254 Ok(out)
255}
256
257#[cfg(test)]
258mod tests {
259 use super::*;
260 use crate::frames::{decode_length, OpusPacket};
261 use crate::framing_self_delim::parse_self_delimited;
262 use crate::toc::{Bandwidth, Mode};
263
264 struct Lcg(u64);
266 impl Lcg {
267 fn next_u32(&mut self) -> u32 {
268 self.0 = self
269 .0
270 .wrapping_mul(6364136223846793005)
271 .wrapping_add(1442695040888963407);
272 (self.0 >> 32) as u32
273 }
274 fn below(&mut self, n: u32) -> u32 {
275 self.next_u32() % n
276 }
277 }
278
279 fn random_frame(rng: &mut Lcg, max_len: u32) -> Vec<u8> {
280 let len = rng.below(max_len + 1) as usize;
281 (0..len).map(|_| rng.next_u32() as u8).collect()
282 }
283
284 fn toc(code: FrameCountCode) -> u8 {
285 OpusTocByte::compose_byte(Mode::CeltOnly, Bandwidth::Fb, 100, false, code).unwrap()
287 }
288
289 #[test]
292 fn encode_length_roundtrips_all_values() {
293 for len in 0..=MAX_FRAME_BYTES {
294 let mut buf = Vec::new();
295 encode_length(len, &mut buf).unwrap();
296 let (decoded, consumed) = decode_length(&buf).unwrap();
297 assert_eq!((decoded, consumed), (len, buf.len()), "length {len}");
298 }
299 let mut buf = Vec::new();
300 assert!(encode_length(MAX_FRAME_BYTES + 1, &mut buf).is_err());
301 }
302
303 #[test]
306 fn compose_parse_roundtrip_all_codes() {
307 let mut rng = Lcg(0x0385_C0DE);
308 for round in 0..200 {
309 let (toc_byte, frames): (u8, Vec<Vec<u8>>) = match rng.below(4) {
310 0 => (toc(FrameCountCode::One), vec![random_frame(&mut rng, 1275)]),
311 1 => {
312 let f = random_frame(&mut rng, 1275);
313 (toc(FrameCountCode::TwoEqual), vec![f.clone(), f])
314 }
315 2 => (
316 toc(FrameCountCode::TwoUnequal),
317 vec![random_frame(&mut rng, 1275), random_frame(&mut rng, 1275)],
318 ),
319 _ => {
320 let m = 1 + rng.below(12) as usize;
321 (
322 toc(FrameCountCode::Arbitrary),
323 (0..m).map(|_| random_frame(&mut rng, 300)).collect(),
324 )
325 }
326 };
327 let slices: Vec<&[u8]> = frames.iter().map(|f| f.as_slice()).collect();
328 let packet = compose_packet(toc_byte, &slices).expect("compose");
329 let parsed = OpusPacket::parse(&packet).expect("parse");
330 assert_eq!(
331 parsed.toc,
332 OpusTocByte::from_byte(toc_byte),
333 "round {round}"
334 );
335 assert_eq!(parsed.frames(), &slices[..], "round {round}");
336 assert_eq!(parsed.padding, 0, "round {round}");
337 }
338 }
339
340 #[test]
344 fn compose_code3_vbr_and_padding_roundtrip() {
345 let mut rng = Lcg(0x0AD5_0385);
346 let toc_byte = toc(FrameCountCode::Arbitrary);
347 for &padding in &[0usize, 1, 42, 253, 254, 255, 300, 600] {
348 let m = 1 + rng.below(6) as usize;
349 let frames: Vec<Vec<u8>> = (0..m).map(|_| random_frame(&mut rng, 200)).collect();
350 let slices: Vec<&[u8]> = frames.iter().map(|f| f.as_slice()).collect();
351 for vbr in [false, true] {
352 if !vbr && !slices.iter().all(|f| f.len() == slices[0].len()) {
353 continue;
354 }
355 let packet =
356 compose_packet_code3(toc_byte, &slices, vbr, padding).expect("compose");
357 let parsed = OpusPacket::parse(&packet).expect("parse");
358 assert_eq!(parsed.frames(), &slices[..], "vbr={vbr} padding={padding}");
359 assert_eq!(parsed.padding, padding, "vbr={vbr} padding={padding}");
360 }
361 }
362 }
363
364 #[test]
368 fn compose_self_delimited_roundtrip_and_chain() {
369 let mut rng = Lcg(0x5E1F_DE11);
370 let mut chained = Vec::new();
371 let mut expected: Vec<(u8, Vec<Vec<u8>>)> = Vec::new();
372 for code_pick in 0..4u32 {
373 let (toc_byte, frames, vbr, padding): (u8, Vec<Vec<u8>>, bool, usize) = match code_pick
374 {
375 0 => (
376 toc(FrameCountCode::One),
377 vec![random_frame(&mut rng, 400)],
378 false,
379 0,
380 ),
381 1 => {
382 let f = random_frame(&mut rng, 400);
383 (toc(FrameCountCode::TwoEqual), vec![f.clone(), f], false, 0)
384 }
385 2 => (
386 toc(FrameCountCode::TwoUnequal),
387 vec![random_frame(&mut rng, 400), random_frame(&mut rng, 400)],
388 false,
389 0,
390 ),
391 _ => (
392 toc(FrameCountCode::Arbitrary),
393 (0..5).map(|_| random_frame(&mut rng, 300)).collect(),
394 true,
395 77,
396 ),
397 };
398 let slices: Vec<&[u8]> = frames.iter().map(|f| f.as_slice()).collect();
399 let packet =
400 compose_self_delimited(toc_byte, &slices, vbr, padding).expect("compose sd");
401 let parsed = parse_self_delimited(&packet).expect("parse sd");
403 assert_eq!(parsed.consumed, packet.len(), "code {code_pick}");
404 assert_eq!(parsed.packet.frames(), &slices[..], "code {code_pick}");
405 assert_eq!(parsed.packet.padding, padding, "code {code_pick}");
406 chained.extend_from_slice(&packet);
407 expected.push((toc_byte, frames));
408 }
409 let mut cursor = 0usize;
411 for (toc_byte, frames) in &expected {
412 let parsed = parse_self_delimited(&chained[cursor..]).expect("chained parse");
413 assert_eq!(parsed.packet.toc, OpusTocByte::from_byte(*toc_byte));
414 let slices: Vec<&[u8]> = frames.iter().map(|f| f.as_slice()).collect();
415 assert_eq!(parsed.packet.frames(), &slices[..]);
416 cursor += parsed.consumed;
417 }
418 assert_eq!(cursor, chained.len());
419 }
420
421 #[test]
426 fn compose_rejects_shape_violations() {
427 let f10 = vec![0u8; 10];
428 let f11 = vec![0u8; 11];
429 let big = vec![0u8; MAX_FRAME_BYTES + 1];
430 assert!(compose_packet(toc(FrameCountCode::One), &[&f10, &f10]).is_err());
432 assert!(compose_packet(toc(FrameCountCode::TwoEqual), &[&f10]).is_err());
433 assert!(compose_packet(toc(FrameCountCode::TwoUnequal), &[&f10]).is_err());
434 assert!(compose_packet(toc(FrameCountCode::Arbitrary), &[]).is_err());
435 assert!(compose_packet(toc(FrameCountCode::TwoEqual), &[&f10, &f11]).is_err());
437 assert!(compose_packet(toc(FrameCountCode::One), &[&big]).is_err());
439 let toc_25 = OpusTocByte::compose_byte(
443 Mode::CeltOnly,
444 Bandwidth::Fb,
445 25,
446 false,
447 FrameCountCode::Arbitrary,
448 )
449 .unwrap();
450 let many: Vec<&[u8]> = (0..49).map(|_| f10.as_slice()).collect();
451 assert!(compose_packet(toc_25, &many).is_err());
452 assert!(compose_packet(toc_25, &many[..48]).is_ok());
453 let toc_60 = OpusTocByte::compose_byte(
455 Mode::SilkOnly,
456 Bandwidth::Nb,
457 600,
458 false,
459 FrameCountCode::Arbitrary,
460 )
461 .unwrap();
462 assert!(compose_packet(toc_60, &[&f10, &f10, &f10]).is_err());
463 assert!(compose_packet(toc_60, &[&f10, &f10]).is_ok());
464 assert!(
466 compose_packet_code3(toc(FrameCountCode::Arbitrary), &[&f10, &f11], false, 0).is_err()
467 );
468 assert!(compose_packet_code3(toc(FrameCountCode::One), &[&f10], false, 0).is_err());
470 assert!(compose_self_delimited(toc(FrameCountCode::One), &[&f10], false, 4).is_err());
472 assert!(compose_self_delimited(toc(FrameCountCode::One), &[&f10], true, 0).is_err());
473 assert!(
474 compose_self_delimited(toc(FrameCountCode::Arbitrary), &[&f10, &f11], false, 0)
475 .is_err()
476 );
477 }
478
479 struct SilkScript {
481 frame_type: u8,
482 gains: Vec<crate::silk_gains::GainSymbol>,
483 i2: Vec<i8>,
484 lsb: Vec<u8>,
485 e_raw: Vec<i32>,
486 }
487
488 impl SilkScript {
489 fn new(frame_type: u8, pulses: i32) -> Self {
493 use crate::silk_excitation::{shell_block_count, SilkFrameSize, SHELL_BLOCK_SAMPLES};
494 use crate::silk_gains::GainSymbol;
495 assert!(frame_type < 4, "voiced scripts would need LTP symbols");
496 let blocks = shell_block_count(Bandwidth::Nb, SilkFrameSize::TwentyMs).unwrap();
497 let mut e_raw = vec![0i32; blocks * SHELL_BLOCK_SAMPLES];
498 for b in 0..blocks {
499 e_raw[b * SHELL_BLOCK_SAMPLES] = pulses;
500 }
501 SilkScript {
502 frame_type,
503 gains: vec![
504 GainSymbol::Independent(40),
505 GainSymbol::Delta(10),
506 GainSymbol::Delta(15),
507 GainSymbol::Delta(20),
508 ],
509 i2: vec![0i8; 10],
510 lsb: vec![0u8; blocks],
511 e_raw,
512 }
513 }
514
515 fn symbols(&self) -> crate::silk_decode::SilkFrameSymbols<'_> {
516 crate::silk_decode::SilkFrameSymbols {
517 header: crate::silk_frame::SilkHeaderSymbols {
518 stereo: None,
519 mid_only_flag: None,
520 frame_type: self.frame_type,
521 },
522 gains: &self.gains,
523 lsf_stage1: 5,
524 lsf_stage2_i2: &self.i2,
525 lsf_interp_w_q2: Some(4),
526 ltp: None,
527 lcg_seed: 1,
528 excitation: crate::silk_excitation::ExcitationSymbols {
529 rate_level: 3,
530 lsb_counts: &self.lsb,
531 e_raw: &self.e_raw,
532 },
533 }
534 }
535 }
536
537 #[test]
542 fn composed_multiframe_silk_packets_decode_end_to_end() {
543 use crate::decoder::{FrameDecodeStatus, OpusDecoder};
544 use crate::silk_packet_encode::encode_silk_only_packet_mono;
545
546 let script1 = SilkScript::new(0, 1);
551 let script2 = SilkScript::new(2, 7);
552 let (p1, _) = encode_silk_only_packet_mono(Bandwidth::Nb, 200, &[script1.symbols()])
553 .expect("encode 1");
554 let (p2, _) = encode_silk_only_packet_mono(Bandwidth::Nb, 200, &[script2.symbols()])
555 .expect("encode 2");
556 let body1 = &p1[1..];
557 let body2 = &p2[1..];
558
559 let toc_code2 = OpusTocByte::compose_byte(
560 Mode::SilkOnly,
561 Bandwidth::Nb,
562 200,
563 false,
564 FrameCountCode::TwoUnequal,
565 )
566 .unwrap();
567 let toc_code3 = OpusTocByte::compose_byte(
568 Mode::SilkOnly,
569 Bandwidth::Nb,
570 200,
571 false,
572 FrameCountCode::Arbitrary,
573 )
574 .unwrap();
575 let toc_code1 = OpusTocByte::compose_byte(
576 Mode::SilkOnly,
577 Bandwidth::Nb,
578 200,
579 false,
580 FrameCountCode::TwoEqual,
581 )
582 .unwrap();
583
584 let mut candidates: Vec<Vec<u8>> = vec![
585 compose_packet(toc_code2, &[body1, body2]).unwrap(),
586 compose_packet_code3(toc_code3, &[body1, body2], true, 9).unwrap(),
587 ];
588 candidates.push(compose_packet(toc_code1, &[body1, body1]).unwrap());
590
591 for (idx, packet) in candidates.iter().enumerate() {
592 let mut dec = OpusDecoder::new();
593 let out = dec.decode_packet(packet).expect("decode");
594 assert_eq!(out.frame_outcomes.len(), 2, "candidate {idx}");
595 for fo in &out.frame_outcomes {
596 assert_eq!(
597 fo.status,
598 FrameDecodeStatus::SilkParamsDecoded,
599 "candidate {idx}"
600 );
601 }
602 assert_eq!(out.samples_per_channel(), 2 * 960, "candidate {idx}");
603 }
604 }
605}