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