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(&params).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