Move more tests from test.rs to api.rs
This commit is contained in:
Родитель
7cc1819ece
Коммит
8308025ae2
|
@ -492,3 +492,414 @@ fn test_set_device_info_and_get_default_device(
|
|||
// property_listener_callback
|
||||
// ------------------------------------
|
||||
// TODO
|
||||
|
||||
// add_listener (for default output device)
|
||||
// ------------------------------------
|
||||
#[test]
|
||||
fn test_add_listener_unknown_device() {
|
||||
extern "C" fn callback(
|
||||
_id: AudioObjectID,
|
||||
_number_of_addresses: u32,
|
||||
_addresses: *const AudioObjectPropertyAddress,
|
||||
_data: *mut c_void,
|
||||
) -> OSStatus {
|
||||
assert!(false, "Should not be called.");
|
||||
kAudioHardwareUnspecifiedError as OSStatus
|
||||
}
|
||||
|
||||
test_get_empty_stream(|stream| {
|
||||
let mut listener = property_listener::new(
|
||||
kAudioObjectUnknown,
|
||||
&DEFAULT_OUTPUT_DEVICE_PROPERTY_ADDRESS,
|
||||
callback,
|
||||
stream,
|
||||
);
|
||||
assert_eq!(
|
||||
audiounit_add_listener(&mut listener),
|
||||
kAudioHardwareBadObjectError as OSStatus
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// remove_listener (for default output device)
|
||||
// ------------------------------------
|
||||
#[test]
|
||||
fn test_add_listener_then_remove_system_device() {
|
||||
extern "C" fn callback(
|
||||
_id: AudioObjectID,
|
||||
_number_of_addresses: u32,
|
||||
_addresses: *const AudioObjectPropertyAddress,
|
||||
_data: *mut c_void,
|
||||
) -> OSStatus {
|
||||
assert!(false, "Should not be called.");
|
||||
kAudioHardwareUnspecifiedError as OSStatus
|
||||
}
|
||||
|
||||
test_get_empty_stream(|stream| {
|
||||
let mut listener = property_listener::new(
|
||||
kAudioObjectSystemObject,
|
||||
&DEFAULT_OUTPUT_DEVICE_PROPERTY_ADDRESS,
|
||||
callback,
|
||||
stream,
|
||||
);
|
||||
assert_eq!(audiounit_add_listener(&mut listener), NO_ERR);
|
||||
assert_eq!(audiounit_remove_listener(&mut listener), NO_ERR);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_listener_without_adding_any_listener_before_system_device() {
|
||||
extern "C" fn callback(
|
||||
_id: AudioObjectID,
|
||||
_number_of_addresses: u32,
|
||||
_addresses: *const AudioObjectPropertyAddress,
|
||||
_data: *mut c_void,
|
||||
) -> OSStatus {
|
||||
assert!(false, "Should not be called.");
|
||||
kAudioHardwareUnspecifiedError as OSStatus
|
||||
}
|
||||
|
||||
test_get_empty_stream(|stream| {
|
||||
let mut listener = property_listener::new(
|
||||
kAudioObjectSystemObject,
|
||||
&DEFAULT_OUTPUT_DEVICE_PROPERTY_ADDRESS,
|
||||
callback,
|
||||
stream,
|
||||
);
|
||||
assert_eq!(audiounit_remove_listener(&mut listener), NO_ERR);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_listener_unknown_device() {
|
||||
extern "C" fn callback(
|
||||
_id: AudioObjectID,
|
||||
_number_of_addresses: u32,
|
||||
_addresses: *const AudioObjectPropertyAddress,
|
||||
_data: *mut c_void,
|
||||
) -> OSStatus {
|
||||
assert!(false, "Should not be called.");
|
||||
kAudioHardwareUnspecifiedError as OSStatus
|
||||
}
|
||||
|
||||
test_get_empty_stream(|stream| {
|
||||
let mut listener = property_listener::new(
|
||||
kAudioObjectUnknown,
|
||||
&DEFAULT_OUTPUT_DEVICE_PROPERTY_ADDRESS,
|
||||
callback,
|
||||
stream,
|
||||
);
|
||||
assert_eq!(
|
||||
audiounit_remove_listener(&mut listener),
|
||||
kAudioHardwareBadObjectError as OSStatus
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// install_system_changed_callback
|
||||
// ------------------------------------
|
||||
// TODO
|
||||
|
||||
// uninstall_system_changed_callback
|
||||
// ------------------------------------
|
||||
// TODO
|
||||
|
||||
// get_acceptable_latency_range
|
||||
// ------------------------------------
|
||||
#[test]
|
||||
fn test_get_acceptable_latency_range() {
|
||||
let mut latency_range = AudioValueRange::default();
|
||||
|
||||
let default_output = test_get_default_device(Scope::Output);
|
||||
if default_output.is_none() {
|
||||
assert_eq!(
|
||||
audiounit_get_acceptable_latency_range(&mut latency_range).unwrap_err(),
|
||||
Error::error()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
assert!(audiounit_get_acceptable_latency_range(&mut latency_range).is_ok());
|
||||
assert!(latency_range.mMinimum > 0.0);
|
||||
assert!(latency_range.mMaximum > 0.0);
|
||||
assert!(latency_range.mMaximum > latency_range.mMinimum);
|
||||
}
|
||||
|
||||
// get_default_device_id
|
||||
// ------------------------------------
|
||||
#[test]
|
||||
fn test_get_default_device_id() {
|
||||
// Invalid types:
|
||||
assert_eq!(
|
||||
audiounit_get_default_device_id(DeviceType::UNKNOWN),
|
||||
kAudioObjectUnknown,
|
||||
);
|
||||
assert_eq!(
|
||||
audiounit_get_default_device_id(DeviceType::INPUT | DeviceType::OUTPUT),
|
||||
kAudioObjectUnknown,
|
||||
);
|
||||
|
||||
if test_get_default_device(Scope::Input).is_some() {
|
||||
assert_ne!(
|
||||
audiounit_get_default_device_id(DeviceType::INPUT),
|
||||
kAudioObjectUnknown,
|
||||
);
|
||||
}
|
||||
|
||||
if test_get_default_device(Scope::Output).is_some() {
|
||||
assert_ne!(
|
||||
audiounit_get_default_device_id(DeviceType::OUTPUT),
|
||||
kAudioObjectUnknown,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// convert_channel_layout
|
||||
// ------------------------------------
|
||||
#[test]
|
||||
fn test_convert_channel_layout() {
|
||||
let pairs = [
|
||||
// The single channel is mapped to mono now.
|
||||
(vec![kAudioObjectUnknown], ChannelLayout::MONO),
|
||||
(vec![kAudioChannelLabel_Mono], ChannelLayout::MONO),
|
||||
// The dual channels are mapped to stereo now.
|
||||
(
|
||||
vec![kAudioChannelLabel_Mono, kAudioChannelLabel_LFEScreen],
|
||||
ChannelLayout::STEREO,
|
||||
),
|
||||
(
|
||||
vec![kAudioChannelLabel_Left, kAudioChannelLabel_Right],
|
||||
ChannelLayout::STEREO,
|
||||
),
|
||||
// The Layouts containing any unknonwn channel will be mapped to UNDEFINED.
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Unknown,
|
||||
],
|
||||
ChannelLayout::UNDEFINED,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Unused,
|
||||
],
|
||||
ChannelLayout::UNDEFINED,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_ForeignLanguage,
|
||||
],
|
||||
ChannelLayout::UNDEFINED,
|
||||
),
|
||||
// The SMPTE layouts.
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::STEREO_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
],
|
||||
ChannelLayout::_3F,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::_3F_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_CenterSurround,
|
||||
],
|
||||
ChannelLayout::_2F1,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_CenterSurround,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::_2F1_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_CenterSurround,
|
||||
],
|
||||
ChannelLayout::_3F1,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_CenterSurround,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::_3F1_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_LeftSurroundDirect,
|
||||
kAudioChannelLabel_RightSurroundDirect,
|
||||
],
|
||||
ChannelLayout::_2F2,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_LeftSurroundDirect,
|
||||
kAudioChannelLabel_RightSurroundDirect,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::_2F2_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_LeftSurround,
|
||||
kAudioChannelLabel_RightSurround,
|
||||
],
|
||||
ChannelLayout::QUAD,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_LeftSurround,
|
||||
kAudioChannelLabel_RightSurround,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::QUAD_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_LeftSurroundDirect,
|
||||
kAudioChannelLabel_RightSurroundDirect,
|
||||
],
|
||||
ChannelLayout::_3F2,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_LeftSurroundDirect,
|
||||
kAudioChannelLabel_RightSurroundDirect,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::_3F2_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_LeftSurround,
|
||||
kAudioChannelLabel_RightSurround,
|
||||
kAudioChannelLabel_Center,
|
||||
],
|
||||
ChannelLayout::_3F2_BACK,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_LeftSurround,
|
||||
kAudioChannelLabel_RightSurround,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::_3F2_LFE_BACK,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
kAudioChannelLabel_CenterSurround,
|
||||
kAudioChannelLabel_LeftSurroundDirect,
|
||||
kAudioChannelLabel_RightSurroundDirect,
|
||||
],
|
||||
ChannelLayout::_3F3R_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
kAudioChannelLabel_LeftSurround,
|
||||
kAudioChannelLabel_RightSurround,
|
||||
kAudioChannelLabel_LeftSurroundDirect,
|
||||
kAudioChannelLabel_RightSurroundDirect,
|
||||
],
|
||||
ChannelLayout::_3F4_LFE,
|
||||
),
|
||||
];
|
||||
|
||||
const MAX_CHANNELS: usize = 10;
|
||||
// A Rust mapping structure of the AudioChannelLayout with MAX_CHANNELS channels
|
||||
// https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.13.sdk/System/Library/Frameworks/CoreAudio.framework/Versions/A/Headers/CoreAudioTypes.h#L1332
|
||||
#[repr(C)]
|
||||
struct TestLayout {
|
||||
tag: AudioChannelLayoutTag,
|
||||
map: AudioChannelBitmap,
|
||||
number_channel_descriptions: UInt32,
|
||||
channel_descriptions: [AudioChannelDescription; MAX_CHANNELS],
|
||||
}
|
||||
|
||||
impl Default for TestLayout {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
tag: AudioChannelLayoutTag::default(),
|
||||
map: AudioChannelBitmap::default(),
|
||||
number_channel_descriptions: UInt32::default(),
|
||||
channel_descriptions: [AudioChannelDescription::default(); MAX_CHANNELS],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut layout = TestLayout::default();
|
||||
layout.tag = kAudioChannelLayoutTag_UseChannelDescriptions;
|
||||
|
||||
for (labels, expected_layout) in pairs.iter() {
|
||||
assert!(labels.len() <= MAX_CHANNELS);
|
||||
layout.number_channel_descriptions = labels.len() as u32;
|
||||
for (idx, label) in labels.iter().enumerate() {
|
||||
layout.channel_descriptions[idx].mChannelLabel = *label;
|
||||
}
|
||||
let layout_ref = unsafe { &(*(&layout as *const TestLayout as *const AudioChannelLayout)) };
|
||||
assert_eq!(
|
||||
audiounit_convert_channel_layout(layout_ref),
|
||||
*expected_layout
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -231,527 +231,6 @@ fn test_context_register_device_collection_changed_twice_inout() {
|
|||
|
||||
// Private APIs
|
||||
// ============================================================================
|
||||
// add_listener
|
||||
// ------------------------------------
|
||||
#[test]
|
||||
fn test_add_listener_for_unknown_device() {
|
||||
extern fn listener(
|
||||
_: AudioObjectID,
|
||||
_: u32,
|
||||
_: *const AudioObjectPropertyAddress,
|
||||
_: *mut c_void
|
||||
) -> OSStatus {
|
||||
assert!(false, "Should not be called.");
|
||||
kAudioHardwareUnspecifiedError as OSStatus
|
||||
}
|
||||
|
||||
// We need to initialize the members with type OwnedCriticalSection in
|
||||
// AudioUnitContext and AudioUnitStream, since those OwnedCriticalSection
|
||||
// will be used when AudioUnitStream::drop/destroy is called.
|
||||
let mut ctx = AudioUnitContext::new();
|
||||
ctx.init();
|
||||
|
||||
// Add a stream to the context. `AudioUnitStream::drop()` will check
|
||||
// the context has at least one stream.
|
||||
{
|
||||
// Create a `mutext_ptr` here to avoid borrowing issues for `ctx`.
|
||||
let mutex_ptr = &mut ctx.mutex as *mut OwnedCriticalSection;
|
||||
// The scope of `_lock` is a critical section.
|
||||
let _lock = AutoLock::new(unsafe { &mut (*mutex_ptr) });
|
||||
audiounit_increment_active_streams(&mut ctx);
|
||||
}
|
||||
|
||||
let mut stream = AudioUnitStream::new(
|
||||
&mut ctx,
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
None,
|
||||
0
|
||||
);
|
||||
stream.init();
|
||||
|
||||
let mut listener = property_listener::new(
|
||||
kAudioObjectUnknown,
|
||||
&DEFAULT_OUTPUT_DEVICE_PROPERTY_ADDRESS,
|
||||
listener,
|
||||
&mut stream
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
audiounit_add_listener(&mut listener),
|
||||
kAudioHardwareBadObjectError as OSStatus
|
||||
);
|
||||
}
|
||||
|
||||
// remove_listener
|
||||
// ------------------------------------
|
||||
#[test]
|
||||
fn test_remove_listener_for_unknown_device() {
|
||||
extern fn listener(
|
||||
_: AudioObjectID,
|
||||
_: u32,
|
||||
_: *const AudioObjectPropertyAddress,
|
||||
_: *mut c_void
|
||||
) -> OSStatus {
|
||||
assert!(false, "Should not be called.");
|
||||
kAudioHardwareUnspecifiedError as OSStatus
|
||||
}
|
||||
|
||||
// We need to initialize the members with type OwnedCriticalSection in
|
||||
// AudioUnitContext and AudioUnitStream, since those OwnedCriticalSection
|
||||
// will be used when AudioUnitStream::drop/destroy is called.
|
||||
let mut ctx = AudioUnitContext::new();
|
||||
ctx.init();
|
||||
|
||||
// Add a stream to the context. `AudioUnitStream::drop()` will check
|
||||
// the context has at least one stream.
|
||||
{
|
||||
// Create a `mutext_ptr` here to avoid borrowing issues for `ctx`.
|
||||
let mutex_ptr = &mut ctx.mutex as *mut OwnedCriticalSection;
|
||||
// The scope of `_lock` is a critical section.
|
||||
let _lock = AutoLock::new(unsafe { &mut (*mutex_ptr) });
|
||||
audiounit_increment_active_streams(&mut ctx);
|
||||
}
|
||||
|
||||
let mut stream = AudioUnitStream::new(
|
||||
&mut ctx,
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
None,
|
||||
0
|
||||
);
|
||||
stream.init();
|
||||
|
||||
let mut listener = property_listener::new(
|
||||
kAudioObjectUnknown,
|
||||
&DEFAULT_OUTPUT_DEVICE_PROPERTY_ADDRESS,
|
||||
listener,
|
||||
&mut stream
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
audiounit_remove_listener(&mut listener),
|
||||
kAudioHardwareBadObjectError as OSStatus
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_listener_without_adding_any_listener() {
|
||||
extern fn listener(
|
||||
_: AudioObjectID,
|
||||
_: u32,
|
||||
_: *const AudioObjectPropertyAddress,
|
||||
_: *mut c_void
|
||||
) -> OSStatus {
|
||||
assert!(false, "Should not be called.");
|
||||
kAudioHardwareUnspecifiedError as OSStatus
|
||||
}
|
||||
|
||||
// We need to initialize the members with type OwnedCriticalSection in
|
||||
// AudioUnitContext and AudioUnitStream, since those OwnedCriticalSection
|
||||
// will be used when AudioUnitStream::drop/destroy is called.
|
||||
let mut ctx = AudioUnitContext::new();
|
||||
ctx.init();
|
||||
|
||||
// Add a stream to the context. `AudioUnitStream::drop()` will check
|
||||
// the context has at least one stream.
|
||||
{
|
||||
// Create a `mutext_ptr` here to avoid borrowing issues for `ctx`.
|
||||
let mutex_ptr = &mut ctx.mutex as *mut OwnedCriticalSection;
|
||||
// The scope of `_lock` is a critical section.
|
||||
let _lock = AutoLock::new(unsafe { &mut (*mutex_ptr) });
|
||||
audiounit_increment_active_streams(&mut ctx);
|
||||
}
|
||||
|
||||
let mut stream = AudioUnitStream::new(
|
||||
&mut ctx,
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
None,
|
||||
0
|
||||
);
|
||||
stream.init();
|
||||
|
||||
let mut listener = property_listener::new(
|
||||
kAudioObjectSystemObject,
|
||||
&DEFAULT_OUTPUT_DEVICE_PROPERTY_ADDRESS,
|
||||
listener,
|
||||
&mut stream
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
audiounit_remove_listener(&mut listener),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add_then_remove_listener() {
|
||||
extern fn listener(
|
||||
_: AudioObjectID,
|
||||
_: u32,
|
||||
_: *const AudioObjectPropertyAddress,
|
||||
_: *mut c_void
|
||||
) -> OSStatus {
|
||||
assert!(false, "Should not be called.");
|
||||
kAudioHardwareUnspecifiedError as OSStatus
|
||||
}
|
||||
|
||||
// We need to initialize the members with type OwnedCriticalSection in
|
||||
// AudioUnitContext and AudioUnitStream, since those OwnedCriticalSection
|
||||
// will be used when AudioUnitStream::drop/destroy is called.
|
||||
let mut ctx = AudioUnitContext::new();
|
||||
ctx.init();
|
||||
|
||||
// Add a stream to the context. `AudioUnitStream::drop()` will check
|
||||
// the context has at least one stream.
|
||||
{
|
||||
// Create a `mutext_ptr` here to avoid borrowing issues for `ctx`.
|
||||
let mutex_ptr = &mut ctx.mutex as *mut OwnedCriticalSection;
|
||||
// The scope of `_lock` is a critical section.
|
||||
let _lock = AutoLock::new(unsafe { &mut (*mutex_ptr) });
|
||||
audiounit_increment_active_streams(&mut ctx);
|
||||
}
|
||||
|
||||
let mut stream = AudioUnitStream::new(
|
||||
&mut ctx,
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
None,
|
||||
0
|
||||
);
|
||||
stream.init();
|
||||
|
||||
let mut listener = property_listener::new(
|
||||
kAudioObjectSystemObject,
|
||||
&DEFAULT_OUTPUT_DEVICE_PROPERTY_ADDRESS,
|
||||
listener,
|
||||
&mut stream
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
audiounit_add_listener(&mut listener),
|
||||
0
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
audiounit_remove_listener(&mut listener),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// install_system_changed_callback
|
||||
// ------------------------------------
|
||||
// TODO
|
||||
|
||||
// uninstall_system_changed_callback
|
||||
// ------------------------------------
|
||||
// TODO
|
||||
|
||||
// get_acceptable_latency_range
|
||||
// ------------------------------------
|
||||
#[test]
|
||||
fn test_get_acceptable_latency_range() {
|
||||
let mut latency_range = AudioValueRange::default();
|
||||
|
||||
// Get an error if there is no avaiable output device.
|
||||
let output_id = audiounit_get_default_device_id(DeviceType::OUTPUT);
|
||||
if !valid_id(output_id) {
|
||||
assert_eq!(
|
||||
audiounit_get_acceptable_latency_range(
|
||||
&mut latency_range
|
||||
).unwrap_err(),
|
||||
Error::error()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
assert!(
|
||||
audiounit_get_acceptable_latency_range(
|
||||
&mut latency_range
|
||||
).is_ok()
|
||||
);
|
||||
assert!(latency_range.mMinimum > 0.0);
|
||||
assert!(latency_range.mMaximum > 0.0);
|
||||
assert!(latency_range.mMaximum > latency_range.mMinimum);
|
||||
}
|
||||
|
||||
// get_default_device_id
|
||||
// ------------------------------------
|
||||
#[test]
|
||||
fn test_get_default_device_id() {
|
||||
// Invalid types:
|
||||
assert_eq!(
|
||||
audiounit_get_default_device_id(DeviceType::UNKNOWN),
|
||||
kAudioObjectUnknown,
|
||||
);
|
||||
assert_eq!(
|
||||
audiounit_get_default_device_id(DeviceType::INPUT | DeviceType::OUTPUT),
|
||||
kAudioObjectUnknown,
|
||||
);
|
||||
|
||||
// Valid types:
|
||||
// P.S. Works only when there is available default input and output.
|
||||
assert_ne!(
|
||||
audiounit_get_default_device_id(DeviceType::INPUT),
|
||||
kAudioObjectUnknown,
|
||||
);
|
||||
assert_ne!(
|
||||
audiounit_get_default_device_id(DeviceType::OUTPUT),
|
||||
kAudioObjectUnknown,
|
||||
)
|
||||
}
|
||||
|
||||
// convert_channel_layout
|
||||
// ------------------------------------
|
||||
#[test]
|
||||
fn test_convert_channel_layout() {
|
||||
let pairs = [
|
||||
// The single channel is mapped to mono now.
|
||||
(vec![kAudioObjectUnknown], ChannelLayout::MONO),
|
||||
(vec![kAudioChannelLabel_Mono], ChannelLayout::MONO),
|
||||
// The dual channels are mapped to stereo now.
|
||||
(
|
||||
vec![kAudioChannelLabel_Mono, kAudioChannelLabel_LFEScreen],
|
||||
ChannelLayout::STEREO,
|
||||
),
|
||||
(
|
||||
vec![kAudioChannelLabel_Left, kAudioChannelLabel_Right],
|
||||
ChannelLayout::STEREO,
|
||||
),
|
||||
// The Layouts containing any unknonwn channel will be mapped to UNDEFINED.
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Unknown,
|
||||
],
|
||||
ChannelLayout::UNDEFINED,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Unused,
|
||||
],
|
||||
ChannelLayout::UNDEFINED,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_ForeignLanguage,
|
||||
],
|
||||
ChannelLayout::UNDEFINED,
|
||||
),
|
||||
// The SMPTE layouts.
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::STEREO_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
],
|
||||
ChannelLayout::_3F,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::_3F_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_CenterSurround,
|
||||
],
|
||||
ChannelLayout::_2F1,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_CenterSurround,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::_2F1_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_CenterSurround,
|
||||
],
|
||||
ChannelLayout::_3F1,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_CenterSurround,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::_3F1_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_LeftSurroundDirect,
|
||||
kAudioChannelLabel_RightSurroundDirect,
|
||||
],
|
||||
ChannelLayout::_2F2,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_LeftSurroundDirect,
|
||||
kAudioChannelLabel_RightSurroundDirect,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::_2F2_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_LeftSurround,
|
||||
kAudioChannelLabel_RightSurround,
|
||||
],
|
||||
ChannelLayout::QUAD,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_LeftSurround,
|
||||
kAudioChannelLabel_RightSurround,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::QUAD_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_LeftSurroundDirect,
|
||||
kAudioChannelLabel_RightSurroundDirect,
|
||||
],
|
||||
ChannelLayout::_3F2,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_LeftSurroundDirect,
|
||||
kAudioChannelLabel_RightSurroundDirect,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::_3F2_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_LeftSurround,
|
||||
kAudioChannelLabel_RightSurround,
|
||||
kAudioChannelLabel_Center,
|
||||
],
|
||||
ChannelLayout::_3F2_BACK,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_LeftSurround,
|
||||
kAudioChannelLabel_RightSurround,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
],
|
||||
ChannelLayout::_3F2_LFE_BACK,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
kAudioChannelLabel_CenterSurround,
|
||||
kAudioChannelLabel_LeftSurroundDirect,
|
||||
kAudioChannelLabel_RightSurroundDirect,
|
||||
],
|
||||
ChannelLayout::_3F3R_LFE,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
kAudioChannelLabel_Left,
|
||||
kAudioChannelLabel_Right,
|
||||
kAudioChannelLabel_Center,
|
||||
kAudioChannelLabel_LFEScreen,
|
||||
kAudioChannelLabel_LeftSurround,
|
||||
kAudioChannelLabel_RightSurround,
|
||||
kAudioChannelLabel_LeftSurroundDirect,
|
||||
kAudioChannelLabel_RightSurroundDirect,
|
||||
],
|
||||
ChannelLayout::_3F4_LFE,
|
||||
),
|
||||
];
|
||||
|
||||
const MAX_CHANNELS: usize = 10;
|
||||
// A Rust mapping structure of the AudioChannelLayout with MAX_CHANNELS channels
|
||||
// https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.13.sdk/System/Library/Frameworks/CoreAudio.framework/Versions/A/Headers/CoreAudioTypes.h#L1332
|
||||
#[repr(C)]
|
||||
struct TestLayout {
|
||||
tag: AudioChannelLayoutTag,
|
||||
map: AudioChannelBitmap,
|
||||
number_channel_descriptions: UInt32,
|
||||
channel_descriptions: [AudioChannelDescription; MAX_CHANNELS],
|
||||
}
|
||||
|
||||
impl Default for TestLayout {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
tag: AudioChannelLayoutTag::default(),
|
||||
map: AudioChannelBitmap::default(),
|
||||
number_channel_descriptions: UInt32::default(),
|
||||
channel_descriptions: [AudioChannelDescription::default(); MAX_CHANNELS],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut layout = TestLayout::default();
|
||||
layout.tag = kAudioChannelLayoutTag_UseChannelDescriptions;
|
||||
|
||||
for (labels, expected_layout) in pairs.iter() {
|
||||
assert!(labels.len() <= MAX_CHANNELS);
|
||||
layout.number_channel_descriptions = labels.len() as u32;
|
||||
for (idx, label) in labels.iter().enumerate() {
|
||||
layout.channel_descriptions[idx].mChannelLabel = *label;
|
||||
}
|
||||
let layout_ref = unsafe { &(*(&layout as *const TestLayout as *const AudioChannelLayout)) };
|
||||
assert_eq!(
|
||||
audiounit_convert_channel_layout(layout_ref),
|
||||
*expected_layout
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// get_preferred_channel_layout
|
||||
// ------------------------------------
|
||||
// TODO: Should it be prevented ? The AudioUnitElement is for output only.
|
||||
|
|
Загрузка…
Ссылка в новой задаче