@@ -4,6 +4,7 @@ use std::collections::VecDeque;
4
4
use std:: ffi:: CStr ;
5
5
use std:: os:: raw:: { c_char, c_void} ;
6
6
use std:: ptr:: null;
7
+ use std:: sync:: atomic:: { AtomicBool , Ordering } ;
7
8
use std:: sync:: mpsc:: { channel, Sender } ;
8
9
use std:: sync:: Mutex ;
9
10
use std:: time:: Duration ;
@@ -12,12 +13,12 @@ use std::{mem, slice, thread};
12
13
use core_foundation_sys:: string:: { CFStringGetCString , CFStringGetCStringPtr , CFStringRef } ;
13
14
use sys;
14
15
use sys:: {
15
- kAudioDevicePropertyAvailableNominalSampleRates, kAudioDevicePropertyDeviceNameCFString,
16
- kAudioDevicePropertyNominalSampleRate, kAudioDevicePropertyScopeOutput, kAudioHardwareNoError,
16
+ kAudioDevicePropertyAvailableNominalSampleRates, kAudioDevicePropertyDeviceIsAlive,
17
+ kAudioDevicePropertyDeviceNameCFString, kAudioDevicePropertyNominalSampleRate,
18
+ kAudioDevicePropertyScopeOutput, kAudioHardwareNoError,
17
19
kAudioHardwarePropertyDefaultInputDevice, kAudioHardwarePropertyDefaultOutputDevice,
18
20
kAudioHardwarePropertyDevices, kAudioObjectPropertyElementMaster,
19
- kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyScopeInput,
20
- kAudioObjectPropertyScopeOutput, kAudioObjectSystemObject,
21
+ kAudioObjectPropertyScopeGlobal, kAudioObjectSystemObject,
21
22
kAudioOutputUnitProperty_CurrentDevice, kAudioOutputUnitProperty_EnableIO,
22
23
kAudioStreamPropertyAvailablePhysicalFormats, kAudioStreamPropertyPhysicalFormat,
23
24
kCFStringEncodingUTF8, AudioDeviceID , AudioObjectAddPropertyListener ,
@@ -67,11 +68,10 @@ pub fn get_device_id_from_name(name: &str) -> Option<AudioDeviceID> {
67
68
if let Ok ( all_ids) = get_audio_device_ids ( ) {
68
69
return all_ids
69
70
. iter ( )
70
- . find ( |id| get_device_name ( * * id) . unwrap_or ( "" . to_string ( ) ) == name)
71
- . map ( |id| * id) ;
72
- } else {
73
- return None ;
71
+ . find ( |id| get_device_name ( * * id) . unwrap_or_else ( |_| "" . to_string ( ) ) == name)
72
+ . copied ( ) ;
74
73
}
74
+ None
75
75
}
76
76
77
77
/// Create an AudioUnit instance from a device id.
@@ -305,31 +305,17 @@ pub fn set_device_sample_rate(device_id: AudioDeviceID, new_rate: f64) -> Result
305
305
306
306
// Wait for the reported_rate to change.
307
307
//
308
- // This should not take longer than a few ms, but we timeout after 1 sec just in case .
308
+ // This sometimes takes up to half a second, timeout after 2 sec to have a little margin .
309
309
let timer = :: std:: time:: Instant :: now ( ) ;
310
310
loop {
311
- println ! ( "waiting for rate change" ) ;
312
311
if let Ok ( reported_rate) = receiver. recv_timeout ( Duration :: from_millis ( 100 ) ) {
313
- println ! ( "got rate change event" ) ;
314
312
if new_rate as usize == reported_rate as usize {
315
- println ! ( "rate was updated!" ) ;
316
313
break ;
317
314
}
318
315
}
319
- /*
320
- if listener.get_nbr_values() > 0 {
321
- if let Some(reported_rate) = listener.copy_values().last() {
322
- if new_rate as usize == *reported_rate as usize {
323
- println!("rate was updated!");
324
- break;
325
- }
326
- }
327
- }
328
- */
329
- if timer. elapsed ( ) > Duration :: from_secs ( 1 ) {
316
+ if timer. elapsed ( ) > Duration :: from_secs ( 2 ) {
330
317
return Err ( Error :: UnsupportedSampleRate ) ;
331
318
}
332
- //thread::sleep(Duration::from_millis(5));
333
319
}
334
320
} ;
335
321
Ok ( ( ) )
@@ -348,9 +334,6 @@ pub fn set_device_sample_format(
348
334
let property_address = AudioObjectPropertyAddress {
349
335
mSelector : kAudioStreamPropertyPhysicalFormat,
350
336
mScope : kAudioObjectPropertyScopeGlobal,
351
- //mScope: kAudioDevicePropertyScopeInput,
352
- //mScope: kAudioObjectPropertyScopeOutput,
353
- //mScope: kAudioDevicePropertyScopeOutput,
354
337
mElement : kAudioObjectPropertyElementMaster,
355
338
} ;
356
339
let maybe_asbd: mem:: MaybeUninit < AudioStreamBasicDescription > = mem:: MaybeUninit :: zeroed ( ) ;
@@ -365,9 +348,6 @@ pub fn set_device_sample_format(
365
348
) ;
366
349
Error :: from_os_status ( status) ?;
367
350
let asbd = maybe_asbd. assume_init ( ) ;
368
- println ! ( "---- Current format ----" ) ;
369
- println ! ( "{:#?}" , asbd) ;
370
- //println!("{:#?}", StreamFormat::from_asbd(asbd).unwrap());
371
351
372
352
// If the requested sample rate and/or format is different to the device sample rate, update the device.
373
353
if !asbds_are_equal ( & asbd, & new_asbd) {
@@ -394,7 +374,6 @@ pub fn set_device_sample_format(
394
374
// Wait for the reported format to change.
395
375
//
396
376
// This should not take longer than a few ms, but we timeout after 1 sec just in case.
397
- println ! ( "{:#?}" , reported_asbd) ;
398
377
let timer = :: std:: time:: Instant :: now ( ) ;
399
378
loop {
400
379
let status = AudioObjectGetPropertyData (
@@ -409,13 +388,11 @@ pub fn set_device_sample_format(
409
388
if asbds_are_equal ( & reported_asbd, & new_asbd) {
410
389
break ;
411
390
}
412
- println ! ( "spinning" ) ;
413
391
thread:: sleep ( Duration :: from_millis ( 5 ) ) ;
414
392
if timer. elapsed ( ) > Duration :: from_secs ( 1 ) {
415
393
return Err ( Error :: UnsupportedSampleRate ) ;
416
394
}
417
395
}
418
- println ! ( "{:#?}" , reported_asbd) ;
419
396
}
420
397
Ok ( ( ) )
421
398
}
@@ -503,7 +480,6 @@ pub struct RateListener {
503
480
504
481
impl Drop for RateListener {
505
482
fn drop ( & mut self ) {
506
- println ! ( "Dropping RateListener!" ) ;
507
483
let _ = self . unregister ( ) ;
508
484
}
509
485
}
@@ -619,3 +595,105 @@ impl RateListener {
619
595
self . queue . lock ( ) . unwrap ( ) . drain ( ..) . collect :: < Vec < f64 > > ( )
620
596
}
621
597
}
598
+
599
+ /// Use an AliveListener to get notified when a device is disconnected.
600
+ /// Only implemented for macOS, not iOS.
601
+ pub struct AliveListener {
602
+ alive : AtomicBool ,
603
+ device_id : AudioDeviceID ,
604
+ property_address : AudioObjectPropertyAddress ,
605
+ alive_listener : Option <
606
+ unsafe extern "C" fn ( u32 , u32 , * const AudioObjectPropertyAddress , * mut c_void ) -> i32 ,
607
+ > ,
608
+ }
609
+
610
+ impl Drop for AliveListener {
611
+ fn drop ( & mut self ) {
612
+ let _ = self . unregister ( ) ;
613
+ }
614
+ }
615
+
616
+ impl AliveListener {
617
+ /// Create a new ErrorListener for the given AudioDeviceID.
618
+ /// If a sync Sender is provided, then events will be pushed to that channel.
619
+ /// If not, they will be stored in an internal queue that will need to be polled.
620
+ pub fn new ( device_id : AudioDeviceID ) -> Result < AliveListener , Error > {
621
+ // Add our error listener callback.
622
+ let property_address = AudioObjectPropertyAddress {
623
+ mSelector : kAudioDevicePropertyDeviceIsAlive,
624
+ mScope : kAudioObjectPropertyScopeGlobal,
625
+ mElement : kAudioObjectPropertyElementMaster,
626
+ } ;
627
+ Ok ( AliveListener {
628
+ alive : AtomicBool :: new ( true ) ,
629
+ device_id,
630
+ property_address,
631
+ alive_listener : None ,
632
+ } )
633
+ }
634
+
635
+ /// Register this listener to receive notifications.
636
+ pub fn register ( & mut self ) -> Result < ( ) , Error > {
637
+ unsafe extern "C" fn alive_listener (
638
+ device_id : AudioObjectID ,
639
+ _n_addresses : u32 ,
640
+ _properties : * const AudioObjectPropertyAddress ,
641
+ self_ptr : * mut :: std:: os:: raw:: c_void ,
642
+ ) -> OSStatus {
643
+ let self_ptr: & mut AliveListener = & mut * ( self_ptr as * mut AliveListener ) ;
644
+ let alive: u32 = 0 ;
645
+ let data_size = mem:: size_of :: < u32 > ( ) ;
646
+ let property_address = AudioObjectPropertyAddress {
647
+ mSelector : kAudioDevicePropertyDeviceIsAlive,
648
+ mScope : kAudioObjectPropertyScopeGlobal,
649
+ mElement : kAudioObjectPropertyElementMaster,
650
+ } ;
651
+ let result = AudioObjectGetPropertyData (
652
+ device_id,
653
+ & property_address as * const _ ,
654
+ 0 ,
655
+ null ( ) ,
656
+ & data_size as * const _ as * mut _ ,
657
+ & alive as * const _ as * mut _ ,
658
+ ) ;
659
+ self_ptr. alive . store ( alive > 0 , Ordering :: Relaxed ) ;
660
+ result
661
+ }
662
+
663
+ // Add our listener callback.
664
+ let status = unsafe {
665
+ AudioObjectAddPropertyListener (
666
+ self . device_id ,
667
+ & self . property_address as * const _ ,
668
+ Some ( alive_listener) ,
669
+ self as * const _ as * mut _ ,
670
+ )
671
+ } ;
672
+ Error :: from_os_status ( status) ?;
673
+ self . alive_listener = Some ( alive_listener) ;
674
+ Ok ( ( ) )
675
+ }
676
+
677
+ /// Unregister this listener to stop receiving notifications
678
+ pub fn unregister ( & mut self ) -> Result < ( ) , Error > {
679
+ // Add our sample rate change listener callback.
680
+ if self . alive_listener . is_some ( ) {
681
+ let status = unsafe {
682
+ AudioObjectRemovePropertyListener (
683
+ self . device_id ,
684
+ & self . property_address as * const _ ,
685
+ self . alive_listener ,
686
+ self as * const _ as * mut _ ,
687
+ )
688
+ } ;
689
+ Error :: from_os_status ( status) ?;
690
+ self . alive_listener = None ;
691
+ }
692
+ Ok ( ( ) )
693
+ }
694
+
695
+ /// Get the number of sample rate values received (equals the number of change events).
696
+ pub fn is_alive ( & self ) -> bool {
697
+ self . alive . load ( Ordering :: Relaxed )
698
+ }
699
+ }
0 commit comments