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)]
33#[non_exhaustive]
34#[doc(alias = "GstAudioChannelPosition")]
35#[repr(i32)]
36pub enum AudioChannelPosition {
37 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_NONE")]
41 None = ffi::GST_AUDIO_CHANNEL_POSITION_NONE,
42 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_MONO")]
45 Mono,
46 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_INVALID")]
48 Invalid,
49 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT")]
51 FrontLeft,
52 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT")]
54 FrontRight,
55 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER")]
57 FrontCenter,
58 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_LFE1")]
60 Lfe1,
61 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_REAR_LEFT")]
63 RearLeft,
64 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT")]
66 RearRight,
67 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER")]
69 FrontLeftOfCenter,
70 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER")]
72 FrontRightOfCenter,
73 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_REAR_CENTER")]
75 RearCenter,
76 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_LFE2")]
78 Lfe2,
79 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT")]
81 SideLeft,
82 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT")]
84 SideRight,
85 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT")]
87 TopFrontLeft,
88 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT")]
90 TopFrontRight,
91 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER")]
93 TopFrontCenter,
94 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_CENTER")]
96 TopCenter,
97 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT")]
99 TopRearLeft,
100 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT")]
102 TopRearRight,
103 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_LEFT")]
105 TopSideLeft,
106 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_RIGHT")]
108 TopSideRight,
109 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER")]
111 TopRearCenter,
112 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_CENTER")]
114 BottomFrontCenter,
115 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_LEFT")]
117 BottomFrontLeft,
118 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_RIGHT")]
120 BottomFrontRight,
121 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_WIDE_LEFT")]
123 WideLeft,
124 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_WIDE_RIGHT")]
126 WideRight,
127 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SURROUND_LEFT")]
129 SurroundLeft,
130 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SURROUND_RIGHT")]
132 SurroundRight = ffi::GST_AUDIO_CHANNEL_POSITION_SURROUND_RIGHT,
133 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_SURROUND_LEFT")]
135 TopSurroundLeft = 28,
136 #[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}