media_core/audio/
channel_layout.rs

1use std::{mem, num::NonZeroU8, sync::LazyLock};
2
3use bitflags::bitflags;
4use smallvec::SmallVec;
5use strum::EnumCount;
6
7use crate::{error::Error, invalid_param_error, Result};
8
9#[derive(Clone, Copy, Debug, EnumCount, Eq, PartialEq)]
10#[repr(u8)]
11pub enum Channel {
12    FrontLeft,
13    FrontRight,
14    FrontCenter,
15    LowFrequency,
16    BackLeft,
17    BackRight,
18    FrontLeftOfCenter,
19    FrontRightOfCenter,
20    BackCenter,
21    SideLeft,
22    SideRight,
23    TopCenter,
24    TopFrontLeft,
25    TopFrontCenter,
26    TopFrontRight,
27    TopBackLeft,
28    TopBackCenter,
29    TopBackRight,
30}
31
32impl From<Channel> for u32 {
33    fn from(chn: Channel) -> Self {
34        chn as u32
35    }
36}
37
38impl From<Channel> for ChannelMasks {
39    fn from(chn: Channel) -> Self {
40        ChannelMasks::from_bits_truncate(1u32 << chn as u32)
41    }
42}
43
44impl TryFrom<u8> for Channel {
45    type Error = Error;
46
47    fn try_from(value: u8) -> Result<Self> {
48        if value < Channel::COUNT as u8 {
49            Ok(unsafe { mem::transmute::<u8, Channel>(value) })
50        } else {
51            Err(invalid_param_error!(value))
52        }
53    }
54}
55
56macro_rules! channel_masks {
57    ($($mask:ident)|+) => {
58        0 $(| ChannelMasks::$mask.bits())+
59    };
60    ($mask:ident) => {
61        ChannelMasks::$mask.bits()
62    };
63}
64
65bitflags! {
66    #[repr(transparent)]
67    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
68    pub struct ChannelMasks: u32 {
69        const FrontLeft             = 1u32 << Channel::FrontLeft as u32;
70        const FrontRight            = 1u32 << Channel::FrontRight as u32;
71        const FrontCenter           = 1u32 << Channel::FrontCenter as u32;
72        const LowFrequency          = 1u32 << Channel::LowFrequency as u32;
73        const BackLeft              = 1u32 << Channel::BackLeft as u32;
74        const BackRight             = 1u32 << Channel::BackRight as u32;
75        const FrontLeftOfCenter     = 1u32 << Channel::FrontLeftOfCenter as u32;
76        const FrontRightOfCenter    = 1u32 << Channel::FrontRightOfCenter as u32;
77        const BackCenter            = 1u32 << Channel::BackCenter as u32;
78        const SideLeft              = 1u32 << Channel::SideLeft as u32;
79        const SideRight             = 1u32 << Channel::SideRight as u32;
80        const TopCenter             = 1u32 << Channel::TopCenter as u32;
81        const TopFrontLeft          = 1u32 << Channel::TopFrontLeft as u32;
82        const TopFrontCenter        = 1u32 << Channel::TopFrontCenter as u32;
83        const TopFrontRight         = 1u32 << Channel::TopFrontRight as u32;
84        const TopBackLeft           = 1u32 << Channel::TopBackLeft as u32;
85        const TopBackCenter         = 1u32 << Channel::TopBackCenter as u32;
86        const TopBackRight          = 1u32 << Channel::TopBackRight as u32;
87
88        const Mono                      = channel_masks!(FrontCenter);
89        const Stereo                    = channel_masks!(FrontLeft | FrontRight);
90        const Surround_2_1              = channel_masks!(Stereo | LowFrequency);
91        const Surround                  = channel_masks!(Stereo | FrontCenter);
92        const Surround_3_0              = channel_masks!(Surround);
93        const Surround_3_0_FRONT        = channel_masks!(Surround);
94        const Surround_3_0_BACK         = channel_masks!(Stereo | BackCenter);
95        const Surround_3_1              = channel_masks!(Surround_3_0 | LowFrequency);
96        const Surround_3_1_2            = channel_masks!(Surround_3_1 | TopFrontLeft | TopFrontRight);
97        const Surround_4_0              = channel_masks!(Surround_3_0 | BackCenter);
98        const Surround_4_1              = channel_masks!(Surround_4_0 | LowFrequency);
99        const Surround_2_2              = channel_masks!(Stereo | SideLeft | SideRight);
100        const Quad                      = channel_masks!(Stereo | BackLeft | BackRight);
101        const Surround_5_0              = channel_masks!(Surround_3_0 | SideLeft | SideRight);
102        const Surround_5_1              = channel_masks!(Surround_5_0 | LowFrequency);
103        const Surround_5_0_BACK         = channel_masks!(Surround_3_0 | BackLeft | BackRight);
104        const Surround_5_1_BACK         = channel_masks!(Surround_5_0_BACK | LowFrequency);
105        const Surround_6_0              = channel_masks!(Surround_5_0 | BackCenter);
106        const Hexagonal                 = channel_masks!(Surround_5_0_BACK | BackCenter);
107        const Surround_6_1              = channel_masks!(Surround_6_0 | LowFrequency);
108        const Surround_6_0_FRONT        = channel_masks!(Surround_2_2 | FrontLeftOfCenter | FrontRightOfCenter);
109        const Surround_6_1_FRONT        = channel_masks!(Surround_6_0_FRONT | LowFrequency);
110        const Surround_6_1_BACK         = channel_masks!(Surround_5_1_BACK | BackCenter);
111        const Surround_7_0              = channel_masks!(Surround_5_0 | BackLeft | BackRight);
112        const Surround_7_1              = channel_masks!(Surround_7_0 | LowFrequency);
113        const Surround_7_0_FRONT        = channel_masks!(Surround_5_0 | FrontLeftOfCenter | FrontRightOfCenter);
114        const Surround_7_1_WIDE         = channel_masks!(Surround_5_1 | FrontLeftOfCenter | FrontRightOfCenter);
115        const Surround_7_1_WIDE_BACK    = channel_masks!(Surround_5_1_BACK | FrontLeftOfCenter | FrontRightOfCenter);
116        const Surround_5_1_2            = channel_masks!(Surround_5_1 | TopFrontLeft | TopFrontRight);
117        const Surround_5_1_2_BACK       = channel_masks!(Surround_5_1_BACK | TopFrontLeft | TopFrontRight);
118        const Octagonal                 = channel_masks!(Surround_5_0 | BackLeft | BackCenter | BackRight);
119        const Cube                      = channel_masks!(Quad | TopFrontLeft | TopFrontRight | TopBackLeft | TopBackRight);
120        const Surround_5_1_4_BACK       = channel_masks!(Surround_5_1_2 | TopBackLeft | TopBackRight);
121        const Surround_7_1_2            = channel_masks!(Surround_7_1 | TopFrontLeft | TopFrontRight);
122        const Surround_7_1_4_BACK       = channel_masks!(Surround_7_1_2 | TopBackLeft | TopBackRight);
123        const Surround_9_1_4_BACK       = channel_masks!(Surround_7_1_4_BACK | FrontLeftOfCenter | FrontRightOfCenter);
124    }
125}
126
127#[derive(Clone, Copy, Debug, Eq, PartialEq)]
128pub enum ChannelOrder {
129    Unspecified,
130    Native,
131    Custom,
132    MAX,
133}
134
135struct ChannelLayoutMap {
136    map: Vec<Option<Vec<(&'static str, ChannelLayout)>>>,
137}
138
139macro_rules! define_channel_layouts {
140    ( $(
141        $const_name:ident: [$name:literal, $mask:ident($channel_count:literal)]
142        ),* $(,)?
143    ) => {
144        impl ChannelLayout {
145            $(
146                pub const $const_name: Self = Self {
147                    order: ChannelOrder::Native,
148                    channels: NonZeroU8::new($channel_count).unwrap(),
149                    spec: ChannelLayoutSpec::Mask(ChannelMasks::$mask),
150                };
151            )*
152        }
153
154        static CHANNEL_LAYOUT_MAP: LazyLock<ChannelLayoutMap> = LazyLock::new(|| {
155            let mut map = vec![None; DEFAULT_MAX_CHANNELS];
156            $(
157                let entry = map[($channel_count - 1) as usize].get_or_insert_with(Vec::new);
158                entry.push((
159                    $name,
160                    ChannelLayout::$const_name,
161                ));
162            )*
163            ChannelLayoutMap { map }
164        });
165    };
166}
167
168define_channel_layouts! {
169    MONO: ["mono", Mono(1)],
170    STEREO: ["stereo", Stereo(2)],
171    SURROUND_2_1: ["2.1", Surround_2_1(3)],
172    SURROUND_3_0: ["3.0", Surround_3_0(3)],
173    SURROUND_3_0_BACK: ["3.0(back)", Surround_3_0_BACK(3)],
174    SURROUND_4_0: ["4.0", Surround_4_0(4)],
175    QUAD: ["quad", Quad(4)],
176    SURROUND_2_2: ["quad(side)", Surround_2_2(4)],
177    SURROUND_3_1: ["3.1", Surround_3_1(4)],
178    SURROUND_5_0_BACK: ["5.0", Surround_5_0_BACK(5)],
179    SURROUND_5_0: ["5.0(side)", Surround_5_0(5)],
180    SURROUND_4_1: ["4.1", Surround_4_1(5)],
181    SURROUND_5_1_BACK: ["5.1", Surround_5_1_BACK(6)],
182    SURROUND_5_1: ["5.1(side)", Surround_5_1(6)],
183    SURROUND_6_0: ["6.0", Surround_6_0(6)],
184    SURROUND_6_0_FRONT: ["6.0(front)", Surround_6_0_FRONT(6)],
185    SURROUND_3_1_2: ["3.1.2", Surround_3_1_2(6)],
186    HEXAGONAL: ["hexagonal", Hexagonal(6)],
187    SURROUND_6_1: ["6.1", Surround_6_1(7)],
188    SURROUND_6_1_BACK: ["6.1(back)", Surround_6_1_BACK(7)],
189    SURROUND_6_1_FRONT: ["6.1(front)", Surround_6_1_FRONT(7)],
190    SURROUND_7_0: ["7.0", Surround_7_0(7)],
191    SURROUND_7_0_FRONT: ["7.0(front)", Surround_7_0_FRONT(7)],
192    SURROUND_7_1: ["7.1", Surround_7_1(8)],
193    SURROUND_7_1_WIDE_BACK: ["7.1(wide)", Surround_7_1_WIDE_BACK(8)],
194    SURROUND_7_1_WIDE: ["7.1(wide-side)", Surround_7_1_WIDE(8)],
195    SURROUND_5_1_2: ["5.1.2", Surround_5_1_2(8)],
196    SURROUND_5_1_2_BACK: ["5.1.2(back)", Surround_5_1_2_BACK(8)],
197    OCTAGONAL: ["octagonal", Octagonal(8)],
198    CUBE: ["cube", Cube(8)],
199    SURROUND_5_1_4_BACK: ["5.1.4", Surround_5_1_4_BACK(10)],
200    SURROUND_7_1_2: ["7.1.2", Surround_7_1_2(10)],
201    SURROUND_7_1_4_BACK: ["7.1.4", Surround_7_1_4_BACK(12)],
202    SURROUND_9_1_4_BACK: ["9.1.4", Surround_9_1_4_BACK(14)],
203}
204
205const DEFAULT_MAX_CHANNELS: usize = 16;
206
207#[derive(Clone, Debug, Eq, PartialEq)]
208pub enum ChannelLayoutSpec {
209    Mask(ChannelMasks),
210    Map(Option<SmallVec<[Channel; DEFAULT_MAX_CHANNELS]>>),
211}
212
213#[derive(Clone, Debug, Eq, PartialEq)]
214pub struct ChannelLayout {
215    pub order: ChannelOrder,
216    pub channels: NonZeroU8,
217    pub spec: ChannelLayoutSpec,
218}
219
220impl Default for ChannelLayout {
221    fn default() -> Self {
222        Self {
223            order: ChannelOrder::Unspecified,
224            channels: NonZeroU8::new(1).unwrap(),
225            spec: ChannelLayoutSpec::Mask(ChannelMasks::from_bits_truncate(0)),
226        }
227    }
228}
229
230impl TryFrom<ChannelMasks> for ChannelLayout {
231    type Error = Error;
232
233    fn try_from(mask: ChannelMasks) -> std::result::Result<Self, Self::Error> {
234        Self::from_mask(mask)
235    }
236}
237
238impl TryFrom<u8> for ChannelLayout {
239    type Error = Error;
240
241    fn try_from(channels: u8) -> std::result::Result<Self, Self::Error> {
242        Self::default_from_channels(channels)
243    }
244}
245
246impl ChannelLayout {
247    pub fn from_mask(mask: ChannelMasks) -> Result<Self> {
248        let channels = mask.bits().count_ones() as u8;
249        let spec = ChannelLayoutSpec::Mask(mask);
250
251        NonZeroU8::new(channels)
252            .map(|channels| Self {
253                order: ChannelOrder::Native,
254                channels,
255                spec,
256            })
257            .ok_or_else(|| invalid_param_error!("channel mask is empty"))
258    }
259
260    pub fn default_from_channels(channels: u8) -> Result<Self> {
261        let channels = NonZeroU8::new(channels).ok_or_else(|| invalid_param_error!(channels))?;
262
263        Ok(CHANNEL_LAYOUT_MAP
264            .map
265            .get((channels.get() - 1) as usize)
266            .and_then(|opt| opt.as_ref()?.first())
267            .map(|(_, layout)| layout.clone())
268            .unwrap_or_else(|| Self {
269                order: ChannelOrder::Unspecified,
270                channels,
271                spec: ChannelLayoutSpec::Mask(ChannelMasks::from_bits_truncate(0)),
272            }))
273    }
274
275    pub fn get_channel_from_index(&self, index: usize) -> Option<Channel> {
276        if index >= self.channels.get() as usize {
277            return None;
278        }
279
280        match (&self.order, &self.spec) {
281            (ChannelOrder::Native, ChannelLayoutSpec::Mask(mask)) => {
282                let mut remaining = index;
283                for chn in 0..Channel::COUNT {
284                    let channel = Channel::try_from(chn as u8).ok()?;
285                    if mask.contains(ChannelMasks::from(channel)) {
286                        if remaining == 0 {
287                            return Some(channel);
288                        }
289                        remaining -= 1;
290                    }
291                }
292                None
293            }
294            (ChannelOrder::Custom, ChannelLayoutSpec::Map(Some(map))) => map.get(index).copied(),
295            _ => None,
296        }
297    }
298
299    pub fn get_index_from_channel(&self, channel: Channel) -> Option<usize> {
300        match (&self.order, &self.spec) {
301            (ChannelOrder::Native, ChannelLayoutSpec::Mask(mask)) => {
302                let channel_mask = ChannelMasks::from(channel);
303                mask.contains(channel_mask).then(|| {
304                    let lower_bits = channel_mask.bits() - 1;
305                    (mask.bits() & lower_bits).count_ones() as usize
306                })
307            }
308            (ChannelOrder::Custom, ChannelLayoutSpec::Map(Some(map))) => map.iter().position(|&c| c == channel),
309            _ => None,
310        }
311    }
312
313    pub fn is_valid(&self) -> bool {
314        if self.channels.get() == 0 {
315            return false;
316        }
317
318        match (&self.order, &self.spec) {
319            (ChannelOrder::Unspecified, _) => true,
320            (ChannelOrder::Native, ChannelLayoutSpec::Mask(mask)) => mask.bits().count_ones() as u8 == self.channels.get(),
321            (ChannelOrder::Custom, ChannelLayoutSpec::Map(Some(map))) => map.len() == self.channels.get() as usize,
322            _ => false,
323        }
324    }
325
326    pub fn subset(&self, mask: ChannelMasks) -> ChannelMasks {
327        match (&self.order, &self.spec) {
328            (ChannelOrder::Native, ChannelLayoutSpec::Mask(channel_mask)) => *channel_mask & mask,
329            (ChannelOrder::Custom, ChannelLayoutSpec::Map(Some(map))) => {
330                let mut subset_mask = ChannelMasks::empty();
331                for &channel in map.iter() {
332                    let channel_mask = ChannelMasks::from(channel);
333                    if mask.contains(channel_mask) {
334                        subset_mask |= channel_mask;
335                    }
336                }
337                subset_mask
338            }
339            _ => ChannelMasks::from_bits_truncate(0),
340        }
341    }
342}