1 use super::utils::{
2 test_audiounit_get_buffer_frame_size, test_audiounit_scope_is_enabled, test_create_audiounit,
3 test_device_channels_in_scope, test_device_in_scope, test_get_all_devices,
4 test_get_default_audiounit, test_get_default_device, test_get_default_raw_stream,
5 test_get_default_source_name, test_get_devices_in_scope, test_get_raw_context,
6 ComponentSubType, PropertyScope, Scope,
7 };
8 use super::*;
9
10 // make_sized_audio_channel_layout
11 // ------------------------------------
12 #[test]
test_make_sized_audio_channel_layout()13 fn test_make_sized_audio_channel_layout() {
14 for channels in 1..10 {
15 let size = mem::size_of::<AudioChannelLayout>()
16 + (channels - 1) * mem::size_of::<AudioChannelDescription>();
17 let _ = make_sized_audio_channel_layout(size);
18 }
19 }
20
21 #[test]
22 #[should_panic]
test_make_sized_audio_channel_layout_with_wrong_size()23 fn test_make_sized_audio_channel_layout_with_wrong_size() {
24 // let _ = make_sized_audio_channel_layout(0);
25 let one_channel_size = mem::size_of::<AudioChannelLayout>();
26 let padding_size = 10;
27 assert_ne!(mem::size_of::<AudioChannelDescription>(), padding_size);
28 let wrong_size = one_channel_size + padding_size;
29 let _ = make_sized_audio_channel_layout(wrong_size);
30 }
31
32 // active_streams
33 // update_latency_by_adding_stream
34 // update_latency_by_removing_stream
35 // ------------------------------------
36 #[test]
test_increase_and_decrease_context_streams()37 fn test_increase_and_decrease_context_streams() {
38 use std::thread;
39 const STREAMS: u32 = 10;
40
41 let context = AudioUnitContext::new();
42 let context_ptr_value = &context as *const AudioUnitContext as usize;
43
44 let mut join_handles = vec![];
45 for i in 0..STREAMS {
46 join_handles.push(thread::spawn(move || {
47 let context = unsafe { &*(context_ptr_value as *const AudioUnitContext) };
48 let global_latency = context.update_latency_by_adding_stream(i);
49 global_latency
50 }));
51 }
52 let mut latencies = vec![];
53 for handle in join_handles {
54 latencies.push(handle.join().unwrap());
55 }
56 assert_eq!(context.active_streams(), STREAMS);
57 check_streams(&context, STREAMS);
58
59 check_latency(&context, latencies[0]);
60 for i in 0..latencies.len() - 1 {
61 assert_eq!(latencies[i], latencies[i + 1]);
62 }
63
64 let mut join_handles = vec![];
65 for _ in 0..STREAMS {
66 join_handles.push(thread::spawn(move || {
67 let context = unsafe { &*(context_ptr_value as *const AudioUnitContext) };
68 context.update_latency_by_removing_stream();
69 }));
70 }
71 for handle in join_handles {
72 let _ = handle.join();
73 }
74 check_streams(&context, 0);
75
76 check_latency(&context, None);
77 }
78
check_streams(context: &AudioUnitContext, number: u32)79 fn check_streams(context: &AudioUnitContext, number: u32) {
80 let guard = context.latency_controller.lock().unwrap();
81 assert_eq!(guard.streams, number);
82 }
83
check_latency(context: &AudioUnitContext, latency: Option<u32>)84 fn check_latency(context: &AudioUnitContext, latency: Option<u32>) {
85 let guard = context.latency_controller.lock().unwrap();
86 assert_eq!(guard.latency, latency);
87 }
88
89 // make_silent
90 // ------------------------------------
91 #[test]
test_make_silent()92 fn test_make_silent() {
93 let mut array = allocate_array::<u32>(10);
94 for data in array.iter_mut() {
95 *data = 0xFFFF;
96 }
97
98 let mut buffer = AudioBuffer::default();
99 buffer.mData = array.as_mut_ptr() as *mut c_void;
100 buffer.mDataByteSize = (array.len() * mem::size_of::<u32>()) as u32;
101 buffer.mNumberChannels = 1;
102
103 audiounit_make_silent(&mut buffer);
104 for data in array {
105 assert_eq!(data, 0);
106 }
107 }
108
109 // minimum_resampling_input_frames
110 // ------------------------------------
111 #[test]
test_minimum_resampling_input_frames()112 fn test_minimum_resampling_input_frames() {
113 let input_rate = 48000_f64;
114 let output_rate = 44100_f64;
115
116 let frames = 100;
117 let times = input_rate / output_rate;
118 let expected = (frames as f64 * times).ceil() as usize;
119
120 assert_eq!(
121 minimum_resampling_input_frames(input_rate, output_rate, frames),
122 expected
123 );
124 }
125
126 #[test]
127 #[should_panic]
test_minimum_resampling_input_frames_zero_input_rate()128 fn test_minimum_resampling_input_frames_zero_input_rate() {
129 minimum_resampling_input_frames(0_f64, 44100_f64, 1);
130 }
131
132 #[test]
133 #[should_panic]
test_minimum_resampling_input_frames_zero_output_rate()134 fn test_minimum_resampling_input_frames_zero_output_rate() {
135 minimum_resampling_input_frames(48000_f64, 0_f64, 1);
136 }
137
138 #[test]
test_minimum_resampling_input_frames_equal_input_output_rate()139 fn test_minimum_resampling_input_frames_equal_input_output_rate() {
140 let frames = 100;
141 assert_eq!(
142 minimum_resampling_input_frames(44100_f64, 44100_f64, frames),
143 frames
144 );
145 }
146
147 // create_device_info
148 // ------------------------------------
149 #[test]
test_create_device_info_from_unknown_input_device()150 fn test_create_device_info_from_unknown_input_device() {
151 if let Some(default_device_id) = test_get_default_device(Scope::Input) {
152 let default_device = create_device_info(kAudioObjectUnknown, DeviceType::INPUT).unwrap();
153 assert_eq!(default_device.id, default_device_id);
154 assert_eq!(
155 default_device.flags,
156 device_flags::DEV_INPUT
157 | device_flags::DEV_SELECTED_DEFAULT
158 | device_flags::DEV_SYSTEM_DEFAULT
159 );
160 } else {
161 println!("No input device to perform test.");
162 }
163 }
164
165 #[test]
test_create_device_info_from_unknown_output_device()166 fn test_create_device_info_from_unknown_output_device() {
167 if let Some(default_device_id) = test_get_default_device(Scope::Output) {
168 let default_device = create_device_info(kAudioObjectUnknown, DeviceType::OUTPUT).unwrap();
169 assert_eq!(default_device.id, default_device_id);
170 assert_eq!(
171 default_device.flags,
172 device_flags::DEV_OUTPUT
173 | device_flags::DEV_SELECTED_DEFAULT
174 | device_flags::DEV_SYSTEM_DEFAULT
175 );
176 } else {
177 println!("No output device to perform test.");
178 }
179 }
180
181 #[test]
182 #[should_panic]
test_set_device_info_to_system_input_device()183 fn test_set_device_info_to_system_input_device() {
184 let _device = create_device_info(kAudioObjectSystemObject, DeviceType::INPUT);
185 }
186
187 #[test]
188 #[should_panic]
test_set_device_info_to_system_output_device()189 fn test_set_device_info_to_system_output_device() {
190 let _device = create_device_info(kAudioObjectSystemObject, DeviceType::OUTPUT);
191 }
192
193 // FIXIT: Is it ok to set input device to a nonexistent device ?
194 #[ignore]
195 #[test]
196 #[should_panic]
test_set_device_info_to_nonexistent_input_device()197 fn test_set_device_info_to_nonexistent_input_device() {
198 let nonexistent_id = std::u32::MAX;
199 let _device = create_device_info(nonexistent_id, DeviceType::INPUT);
200 }
201
202 // FIXIT: Is it ok to set output device to a nonexistent device ?
203 #[ignore]
204 #[test]
205 #[should_panic]
test_set_device_info_to_nonexistent_output_device()206 fn test_set_device_info_to_nonexistent_output_device() {
207 let nonexistent_id = std::u32::MAX;
208 let _device = create_device_info(nonexistent_id, DeviceType::OUTPUT);
209 }
210
211 // add_listener (for default output device)
212 // ------------------------------------
213 #[test]
test_add_listener_unknown_device()214 fn test_add_listener_unknown_device() {
215 extern "C" fn callback(
216 _id: AudioObjectID,
217 _number_of_addresses: u32,
218 _addresses: *const AudioObjectPropertyAddress,
219 _data: *mut c_void,
220 ) -> OSStatus {
221 assert!(false, "Should not be called.");
222 kAudioHardwareUnspecifiedError as OSStatus
223 }
224
225 test_get_default_raw_stream(|stream| {
226 let listener = device_property_listener::new(
227 kAudioObjectUnknown,
228 get_property_address(
229 Property::HardwareDefaultOutputDevice,
230 DeviceType::INPUT | DeviceType::OUTPUT,
231 ),
232 callback,
233 );
234 assert_eq!(
235 stream.add_device_listener(&listener),
236 kAudioHardwareBadObjectError as OSStatus
237 );
238 });
239 }
240
241 // remove_listener (for default output device)
242 // ------------------------------------
243 #[test]
test_add_listener_then_remove_system_device()244 fn test_add_listener_then_remove_system_device() {
245 extern "C" fn callback(
246 _id: AudioObjectID,
247 _number_of_addresses: u32,
248 _addresses: *const AudioObjectPropertyAddress,
249 _data: *mut c_void,
250 ) -> OSStatus {
251 assert!(false, "Should not be called.");
252 kAudioHardwareUnspecifiedError as OSStatus
253 }
254
255 test_get_default_raw_stream(|stream| {
256 let listener = device_property_listener::new(
257 kAudioObjectSystemObject,
258 get_property_address(
259 Property::HardwareDefaultOutputDevice,
260 DeviceType::INPUT | DeviceType::OUTPUT,
261 ),
262 callback,
263 );
264 assert_eq!(stream.add_device_listener(&listener), NO_ERR);
265 assert_eq!(stream.remove_device_listener(&listener), NO_ERR);
266 });
267 }
268
269 #[test]
test_remove_listener_without_adding_any_listener_before_system_device()270 fn test_remove_listener_without_adding_any_listener_before_system_device() {
271 extern "C" fn callback(
272 _id: AudioObjectID,
273 _number_of_addresses: u32,
274 _addresses: *const AudioObjectPropertyAddress,
275 _data: *mut c_void,
276 ) -> OSStatus {
277 assert!(false, "Should not be called.");
278 kAudioHardwareUnspecifiedError as OSStatus
279 }
280
281 test_get_default_raw_stream(|stream| {
282 let listener = device_property_listener::new(
283 kAudioObjectSystemObject,
284 get_property_address(
285 Property::HardwareDefaultOutputDevice,
286 DeviceType::INPUT | DeviceType::OUTPUT,
287 ),
288 callback,
289 );
290 assert_eq!(stream.remove_device_listener(&listener), NO_ERR);
291 });
292 }
293
294 #[test]
test_remove_listener_unknown_device()295 fn test_remove_listener_unknown_device() {
296 extern "C" fn callback(
297 _id: AudioObjectID,
298 _number_of_addresses: u32,
299 _addresses: *const AudioObjectPropertyAddress,
300 _data: *mut c_void,
301 ) -> OSStatus {
302 assert!(false, "Should not be called.");
303 kAudioHardwareUnspecifiedError as OSStatus
304 }
305
306 test_get_default_raw_stream(|stream| {
307 let listener = device_property_listener::new(
308 kAudioObjectUnknown,
309 get_property_address(
310 Property::HardwareDefaultOutputDevice,
311 DeviceType::INPUT | DeviceType::OUTPUT,
312 ),
313 callback,
314 );
315 assert_eq!(
316 stream.remove_device_listener(&listener),
317 kAudioHardwareBadObjectError as OSStatus
318 );
319 });
320 }
321
322 // get_default_device_id
323 // ------------------------------------
324 #[test]
test_get_default_device_id()325 fn test_get_default_device_id() {
326 if test_get_default_device(Scope::Input).is_some() {
327 assert_ne!(
328 audiounit_get_default_device_id(DeviceType::INPUT),
329 kAudioObjectUnknown,
330 );
331 }
332
333 if test_get_default_device(Scope::Output).is_some() {
334 assert_ne!(
335 audiounit_get_default_device_id(DeviceType::OUTPUT),
336 kAudioObjectUnknown,
337 );
338 }
339 }
340
341 #[test]
342 #[should_panic]
test_get_default_device_id_with_unknown_type()343 fn test_get_default_device_id_with_unknown_type() {
344 assert_eq!(
345 audiounit_get_default_device_id(DeviceType::UNKNOWN),
346 kAudioObjectUnknown,
347 );
348 }
349
350 #[test]
351 #[should_panic]
test_get_default_device_id_with_inout_type()352 fn test_get_default_device_id_with_inout_type() {
353 assert_eq!(
354 audiounit_get_default_device_id(DeviceType::INPUT | DeviceType::OUTPUT),
355 kAudioObjectUnknown,
356 );
357 }
358
359 // convert_channel_layout
360 // ------------------------------------
361 #[test]
test_convert_channel_layout()362 fn test_convert_channel_layout() {
363 let pairs = [
364 (vec![kAudioObjectUnknown], vec![mixer::Channel::Silence]),
365 (
366 vec![kAudioChannelLabel_Mono],
367 vec![mixer::Channel::FrontCenter],
368 ),
369 (
370 vec![kAudioChannelLabel_Mono, kAudioChannelLabel_LFEScreen],
371 vec![mixer::Channel::FrontCenter, mixer::Channel::LowFrequency],
372 ),
373 (
374 vec![kAudioChannelLabel_Left, kAudioChannelLabel_Right],
375 vec![mixer::Channel::FrontLeft, mixer::Channel::FrontRight],
376 ),
377 (
378 vec![
379 kAudioChannelLabel_Left,
380 kAudioChannelLabel_Right,
381 kAudioChannelLabel_Unknown,
382 ],
383 vec![
384 mixer::Channel::FrontLeft,
385 mixer::Channel::FrontRight,
386 mixer::Channel::Silence,
387 ],
388 ),
389 (
390 vec![
391 kAudioChannelLabel_Left,
392 kAudioChannelLabel_Right,
393 kAudioChannelLabel_Unused,
394 ],
395 vec![
396 mixer::Channel::FrontLeft,
397 mixer::Channel::FrontRight,
398 mixer::Channel::Silence,
399 ],
400 ),
401 (
402 vec![
403 kAudioChannelLabel_Left,
404 kAudioChannelLabel_Right,
405 kAudioChannelLabel_ForeignLanguage,
406 ],
407 vec![
408 mixer::Channel::FrontLeft,
409 mixer::Channel::FrontRight,
410 mixer::Channel::Silence,
411 ],
412 ),
413 // The SMPTE layouts.
414 (
415 vec![
416 kAudioChannelLabel_Left,
417 kAudioChannelLabel_Right,
418 kAudioChannelLabel_LFEScreen,
419 ],
420 vec![
421 mixer::Channel::FrontLeft,
422 mixer::Channel::FrontRight,
423 mixer::Channel::LowFrequency,
424 ],
425 ),
426 (
427 vec![
428 kAudioChannelLabel_Left,
429 kAudioChannelLabel_Right,
430 kAudioChannelLabel_Center,
431 ],
432 vec![
433 mixer::Channel::FrontLeft,
434 mixer::Channel::FrontRight,
435 mixer::Channel::FrontCenter,
436 ],
437 ),
438 (
439 vec![
440 kAudioChannelLabel_Left,
441 kAudioChannelLabel_Right,
442 kAudioChannelLabel_Center,
443 kAudioChannelLabel_LFEScreen,
444 ],
445 vec![
446 mixer::Channel::FrontLeft,
447 mixer::Channel::FrontRight,
448 mixer::Channel::FrontCenter,
449 mixer::Channel::LowFrequency,
450 ],
451 ),
452 (
453 vec![
454 kAudioChannelLabel_Left,
455 kAudioChannelLabel_Right,
456 kAudioChannelLabel_CenterSurround,
457 ],
458 vec![
459 mixer::Channel::FrontLeft,
460 mixer::Channel::FrontRight,
461 mixer::Channel::BackCenter,
462 ],
463 ),
464 (
465 vec![
466 kAudioChannelLabel_Left,
467 kAudioChannelLabel_Right,
468 kAudioChannelLabel_CenterSurround,
469 kAudioChannelLabel_LFEScreen,
470 ],
471 vec![
472 mixer::Channel::FrontLeft,
473 mixer::Channel::FrontRight,
474 mixer::Channel::BackCenter,
475 mixer::Channel::LowFrequency,
476 ],
477 ),
478 (
479 vec![
480 kAudioChannelLabel_Left,
481 kAudioChannelLabel_Right,
482 kAudioChannelLabel_Center,
483 kAudioChannelLabel_CenterSurround,
484 ],
485 vec![
486 mixer::Channel::FrontLeft,
487 mixer::Channel::FrontRight,
488 mixer::Channel::FrontCenter,
489 mixer::Channel::BackCenter,
490 ],
491 ),
492 (
493 vec![
494 kAudioChannelLabel_Left,
495 kAudioChannelLabel_Right,
496 kAudioChannelLabel_Center,
497 kAudioChannelLabel_CenterSurround,
498 kAudioChannelLabel_LFEScreen,
499 ],
500 vec![
501 mixer::Channel::FrontLeft,
502 mixer::Channel::FrontRight,
503 mixer::Channel::FrontCenter,
504 mixer::Channel::BackCenter,
505 mixer::Channel::LowFrequency,
506 ],
507 ),
508 (
509 vec![
510 kAudioChannelLabel_Left,
511 kAudioChannelLabel_Right,
512 kAudioChannelLabel_LeftSurroundDirect,
513 kAudioChannelLabel_RightSurroundDirect,
514 ],
515 vec![
516 mixer::Channel::FrontLeft,
517 mixer::Channel::FrontRight,
518 mixer::Channel::SideLeft,
519 mixer::Channel::SideRight,
520 ],
521 ),
522 (
523 vec![
524 kAudioChannelLabel_Left,
525 kAudioChannelLabel_Right,
526 kAudioChannelLabel_LeftSurroundDirect,
527 kAudioChannelLabel_RightSurroundDirect,
528 kAudioChannelLabel_LFEScreen,
529 ],
530 vec![
531 mixer::Channel::FrontLeft,
532 mixer::Channel::FrontRight,
533 mixer::Channel::SideLeft,
534 mixer::Channel::SideRight,
535 mixer::Channel::LowFrequency,
536 ],
537 ),
538 (
539 vec![
540 kAudioChannelLabel_Left,
541 kAudioChannelLabel_Right,
542 kAudioChannelLabel_LeftSurround,
543 kAudioChannelLabel_RightSurround,
544 ],
545 vec![
546 mixer::Channel::FrontLeft,
547 mixer::Channel::FrontRight,
548 mixer::Channel::BackLeft,
549 mixer::Channel::BackRight,
550 ],
551 ),
552 (
553 vec![
554 kAudioChannelLabel_Left,
555 kAudioChannelLabel_Right,
556 kAudioChannelLabel_LeftSurround,
557 kAudioChannelLabel_RightSurround,
558 kAudioChannelLabel_LFEScreen,
559 ],
560 vec![
561 mixer::Channel::FrontLeft,
562 mixer::Channel::FrontRight,
563 mixer::Channel::BackLeft,
564 mixer::Channel::BackRight,
565 mixer::Channel::LowFrequency,
566 ],
567 ),
568 (
569 vec![
570 kAudioChannelLabel_Left,
571 kAudioChannelLabel_Right,
572 kAudioChannelLabel_Center,
573 kAudioChannelLabel_LeftSurroundDirect,
574 kAudioChannelLabel_RightSurroundDirect,
575 ],
576 vec![
577 mixer::Channel::FrontLeft,
578 mixer::Channel::FrontRight,
579 mixer::Channel::FrontCenter,
580 mixer::Channel::SideLeft,
581 mixer::Channel::SideRight,
582 ],
583 ),
584 (
585 vec![
586 kAudioChannelLabel_Left,
587 kAudioChannelLabel_Right,
588 kAudioChannelLabel_Center,
589 kAudioChannelLabel_LeftSurroundDirect,
590 kAudioChannelLabel_RightSurroundDirect,
591 kAudioChannelLabel_LFEScreen,
592 ],
593 vec![
594 mixer::Channel::FrontLeft,
595 mixer::Channel::FrontRight,
596 mixer::Channel::FrontCenter,
597 mixer::Channel::SideLeft,
598 mixer::Channel::SideRight,
599 mixer::Channel::LowFrequency,
600 ],
601 ),
602 (
603 vec![
604 kAudioChannelLabel_Left,
605 kAudioChannelLabel_Right,
606 kAudioChannelLabel_LeftSurround,
607 kAudioChannelLabel_RightSurround,
608 kAudioChannelLabel_Center,
609 ],
610 vec![
611 mixer::Channel::FrontLeft,
612 mixer::Channel::FrontRight,
613 mixer::Channel::BackLeft,
614 mixer::Channel::BackRight,
615 mixer::Channel::FrontCenter,
616 ],
617 ),
618 (
619 vec![
620 kAudioChannelLabel_Left,
621 kAudioChannelLabel_Right,
622 kAudioChannelLabel_LeftSurround,
623 kAudioChannelLabel_RightSurround,
624 kAudioChannelLabel_Center,
625 kAudioChannelLabel_LFEScreen,
626 ],
627 vec![
628 mixer::Channel::FrontLeft,
629 mixer::Channel::FrontRight,
630 mixer::Channel::BackLeft,
631 mixer::Channel::BackRight,
632 mixer::Channel::FrontCenter,
633 mixer::Channel::LowFrequency,
634 ],
635 ),
636 (
637 vec![
638 kAudioChannelLabel_Left,
639 kAudioChannelLabel_Right,
640 kAudioChannelLabel_Center,
641 kAudioChannelLabel_LFEScreen,
642 kAudioChannelLabel_CenterSurround,
643 kAudioChannelLabel_LeftSurroundDirect,
644 kAudioChannelLabel_RightSurroundDirect,
645 ],
646 vec![
647 mixer::Channel::FrontLeft,
648 mixer::Channel::FrontRight,
649 mixer::Channel::FrontCenter,
650 mixer::Channel::LowFrequency,
651 mixer::Channel::BackCenter,
652 mixer::Channel::SideLeft,
653 mixer::Channel::SideRight,
654 ],
655 ),
656 (
657 vec![
658 kAudioChannelLabel_Left,
659 kAudioChannelLabel_Right,
660 kAudioChannelLabel_Center,
661 kAudioChannelLabel_LFEScreen,
662 kAudioChannelLabel_LeftSurround,
663 kAudioChannelLabel_RightSurround,
664 kAudioChannelLabel_LeftSurroundDirect,
665 kAudioChannelLabel_RightSurroundDirect,
666 ],
667 vec![
668 mixer::Channel::FrontLeft,
669 mixer::Channel::FrontRight,
670 mixer::Channel::FrontCenter,
671 mixer::Channel::LowFrequency,
672 mixer::Channel::BackLeft,
673 mixer::Channel::BackRight,
674 mixer::Channel::SideLeft,
675 mixer::Channel::SideRight,
676 ],
677 ),
678 ];
679
680 const MAX_CHANNELS: usize = 10;
681 // A Rust mapping structure of the AudioChannelLayout with MAX_CHANNELS channels
682 // https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.13.sdk/System/Library/Frameworks/CoreAudio.framework/Versions/A/Headers/CoreAudioTypes.h#L1332
683 #[repr(C)]
684 struct TestLayout {
685 tag: AudioChannelLayoutTag,
686 map: AudioChannelBitmap,
687 number_channel_descriptions: UInt32,
688 channel_descriptions: [AudioChannelDescription; MAX_CHANNELS],
689 }
690
691 impl Default for TestLayout {
692 fn default() -> Self {
693 Self {
694 tag: AudioChannelLayoutTag::default(),
695 map: AudioChannelBitmap::default(),
696 number_channel_descriptions: UInt32::default(),
697 channel_descriptions: [AudioChannelDescription::default(); MAX_CHANNELS],
698 }
699 }
700 }
701
702 let mut layout = TestLayout::default();
703 layout.tag = kAudioChannelLayoutTag_UseChannelDescriptions;
704
705 for (labels, expected_layout) in pairs.iter() {
706 assert!(labels.len() <= MAX_CHANNELS);
707 layout.number_channel_descriptions = labels.len() as u32;
708 for (idx, label) in labels.iter().enumerate() {
709 layout.channel_descriptions[idx].mChannelLabel = *label;
710 }
711 let layout_ref = unsafe { &(*(&layout as *const TestLayout as *const AudioChannelLayout)) };
712 assert_eq!(
713 &audiounit_convert_channel_layout(layout_ref),
714 expected_layout
715 );
716 }
717 }
718
719 // get_preferred_channel_layout
720 // ------------------------------------
721 #[test]
test_get_preferred_channel_layout_output()722 fn test_get_preferred_channel_layout_output() {
723 match test_get_default_audiounit(Scope::Output) {
724 Some(unit) => assert!(!audiounit_get_preferred_channel_layout(unit.get_inner()).is_empty()),
725 None => println!("No output audiounit for test."),
726 }
727 }
728
729 // get_current_channel_layout
730 // ------------------------------------
731 #[test]
test_get_current_channel_layout_output()732 fn test_get_current_channel_layout_output() {
733 match test_get_default_audiounit(Scope::Output) {
734 Some(unit) => assert!(!audiounit_get_current_channel_layout(unit.get_inner()).is_empty()),
735 None => println!("No output audiounit for test."),
736 }
737 }
738
739 // create_stream_description
740 // ------------------------------------
741 #[test]
test_create_stream_description()742 fn test_create_stream_description() {
743 let mut channels = 0;
744 for (bits, format, flags) in [
745 (
746 16_u32,
747 ffi::CUBEB_SAMPLE_S16LE,
748 kAudioFormatFlagIsSignedInteger,
749 ),
750 (
751 16_u32,
752 ffi::CUBEB_SAMPLE_S16BE,
753 kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsBigEndian,
754 ),
755 (32_u32, ffi::CUBEB_SAMPLE_FLOAT32LE, kAudioFormatFlagIsFloat),
756 (
757 32_u32,
758 ffi::CUBEB_SAMPLE_FLOAT32BE,
759 kAudioFormatFlagIsFloat | kAudioFormatFlagIsBigEndian,
760 ),
761 ]
762 .iter()
763 {
764 let bytes = bits / 8;
765 channels += 1;
766
767 let mut raw = ffi::cubeb_stream_params::default();
768 raw.format = *format;
769 raw.rate = 48_000;
770 raw.channels = channels;
771 raw.layout = ffi::CUBEB_LAYOUT_UNDEFINED;
772 raw.prefs = ffi::CUBEB_STREAM_PREF_NONE;
773 let params = StreamParams::from(raw);
774 let description = create_stream_description(¶ms).unwrap();
775 assert_eq!(description.mFormatID, kAudioFormatLinearPCM);
776 assert_eq!(
777 description.mFormatFlags,
778 flags | kLinearPCMFormatFlagIsPacked
779 );
780 assert_eq!(description.mSampleRate as u32, raw.rate);
781 assert_eq!(description.mChannelsPerFrame, raw.channels);
782 assert_eq!(description.mBytesPerFrame, bytes * raw.channels);
783 assert_eq!(description.mFramesPerPacket, 1);
784 assert_eq!(description.mBytesPerPacket, bytes * raw.channels);
785 assert_eq!(description.mReserved, 0);
786 }
787 }
788
789 // create_default_audiounit
790 // ------------------------------------
791 #[test]
test_create_default_audiounit()792 fn test_create_default_audiounit() {
793 let flags_list = [
794 device_flags::DEV_UNKNOWN,
795 device_flags::DEV_INPUT,
796 device_flags::DEV_OUTPUT,
797 device_flags::DEV_INPUT | device_flags::DEV_OUTPUT,
798 device_flags::DEV_INPUT | device_flags::DEV_SYSTEM_DEFAULT,
799 device_flags::DEV_OUTPUT | device_flags::DEV_SYSTEM_DEFAULT,
800 device_flags::DEV_INPUT | device_flags::DEV_OUTPUT | device_flags::DEV_SYSTEM_DEFAULT,
801 ];
802
803 for flags in flags_list.iter() {
804 let unit = create_default_audiounit(*flags).unwrap();
805 assert!(!unit.is_null());
806 // Destroy the AudioUnits
807 unsafe {
808 AudioUnitUninitialize(unit);
809 AudioComponentInstanceDispose(unit);
810 }
811 }
812 }
813
814 // enable_audiounit_scope
815 // ------------------------------------
816 #[test]
test_enable_audiounit_scope()817 fn test_enable_audiounit_scope() {
818 // It's ok to enable and disable the scopes of input or output
819 // for the unit whose subtype is kAudioUnitSubType_HALOutput
820 // even when there is no available input or output devices.
821 if let Some(unit) = test_create_audiounit(ComponentSubType::HALOutput) {
822 assert!(enable_audiounit_scope(unit.get_inner(), DeviceType::OUTPUT, true).is_ok());
823 assert!(enable_audiounit_scope(unit.get_inner(), DeviceType::OUTPUT, false).is_ok());
824 assert!(enable_audiounit_scope(unit.get_inner(), DeviceType::INPUT, true).is_ok());
825 assert!(enable_audiounit_scope(unit.get_inner(), DeviceType::INPUT, false).is_ok());
826 } else {
827 println!("No audiounit to perform test.");
828 }
829 }
830
831 #[test]
test_enable_audiounit_scope_for_default_output_unit()832 fn test_enable_audiounit_scope_for_default_output_unit() {
833 if let Some(unit) = test_create_audiounit(ComponentSubType::DefaultOutput) {
834 assert_eq!(
835 enable_audiounit_scope(unit.get_inner(), DeviceType::OUTPUT, true).unwrap_err(),
836 kAudioUnitErr_InvalidProperty
837 );
838 assert_eq!(
839 enable_audiounit_scope(unit.get_inner(), DeviceType::OUTPUT, false).unwrap_err(),
840 kAudioUnitErr_InvalidProperty
841 );
842 assert_eq!(
843 enable_audiounit_scope(unit.get_inner(), DeviceType::INPUT, true).unwrap_err(),
844 kAudioUnitErr_InvalidProperty
845 );
846 assert_eq!(
847 enable_audiounit_scope(unit.get_inner(), DeviceType::INPUT, false).unwrap_err(),
848 kAudioUnitErr_InvalidProperty
849 );
850 }
851 }
852
853 #[test]
854 #[should_panic]
test_enable_audiounit_scope_with_null_unit()855 fn test_enable_audiounit_scope_with_null_unit() {
856 let unit: AudioUnit = ptr::null_mut();
857 assert!(enable_audiounit_scope(unit, DeviceType::INPUT, false).is_err());
858 }
859
860 // create_audiounit
861 // ------------------------------------
862 #[test]
test_for_create_audiounit()863 fn test_for_create_audiounit() {
864 let flags_list = [
865 device_flags::DEV_INPUT,
866 device_flags::DEV_OUTPUT,
867 device_flags::DEV_INPUT | device_flags::DEV_SYSTEM_DEFAULT,
868 device_flags::DEV_OUTPUT | device_flags::DEV_SYSTEM_DEFAULT,
869 ];
870
871 let default_input = test_get_default_device(Scope::Input);
872 let default_output = test_get_default_device(Scope::Output);
873
874 for flags in flags_list.iter() {
875 let mut device = device_info::default();
876 device.flags |= *flags;
877
878 // Check the output scope is enabled.
879 if device.flags.contains(device_flags::DEV_OUTPUT) && default_output.is_some() {
880 let device_id = default_output.clone().unwrap();
881 device.id = device_id;
882 let unit = create_audiounit(&device).unwrap();
883 assert!(!unit.is_null());
884 assert!(test_audiounit_scope_is_enabled(unit, Scope::Output));
885
886 // For default output device, the input scope is enabled
887 // if it's also a input device. Otherwise, it's disabled.
888 if device
889 .flags
890 .contains(device_flags::DEV_INPUT | device_flags::DEV_SYSTEM_DEFAULT)
891 {
892 assert_eq!(
893 test_device_in_scope(device_id, Scope::Input),
894 test_audiounit_scope_is_enabled(unit, Scope::Input)
895 );
896
897 // Destroy the audioUnit.
898 unsafe {
899 AudioUnitUninitialize(unit);
900 AudioComponentInstanceDispose(unit);
901 }
902 continue;
903 }
904
905 // Destroy the audioUnit.
906 unsafe {
907 AudioUnitUninitialize(unit);
908 AudioComponentInstanceDispose(unit);
909 }
910 }
911
912 // Check the input scope is enabled.
913 if device.flags.contains(device_flags::DEV_INPUT) && default_input.is_some() {
914 let device_id = default_input.clone().unwrap();
915 device.id = device_id;
916 let unit = create_audiounit(&device).unwrap();
917 assert!(!unit.is_null());
918 assert!(test_audiounit_scope_is_enabled(unit, Scope::Input));
919 // Destroy the audioUnit.
920 unsafe {
921 AudioUnitUninitialize(unit);
922 AudioComponentInstanceDispose(unit);
923 }
924 }
925 }
926 }
927
928 #[test]
929 #[should_panic]
test_create_audiounit_with_unknown_scope()930 fn test_create_audiounit_with_unknown_scope() {
931 let device = device_info::default();
932 let _unit = create_audiounit(&device);
933 }
934
935 // clamp_latency
936 // ------------------------------------
937 #[test]
test_clamp_latency()938 fn test_clamp_latency() {
939 let range = 0..2 * SAFE_MAX_LATENCY_FRAMES;
940 assert!(range.start < SAFE_MIN_LATENCY_FRAMES);
941 // assert!(range.end < SAFE_MAX_LATENCY_FRAMES);
942 for latency_frames in range {
943 let clamp = clamp_latency(latency_frames);
944 assert!(clamp >= SAFE_MIN_LATENCY_FRAMES);
945 assert!(clamp <= SAFE_MAX_LATENCY_FRAMES);
946 }
947 }
948
949 // set_buffer_size_sync
950 // ------------------------------------
951 #[test]
test_set_buffer_size_sync()952 fn test_set_buffer_size_sync() {
953 test_set_buffer_size_by_scope(Scope::Input);
954 test_set_buffer_size_by_scope(Scope::Output);
955 fn test_set_buffer_size_by_scope(scope: Scope) {
956 let unit = test_get_default_audiounit(scope.clone());
957 if unit.is_none() {
958 println!("No audiounit for {:?}.", scope);
959 return;
960 }
961 let unit = unit.unwrap();
962 let prop_scope = match scope {
963 Scope::Input => PropertyScope::Output,
964 Scope::Output => PropertyScope::Input,
965 };
966 let mut buffer_frames = test_audiounit_get_buffer_frame_size(
967 unit.get_inner(),
968 scope.clone(),
969 prop_scope.clone(),
970 )
971 .unwrap();
972 assert_ne!(buffer_frames, 0);
973 buffer_frames *= 2;
974 assert!(
975 set_buffer_size_sync(unit.get_inner(), scope.clone().into(), buffer_frames).is_ok()
976 );
977 let new_buffer_frames =
978 test_audiounit_get_buffer_frame_size(unit.get_inner(), scope.clone(), prop_scope)
979 .unwrap();
980 assert_eq!(buffer_frames, new_buffer_frames);
981 }
982 }
983
984 #[test]
985 #[should_panic]
test_set_buffer_size_sync_for_input_with_null_input_unit()986 fn test_set_buffer_size_sync_for_input_with_null_input_unit() {
987 test_set_buffer_size_sync_by_scope_with_null_unit(Scope::Input);
988 }
989
990 #[test]
991 #[should_panic]
test_set_buffer_size_sync_for_output_with_null_output_unit()992 fn test_set_buffer_size_sync_for_output_with_null_output_unit() {
993 test_set_buffer_size_sync_by_scope_with_null_unit(Scope::Output);
994 }
995
test_set_buffer_size_sync_by_scope_with_null_unit(scope: Scope)996 fn test_set_buffer_size_sync_by_scope_with_null_unit(scope: Scope) {
997 let unit: AudioUnit = ptr::null_mut();
998 assert!(set_buffer_size_sync(unit, scope.into(), 2048).is_err());
999 }
1000
1001 // get_volume, set_volume
1002 // ------------------------------------
1003 #[test]
test_stream_get_volume()1004 fn test_stream_get_volume() {
1005 if let Some(unit) = test_get_default_audiounit(Scope::Output) {
1006 let expected_volume: f32 = 0.5;
1007 set_volume(unit.get_inner(), expected_volume);
1008 assert_eq!(expected_volume, get_volume(unit.get_inner()).unwrap());
1009 } else {
1010 println!("No output audiounit.");
1011 }
1012 }
1013
1014 // convert_uint32_into_string
1015 // ------------------------------------
1016 #[test]
test_convert_uint32_into_string()1017 fn test_convert_uint32_into_string() {
1018 let empty = convert_uint32_into_string(0);
1019 assert_eq!(empty, CString::default());
1020
1021 let data: u32 = ('R' as u32) << 24 | ('U' as u32) << 16 | ('S' as u32) << 8 | 'T' as u32;
1022 let data_string = convert_uint32_into_string(data);
1023 assert_eq!(data_string, CString::new("RUST").unwrap());
1024 }
1025
1026 // get_default_datasource_string
1027 // ------------------------------------
1028 #[test]
test_get_default_device_name()1029 fn test_get_default_device_name() {
1030 test_get_default_device_name_in_scope(Scope::Input);
1031 test_get_default_device_name_in_scope(Scope::Output);
1032
1033 fn test_get_default_device_name_in_scope(scope: Scope) {
1034 if let Some(name) = test_get_default_source_name(scope.clone()) {
1035 let source = audiounit_get_default_datasource_string(scope.into())
1036 .unwrap()
1037 .into_string()
1038 .unwrap();
1039 assert_eq!(name, source);
1040 } else {
1041 println!("No source name for {:?}", scope);
1042 }
1043 }
1044 }
1045
1046 // is_device_a_type_of
1047 // ------------------------------------
1048 #[test]
test_is_device_a_type_of()1049 fn test_is_device_a_type_of() {
1050 test_is_device_in_scope(Scope::Input);
1051 test_is_device_in_scope(Scope::Output);
1052
1053 fn test_is_device_in_scope(scope: Scope) {
1054 if let Some(device) = test_get_default_device(scope.clone()) {
1055 assert!(is_device_a_type_of(device, scope.into()));
1056 } else {
1057 println!("No device for {:?}.", scope);
1058 }
1059 }
1060 }
1061
1062 // get_channel_count
1063 // ------------------------------------
1064 #[test]
test_get_channel_count()1065 fn test_get_channel_count() {
1066 test_channel_count(Scope::Input);
1067 test_channel_count(Scope::Output);
1068
1069 fn test_channel_count(scope: Scope) {
1070 if let Some(device) = test_get_default_device(scope.clone()) {
1071 let channels = get_channel_count(device, DeviceType::from(scope.clone())).unwrap();
1072 assert!(channels > 0);
1073 assert_eq!(
1074 channels,
1075 test_device_channels_in_scope(device, scope).unwrap()
1076 );
1077 } else {
1078 println!("No device for {:?}.", scope);
1079 }
1080 }
1081 }
1082
1083 #[test]
test_get_channel_count_of_input_for_a_output_only_deivce()1084 fn test_get_channel_count_of_input_for_a_output_only_deivce() {
1085 let devices = test_get_devices_in_scope(Scope::Output);
1086 for device in devices {
1087 // Skip in-out devices.
1088 if test_device_in_scope(device, Scope::Input) {
1089 continue;
1090 }
1091 let count = get_channel_count(device, DeviceType::INPUT).unwrap();
1092 assert_eq!(count, 0);
1093 }
1094 }
1095
1096 #[test]
test_get_channel_count_of_output_for_a_input_only_deivce()1097 fn test_get_channel_count_of_output_for_a_input_only_deivce() {
1098 let devices = test_get_devices_in_scope(Scope::Input);
1099 for device in devices {
1100 // Skip in-out devices.
1101 if test_device_in_scope(device, Scope::Output) {
1102 continue;
1103 }
1104 let count = get_channel_count(device, DeviceType::OUTPUT).unwrap();
1105 assert_eq!(count, 0);
1106 }
1107 }
1108
1109 #[test]
1110 #[should_panic]
test_get_channel_count_of_unknown_device()1111 fn test_get_channel_count_of_unknown_device() {
1112 assert_eq!(
1113 get_channel_count(kAudioObjectUnknown, DeviceType::OUTPUT).unwrap_err(),
1114 Error::error()
1115 );
1116 }
1117
1118 #[test]
test_get_channel_count_of_inout_type()1119 fn test_get_channel_count_of_inout_type() {
1120 test_channel_count(Scope::Input);
1121 test_channel_count(Scope::Output);
1122
1123 fn test_channel_count(scope: Scope) {
1124 if let Some(device) = test_get_default_device(scope.clone()) {
1125 assert_eq!(
1126 // Get a kAudioHardwareUnknownPropertyError in get_channel_count actually.
1127 get_channel_count(device, DeviceType::INPUT | DeviceType::OUTPUT).unwrap_err(),
1128 Error::error()
1129 );
1130 } else {
1131 println!("No device for {:?}.", scope);
1132 }
1133 }
1134 }
1135
1136 #[test]
1137 #[should_panic]
test_get_channel_count_of_unknwon_type()1138 fn test_get_channel_count_of_unknwon_type() {
1139 test_channel_count(Scope::Input);
1140 test_channel_count(Scope::Output);
1141
1142 fn test_channel_count(scope: Scope) {
1143 if let Some(device) = test_get_default_device(scope.clone()) {
1144 assert_eq!(
1145 get_channel_count(device, DeviceType::UNKNOWN).unwrap_err(),
1146 Error::error()
1147 );
1148 } else {
1149 panic!("Panic by default: No device for {:?}.", scope);
1150 }
1151 }
1152 }
1153
1154 // get_range_of_sample_rates
1155 // ------------------------------------
1156 #[test]
test_get_range_of_sample_rates()1157 fn test_get_range_of_sample_rates() {
1158 test_get_range_of_sample_rates_in_scope(Scope::Input);
1159 test_get_range_of_sample_rates_in_scope(Scope::Output);
1160
1161 fn test_get_range_of_sample_rates_in_scope(scope: Scope) {
1162 if let Some(device) = test_get_default_device(scope.clone()) {
1163 let ranges = test_get_available_samplerate_of_device(device);
1164 for range in ranges {
1165 // Surprisingly, we can get the input/output sample rates from a non-input/non-output device.
1166 check_samplerates(range);
1167 }
1168 } else {
1169 println!("No device for {:?}.", scope);
1170 }
1171 }
1172
1173 fn test_get_available_samplerate_of_device(id: AudioObjectID) -> Vec<(f64, f64)> {
1174 let scopes = [
1175 DeviceType::INPUT,
1176 DeviceType::OUTPUT,
1177 DeviceType::INPUT | DeviceType::OUTPUT,
1178 ];
1179 let mut ranges = Vec::new();
1180 for scope in scopes.iter() {
1181 ranges.push(get_range_of_sample_rates(id, *scope).unwrap());
1182 }
1183 ranges
1184 }
1185
1186 fn check_samplerates((min, max): (f64, f64)) {
1187 assert!(min > 0.0);
1188 assert!(max > 0.0);
1189 assert!(min <= max);
1190 }
1191 }
1192
1193 // get_presentation_latency
1194 // ------------------------------------
1195 #[test]
test_get_device_presentation_latency()1196 fn test_get_device_presentation_latency() {
1197 test_get_device_presentation_latencies_in_scope(Scope::Input);
1198 test_get_device_presentation_latencies_in_scope(Scope::Output);
1199
1200 fn test_get_device_presentation_latencies_in_scope(scope: Scope) {
1201 if let Some(device) = test_get_default_device(scope.clone()) {
1202 // TODO: The latencies very from devices to devices. Check nothing here.
1203 let latency = get_fixed_latency(device, scope.clone().into());
1204 println!(
1205 "present latency on the device {} in scope {:?}: {}",
1206 device, scope, latency
1207 );
1208 } else {
1209 println!("No device for {:?}.", scope);
1210 }
1211 }
1212 }
1213
1214 // get_device_group_id
1215 // ------------------------------------
1216 #[test]
test_get_device_group_id()1217 fn test_get_device_group_id() {
1218 if let Some(device) = test_get_default_device(Scope::Input) {
1219 match get_device_group_id(device, DeviceType::INPUT) {
1220 Ok(id) => println!("input group id: {:?}", id),
1221 Err(e) => println!("No input group id. Error: {}", e),
1222 }
1223 } else {
1224 println!("No input device.");
1225 }
1226
1227 if let Some(device) = test_get_default_device(Scope::Output) {
1228 match get_device_group_id(device, DeviceType::OUTPUT) {
1229 Ok(id) => println!("output group id: {:?}", id),
1230 Err(e) => println!("No output group id. Error: {}", e),
1231 }
1232 } else {
1233 println!("No output device.");
1234 }
1235 }
1236
1237 #[test]
test_get_same_group_id_for_builtin_device_pairs()1238 fn test_get_same_group_id_for_builtin_device_pairs() {
1239 use std::collections::HashMap;
1240
1241 // These device sources have custom group id. See `get_custom_group_id`.
1242 const IMIC: u32 = 0x696D_6963; // "imic"
1243 const ISPK: u32 = 0x6973_706B; // "ispk"
1244 const EMIC: u32 = 0x656D_6963; // "emic"
1245 const HDPN: u32 = 0x6864_706E; // "hdpn"
1246 let pairs = [(IMIC, ISPK), (EMIC, HDPN)];
1247
1248 let mut input_group_ids = HashMap::<u32, String>::new();
1249 let input_devices = test_get_devices_in_scope(Scope::Input);
1250 for device in input_devices.iter() {
1251 match get_device_source(*device, DeviceType::INPUT) {
1252 Ok(source) => match get_device_group_id(*device, DeviceType::INPUT) {
1253 Ok(id) => assert!(input_group_ids
1254 .insert(source, id.into_string().unwrap())
1255 .is_none()),
1256 Err(e) => assert!(input_group_ids
1257 .insert(source, format!("Error {}", e))
1258 .is_none()),
1259 },
1260 _ => {} // do nothing when failing to get source.
1261 }
1262 }
1263
1264 let mut output_group_ids = HashMap::<u32, String>::new();
1265 let output_devices = test_get_devices_in_scope(Scope::Output);
1266 for device in output_devices.iter() {
1267 match get_device_source(*device, DeviceType::OUTPUT) {
1268 Ok(source) => match get_device_group_id(*device, DeviceType::OUTPUT) {
1269 Ok(id) => assert!(output_group_ids
1270 .insert(source, id.into_string().unwrap())
1271 .is_none()),
1272 Err(e) => assert!(output_group_ids
1273 .insert(source, format!("Error {}", e))
1274 .is_none()),
1275 },
1276 _ => {} // do nothing when failing to get source.
1277 }
1278 }
1279
1280 for (input, output) in pairs.iter() {
1281 let input_group_id = input_group_ids.get(input);
1282 let output_group_id = output_group_ids.get(output);
1283
1284 if input_group_id.is_some() && output_group_id.is_some() {
1285 assert_eq!(input_group_id, output_group_id);
1286 }
1287
1288 input_group_ids.remove(input);
1289 output_group_ids.remove(output);
1290 }
1291 }
1292
1293 #[test]
1294 #[should_panic]
test_get_device_group_id_by_unknown_device()1295 fn test_get_device_group_id_by_unknown_device() {
1296 assert!(get_device_group_id(kAudioObjectUnknown, DeviceType::INPUT).is_err());
1297 }
1298
1299 // get_device_label
1300 // ------------------------------------
1301 #[test]
test_get_device_label()1302 fn test_get_device_label() {
1303 if let Some(device) = test_get_default_device(Scope::Input) {
1304 let name = get_device_label(device, DeviceType::INPUT).unwrap();
1305 println!("input device label: {}", name.into_string());
1306 } else {
1307 println!("No input device.");
1308 }
1309
1310 if let Some(device) = test_get_default_device(Scope::Output) {
1311 let name = get_device_label(device, DeviceType::OUTPUT).unwrap();
1312 println!("output device label: {}", name.into_string());
1313 } else {
1314 println!("No output device.");
1315 }
1316 }
1317
1318 #[test]
1319 #[should_panic]
test_get_device_label_by_unknown_device()1320 fn test_get_device_label_by_unknown_device() {
1321 assert!(get_device_label(kAudioObjectUnknown, DeviceType::INPUT).is_err());
1322 }
1323
1324 // get_device_global_uid
1325 // ------------------------------------
1326 #[test]
test_get_device_global_uid()1327 fn test_get_device_global_uid() {
1328 // Input device.
1329 if let Some(input) = test_get_default_device(Scope::Input) {
1330 let uid = get_device_global_uid(input).unwrap();
1331 let uid = uid.into_string();
1332 assert!(!uid.is_empty());
1333 }
1334
1335 // Output device.
1336 if let Some(output) = test_get_default_device(Scope::Output) {
1337 let uid = get_device_global_uid(output).unwrap();
1338 let uid = uid.into_string();
1339 assert!(!uid.is_empty());
1340 }
1341 }
1342
1343 #[test]
1344 #[should_panic]
test_get_device_global_uid_by_unknwon_device()1345 fn test_get_device_global_uid_by_unknwon_device() {
1346 // Unknown device.
1347 assert!(get_device_global_uid(kAudioObjectUnknown).is_err());
1348 }
1349
1350 // create_cubeb_device_info
1351 // destroy_cubeb_device_info
1352 // ------------------------------------
1353 #[test]
test_create_cubeb_device_info()1354 fn test_create_cubeb_device_info() {
1355 use std::collections::VecDeque;
1356
1357 test_create_device_from_hwdev_in_scope(Scope::Input);
1358 test_create_device_from_hwdev_in_scope(Scope::Output);
1359
1360 fn test_create_device_from_hwdev_in_scope(scope: Scope) {
1361 if let Some(device) = test_get_default_device(scope.clone()) {
1362 let is_input = test_device_in_scope(device, Scope::Input);
1363 let is_output = test_device_in_scope(device, Scope::Output);
1364 let mut results = test_create_device_infos_by_device(device);
1365 assert_eq!(results.len(), 2);
1366 // Input device type:
1367 let input_result = results.pop_front().unwrap();
1368 if is_input {
1369 let mut input_device_info = input_result.unwrap();
1370 check_device_info_by_device(&input_device_info, device, Scope::Input);
1371 destroy_cubeb_device_info(&mut input_device_info);
1372 } else {
1373 assert_eq!(input_result.unwrap_err(), Error::error());
1374 }
1375 // Output device type:
1376 let output_result = results.pop_front().unwrap();
1377 if is_output {
1378 let mut output_device_info = output_result.unwrap();
1379 check_device_info_by_device(&output_device_info, device, Scope::Output);
1380 destroy_cubeb_device_info(&mut output_device_info);
1381 } else {
1382 assert_eq!(output_result.unwrap_err(), Error::error());
1383 }
1384 } else {
1385 println!("No device for {:?}.", scope);
1386 }
1387 }
1388
1389 fn test_create_device_infos_by_device(
1390 id: AudioObjectID,
1391 ) -> VecDeque<std::result::Result<ffi::cubeb_device_info, Error>> {
1392 let dev_types = [DeviceType::INPUT, DeviceType::OUTPUT];
1393 let mut results = VecDeque::new();
1394 for dev_type in dev_types.iter() {
1395 results.push_back(create_cubeb_device_info(id, *dev_type));
1396 }
1397 results
1398 }
1399
1400 fn check_device_info_by_device(info: &ffi::cubeb_device_info, id: AudioObjectID, scope: Scope) {
1401 assert!(!info.devid.is_null());
1402 assert!(mem::size_of_val(&info.devid) >= mem::size_of::<AudioObjectID>());
1403 assert_eq!(info.devid as AudioObjectID, id);
1404 assert!(!info.device_id.is_null());
1405 assert!(!info.friendly_name.is_null());
1406 assert!(!info.group_id.is_null());
1407
1408 // TODO: Hit a kAudioHardwareUnknownPropertyError for AirPods
1409 // assert!(!info.vendor_name.is_null());
1410
1411 // FIXIT: The device is defined to input-only or output-only, but some device is in-out!
1412 assert_eq!(info.device_type, DeviceType::from(scope.clone()).bits());
1413 assert_eq!(info.state, ffi::CUBEB_DEVICE_STATE_ENABLED);
1414 // TODO: The preference is set when the device is default input/output device if the device
1415 // info is created from input/output scope. Should the preference be set if the
1416 // device is a default input/output device if the device info is created from
1417 // output/input scope ? The device may be a in-out device!
1418 assert_eq!(info.preferred, get_cubeb_device_pref(id, scope));
1419
1420 assert_eq!(info.format, ffi::CUBEB_DEVICE_FMT_ALL);
1421 assert_eq!(info.default_format, ffi::CUBEB_DEVICE_FMT_F32NE);
1422 assert!(info.max_channels > 0);
1423 assert!(info.min_rate <= info.max_rate);
1424 assert!(info.min_rate <= info.default_rate);
1425 assert!(info.default_rate <= info.max_rate);
1426
1427 assert!(info.latency_lo > 0);
1428 assert!(info.latency_hi > 0);
1429 assert!(info.latency_lo <= info.latency_hi);
1430
1431 fn get_cubeb_device_pref(id: AudioObjectID, scope: Scope) -> ffi::cubeb_device_pref {
1432 let default_device = test_get_default_device(scope);
1433 if default_device.is_some() && default_device.unwrap() == id {
1434 ffi::CUBEB_DEVICE_PREF_ALL
1435 } else {
1436 ffi::CUBEB_DEVICE_PREF_NONE
1437 }
1438 }
1439 }
1440 }
1441
1442 #[test]
1443 #[should_panic]
test_create_device_info_by_unknown_device()1444 fn test_create_device_info_by_unknown_device() {
1445 assert!(create_cubeb_device_info(kAudioObjectUnknown, DeviceType::OUTPUT).is_err());
1446 }
1447
1448 #[test]
1449 #[should_panic]
test_create_device_info_with_unknown_type()1450 fn test_create_device_info_with_unknown_type() {
1451 test_create_device_info_with_unknown_type_by_scope(Scope::Input);
1452 test_create_device_info_with_unknown_type_by_scope(Scope::Output);
1453
1454 fn test_create_device_info_with_unknown_type_by_scope(scope: Scope) {
1455 if let Some(device) = test_get_default_device(scope.clone()) {
1456 assert!(create_cubeb_device_info(device, DeviceType::UNKNOWN).is_err());
1457 } else {
1458 panic!("Panic by default: No device for {:?}.", scope);
1459 }
1460 }
1461 }
1462
1463 #[test]
1464 #[should_panic]
test_device_destroy_empty_device()1465 fn test_device_destroy_empty_device() {
1466 let mut device = ffi::cubeb_device_info::default();
1467
1468 assert!(device.device_id.is_null());
1469 assert!(device.group_id.is_null());
1470 assert!(device.friendly_name.is_null());
1471 assert!(device.vendor_name.is_null());
1472
1473 // `friendly_name` must be set.
1474 destroy_cubeb_device_info(&mut device);
1475
1476 assert!(device.device_id.is_null());
1477 assert!(device.group_id.is_null());
1478 assert!(device.friendly_name.is_null());
1479 assert!(device.vendor_name.is_null());
1480 }
1481
1482 #[test]
test_create_device_from_hwdev_with_inout_type()1483 fn test_create_device_from_hwdev_with_inout_type() {
1484 test_create_device_from_hwdev_with_inout_type_by_scope(Scope::Input);
1485 test_create_device_from_hwdev_with_inout_type_by_scope(Scope::Output);
1486
1487 fn test_create_device_from_hwdev_with_inout_type_by_scope(scope: Scope) {
1488 if let Some(device) = test_get_default_device(scope.clone()) {
1489 // Get a kAudioHardwareUnknownPropertyError in get_channel_count actually.
1490 assert!(
1491 create_cubeb_device_info(device, DeviceType::INPUT | DeviceType::OUTPUT).is_err()
1492 );
1493 } else {
1494 println!("No device for {:?}.", scope);
1495 }
1496 }
1497 }
1498
1499 // is_aggregate_device
1500 // ------------------------------------
1501 #[test]
test_is_aggregate_device()1502 fn test_is_aggregate_device() {
1503 let mut aggregate_name = String::from(PRIVATE_AGGREGATE_DEVICE_NAME);
1504 aggregate_name.push_str("_something");
1505 let aggregate_name_cstring = CString::new(aggregate_name).unwrap();
1506
1507 let mut info = ffi::cubeb_device_info::default();
1508 info.friendly_name = aggregate_name_cstring.as_ptr();
1509 assert!(is_aggregate_device(&info));
1510
1511 let non_aggregate_name_cstring = CString::new("Hello World!").unwrap();
1512 info.friendly_name = non_aggregate_name_cstring.as_ptr();
1513 assert!(!is_aggregate_device(&info));
1514 }
1515
1516 // get_devices_of_type
1517 // ------------------------------------
1518 #[test]
test_get_devices_of_type()1519 fn test_get_devices_of_type() {
1520 use std::collections::HashSet;
1521
1522 let all_devices = audiounit_get_devices_of_type(DeviceType::INPUT | DeviceType::OUTPUT);
1523 let input_devices = audiounit_get_devices_of_type(DeviceType::INPUT);
1524 let output_devices = audiounit_get_devices_of_type(DeviceType::OUTPUT);
1525
1526 let mut expected_all = test_get_all_devices();
1527 expected_all.sort();
1528 assert_eq!(all_devices, expected_all);
1529 for device in all_devices.iter() {
1530 if test_device_in_scope(*device, Scope::Input) {
1531 assert!(input_devices.contains(device));
1532 }
1533 if test_device_in_scope(*device, Scope::Output) {
1534 assert!(output_devices.contains(device));
1535 }
1536 }
1537
1538 let input: HashSet<AudioObjectID> = input_devices.iter().cloned().collect();
1539 let output: HashSet<AudioObjectID> = output_devices.iter().cloned().collect();
1540 let union: HashSet<AudioObjectID> = input.union(&output).cloned().collect();
1541 let mut union_devices: Vec<AudioObjectID> = union.iter().cloned().collect();
1542 union_devices.sort();
1543 assert_eq!(all_devices, union_devices);
1544 }
1545
1546 #[test]
1547 #[should_panic]
test_get_devices_of_type_unknown()1548 fn test_get_devices_of_type_unknown() {
1549 let no_devs = audiounit_get_devices_of_type(DeviceType::UNKNOWN);
1550 assert!(no_devs.is_empty());
1551 }
1552
1553 // add_devices_changed_listener
1554 // ------------------------------------
1555 #[test]
test_add_devices_changed_listener()1556 fn test_add_devices_changed_listener() {
1557 use std::collections::HashMap;
1558
1559 extern "C" fn inout_callback(_: *mut ffi::cubeb, _: *mut c_void) {}
1560 extern "C" fn in_callback(_: *mut ffi::cubeb, _: *mut c_void) {}
1561 extern "C" fn out_callback(_: *mut ffi::cubeb, _: *mut c_void) {}
1562
1563 let mut map: HashMap<DeviceType, extern "C" fn(*mut ffi::cubeb, *mut c_void)> = HashMap::new();
1564 map.insert(DeviceType::INPUT, in_callback);
1565 map.insert(DeviceType::OUTPUT, out_callback);
1566 map.insert(DeviceType::INPUT | DeviceType::OUTPUT, inout_callback);
1567
1568 test_get_raw_context(|context| {
1569 for (devtype, callback) in map.iter() {
1570 assert!(get_devices_changed_callback(context, Scope::Input).is_none());
1571 assert!(get_devices_changed_callback(context, Scope::Output).is_none());
1572
1573 // Register a callback within a specific scope.
1574 assert!(context
1575 .add_devices_changed_listener(*devtype, Some(*callback), ptr::null_mut())
1576 .is_ok());
1577
1578 if devtype.contains(DeviceType::INPUT) {
1579 let cb = get_devices_changed_callback(context, Scope::Input);
1580 assert!(cb.is_some());
1581 assert_eq!(cb.unwrap(), *callback);
1582 } else {
1583 let cb = get_devices_changed_callback(context, Scope::Input);
1584 assert!(cb.is_none());
1585 }
1586
1587 if devtype.contains(DeviceType::OUTPUT) {
1588 let cb = get_devices_changed_callback(context, Scope::Output);
1589 assert!(cb.is_some());
1590 assert_eq!(cb.unwrap(), *callback);
1591 } else {
1592 let cb = get_devices_changed_callback(context, Scope::Output);
1593 assert!(cb.is_none());
1594 }
1595
1596 // Unregister the callbacks within all scopes.
1597 assert!(context
1598 .remove_devices_changed_listener(DeviceType::INPUT | DeviceType::OUTPUT)
1599 .is_ok());
1600
1601 assert!(get_devices_changed_callback(context, Scope::Input).is_none());
1602 assert!(get_devices_changed_callback(context, Scope::Output).is_none());
1603 }
1604 });
1605 }
1606
1607 #[test]
1608 #[should_panic]
test_add_devices_changed_listener_in_unknown_scope()1609 fn test_add_devices_changed_listener_in_unknown_scope() {
1610 extern "C" fn callback(_: *mut ffi::cubeb, _: *mut c_void) {}
1611
1612 test_get_raw_context(|context| {
1613 let _ = context.add_devices_changed_listener(
1614 DeviceType::UNKNOWN,
1615 Some(callback),
1616 ptr::null_mut(),
1617 );
1618 });
1619 }
1620
1621 #[test]
1622 #[should_panic]
test_add_devices_changed_listener_with_none_callback()1623 fn test_add_devices_changed_listener_with_none_callback() {
1624 test_get_raw_context(|context| {
1625 for devtype in &[DeviceType::INPUT, DeviceType::OUTPUT] {
1626 assert!(context
1627 .add_devices_changed_listener(*devtype, None, ptr::null_mut())
1628 .is_ok());
1629 }
1630 });
1631 }
1632
1633 // remove_devices_changed_listener
1634 // ------------------------------------
1635 #[test]
test_remove_devices_changed_listener()1636 fn test_remove_devices_changed_listener() {
1637 use std::collections::HashMap;
1638
1639 extern "C" fn in_callback(_: *mut ffi::cubeb, _: *mut c_void) {}
1640 extern "C" fn out_callback(_: *mut ffi::cubeb, _: *mut c_void) {}
1641
1642 let mut map: HashMap<DeviceType, extern "C" fn(*mut ffi::cubeb, *mut c_void)> = HashMap::new();
1643 map.insert(DeviceType::INPUT, in_callback);
1644 map.insert(DeviceType::OUTPUT, out_callback);
1645
1646 test_get_raw_context(|context| {
1647 for (devtype, _callback) in map.iter() {
1648 assert!(get_devices_changed_callback(context, Scope::Input).is_none());
1649 assert!(get_devices_changed_callback(context, Scope::Output).is_none());
1650
1651 // Register callbacks within all scopes.
1652 for (scope, listener) in map.iter() {
1653 assert!(context
1654 .add_devices_changed_listener(*scope, Some(*listener), ptr::null_mut())
1655 .is_ok());
1656 }
1657
1658 let input_callback = get_devices_changed_callback(context, Scope::Input);
1659 assert!(input_callback.is_some());
1660 assert_eq!(
1661 input_callback.unwrap(),
1662 *(map.get(&DeviceType::INPUT).unwrap())
1663 );
1664 let output_callback = get_devices_changed_callback(context, Scope::Output);
1665 assert!(output_callback.is_some());
1666 assert_eq!(
1667 output_callback.unwrap(),
1668 *(map.get(&DeviceType::OUTPUT).unwrap())
1669 );
1670
1671 // Unregister the callbacks within one specific scopes.
1672 assert!(context.remove_devices_changed_listener(*devtype).is_ok());
1673
1674 if devtype.contains(DeviceType::INPUT) {
1675 let cb = get_devices_changed_callback(context, Scope::Input);
1676 assert!(cb.is_none());
1677 } else {
1678 let cb = get_devices_changed_callback(context, Scope::Input);
1679 assert!(cb.is_some());
1680 assert_eq!(cb.unwrap(), *(map.get(&DeviceType::INPUT).unwrap()));
1681 }
1682
1683 if devtype.contains(DeviceType::OUTPUT) {
1684 let cb = get_devices_changed_callback(context, Scope::Output);
1685 assert!(cb.is_none());
1686 } else {
1687 let cb = get_devices_changed_callback(context, Scope::Output);
1688 assert!(cb.is_some());
1689 assert_eq!(cb.unwrap(), *(map.get(&DeviceType::OUTPUT).unwrap()));
1690 }
1691
1692 // Unregister the callbacks within all scopes.
1693 assert!(context
1694 .remove_devices_changed_listener(DeviceType::INPUT | DeviceType::OUTPUT)
1695 .is_ok());
1696 }
1697 });
1698 }
1699
1700 #[test]
test_remove_devices_changed_listener_without_adding_listeners()1701 fn test_remove_devices_changed_listener_without_adding_listeners() {
1702 test_get_raw_context(|context| {
1703 for devtype in &[
1704 DeviceType::INPUT,
1705 DeviceType::OUTPUT,
1706 DeviceType::INPUT | DeviceType::OUTPUT,
1707 ] {
1708 assert!(context.remove_devices_changed_listener(*devtype).is_ok());
1709 }
1710 });
1711 }
1712
1713 #[test]
test_remove_devices_changed_listener_within_all_scopes()1714 fn test_remove_devices_changed_listener_within_all_scopes() {
1715 use std::collections::HashMap;
1716
1717 extern "C" fn inout_callback(_: *mut ffi::cubeb, _: *mut c_void) {}
1718 extern "C" fn in_callback(_: *mut ffi::cubeb, _: *mut c_void) {}
1719 extern "C" fn out_callback(_: *mut ffi::cubeb, _: *mut c_void) {}
1720
1721 let mut map: HashMap<DeviceType, extern "C" fn(*mut ffi::cubeb, *mut c_void)> = HashMap::new();
1722 map.insert(DeviceType::INPUT, in_callback);
1723 map.insert(DeviceType::OUTPUT, out_callback);
1724 map.insert(DeviceType::INPUT | DeviceType::OUTPUT, inout_callback);
1725
1726 test_get_raw_context(|context| {
1727 for (devtype, callback) in map.iter() {
1728 assert!(get_devices_changed_callback(context, Scope::Input).is_none());
1729 assert!(get_devices_changed_callback(context, Scope::Output).is_none());
1730
1731 assert!(context
1732 .add_devices_changed_listener(*devtype, Some(*callback), ptr::null_mut())
1733 .is_ok());
1734
1735 if devtype.contains(DeviceType::INPUT) {
1736 let cb = get_devices_changed_callback(context, Scope::Input);
1737 assert!(cb.is_some());
1738 assert_eq!(cb.unwrap(), *callback);
1739 }
1740
1741 if devtype.contains(DeviceType::OUTPUT) {
1742 let cb = get_devices_changed_callback(context, Scope::Output);
1743 assert!(cb.is_some());
1744 assert_eq!(cb.unwrap(), *callback);
1745 }
1746
1747 assert!(context
1748 .remove_devices_changed_listener(DeviceType::INPUT | DeviceType::OUTPUT)
1749 .is_ok());
1750
1751 assert!(get_devices_changed_callback(context, Scope::Input).is_none());
1752 assert!(get_devices_changed_callback(context, Scope::Output).is_none());
1753 }
1754 });
1755 }
1756
get_devices_changed_callback( context: &AudioUnitContext, scope: Scope, ) -> ffi::cubeb_device_collection_changed_callback1757 fn get_devices_changed_callback(
1758 context: &AudioUnitContext,
1759 scope: Scope,
1760 ) -> ffi::cubeb_device_collection_changed_callback {
1761 let devices_guard = context.devices.lock().unwrap();
1762 match scope {
1763 Scope::Input => devices_guard.input.changed_callback,
1764 Scope::Output => devices_guard.output.changed_callback,
1765 }
1766 }
1767