@@ -24,10 +24,13 @@ use sys::{
24
24
kCFStringEncodingUTF8, AudioDeviceID , AudioObjectAddPropertyListener ,
25
25
AudioObjectGetPropertyData , AudioObjectGetPropertyDataSize , AudioObjectID ,
26
26
AudioObjectPropertyAddress , AudioObjectRemovePropertyListener , AudioObjectSetPropertyData ,
27
- AudioStreamBasicDescription , AudioValueRange , OSStatus ,
27
+ AudioStreamBasicDescription , AudioValueRange , OSStatus , AudioStreamRangedDescription ,
28
28
} ;
29
29
30
+ use crate :: audio_unit:: audio_format:: { AudioFormat , LinearPcmFlags } ;
30
31
use crate :: audio_unit:: { AudioUnit , Element , IOType , Scope } ;
32
+ use crate :: audio_unit:: stream_format:: StreamFormat ;
33
+ use crate :: audio_unit:: sample_format:: SampleFormat ;
31
34
32
35
/// Helper function to get the device id of the default input or output device
33
36
/// Only implemented for macOS, not iOS.
@@ -319,6 +322,41 @@ pub fn set_device_sample_rate(device_id: AudioDeviceID, new_rate: f64) -> Result
319
322
}
320
323
}
321
324
325
+ /// Find the closest match of the physical formats to the provided StreamFormat.
326
+ /// Note that only the sample format and rate will be matched, the flags will be ignored.
327
+ pub fn find_matching_physical_format (
328
+ device_id : AudioDeviceID ,
329
+ stream_format : StreamFormat ,
330
+ ) -> Option < AudioStreamBasicDescription > {
331
+ if let Ok ( all_formats) = get_supported_physical_stream_formats ( device_id) {
332
+ let wanted_samplerate = stream_format. sample_rate as usize ;
333
+ let wanted_bits = stream_format. sample_format . size_in_bits ( ) ;
334
+ let wanted_float = stream_format. sample_format == SampleFormat :: F32 ;
335
+ for fmt in all_formats {
336
+ let minrate = fmt. mSampleRateRange . mMinimum as usize ;
337
+ let maxrate = fmt. mSampleRateRange . mMaximum as usize ;
338
+ let rate = fmt. mFormat . mSampleRate as usize ;
339
+ if let Some ( AudioFormat :: LinearPCM ( flags) ) = AudioFormat :: from_format_and_flag ( fmt. mFormat . mFormatID , Some ( fmt. mFormat . mFormatFlags ) ) {
340
+ let floats = flags. contains ( LinearPcmFlags :: IS_FLOAT ) ;
341
+ let ints = flags. contains ( LinearPcmFlags :: IS_SIGNED_INTEGER ) ;
342
+ if wanted_float != floats || wanted_float == ints {
343
+ // Wrong number type
344
+ continue ;
345
+ }
346
+ if wanted_bits != fmt. mFormat . mBitsPerChannel {
347
+ // Wrong number of bits
348
+ continue ;
349
+ }
350
+ if rate == wanted_samplerate || ( wanted_samplerate >= minrate && wanted_samplerate <= maxrate) {
351
+ return Some ( fmt. mFormat ) ;
352
+ }
353
+
354
+ }
355
+ }
356
+ }
357
+ return None
358
+ }
359
+
322
360
/// Change the physical stream format (sample rate and format) of a device.
323
361
/// Only implemented for macOS, not iOS.
324
362
pub fn set_device_physical_stream_format (
@@ -345,6 +383,8 @@ pub fn set_device_physical_stream_format(
345
383
) ;
346
384
Error :: from_os_status ( status) ?;
347
385
let asbd = maybe_asbd. assume_init ( ) ;
386
+ //println!("Current: {:?}", asbd);
387
+ //println!("New: {:?}", new_asbd);
348
388
349
389
// If the requested sample rate and/or format is different to the device sample rate, update the device.
350
390
if !asbds_are_equal ( & asbd, & new_asbd) {
@@ -386,8 +426,8 @@ pub fn set_device_physical_stream_format(
386
426
break ;
387
427
}
388
428
thread:: sleep ( Duration :: from_millis ( 5 ) ) ;
389
- if timer. elapsed ( ) > Duration :: from_secs ( 1 ) {
390
- return Err ( Error :: UnsupportedSampleRate ) ;
429
+ if timer. elapsed ( ) > Duration :: from_secs ( 2 ) {
430
+ return Err ( Error :: UnsupportedStreamFormat ) ;
391
431
}
392
432
}
393
433
}
@@ -416,7 +456,7 @@ fn asbds_are_equal(
416
456
/// malloc: Incorrect checksum for freed object 0x7fca6bc3c538: probably modified after being freed.
417
457
pub fn get_supported_physical_stream_formats (
418
458
device_id : AudioDeviceID ,
419
- ) -> Result < Vec < AudioStreamBasicDescription > , Error > {
459
+ ) -> Result < Vec < AudioStreamRangedDescription > , Error > {
420
460
// Get available formats.
421
461
let mut property_address = AudioObjectPropertyAddress {
422
462
mSelector : kAudioStreamPropertyPhysicalFormat,
@@ -437,11 +477,11 @@ pub fn get_supported_physical_stream_formats(
437
477
& mut data_size as * mut _ ,
438
478
) ;
439
479
Error :: from_os_status ( status) ?;
440
- let n_formats = data_size as usize / mem:: size_of :: < AudioStreamBasicDescription > ( ) ;
441
- println ! ( "n_formats {}" , n_formats) ;
442
- let mut formats: Vec < AudioStreamBasicDescription > = vec ! [ ] ;
480
+ let n_formats = data_size as usize / mem:: size_of :: < AudioStreamRangedDescription > ( ) ;
481
+ let mut formats: Vec < AudioStreamRangedDescription > = vec ! [ ] ;
443
482
formats. reserve_exact ( n_formats as usize ) ;
444
483
formats. set_len ( n_formats) ;
484
+
445
485
let status = AudioObjectGetPropertyData (
446
486
device_id,
447
487
& property_address as * const _ ,
0 commit comments