Skip to main content

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