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
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}