gstreamer_audio/
audio_channel_position.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{mem, slice};
4
5use crate::ffi;
6use glib::{prelude::*, translate::*, value::FromValue, Type};
7
8/// Audio channel positions.
9///
10/// These are the channels defined in SMPTE 2036-2-2008
11/// Table 1 for 22.2 audio systems with the Surround and Wide channels from
12/// DTS Coherent Acoustics (v.1.3.1) and 10.2 and 7.1 layouts. In the caps the
13/// actual channel layout is expressed with a channel count and a channel mask,
14/// which describes the existing channels. The positions in the bit mask correspond
15/// to the enum values.
16/// For negotiation it is allowed to have more bits set in the channel mask than
17/// the number of channels to specify the allowed channel positions but this is
18/// not allowed in negotiated caps. It is not allowed in any situation other
19/// than the one mentioned below to have less bits set in the channel mask than
20/// the number of channels.
21///
22/// [`Mono`][Self::Mono] can only be used with a single mono channel that
23/// has no direction information and would be mixed into all directional channels.
24/// This is expressed in caps by having a single channel and no channel mask.
25///
26/// [`None`][Self::None] can only be used if all channels have this position.
27/// This is expressed in caps by having a channel mask with no bits set.
28///
29/// As another special case it is allowed to have two channels without a channel mask.
30/// This implicitly means that this is a stereo stream with a front left and front right
31/// channel.
32#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
33#[non_exhaustive]
34#[doc(alias = "GstAudioChannelPosition")]
35#[repr(i32)]
36pub enum AudioChannelPosition {
37    /// used for position-less channels, e.g.
38    ///  from a sound card that records 1024 channels; mutually exclusive with
39    ///  any other channel position
40    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_NONE")]
41    None = ffi::GST_AUDIO_CHANNEL_POSITION_NONE,
42    /// Mono without direction;
43    ///  can only be used with 1 channel
44    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_MONO")]
45    Mono,
46    /// invalid position
47    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_INVALID")]
48    Invalid,
49    /// Front left
50    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT")]
51    FrontLeft,
52    /// Front right
53    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT")]
54    FrontRight,
55    /// Front center
56    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER")]
57    FrontCenter,
58    /// Low-frequency effects 1 (subwoofer)
59    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_LFE1")]
60    Lfe1,
61    /// Rear left
62    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_REAR_LEFT")]
63    RearLeft,
64    /// Rear right
65    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT")]
66    RearRight,
67    /// Front left of center
68    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER")]
69    FrontLeftOfCenter,
70    /// Front right of center
71    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER")]
72    FrontRightOfCenter,
73    /// Rear center
74    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_REAR_CENTER")]
75    RearCenter,
76    /// Low-frequency effects 2 (subwoofer)
77    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_LFE2")]
78    Lfe2,
79    /// Side left
80    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT")]
81    SideLeft,
82    /// Side right
83    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT")]
84    SideRight,
85    /// Top front left
86    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT")]
87    TopFrontLeft,
88    /// Top front right
89    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT")]
90    TopFrontRight,
91    /// Top front center
92    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER")]
93    TopFrontCenter,
94    /// Top center
95    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_CENTER")]
96    TopCenter,
97    /// Top rear left
98    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT")]
99    TopRearLeft,
100    /// Top rear right
101    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT")]
102    TopRearRight,
103    /// Top side right
104    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_LEFT")]
105    TopSideLeft,
106    /// Top rear right
107    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_RIGHT")]
108    TopSideRight,
109    /// Top rear center
110    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER")]
111    TopRearCenter,
112    /// Bottom front center
113    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_CENTER")]
114    BottomFrontCenter,
115    /// Bottom front left
116    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_LEFT")]
117    BottomFrontLeft,
118    /// Bottom front right
119    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_RIGHT")]
120    BottomFrontRight,
121    /// Wide left (between front left and side left)
122    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_WIDE_LEFT")]
123    WideLeft,
124    /// Wide right (between front right and side right)
125    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_WIDE_RIGHT")]
126    WideRight,
127    /// Surround left (between rear left and side left)
128    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SURROUND_LEFT")]
129    SurroundLeft,
130    /// Surround right (between rear right and side right)
131    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SURROUND_RIGHT")]
132    SurroundRight = ffi::GST_AUDIO_CHANNEL_POSITION_SURROUND_RIGHT,
133    /// Top surround left (between rear left and side left).
134    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_SURROUND_LEFT")]
135    TopSurroundLeft = 28,
136    /// Top surround right (between rear right and side right).
137    #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_SURROUND_RIGHT")]
138    TopSurroundRight = 29,
139    #[doc(hidden)]
140    UnknownChannel30 = 30,
141    #[doc(hidden)]
142    UnknownChannel31 = 31,
143    #[doc(hidden)]
144    UnknownChannel32 = 32,
145    #[doc(hidden)]
146    UnknownChannel33 = 33,
147    #[doc(hidden)]
148    UnknownChannel34 = 34,
149    #[doc(hidden)]
150    UnknownChannel35 = 35,
151    #[doc(hidden)]
152    UnknownChannel36 = 36,
153    #[doc(hidden)]
154    UnknownChannel37 = 37,
155    #[doc(hidden)]
156    UnknownChannel38 = 38,
157    #[doc(hidden)]
158    UnknownChannel39 = 39,
159    #[doc(hidden)]
160    UnknownChannel40 = 40,
161    #[doc(hidden)]
162    UnknownChannel41 = 41,
163    #[doc(hidden)]
164    UnknownChannel42 = 42,
165    #[doc(hidden)]
166    UnknownChannel43 = 43,
167    #[doc(hidden)]
168    UnknownChannel44 = 44,
169    #[doc(hidden)]
170    UnknownChannel45 = 45,
171    #[doc(hidden)]
172    UnknownChannel46 = 46,
173    #[doc(hidden)]
174    UnknownChannel47 = 47,
175    #[doc(hidden)]
176    UnknownChannel48 = 48,
177    #[doc(hidden)]
178    UnknownChannel49 = 49,
179    #[doc(hidden)]
180    UnknownChannel50 = 50,
181    #[doc(hidden)]
182    UnknownChannel51 = 51,
183    #[doc(hidden)]
184    UnknownChannel52 = 52,
185    #[doc(hidden)]
186    UnknownChannel53 = 53,
187    #[doc(hidden)]
188    UnknownChannel54 = 54,
189    #[doc(hidden)]
190    UnknownChannel55 = 55,
191    #[doc(hidden)]
192    UnknownChannel56 = 56,
193    #[doc(hidden)]
194    UnknownChannel57 = 57,
195    #[doc(hidden)]
196    UnknownChannel58 = 58,
197    #[doc(hidden)]
198    UnknownChannel59 = 59,
199    #[doc(hidden)]
200    UnknownChannel60 = 60,
201    #[doc(hidden)]
202    UnknownChannel61 = 61,
203    #[doc(hidden)]
204    UnknownChannel62 = 62,
205    #[doc(hidden)]
206    UnknownChannel63 = 63,
207    #[doc(hidden)]
208    UnknownChannel64 = 64,
209}
210
211unsafe impl TransparentType for AudioChannelPosition {
212    type GlibType = ffi::GstAudioChannelPosition;
213}
214
215#[doc(hidden)]
216impl IntoGlib for AudioChannelPosition {
217    type GlibType = ffi::GstAudioChannelPosition;
218
219    #[inline]
220    fn into_glib(self) -> ffi::GstAudioChannelPosition {
221        self as ffi::GstAudioChannelPosition
222    }
223}
224
225#[doc(hidden)]
226impl FromGlib<ffi::GstAudioChannelPosition> for AudioChannelPosition {
227    #[inline]
228    unsafe fn from_glib(value: ffi::GstAudioChannelPosition) -> Self {
229        skip_assert_initialized!();
230        debug_assert!((ffi::GST_AUDIO_CHANNEL_POSITION_NONE..=64).contains(&value));
231        mem::transmute::<ffi::GstAudioChannelPosition, AudioChannelPosition>(value)
232    }
233}
234
235impl StaticType for AudioChannelPosition {
236    #[inline]
237    fn static_type() -> Type {
238        unsafe { from_glib(ffi::gst_audio_channel_position_get_type()) }
239    }
240}
241
242impl glib::value::ValueType for AudioChannelPosition {
243    type Type = Self;
244}
245
246unsafe impl<'a> FromValue<'a> for AudioChannelPosition {
247    type Checker = glib::value::GenericValueTypeChecker<Self>;
248
249    #[inline]
250    unsafe fn from_value(value: &'a glib::Value) -> Self {
251        skip_assert_initialized!();
252        from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0))
253    }
254}
255
256impl ToValue for AudioChannelPosition {
257    #[inline]
258    fn to_value(&self) -> glib::Value {
259        let mut value = glib::Value::for_value_type::<Self>();
260        unsafe {
261            glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib());
262        }
263        value
264    }
265
266    #[inline]
267    fn value_type(&self) -> glib::Type {
268        Self::static_type()
269    }
270}
271
272impl From<AudioChannelPosition> for glib::Value {
273    #[inline]
274    fn from(v: AudioChannelPosition) -> Self {
275        skip_assert_initialized!();
276        ToValue::to_value(&v)
277    }
278}
279
280impl AudioChannelPosition {
281    pub fn to_mask(self) -> u64 {
282        let pos = self.into_glib();
283        if pos < 0 {
284            return 0;
285        }
286
287        1 << (pos as u32)
288    }
289
290    #[doc(alias = "gst_audio_channel_positions_to_mask")]
291    pub fn positions_to_mask(
292        positions: &[Self],
293        force_order: bool,
294    ) -> Result<u64, glib::error::BoolError> {
295        assert_initialized_main_thread!();
296
297        let len = positions.len();
298        if len > 64 {
299            return Err(glib::bool_error!("Invalid number of channels"));
300        }
301
302        unsafe {
303            let mut mask = mem::MaybeUninit::uninit();
304            let valid: bool = from_glib(ffi::gst_audio_channel_positions_to_mask(
305                positions.as_ptr() as *mut _,
306                len as i32,
307                force_order.into_glib(),
308                mask.as_mut_ptr(),
309            ));
310            if valid {
311                Ok(mask.assume_init())
312            } else {
313                Err(glib::bool_error!(
314                    "Couldn't convert channel positions to mask"
315                ))
316            }
317        }
318    }
319
320    #[doc(alias = "gst_audio_channel_positions_from_mask")]
321    pub fn positions_from_mask(mask: u64, positions: &mut [Self]) -> Result<(), glib::BoolError> {
322        assert_initialized_main_thread!();
323
324        if positions.len() > 64 {
325            return Err(glib::bool_error!("Invalid number of channels"));
326        }
327
328        let len = positions.len();
329        let valid: bool = unsafe {
330            from_glib(ffi::gst_audio_channel_positions_from_mask(
331                len as i32,
332                mask,
333                positions.as_mut_ptr() as *mut _,
334            ))
335        };
336
337        if valid {
338            Ok(())
339        } else {
340            Err(glib::bool_error!(
341                "Couldn't convert channel positions to mask",
342            ))
343        }
344    }
345
346    #[doc(alias = "gst_audio_channel_positions_to_valid_order")]
347    pub fn positions_to_valid_order(positions: &mut [Self]) -> Result<(), glib::BoolError> {
348        assert_initialized_main_thread!();
349
350        if positions.len() > 64 {
351            return Err(glib::bool_error!("Invalid number of channels"));
352        }
353
354        let len = positions.len();
355        let valid: bool = unsafe {
356            from_glib(ffi::gst_audio_channel_positions_to_valid_order(
357                positions.as_mut_ptr() as *mut _,
358                len as i32,
359            ))
360        };
361
362        if valid {
363            Ok(())
364        } else {
365            Err(glib::bool_error!(
366                "Couldn't convert channel positions to mask",
367            ))
368        }
369    }
370
371    #[doc(alias = "get_fallback_mask")]
372    #[doc(alias = "gst_audio_channel_get_fallback_mask")]
373    pub fn fallback_mask(channels: u32) -> u64 {
374        assert_initialized_main_thread!();
375
376        unsafe { ffi::gst_audio_channel_get_fallback_mask(channels as i32) }
377    }
378
379    #[doc(alias = "gst_audio_check_valid_channel_positions")]
380    pub fn check_valid_channel_positions(positions: &[Self], force_order: bool) -> bool {
381        assert_initialized_main_thread!();
382
383        if positions.len() > 64 {
384            return false;
385        }
386
387        let len = positions.len();
388        unsafe {
389            from_glib(ffi::gst_audio_check_valid_channel_positions(
390                positions.as_ptr() as *mut _,
391                len as i32,
392                force_order.into_glib(),
393            ))
394        }
395    }
396}
397
398#[doc(alias = "gst_audio_buffer_reorder_channels")]
399pub fn buffer_reorder_channels(
400    buffer: &mut gst::BufferRef,
401    format: crate::AudioFormat,
402    channels: u32,
403    from: &[AudioChannelPosition],
404    to: &[AudioChannelPosition],
405) -> Result<(), glib::BoolError> {
406    skip_assert_initialized!();
407
408    assert!(channels > 0 && channels <= 64);
409
410    if from.len() != to.len() || from.len() > 64 {
411        return Err(glib::bool_error!("Invalid number of channels"));
412    }
413
414    let formatinfo = crate::AudioFormatInfo::from_format(format);
415    if buffer.size() % ((formatinfo.width() * channels) as usize) != 0 {
416        return Err(glib::bool_error!("Incomplete number of samples in buffer"));
417    }
418
419    let valid: bool = unsafe {
420        from_glib(ffi::gst_audio_buffer_reorder_channels(
421            buffer.as_mut_ptr(),
422            format.into_glib(),
423            channels as i32,
424            from.as_ptr() as *mut _,
425            to.as_ptr() as *mut _,
426        ))
427    };
428
429    if valid {
430        Ok(())
431    } else {
432        Err(glib::bool_error!("Failed to reorder channels"))
433    }
434}
435
436#[doc(alias = "gst_audio_reorder_channels")]
437pub fn reorder_channels(
438    data: &mut [u8],
439    format: crate::AudioFormat,
440    channels: u32,
441    from: &[AudioChannelPosition],
442    to: &[AudioChannelPosition],
443) -> Result<(), glib::BoolError> {
444    assert_initialized_main_thread!();
445
446    if from.len() != to.len() || from.len() > 64 {
447        return Err(glib::bool_error!("Invalid number of channels"));
448    }
449    assert!(channels > 0 && channels <= 64);
450
451    let formatinfo = crate::AudioFormatInfo::from_format(format);
452    if data.len() % ((formatinfo.width() * channels) as usize) != 0 {
453        return Err(glib::bool_error!("Incomplete number of samples in buffer"));
454    }
455
456    let valid: bool = unsafe {
457        from_glib(ffi::gst_audio_reorder_channels(
458            data.as_mut_ptr() as *mut _,
459            data.len(),
460            format.into_glib(),
461            channels as i32,
462            from.as_ptr() as *mut _,
463            to.as_ptr() as *mut _,
464        ))
465    };
466
467    if valid {
468        Ok(())
469    } else {
470        Err(glib::bool_error!("Failed to reorder channels"))
471    }
472}
473
474#[doc(alias = "get_channel_reorder_map")]
475#[doc(alias = "gst_audio_get_channel_reorder_map")]
476pub fn channel_reorder_map(
477    from: &[AudioChannelPosition],
478    to: &[AudioChannelPosition],
479    reorder_map: &mut [usize],
480) -> Result<(), glib::BoolError> {
481    assert_initialized_main_thread!();
482
483    if from.len() != to.len() || from.len() != reorder_map.len() || from.len() > 64 {
484        return Err(glib::bool_error!("Invalid number of channels"));
485    }
486
487    let mut reorder_map_raw = mem::MaybeUninit::<[i32; 64]>::uninit();
488    let valid: bool = unsafe {
489        from_glib(ffi::gst_audio_get_channel_reorder_map(
490            from.len() as i32,
491            from.as_ptr() as *mut _,
492            to.as_ptr() as *mut _,
493            reorder_map_raw.as_mut_ptr() as *mut i32,
494        ))
495    };
496
497    if valid {
498        let reorder_map_raw =
499            unsafe { slice::from_raw_parts(reorder_map_raw.as_ptr() as *const i32, from.len()) };
500        for (d, s) in reorder_map.iter_mut().zip(reorder_map_raw.iter()) {
501            *d = *s as usize;
502        }
503        Ok(())
504    } else {
505        Err(glib::bool_error!("Failed to reorder channels"))
506    }
507}
508
509#[cfg(feature = "v1_26")]
510#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
511#[doc(alias = "gst_audio_reorder_channels_with_reorder_map")]
512pub fn reorder_channels_with_reorder_map(
513    data: &mut [u8],
514    bps: usize,
515    channels: u32,
516    reorder_map: &[usize],
517) -> Result<(), glib::BoolError> {
518    skip_assert_initialized!();
519
520    assert!(bps > 0 && bps <= 64);
521    assert!(channels > 0 && channels <= 64);
522    if data.len() % (bps * channels as usize) != 0 {
523        return Err(glib::bool_error!("Incomplete number of samples in buffer"));
524    }
525    if reorder_map.len() < channels as usize {
526        return Err(glib::bool_error!("Too small reorder map"));
527    }
528
529    let mut reorder_map_raw = mem::MaybeUninit::<[i32; 64]>::uninit();
530    for (i, c) in reorder_map[..channels as usize].iter().enumerate() {
531        if *c >= channels as usize {
532            return Err(glib::bool_error!("Invalid channel id in reorder map"));
533        }
534        unsafe {
535            *(reorder_map_raw.as_mut_ptr() as *mut i32).add(i) = *c as i32;
536        }
537    }
538
539    unsafe {
540        ffi::gst_audio_reorder_channels_with_reorder_map(
541            data.as_mut_ptr() as *mut _,
542            data.len(),
543            bps as i32,
544            channels as i32,
545            reorder_map_raw.as_ptr() as *const i32,
546        );
547    };
548
549    Ok(())
550}