opusic_c/multistream/
mod.rs

1//!The multistream API allows individual Opus streams to be combined into a single packet, enabling support for up to 255 channels
2//!
3//!Multistream Opus streams can contain up to 255 elementary Opus streams.
4//!These may be either "uncoupled" or "coupled", indicating that the decoder is configured to decode them to either 1 or 2 channels, respectively.
5//!The streams are ordered so that all coupled streams appear at the beginning.
6//!
7//!The output channels specified by the encoder should use the [Vorbis channel ordering](https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9).
8//!A decoder may wish to apply an additional permutation to the mapping the encoder used to achieve a different output channel order (e.g. for outputting in WAV order).
9//!
10//!Each multistream packet contains an Opus packet for each stream, and all of the Opus packets in
11//!a single multistream packet must have the same duration. Therefore the duration of a multistream
12//!packet can be extracted from the TOC sequence of the first stream, which is located at the
13//!beginning of the packet.
14
15mod encoder;
16pub use encoder::Encoder;
17mod decoder;
18pub use decoder::Decoder;
19
20///Multistream configuration
21///
22///## Parameters
23///
24///`CH` - Number of channels to use. Up to 255.
25pub struct Config<const CH: usize> {
26    streams: u8,
27    coupled_streams: u8,
28    mapping: [u8; CH],
29}
30
31impl<const CH: usize> Config<CH> {
32    const CHANNELS: u8 = match CH {
33        0 => panic!("Unsupported number of channels. Allowed range: 0..=255"),
34        _ => CH as _,
35    };
36
37    ///Creates new config, verifying that specified number of channels is valid and do not exceed `CH`
38    ///
39    ///Following constraints are imposed:
40    ///
41    ///- `streams` cannot be 0 or exceed `CH`
42    ///- `coupled_streams` cannot exceed `streams`
43    ///- Sum of both cannot exceed `CH`
44    pub const fn try_new(streams: u8, coupled_streams: u8, mapping: [u8; CH]) -> Option<Self> {
45        if streams == 0 || coupled_streams > streams {
46            return None;
47        }
48
49        let mut idx = 0;
50        while idx < CH {
51            if mapping[idx] != 255 && (mapping[idx] as usize) >= CH {
52                return None;
53            }
54            idx = idx.saturating_add(1);
55        }
56
57        match streams.checked_add(coupled_streams) {
58            Some(total) => if total == 0 || total > Self::CHANNELS {
59                None
60            } else {
61                Some(Self {
62                    streams,
63                    coupled_streams,
64                    mapping,
65                })
66            }
67            None => None,
68        }
69    }
70
71    ///Creates new config, verifying that specified number of channels is valid and do not exceed `CH`
72    ///
73    ///Following constraints are imposed and will cause panic:
74    ///
75    ///- `streams` cannot be 0 or exceed `CH`
76    ///- `coupled_streams` cannot exceed `streams`
77    ///- Sum of both cannot exceed `CH`
78    pub const fn new(streams: u8, coupled_streams: u8, mapping: [u8; CH]) -> Self {
79        assert!(streams != 0);
80        assert!(coupled_streams <= streams);
81
82        let mut idx = 0;
83        while idx < CH {
84            if mapping[idx] != 255 {
85                assert!((mapping[idx] as usize) < CH, "Non 255 mapping values must be in range 0..CH");
86            }
87            idx = idx.saturating_add(1);
88        }
89
90        match streams.checked_add(coupled_streams) {
91            Some(total_streams) => {
92                assert!(total_streams != 0);
93                assert!(total_streams <= Self::CHANNELS);
94
95                Self {
96                    streams,
97                    coupled_streams,
98                    mapping
99                }
100            },
101            None => panic!("sum(streams, coupled_streams) cannot exceed 255"),
102        }
103    }
104
105    #[inline(always)]
106    ///Accesses mapping
107    pub fn mapping(&self) -> &[u8; CH] {
108        &self.mapping
109    }
110
111    #[inline(always)]
112    ///Accesses mapping
113    pub fn mapping_mut(&mut self) -> &mut [u8; CH] {
114        &mut self.mapping
115    }
116}