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