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
211impl std::fmt::Display for AudioChannelPosition {
212    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
213        <AudioChannelPosition as std::fmt::Debug>::fmt(self, f)
214    }
215}
216
217unsafe impl TransparentType for AudioChannelPosition {
218    type GlibType = ffi::GstAudioChannelPosition;
219}
220
221#[doc(hidden)]
222impl IntoGlib for AudioChannelPosition {
223    type GlibType = ffi::GstAudioChannelPosition;
224
225    #[inline]
226    fn into_glib(self) -> ffi::GstAudioChannelPosition {
227        self as ffi::GstAudioChannelPosition
228    }
229}
230
231#[doc(hidden)]
232impl FromGlib<ffi::GstAudioChannelPosition> for AudioChannelPosition {
233    #[inline]
234    unsafe fn from_glib(value: ffi::GstAudioChannelPosition) -> Self {
235        skip_assert_initialized!();
236        debug_assert!((ffi::GST_AUDIO_CHANNEL_POSITION_NONE..=64).contains(&value));
237        mem::transmute::<ffi::GstAudioChannelPosition, AudioChannelPosition>(value)
238    }
239}
240
241impl StaticType for AudioChannelPosition {
242    #[inline]
243    fn static_type() -> Type {
244        unsafe { from_glib(ffi::gst_audio_channel_position_get_type()) }
245    }
246}
247
248impl glib::value::ValueType for AudioChannelPosition {
249    type Type = Self;
250}
251
252unsafe impl<'a> FromValue<'a> for AudioChannelPosition {
253    type Checker = glib::value::GenericValueTypeChecker<Self>;
254
255    #[inline]
256    unsafe fn from_value(value: &'a glib::Value) -> Self {
257        skip_assert_initialized!();
258        from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0))
259    }
260}
261
262impl ToValue for AudioChannelPosition {
263    #[inline]
264    fn to_value(&self) -> glib::Value {
265        let mut value = glib::Value::for_value_type::<Self>();
266        unsafe {
267            glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib());
268        }
269        value
270    }
271
272    #[inline]
273    fn value_type(&self) -> glib::Type {
274        Self::static_type()
275    }
276}
277
278impl From<AudioChannelPosition> for glib::Value {
279    #[inline]
280    fn from(v: AudioChannelPosition) -> Self {
281        skip_assert_initialized!();
282        ToValue::to_value(&v)
283    }
284}
285
286impl AudioChannelPosition {
287    pub fn to_mask(self) -> u64 {
288        let pos = self.into_glib();
289        if pos < 0 {
290            return 0;
291        }
292
293        1 << (pos as u32)
294    }
295
296    #[doc(alias = "gst_audio_channel_positions_to_mask")]
297    pub fn positions_to_mask(
298        positions: &[Self],
299        force_order: bool,
300    ) -> Result<u64, glib::error::BoolError> {
301        assert_initialized_main_thread!();
302
303        let len = positions.len();
304        if len > 64 {
305            return Err(glib::bool_error!("Invalid number of channels"));
306        }
307
308        unsafe {
309            let mut mask = mem::MaybeUninit::uninit();
310            let valid: bool = from_glib(ffi::gst_audio_channel_positions_to_mask(
311                positions.as_ptr() as *mut _,
312                len as i32,
313                force_order.into_glib(),
314                mask.as_mut_ptr(),
315            ));
316            if valid {
317                Ok(mask.assume_init())
318            } else {
319                Err(glib::bool_error!(
320                    "Couldn't convert channel positions to mask"
321                ))
322            }
323        }
324    }
325
326    #[doc(alias = "gst_audio_channel_positions_from_mask")]
327    pub fn positions_from_mask(mask: u64, positions: &mut [Self]) -> Result<(), glib::BoolError> {
328        assert_initialized_main_thread!();
329
330        if positions.len() > 64 {
331            return Err(glib::bool_error!("Invalid number of channels"));
332        }
333
334        let len = positions.len();
335        let valid: bool = unsafe {
336            from_glib(ffi::gst_audio_channel_positions_from_mask(
337                len as i32,
338                mask,
339                positions.as_mut_ptr() as *mut _,
340            ))
341        };
342
343        if valid {
344            Ok(())
345        } else {
346            Err(glib::bool_error!(
347                "Couldn't convert channel positions to mask",
348            ))
349        }
350    }
351
352    #[doc(alias = "gst_audio_channel_positions_to_valid_order")]
353    pub fn positions_to_valid_order(positions: &mut [Self]) -> Result<(), glib::BoolError> {
354        assert_initialized_main_thread!();
355
356        if positions.len() > 64 {
357            return Err(glib::bool_error!("Invalid number of channels"));
358        }
359
360        let len = positions.len();
361        let valid: bool = unsafe {
362            from_glib(ffi::gst_audio_channel_positions_to_valid_order(
363                positions.as_mut_ptr() as *mut _,
364                len as i32,
365            ))
366        };
367
368        if valid {
369            Ok(())
370        } else {
371            Err(glib::bool_error!(
372                "Couldn't convert channel positions to mask",
373            ))
374        }
375    }
376
377    #[doc(alias = "get_fallback_mask")]
378    #[doc(alias = "gst_audio_channel_get_fallback_mask")]
379    pub fn fallback_mask(channels: u32) -> u64 {
380        assert_initialized_main_thread!();
381
382        unsafe { ffi::gst_audio_channel_get_fallback_mask(channels as i32) }
383    }
384
385    #[doc(alias = "gst_audio_check_valid_channel_positions")]
386    pub fn check_valid_channel_positions(positions: &[Self], force_order: bool) -> bool {
387        assert_initialized_main_thread!();
388
389        if positions.len() > 64 {
390            return false;
391        }
392
393        let len = positions.len();
394        unsafe {
395            from_glib(ffi::gst_audio_check_valid_channel_positions(
396                positions.as_ptr() as *mut _,
397                len as i32,
398                force_order.into_glib(),
399            ))
400        }
401    }
402}
403
404#[doc(alias = "gst_audio_buffer_reorder_channels")]
405pub fn buffer_reorder_channels(
406    buffer: &mut gst::BufferRef,
407    format: crate::AudioFormat,
408    channels: u32,
409    from: &[AudioChannelPosition],
410    to: &[AudioChannelPosition],
411) -> Result<(), glib::BoolError> {
412    skip_assert_initialized!();
413
414    assert!(channels > 0 && channels <= 64);
415
416    if from.len() != to.len() || from.len() > 64 {
417        return Err(glib::bool_error!("Invalid number of channels"));
418    }
419
420    let formatinfo = crate::AudioFormatInfo::from_format(format);
421    if buffer.size() % ((formatinfo.width() * channels) as usize) != 0 {
422        return Err(glib::bool_error!("Incomplete number of samples in buffer"));
423    }
424
425    let valid: bool = unsafe {
426        from_glib(ffi::gst_audio_buffer_reorder_channels(
427            buffer.as_mut_ptr(),
428            format.into_glib(),
429            channels as i32,
430            from.as_ptr() as *mut _,
431            to.as_ptr() as *mut _,
432        ))
433    };
434
435    if valid {
436        Ok(())
437    } else {
438        Err(glib::bool_error!("Failed to reorder channels"))
439    }
440}
441
442#[doc(alias = "gst_audio_reorder_channels")]
443pub fn reorder_channels(
444    data: &mut [u8],
445    format: crate::AudioFormat,
446    channels: u32,
447    from: &[AudioChannelPosition],
448    to: &[AudioChannelPosition],
449) -> Result<(), glib::BoolError> {
450    assert_initialized_main_thread!();
451
452    if from.len() != to.len() || from.len() > 64 {
453        return Err(glib::bool_error!("Invalid number of channels"));
454    }
455    assert!(channels > 0 && channels <= 64);
456
457    let formatinfo = crate::AudioFormatInfo::from_format(format);
458    if data.len() % ((formatinfo.width() * channels) as usize) != 0 {
459        return Err(glib::bool_error!("Incomplete number of samples in buffer"));
460    }
461
462    let valid: bool = unsafe {
463        from_glib(ffi::gst_audio_reorder_channels(
464            data.as_mut_ptr() as *mut _,
465            data.len(),
466            format.into_glib(),
467            channels as i32,
468            from.as_ptr() as *mut _,
469            to.as_ptr() as *mut _,
470        ))
471    };
472
473    if valid {
474        Ok(())
475    } else {
476        Err(glib::bool_error!("Failed to reorder channels"))
477    }
478}
479
480#[doc(alias = "get_channel_reorder_map")]
481#[doc(alias = "gst_audio_get_channel_reorder_map")]
482pub fn channel_reorder_map(
483    from: &[AudioChannelPosition],
484    to: &[AudioChannelPosition],
485    reorder_map: &mut [usize],
486) -> Result<(), glib::BoolError> {
487    assert_initialized_main_thread!();
488
489    if from.len() != to.len() || from.len() != reorder_map.len() || from.len() > 64 {
490        return Err(glib::bool_error!("Invalid number of channels"));
491    }
492
493    let mut reorder_map_raw = mem::MaybeUninit::<[i32; 64]>::uninit();
494    let valid: bool = unsafe {
495        from_glib(ffi::gst_audio_get_channel_reorder_map(
496            from.len() as i32,
497            from.as_ptr() as *mut _,
498            to.as_ptr() as *mut _,
499            reorder_map_raw.as_mut_ptr() as *mut i32,
500        ))
501    };
502
503    if valid {
504        let reorder_map_raw =
505            unsafe { slice::from_raw_parts(reorder_map_raw.as_ptr() as *const i32, from.len()) };
506        for (d, s) in reorder_map.iter_mut().zip(reorder_map_raw.iter()) {
507            *d = *s as usize;
508        }
509        Ok(())
510    } else {
511        Err(glib::bool_error!("Failed to reorder channels"))
512    }
513}
514
515#[cfg(feature = "v1_26")]
516#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
517#[doc(alias = "gst_audio_reorder_channels_with_reorder_map")]
518pub fn reorder_channels_with_reorder_map(
519    data: &mut [u8],
520    bps: usize,
521    channels: u32,
522    reorder_map: &[usize],
523) -> Result<(), glib::BoolError> {
524    skip_assert_initialized!();
525
526    assert!(bps > 0 && bps <= 64);
527    assert!(channels > 0 && channels <= 64);
528    if data.len() % (bps * channels as usize) != 0 {
529        return Err(glib::bool_error!("Incomplete number of samples in buffer"));
530    }
531    if reorder_map.len() < channels as usize {
532        return Err(glib::bool_error!("Too small reorder map"));
533    }
534
535    let mut reorder_map_raw = mem::MaybeUninit::<[i32; 64]>::uninit();
536    for (i, c) in reorder_map[..channels as usize].iter().enumerate() {
537        if *c >= channels as usize {
538            return Err(glib::bool_error!("Invalid channel id in reorder map"));
539        }
540        unsafe {
541            *(reorder_map_raw.as_mut_ptr() as *mut i32).add(i) = *c as i32;
542        }
543    }
544
545    unsafe {
546        ffi::gst_audio_reorder_channels_with_reorder_map(
547            data.as_mut_ptr() as *mut _,
548            data.len(),
549            bps as i32,
550            channels as i32,
551            reorder_map_raw.as_ptr() as *const i32,
552        );
553    };
554
555    Ok(())
556}