@@ -8,7 +8,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
8
8
use std:: sync:: mpsc:: { channel, Sender } ;
9
9
use std:: sync:: Mutex ;
10
10
use std:: time:: Duration ;
11
- use std:: { mem, slice , thread} ;
11
+ use std:: { mem, thread} ;
12
12
13
13
use core_foundation_sys:: string:: { CFStringGetCString , CFStringGetCStringPtr , CFStringRef } ;
14
14
use sys;
@@ -24,9 +24,12 @@ use sys::{
24
24
kCFStringEncodingUTF8, AudioDeviceID , AudioObjectAddPropertyListener ,
25
25
AudioObjectGetPropertyData , AudioObjectGetPropertyDataSize , AudioObjectID ,
26
26
AudioObjectPropertyAddress , AudioObjectRemovePropertyListener , AudioObjectSetPropertyData ,
27
- AudioStreamBasicDescription , AudioValueRange , OSStatus ,
27
+ AudioStreamBasicDescription , AudioStreamRangedDescription , AudioValueRange , OSStatus ,
28
28
} ;
29
29
30
+ use crate :: audio_unit:: audio_format:: { AudioFormat , LinearPcmFlags } ;
31
+ use crate :: audio_unit:: sample_format:: SampleFormat ;
32
+ use crate :: audio_unit:: stream_format:: StreamFormat ;
30
33
use crate :: audio_unit:: { AudioUnit , Element , IOType , Scope } ;
31
34
32
35
/// Helper function to get the device id of the default input or output device
@@ -144,6 +147,7 @@ pub fn get_audio_device_ids() -> Result<Vec<AudioDeviceID>, Error> {
144
147
let device_count = data_size / mem:: size_of :: < AudioDeviceID > ( ) as u32 ;
145
148
let mut audio_devices = vec ! [ ] ;
146
149
audio_devices. reserve_exact ( device_count as usize ) ;
150
+ unsafe { audio_devices. set_len ( device_count as usize ) } ;
147
151
148
152
let status = unsafe {
149
153
AudioObjectGetPropertyData (
@@ -156,9 +160,6 @@ pub fn get_audio_device_ids() -> Result<Vec<AudioDeviceID>, Error> {
156
160
)
157
161
} ;
158
162
try_status_or_return ! ( status) ;
159
-
160
- unsafe { audio_devices. set_len ( device_count as usize ) } ;
161
-
162
163
Ok ( audio_devices)
163
164
}
164
165
@@ -259,8 +260,9 @@ pub fn set_device_sample_rate(device_id: AudioDeviceID, new_rate: f64) -> Result
259
260
) ;
260
261
Error :: from_os_status ( status) ?;
261
262
let n_ranges = data_size as usize / mem:: size_of :: < AudioValueRange > ( ) ;
262
- let mut ranges: Vec < u8 > = vec ! [ ] ;
263
- ranges. reserve_exact ( data_size as usize ) ;
263
+ let mut ranges: Vec < AudioValueRange > = vec ! [ ] ;
264
+ ranges. reserve_exact ( n_ranges as usize ) ;
265
+ ranges. set_len ( n_ranges) ;
264
266
let status = AudioObjectGetPropertyData (
265
267
device_id,
266
268
& property_address as * const _ ,
@@ -270,8 +272,6 @@ pub fn set_device_sample_rate(device_id: AudioDeviceID, new_rate: f64) -> Result
270
272
ranges. as_mut_ptr ( ) as * mut _ ,
271
273
) ;
272
274
Error :: from_os_status ( status) ?;
273
- let ranges: * mut AudioValueRange = ranges. as_mut_ptr ( ) as * mut _ ;
274
- let ranges: & ' static [ AudioValueRange ] = slice:: from_raw_parts ( ranges, n_ranges) ;
275
275
276
276
// Now that we have the available ranges, pick the one matching the desired rate.
277
277
let new_rate_integer = new_rate as u32 ;
@@ -322,15 +322,68 @@ pub fn set_device_sample_rate(device_id: AudioDeviceID, new_rate: f64) -> Result
322
322
}
323
323
}
324
324
325
- /// Change the sample rate and format of a device.
325
+ /// Find the closest match of the physical formats to the provided `StreamFormat`.
326
+ /// It will pick the first format it finds that supports the provided sample format, rate and number of channels.
327
+ /// The provided format flags in the `StreamFormat` are ignored.
328
+ pub fn find_matching_physical_format (
329
+ device_id : AudioDeviceID ,
330
+ stream_format : StreamFormat ,
331
+ ) -> Option < AudioStreamBasicDescription > {
332
+ if let Ok ( all_formats) = get_supported_physical_stream_formats ( device_id) {
333
+ let requested_samplerate = stream_format. sample_rate as usize ;
334
+ let requested_bits = stream_format. sample_format . size_in_bits ( ) ;
335
+ let requested_float = stream_format. sample_format == SampleFormat :: F32 ;
336
+ let requested_channels = stream_format. channels ;
337
+ for fmt in all_formats {
338
+ let min_rate = fmt. mSampleRateRange . mMinimum as usize ;
339
+ let max_rate = fmt. mSampleRateRange . mMaximum as usize ;
340
+ let rate = fmt. mFormat . mSampleRate as usize ;
341
+ let channels = fmt. mFormat . mChannelsPerFrame ;
342
+ if let Some ( AudioFormat :: LinearPCM ( flags) ) = AudioFormat :: from_format_and_flag (
343
+ fmt. mFormat . mFormatID ,
344
+ Some ( fmt. mFormat . mFormatFlags ) ,
345
+ ) {
346
+ let is_float = flags. contains ( LinearPcmFlags :: IS_FLOAT ) ;
347
+ let is_int = flags. contains ( LinearPcmFlags :: IS_SIGNED_INTEGER ) ;
348
+ if is_int && is_float {
349
+ // Probably never occurs, check just in case
350
+ continue ;
351
+ }
352
+ if requested_float && !is_float {
353
+ // Wrong number type
354
+ continue ;
355
+ }
356
+ if !requested_float && !is_int {
357
+ // Wrong number type
358
+ continue ;
359
+ }
360
+ if requested_bits != fmt. mFormat . mBitsPerChannel {
361
+ // Wrong number of bits
362
+ continue ;
363
+ }
364
+ if requested_channels > channels {
365
+ // Too few channels
366
+ continue ;
367
+ }
368
+ if rate == requested_samplerate
369
+ || ( requested_samplerate >= min_rate && requested_samplerate <= max_rate)
370
+ {
371
+ return Some ( fmt. mFormat ) ;
372
+ }
373
+ }
374
+ }
375
+ }
376
+ None
377
+ }
378
+
379
+ /// Change the physical stream format (sample rate and format) of a device.
326
380
/// Only implemented for macOS, not iOS.
327
- pub fn set_device_sample_format (
381
+ pub fn set_device_physical_stream_format (
328
382
device_id : AudioDeviceID ,
329
383
new_asbd : AudioStreamBasicDescription ,
330
384
) -> Result < ( ) , Error > {
331
- // Check whether or not we need to change the device sample format and rate.
332
385
unsafe {
333
- // Get the current sample rate .
386
+ // Get the current format .
334
387
let property_address = AudioObjectPropertyAddress {
335
388
mSelector : kAudioStreamPropertyPhysicalFormat,
336
389
mScope : kAudioObjectPropertyScopeGlobal,
@@ -349,7 +402,6 @@ pub fn set_device_sample_format(
349
402
Error :: from_os_status ( status) ?;
350
403
let asbd = maybe_asbd. assume_init ( ) ;
351
404
352
- // If the requested sample rate and/or format is different to the device sample rate, update the device.
353
405
if !asbds_are_equal ( & asbd, & new_asbd) {
354
406
let property_address = AudioObjectPropertyAddress {
355
407
mSelector : kAudioStreamPropertyPhysicalFormat,
@@ -372,8 +424,7 @@ pub fn set_device_sample_format(
372
424
Error :: from_os_status ( status) ?;
373
425
374
426
// Wait for the reported format to change.
375
- //
376
- // This should not take longer than a few ms, but we timeout after 1 sec just in case.
427
+ // This can take up to half a second, but we timeout after 2 sec just in case.
377
428
let timer = :: std:: time:: Instant :: now ( ) ;
378
429
loop {
379
430
let status = AudioObjectGetPropertyData (
@@ -389,8 +440,8 @@ pub fn set_device_sample_format(
389
440
break ;
390
441
}
391
442
thread:: sleep ( Duration :: from_millis ( 5 ) ) ;
392
- if timer. elapsed ( ) > Duration :: from_secs ( 1 ) {
393
- return Err ( Error :: UnsupportedSampleRate ) ;
443
+ if timer. elapsed ( ) > Duration :: from_secs ( 2 ) {
444
+ return Err ( Error :: UnsupportedStreamFormat ) ;
394
445
}
395
446
}
396
447
}
@@ -413,34 +464,33 @@ fn asbds_are_equal(
413
464
&& left. mBitsPerChannel == right. mBitsPerChannel
414
465
}
415
466
416
- /// Get a vector with all supported formats as AudioBasicStreamDescriptions .
467
+ /// Get a vector with all supported physical formats as AudioBasicRangedDescriptions .
417
468
/// Only implemented for macOS, not iOS.
418
- pub fn get_supported_stream_formats (
469
+ pub fn get_supported_physical_stream_formats (
419
470
device_id : AudioDeviceID ,
420
- ) -> Result < Vec < AudioStreamBasicDescription > , Error > {
471
+ ) -> Result < Vec < AudioStreamRangedDescription > , Error > {
421
472
// Get available formats.
422
473
let mut property_address = AudioObjectPropertyAddress {
423
474
mSelector : kAudioStreamPropertyPhysicalFormat,
424
475
mScope : kAudioObjectPropertyScopeGlobal,
425
- //mScope: kAudioDevicePropertyScopeInput,
426
- //mScope: kAudioObjectPropertyScopeOutput,
427
- //mScope: kAudioDevicePropertyScopeOutput,
428
476
mElement : kAudioObjectPropertyElementMaster,
429
477
} ;
430
- let formats = unsafe {
478
+ let allformats = unsafe {
431
479
property_address. mSelector = kAudioStreamPropertyAvailablePhysicalFormats;
432
- let data_size = 0u32 ;
480
+ let mut data_size = 0u32 ;
433
481
let status = AudioObjectGetPropertyDataSize (
434
482
device_id,
435
483
& property_address as * const _ ,
436
484
0 ,
437
485
null ( ) ,
438
- & data_size as * const _ as * mut _ ,
486
+ & mut data_size as * mut _ ,
439
487
) ;
440
488
Error :: from_os_status ( status) ?;
441
- let n_formats = data_size as usize / mem:: size_of :: < AudioStreamBasicDescription > ( ) ;
442
- let mut formats: Vec < u8 > = vec ! [ ] ;
443
- formats. reserve_exact ( data_size as usize ) ;
489
+ let n_formats = data_size as usize / mem:: size_of :: < AudioStreamRangedDescription > ( ) ;
490
+ let mut formats: Vec < AudioStreamRangedDescription > = vec ! [ ] ;
491
+ formats. reserve_exact ( n_formats as usize ) ;
492
+ formats. set_len ( n_formats) ;
493
+
444
494
let status = AudioObjectGetPropertyData (
445
495
device_id,
446
496
& property_address as * const _ ,
@@ -450,19 +500,9 @@ pub fn get_supported_stream_formats(
450
500
formats. as_mut_ptr ( ) as * mut _ ,
451
501
) ;
452
502
Error :: from_os_status ( status) ?;
453
- let formats: * mut AudioStreamBasicDescription = formats. as_mut_ptr ( ) as * mut _ ;
454
- Vec :: from_raw_parts ( formats, n_formats, n_formats)
503
+ formats
455
504
} ;
456
- /*
457
- println!("---- All supported formats ----");
458
- for asbd in formats.iter() {
459
- if let Ok(sf) = StreamFormat::from_asbd(*asbd) {
460
- println!("{:#?}", asbd);
461
- println!("{:#?}", sf);
462
- }
463
- }
464
- */
465
- Ok ( formats)
505
+ Ok ( allformats)
466
506
}
467
507
468
508
/// Changing the sample rate is an asynchonous process.
0 commit comments