This commit is contained in:
Chun-Min Chang 2019-03-15 16:18:00 -07:00
Родитель 2d0b6dfd29
Коммит ee9d493861
5 изменённых файлов: 162 добавлений и 250 удалений

Просмотреть файл

@ -78,11 +78,15 @@ pub trait Zero {
} }
impl Zero for f32 { impl Zero for f32 {
fn zero() -> Self { 0.0 } fn zero() -> Self {
0.0
}
} }
impl Zero for i16 { impl Zero for i16 {
fn zero() -> Self { 0 } fn zero() -> Self {
0
}
} }
#[cfg(test)] #[cfg(test)]
@ -139,7 +143,10 @@ fn test_auto_array_wrapper<T: Clone + Debug + PartialEq + Zero>(buf: &[T]) {
assert!(data.is_null()); assert!(data.is_null());
// Check if push works. // Check if push works.
auto_array.as_mut().unwrap().push(buf.as_ptr() as *const c_void, buf.len()); auto_array
.as_mut()
.unwrap()
.push(buf.as_ptr() as *const c_void, buf.len());
assert_eq!(auto_array.as_ref().unwrap().elements(), buf.len()); assert_eq!(auto_array.as_ref().unwrap().elements(), buf.len());
let data = auto_array.as_ref().unwrap().as_ptr() as *const T; let data = auto_array.as_ref().unwrap().as_ptr() as *const T;

Просмотреть файл

@ -2,15 +2,12 @@ use std::fmt;
pub struct AutoRelease<T> { pub struct AutoRelease<T> {
ptr: *mut T, ptr: *mut T,
release_func: unsafe extern fn(*mut T) release_func: unsafe extern "C" fn(*mut T),
} }
impl<T> AutoRelease<T> { impl<T> AutoRelease<T> {
pub fn new(ptr: *mut T, release_func: unsafe extern fn(*mut T)) -> Self { pub fn new(ptr: *mut T, release_func: unsafe extern "C" fn(*mut T)) -> Self {
Self { Self { ptr, release_func }
ptr,
release_func
}
} }
pub fn reset(&mut self, ptr: *mut T) { pub fn reset(&mut self, ptr: *mut T) {
@ -34,7 +31,9 @@ impl<T> AutoRelease<T> {
fn release(&self) { fn release(&self) {
if !self.ptr.is_null() { if !self.ptr.is_null() {
unsafe { (self.release_func)(self.ptr); } unsafe {
(self.release_func)(self.ptr);
}
} }
} }
} }
@ -61,12 +60,12 @@ fn test_auto_release() {
use std::mem; use std::mem;
use std::ptr; use std::ptr;
unsafe extern fn allocate() -> *mut libc::c_void { unsafe extern "C" fn allocate() -> *mut libc::c_void {
// println!("Allocate!"); // println!("Allocate!");
libc::calloc(1, mem::size_of::<u32>()) libc::calloc(1, mem::size_of::<u32>())
} }
unsafe extern fn deallocate(ptr: *mut libc::c_void) { unsafe extern "C" fn deallocate(ptr: *mut libc::c_void) {
// println!("Deallocate!"); // println!("Deallocate!");
libc::free(ptr); libc::free(ptr);
} }

Просмотреть файл

@ -15,9 +15,8 @@ pub const DISPATCH_QUEUE_SERIAL: sys::dispatch_queue_attr_t = 0 as sys::dispatch
pub fn create_dispatch_queue( pub fn create_dispatch_queue(
label: &'static str, label: &'static str,
queue_attr: sys::dispatch_queue_attr_t queue_attr: sys::dispatch_queue_attr_t,
) -> sys::dispatch_queue_t ) -> sys::dispatch_queue_t {
{
let label = CString::new(label); let label = CString::new(label);
let c_string = if label.is_ok() { let c_string = if label.is_ok() {
label.unwrap().as_ptr() label.unwrap().as_ptr()
@ -27,20 +26,21 @@ pub fn create_dispatch_queue(
unsafe { sys::dispatch_queue_create(c_string, queue_attr) } unsafe { sys::dispatch_queue_create(c_string, queue_attr) }
} }
pub fn release_dispatch_queue(queue: sys::dispatch_queue_t) pub fn release_dispatch_queue(queue: sys::dispatch_queue_t) {
{
// TODO: This is incredibly unsafe. Find another way to release the queue. // TODO: This is incredibly unsafe. Find another way to release the queue.
unsafe { unsafe {
sys::dispatch_release( sys::dispatch_release(mem::transmute::<
mem::transmute::<sys::dispatch_queue_t, sys::dispatch_object_t>(queue) sys::dispatch_queue_t,
); sys::dispatch_object_t,
>(queue));
} }
} }
// Send: Types that can be transferred across thread boundaries. // Send: Types that can be transferred across thread boundaries.
// FnOnce: One-time function. // FnOnce: One-time function.
pub fn async_dispatch<F>(queue: sys::dispatch_queue_t, work: F) pub fn async_dispatch<F>(queue: sys::dispatch_queue_t, work: F)
where F: 'static + Send + FnOnce() where
F: 'static + Send + FnOnce(),
{ {
let (closure, executor) = create_closure_and_executor(work); let (closure, executor) = create_closure_and_executor(work);
unsafe { unsafe {
@ -51,7 +51,8 @@ pub fn async_dispatch<F>(queue: sys::dispatch_queue_t, work: F)
// Send: Types that can be transferred across thread boundaries. // Send: Types that can be transferred across thread boundaries.
// FnOnce: One-time function. // FnOnce: One-time function.
pub fn sync_dispatch<F>(queue: sys::dispatch_queue_t, work: F) pub fn sync_dispatch<F>(queue: sys::dispatch_queue_t, work: F)
where F: 'static + Send + FnOnce() where
F: 'static + Send + FnOnce(),
{ {
let (closure, executor) = create_closure_and_executor(work); let (closure, executor) = create_closure_and_executor(work);
unsafe { unsafe {
@ -61,18 +62,16 @@ pub fn sync_dispatch<F>(queue: sys::dispatch_queue_t, work: F)
// Return an raw pointer to a (unboxed) closure and an executor that // Return an raw pointer to a (unboxed) closure and an executor that
// will run the closure (after re-boxing the closure) when it's called. // will run the closure (after re-boxing the closure) when it's called.
fn create_closure_and_executor<F>( fn create_closure_and_executor<F>(closure: F) -> (*mut c_void, sys::dispatch_function_t)
closure: F where
) -> (*mut c_void, sys::dispatch_function_t) F: FnOnce(),
where F: FnOnce()
{ {
extern fn closure_executer<F>(unboxed_closure: *mut c_void) extern "C" fn closure_executer<F>(unboxed_closure: *mut c_void)
where F: FnOnce() where
F: FnOnce(),
{ {
// Retake the leaked closure. // Retake the leaked closure.
let closure: Box<F> = unsafe { let closure: Box<F> = unsafe { Box::from_raw(unboxed_closure as *mut F) };
Box::from_raw(unboxed_closure as *mut F)
};
// Execute the closure. // Execute the closure.
(*closure)(); (*closure)();
// closure is released after finishiing this function call. // closure is released after finishiing this function call.
@ -83,7 +82,7 @@ fn create_closure_and_executor<F>(
( (
Box::into_raw(closure) as *mut c_void, // Leak the closure. Box::into_raw(closure) as *mut c_void, // Leak the closure.
executor executor,
) )
} }
@ -96,19 +95,14 @@ fn test_dispatch_async_f() {
ptr::null() ptr::null()
}; };
let queue = unsafe { let queue = unsafe { sys::dispatch_queue_create(c_string, DISPATCH_QUEUE_SERIAL) };
sys::dispatch_queue_create(
c_string,
DISPATCH_QUEUE_SERIAL
)
};
// Allocate the `context` on heap, otherwise the `context` will be // Allocate the `context` on heap, otherwise the `context` will be
// freed before `work` is fired and after program goes out of the // freed before `work` is fired and after program goes out of the
// scope of the unsafe block. // scope of the unsafe block.
let context: Box<i32> = Box::new(123); let context: Box<i32> = Box::new(123);
extern fn work(leaked_ptr: *mut c_void) { extern "C" fn work(leaked_ptr: *mut c_void) {
let leaked_context = leaked_ptr as *mut i32; let leaked_context = leaked_ptr as *mut i32;
// Retake the leaked `context`. // Retake the leaked `context`.
@ -121,7 +115,7 @@ fn test_dispatch_async_f() {
sys::dispatch_async_f( sys::dispatch_async_f(
queue, queue,
Box::into_raw(context) as *mut c_void, // Leak the `context`. Box::into_raw(context) as *mut c_void, // Leak the `context`.
Some(work) Some(work),
); );
} }
} }
@ -135,30 +129,19 @@ fn test_dispatch_sync_f() {
ptr::null() ptr::null()
}; };
let queue = unsafe { let queue = unsafe { sys::dispatch_queue_create(c_string, DISPATCH_QUEUE_SERIAL) };
sys::dispatch_queue_create(
c_string,
DISPATCH_QUEUE_SERIAL
)
};
let mut context: i32 = 20; let mut context: i32 = 20;
extern fn work(context_ptr: *mut c_void) { extern "C" fn work(context_ptr: *mut c_void) {
let ctx_mut_ref = unsafe { let ctx_mut_ref = unsafe { &mut (*(context_ptr as *mut i32)) };
&mut (*(context_ptr as *mut i32))
};
assert_eq!(ctx_mut_ref, &20); assert_eq!(ctx_mut_ref, &20);
*ctx_mut_ref = 30; *ctx_mut_ref = 30;
} }
unsafe { unsafe {
sys::dispatch_sync_f( sys::dispatch_sync_f(queue, &mut context as *mut i32 as *mut c_void, Some(work));
queue,
&mut context as *mut i32 as *mut c_void,
Some(work)
);
} }
assert_eq!(context, 30); assert_eq!(context, 30);
@ -168,10 +151,7 @@ fn test_dispatch_sync_f() {
fn test_async_dispatch() { fn test_async_dispatch() {
let label = "Run with async dispatch api wrappers"; let label = "Run with async dispatch api wrappers";
let queue = create_dispatch_queue( let queue = create_dispatch_queue(label, DISPATCH_QUEUE_SERIAL);
label,
DISPATCH_QUEUE_SERIAL
);
struct Resource { struct Resource {
last_touched: Option<u32>, last_touched: Option<u32>,
@ -232,7 +212,7 @@ fn test_async_dispatch() {
}); });
// Make sure the resource won't be freed before the tasks are finished. // Make sure the resource won't be freed before the tasks are finished.
while resource.touched_count < 2 {}; while resource.touched_count < 2 {}
assert!(resource.last_touched.is_some()); assert!(resource.last_touched.is_some());
assert_eq!(resource.last_touched.unwrap(), 2); assert_eq!(resource.last_touched.unwrap(), 2);
} }
@ -241,10 +221,7 @@ fn test_async_dispatch() {
fn test_sync_dispatch() { fn test_sync_dispatch() {
let label = "Run with sync dispatch api wrappers"; let label = "Run with sync dispatch api wrappers";
let queue = create_dispatch_queue( let queue = create_dispatch_queue(label, DISPATCH_QUEUE_SERIAL);
label,
DISPATCH_QUEUE_SERIAL
);
struct Resource { struct Resource {
last_touched: Option<u32>, last_touched: Option<u32>,

Просмотреть файл

@ -9,7 +9,7 @@ use self::libc::*;
use std::{fmt, mem}; use std::{fmt, mem};
pub struct OwnedCriticalSection { pub struct OwnedCriticalSection {
mutex: pthread_mutex_t mutex: pthread_mutex_t,
} }
// Notice that `OwnedCriticalSection` only works after `init` is called. // Notice that `OwnedCriticalSection` only works after `init` is called.
@ -26,7 +26,7 @@ pub struct OwnedCriticalSection {
impl OwnedCriticalSection { impl OwnedCriticalSection {
pub fn new() -> Self { pub fn new() -> Self {
OwnedCriticalSection { OwnedCriticalSection {
mutex: PTHREAD_MUTEX_INITIALIZER mutex: PTHREAD_MUTEX_INITIALIZER,
} }
} }
@ -91,9 +91,7 @@ pub struct AutoLock<'a> {
impl<'a> AutoLock<'a> { impl<'a> AutoLock<'a> {
pub fn new(mutex: &'a mut OwnedCriticalSection) -> Self { pub fn new(mutex: &'a mut OwnedCriticalSection) -> Self {
mutex.lock(); mutex.lock();
AutoLock { AutoLock { mutex }
mutex,
}
} }
} }

Просмотреть файл

@ -36,13 +36,7 @@ pub fn leak_vec<T>(v: Vec<T>) -> (*mut T, usize) {
pub fn retake_leaked_vec<T>(ptr: *mut T, len: usize) -> Vec<T> { pub fn retake_leaked_vec<T>(ptr: *mut T, len: usize) -> Vec<T> {
// TODO: It's better to set ptr to null and len to 0. // TODO: It's better to set ptr to null and len to 0.
// so the address won't be used again. // so the address won't be used again.
unsafe { unsafe { Vec::from_raw_parts(ptr, len, len) }
Vec::from_raw_parts(
ptr,
len,
len
)
}
} }
// CFSTR doesn't be implemented in core-foundation-sys, so we create a function // CFSTR doesn't be implemented in core-foundation-sys, so we create a function
@ -63,7 +57,7 @@ pub fn cfstringref_from_static_string(string: &'static str) -> sys::CFStringRef
string.len() as sys::CFIndex, string.len() as sys::CFIndex,
sys::kCFStringEncodingUTF8, sys::kCFStringEncodingUTF8,
false as sys::Boolean, false as sys::Boolean,
sys::kCFAllocatorNull sys::kCFAllocatorNull,
) )
} }
} }
@ -80,7 +74,7 @@ pub fn cfstringref_from_string(string: &str) -> sys::CFStringRef {
string.as_ptr(), string.as_ptr(),
string.len() as sys::CFIndex, string.len() as sys::CFIndex,
sys::kCFStringEncodingUTF8, sys::kCFStringEncodingUTF8,
false as sys::Boolean false as sys::Boolean,
) )
} }
} }
@ -89,12 +83,7 @@ pub fn audio_object_has_property(
id: sys::AudioObjectID, id: sys::AudioObjectID,
address: &sys::AudioObjectPropertyAddress, address: &sys::AudioObjectPropertyAddress,
) -> bool { ) -> bool {
unsafe { unsafe { sys::AudioObjectHasProperty(id, address) != 0 }
sys::AudioObjectHasProperty(
id,
address,
) != 0
}
} }
pub fn audio_object_get_property_data<T>( pub fn audio_object_get_property_data<T>(
@ -121,13 +110,7 @@ pub fn audio_object_get_property_data_size(
size: *mut usize, size: *mut usize,
) -> sys::OSStatus { ) -> sys::OSStatus {
unsafe { unsafe {
sys::AudioObjectGetPropertyDataSize( sys::AudioObjectGetPropertyDataSize(id, address, 0, ptr::null(), size as *mut sys::UInt32)
id,
address,
0,
ptr::null(),
size as *mut sys::UInt32,
)
} }
} }
@ -152,7 +135,7 @@ pub fn audio_object_set_property_data<T>(
// Referece: // Referece:
// https://gist.github.com/ChunMinChang/f0f4a71f78d1e1c6390493ab1c9d10d3 // https://gist.github.com/ChunMinChang/f0f4a71f78d1e1c6390493ab1c9d10d3
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub type audio_object_property_listener_proc = extern fn( pub type audio_object_property_listener_proc = extern "C" fn(
sys::AudioObjectID, sys::AudioObjectID,
u32, u32,
*const sys::AudioObjectPropertyAddress, *const sys::AudioObjectPropertyAddress,
@ -165,14 +148,7 @@ pub fn audio_object_add_property_listener(
listener: audio_object_property_listener_proc, listener: audio_object_property_listener_proc,
data: *mut c_void, data: *mut c_void,
) -> sys::OSStatus { ) -> sys::OSStatus {
unsafe { unsafe { sys::AudioObjectAddPropertyListener(id, address, Some(listener), data) }
sys::AudioObjectAddPropertyListener(
id,
address,
Some(listener),
data
)
}
} }
pub fn audio_object_remove_property_listener( pub fn audio_object_remove_property_listener(
@ -181,14 +157,7 @@ pub fn audio_object_remove_property_listener(
listener: audio_object_property_listener_proc, listener: audio_object_property_listener_proc,
data: *mut c_void, data: *mut c_void,
) -> sys::OSStatus { ) -> sys::OSStatus {
unsafe { unsafe { sys::AudioObjectRemovePropertyListener(id, address, Some(listener), data) }
sys::AudioObjectRemovePropertyListener(
id,
address,
Some(listener),
data
)
}
} }
pub fn audio_unit_get_property_info( pub fn audio_unit_get_property_info(
@ -197,7 +166,7 @@ pub fn audio_unit_get_property_info(
scope: sys::AudioUnitScope, scope: sys::AudioUnitScope,
element: sys::AudioUnitElement, element: sys::AudioUnitElement,
size: *mut usize, size: *mut usize,
writable: *mut sys::Boolean writable: *mut sys::Boolean,
) -> sys::OSStatus { ) -> sys::OSStatus {
assert!(!unit.is_null()); assert!(!unit.is_null());
unsafe { unsafe {
@ -207,7 +176,7 @@ pub fn audio_unit_get_property_info(
scope, scope,
element, element,
size as *mut sys::UInt32, size as *mut sys::UInt32,
writable writable,
) )
} }
} }
@ -228,7 +197,7 @@ pub fn audio_unit_get_property<T>(
scope, scope,
element, element,
data as *mut c_void, data as *mut c_void,
size as *mut sys::UInt32 size as *mut sys::UInt32,
) )
} }
} }
@ -256,7 +225,7 @@ pub fn audio_unit_set_property<T>(
pub fn audio_unit_get_parameter( pub fn audio_unit_get_parameter(
unit: sys::AudioUnit, unit: sys::AudioUnit,
id: sys:: AudioUnitParameterID, id: sys::AudioUnitParameterID,
scope: sys::AudioUnitScope, scope: sys::AudioUnitScope,
element: sys::AudioUnitElement, element: sys::AudioUnitElement,
value: &mut sys::AudioUnitParameterValue, value: &mut sys::AudioUnitParameterValue,
@ -268,19 +237,19 @@ pub fn audio_unit_get_parameter(
id, id,
scope, scope,
element, element,
value as *mut sys::AudioUnitParameterValue value as *mut sys::AudioUnitParameterValue,
) )
} }
} }
// https://developer.apple.com/documentation/audiotoolbox/1440111-audiounitaddpropertylistener?language=objc // https://developer.apple.com/documentation/audiotoolbox/1440111-audiounitaddpropertylistener?language=objc
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub type audio_unit_property_listener_proc = extern fn( pub type audio_unit_property_listener_proc = extern "C" fn(
*mut c_void, *mut c_void,
sys::AudioUnit, sys::AudioUnit,
sys::AudioUnitPropertyID, sys::AudioUnitPropertyID,
sys::AudioUnitScope, sys::AudioUnitScope,
sys::AudioUnitElement sys::AudioUnitElement,
); );
pub fn audio_unit_add_property_listener( pub fn audio_unit_add_property_listener(
@ -290,14 +259,7 @@ pub fn audio_unit_add_property_listener(
data: *mut c_void, data: *mut c_void,
) -> sys::OSStatus { ) -> sys::OSStatus {
assert!(!unit.is_null()); assert!(!unit.is_null());
unsafe { unsafe { sys::AudioUnitAddPropertyListener(unit, id, Some(listener), data) }
sys::AudioUnitAddPropertyListener(
unit,
id,
Some(listener),
data
)
}
} }
pub fn audio_unit_remove_property_listener_with_user_data( pub fn audio_unit_remove_property_listener_with_user_data(
@ -307,35 +269,19 @@ pub fn audio_unit_remove_property_listener_with_user_data(
data: *mut c_void, data: *mut c_void,
) -> sys::OSStatus { ) -> sys::OSStatus {
assert!(!unit.is_null()); assert!(!unit.is_null());
unsafe { unsafe { sys::AudioUnitRemovePropertyListenerWithUserData(unit, id, Some(listener), data) }
sys::AudioUnitRemovePropertyListenerWithUserData(
unit,
id,
Some(listener),
data
)
}
} }
pub fn audio_unit_set_parameter( pub fn audio_unit_set_parameter(
unit: sys::AudioUnit, unit: sys::AudioUnit,
id: sys:: AudioUnitParameterID, id: sys::AudioUnitParameterID,
scope: sys::AudioUnitScope, scope: sys::AudioUnitScope,
element: sys::AudioUnitElement, element: sys::AudioUnitElement,
value: sys::AudioUnitParameterValue, value: sys::AudioUnitParameterValue,
buffer_offset_in_frames: sys::UInt32, buffer_offset_in_frames: sys::UInt32,
) -> sys::OSStatus { ) -> sys::OSStatus {
assert!(!unit.is_null()); assert!(!unit.is_null());
unsafe { unsafe { sys::AudioUnitSetParameter(unit, id, scope, element, value, buffer_offset_in_frames) }
sys::AudioUnitSetParameter(
unit,
id,
scope,
element,
value,
buffer_offset_in_frames
)
}
} }
pub fn audio_unit_render( pub fn audio_unit_render(
@ -344,7 +290,7 @@ pub fn audio_unit_render(
in_time_stamp: *const sys::AudioTimeStamp, in_time_stamp: *const sys::AudioTimeStamp,
in_output_bus_number: u32, in_output_bus_number: u32,
in_number_frames: u32, in_number_frames: u32,
io_data: *mut sys::AudioBufferList io_data: *mut sys::AudioBufferList,
) -> sys::OSStatus { ) -> sys::OSStatus {
assert!(!in_unit.is_null()); assert!(!in_unit.is_null());
unsafe { unsafe {
@ -354,57 +300,37 @@ pub fn audio_unit_render(
in_time_stamp, in_time_stamp,
in_output_bus_number, in_output_bus_number,
in_number_frames, in_number_frames,
io_data io_data,
) )
} }
} }
pub fn audio_unit_initialize( pub fn audio_unit_initialize(unit: sys::AudioUnit) -> sys::OSStatus {
unit: sys::AudioUnit,
) -> sys::OSStatus {
assert!(!unit.is_null()); assert!(!unit.is_null());
unsafe { unsafe { sys::AudioUnitInitialize(unit) }
sys::AudioUnitInitialize(unit)
}
} }
// TODO: Maybe we can merge the following two functions into something like // TODO: Maybe we can merge the following two functions into something like
// `destroy_audio_unit(unit: sys::AudioUnit)` and call // `destroy_audio_unit(unit: sys::AudioUnit)` and call
// `AudioUnitUninitialize`, `AudioComponentInstanceDispose` in this // `AudioUnitUninitialize`, `AudioComponentInstanceDispose` in this
// function. // function.
pub fn audio_unit_uninitialize( pub fn audio_unit_uninitialize(unit: sys::AudioUnit) -> sys::OSStatus {
unit: sys::AudioUnit,
) -> sys::OSStatus {
assert!(!unit.is_null()); assert!(!unit.is_null());
unsafe { unsafe { sys::AudioUnitUninitialize(unit) }
sys::AudioUnitUninitialize(unit)
}
} }
pub fn dispose_audio_unit( pub fn dispose_audio_unit(unit: sys::AudioUnit) -> sys::OSStatus {
unit: sys::AudioUnit, unsafe { sys::AudioComponentInstanceDispose(unit) }
) -> sys::OSStatus {
unsafe {
sys::AudioComponentInstanceDispose(unit)
}
} }
pub fn audio_output_unit_start( pub fn audio_output_unit_start(unit: sys::AudioUnit) -> sys::OSStatus {
unit: sys::AudioUnit,
) -> sys::OSStatus {
assert!(!unit.is_null()); assert!(!unit.is_null());
unsafe { unsafe { sys::AudioOutputUnitStart(unit) }
sys::AudioOutputUnitStart(unit)
}
} }
pub fn audio_output_unit_stop( pub fn audio_output_unit_stop(unit: sys::AudioUnit) -> sys::OSStatus {
unit: sys::AudioUnit,
) -> sys::OSStatus {
assert!(!unit.is_null()); assert!(!unit.is_null());
unsafe { unsafe { sys::AudioOutputUnitStop(unit) }
sys::AudioOutputUnitStop(unit)
}
} }
#[test] #[test]
@ -447,10 +373,7 @@ fn test_create_cfstring_ref() {
CFRelease(cfstrref as *const c_void); CFRelease(cfstrref as *const c_void);
} }
assert_eq!( assert_eq!(test_string, cstring.to_string_lossy());
test_string,
cstring.to_string_lossy()
);
// TODO: Find a way to check the string's inner pointer is different. // TODO: Find a way to check the string's inner pointer is different.
} }
@ -459,11 +382,11 @@ fn test_create_cfstring_ref() {
fn test_audio_object_add_property_listener_for_unknown_device() { fn test_audio_object_add_property_listener_for_unknown_device() {
use super::DEVICES_PROPERTY_ADDRESS; use super::DEVICES_PROPERTY_ADDRESS;
extern fn listener( extern "C" fn listener(
id: sys::AudioObjectID, id: sys::AudioObjectID,
number_of_addresses: u32, number_of_addresses: u32,
addresses: *const sys::AudioObjectPropertyAddress, addresses: *const sys::AudioObjectPropertyAddress,
data: *mut c_void data: *mut c_void,
) -> sys::OSStatus { ) -> sys::OSStatus {
assert!(false, "Should not be called."); assert!(false, "Should not be called.");
sys::kAudioHardwareUnspecifiedError as sys::OSStatus sys::kAudioHardwareUnspecifiedError as sys::OSStatus
@ -484,11 +407,11 @@ fn test_audio_object_add_property_listener_for_unknown_device() {
fn test_audio_object_remove_property_listener_for_unknown_device() { fn test_audio_object_remove_property_listener_for_unknown_device() {
use super::DEVICES_PROPERTY_ADDRESS; use super::DEVICES_PROPERTY_ADDRESS;
extern fn listener( extern "C" fn listener(
_: sys::AudioObjectID, _: sys::AudioObjectID,
_: u32, _: u32,
_: *const sys::AudioObjectPropertyAddress, _: *const sys::AudioObjectPropertyAddress,
_: *mut c_void _: *mut c_void,
) -> sys::OSStatus { ) -> sys::OSStatus {
assert!(false, "Should not be called."); assert!(false, "Should not be called.");
sys::kAudioHardwareUnspecifiedError as sys::OSStatus sys::kAudioHardwareUnspecifiedError as sys::OSStatus
@ -509,11 +432,11 @@ fn test_audio_object_remove_property_listener_for_unknown_device() {
fn test_audio_object_remove_property_listener_without_adding_any_listener() { fn test_audio_object_remove_property_listener_without_adding_any_listener() {
use super::DEVICES_PROPERTY_ADDRESS; use super::DEVICES_PROPERTY_ADDRESS;
extern fn listener( extern "C" fn listener(
_: sys::AudioObjectID, _: sys::AudioObjectID,
_: u32, _: u32,
_: *const sys::AudioObjectPropertyAddress, _: *const sys::AudioObjectPropertyAddress,
_: *mut c_void _: *mut c_void,
) -> sys::OSStatus { ) -> sys::OSStatus {
assert!(false, "Should not be called."); assert!(false, "Should not be called.");
sys::kAudioHardwareUnspecifiedError as sys::OSStatus sys::kAudioHardwareUnspecifiedError as sys::OSStatus
@ -535,11 +458,11 @@ fn test_audio_object_remove_property_listener_without_adding_any_listener() {
fn test_audio_object_add_then_remove_property_listener() { fn test_audio_object_add_then_remove_property_listener() {
use super::DEVICES_PROPERTY_ADDRESS; use super::DEVICES_PROPERTY_ADDRESS;
extern fn listener( extern "C" fn listener(
_: sys::AudioObjectID, _: sys::AudioObjectID,
_: u32, _: u32,
_: *const sys::AudioObjectPropertyAddress, _: *const sys::AudioObjectPropertyAddress,
_: *mut c_void _: *mut c_void,
) -> sys::OSStatus { ) -> sys::OSStatus {
assert!(false, "Should not be called."); assert!(false, "Should not be called.");
sys::kAudioHardwareUnspecifiedError as sys::OSStatus sys::kAudioHardwareUnspecifiedError as sys::OSStatus
@ -573,15 +496,13 @@ fn test_manual_audio_object_add_property_listener() {
let mut called: u32 = 0; let mut called: u32 = 0;
extern fn listener( extern "C" fn listener(
id: sys::AudioObjectID, id: sys::AudioObjectID,
number_of_addresses: u32, number_of_addresses: u32,
addresses: *const sys::AudioObjectPropertyAddress, addresses: *const sys::AudioObjectPropertyAddress,
data: *mut c_void data: *mut c_void,
) -> sys::OSStatus { ) -> sys::OSStatus {
let called = unsafe { let called = unsafe { &mut (*(data as *mut u32)) };
&mut (*(data as *mut u32))
};
*called += 1; *called += 1;
0 // noErr. 0 // noErr.
@ -595,7 +516,7 @@ fn test_manual_audio_object_add_property_listener() {
); );
assert_eq!(r, 0); assert_eq!(r, 0);
while called == 0 {}; while called == 0 {}
let r = audio_object_remove_property_listener( let r = audio_object_remove_property_listener(
sys::kAudioObjectSystemObject, sys::kAudioObjectSystemObject,
@ -612,12 +533,12 @@ fn test_manual_audio_object_add_property_listener() {
#[test] #[test]
#[should_panic] #[should_panic]
fn test_audio_unit_add_property_listener_for_null_unit() { fn test_audio_unit_add_property_listener_for_null_unit() {
extern fn listener( extern "C" fn listener(
_: *mut c_void, _: *mut c_void,
_: sys::AudioUnit, _: sys::AudioUnit,
_: sys::AudioUnitPropertyID, _: sys::AudioUnitPropertyID,
_: sys::AudioUnitScope, _: sys::AudioUnitScope,
_: sys::AudioUnitElement _: sys::AudioUnitElement,
) { ) {
assert!(false, "Should not be called."); assert!(false, "Should not be called.");
} }
@ -634,16 +555,15 @@ fn test_audio_unit_add_property_listener_for_null_unit() {
); );
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn test_audio_unit_remove_property_listener_with_user_data_for_null_unit() { fn test_audio_unit_remove_property_listener_with_user_data_for_null_unit() {
extern fn listener( extern "C" fn listener(
_: *mut c_void, _: *mut c_void,
_: sys::AudioUnit, _: sys::AudioUnit,
_: sys::AudioUnitPropertyID, _: sys::AudioUnitPropertyID,
_: sys::AudioUnitScope, _: sys::AudioUnitScope,
_: sys::AudioUnitElement _: sys::AudioUnitElement,
) { ) {
assert!(false, "Should not be called."); assert!(false, "Should not be called.");
} }
@ -662,12 +582,12 @@ fn test_audio_unit_remove_property_listener_with_user_data_for_null_unit() {
#[test] #[test]
fn test_audio_unit_remove_property_listener_with_user_data_without_adding_any() { fn test_audio_unit_remove_property_listener_with_user_data_without_adding_any() {
extern fn listener( extern "C" fn listener(
_: *mut c_void, _: *mut c_void,
_: sys::AudioUnit, _: sys::AudioUnit,
_: sys::AudioUnitPropertyID, _: sys::AudioUnitPropertyID,
_: sys::AudioUnitScope, _: sys::AudioUnitScope,
_: sys::AudioUnitElement _: sys::AudioUnitElement,
) { ) {
assert!(false, "Should not be called."); assert!(false, "Should not be called.");
} }
@ -690,12 +610,12 @@ fn test_audio_unit_remove_property_listener_with_user_data_without_adding_any()
#[test] #[test]
fn test_audio_unit_add_then_remove_property_listener() { fn test_audio_unit_add_then_remove_property_listener() {
extern fn listener( extern "C" fn listener(
_: *mut c_void, _: *mut c_void,
_: sys::AudioUnit, _: sys::AudioUnit,
_: sys::AudioUnitPropertyID, _: sys::AudioUnitPropertyID,
_: sys::AudioUnitScope, _: sys::AudioUnitScope,
_: sys::AudioUnitElement _: sys::AudioUnitElement,
) { ) {
assert!(false, "Should not be called."); assert!(false, "Should not be called.");
} }
@ -732,7 +652,7 @@ fn test_audio_unit_add_then_fire_then_remove_property_listener() {
macro_rules! debug_println { macro_rules! debug_println {
($( $args:expr ),*) => { ($( $args:expr ),*) => {
// println!( $( $args ),* ); // println!( $( $args ),* );
} };
} }
use super::device_flags; use super::device_flags;
@ -742,47 +662,50 @@ fn test_audio_unit_add_then_fire_then_remove_property_listener() {
let mut called: u32 = 0; let mut called: u32 = 0;
extern fn listener( extern "C" fn listener(
data: *mut c_void, data: *mut c_void,
unit: sys::AudioUnit, unit: sys::AudioUnit,
id: sys::AudioUnitPropertyID, id: sys::AudioUnitPropertyID,
scope: sys::AudioUnitScope, scope: sys::AudioUnitScope,
element: sys::AudioUnitElement element: sys::AudioUnitElement,
) { ) {
// This callback will be fired twice. One for input or output scope, // This callback will be fired twice. One for input or output scope,
// the other is for global scope. // the other is for global scope.
debug_println!("listener > id: {}, unit: {:?}, scope: {}, element: {}, data @ {:p}", debug_println!(
id, unit, scope, element, data); "listener > id: {}, unit: {:?}, scope: {}, element: {}, data @ {:p}",
assert_eq!(
id, id,
sys::kAudioDevicePropertyBufferFrameSize unit,
scope,
element,
data
); );
assert!((scope == sys::kAudioUnitScope_Output && element == IN_ELEMENT) || assert_eq!(id, sys::kAudioDevicePropertyBufferFrameSize);
(scope == sys::kAudioUnitScope_Input && element == OUT_ELEMENT) ||
(scope == sys::kAudioUnitScope_Global && element == GLOBAL_ELEMENT)); assert!(
(scope == sys::kAudioUnitScope_Output && element == IN_ELEMENT)
|| (scope == sys::kAudioUnitScope_Input && element == OUT_ELEMENT)
|| (scope == sys::kAudioUnitScope_Global && element == GLOBAL_ELEMENT)
);
let mut buffer_frames: u32 = 0; let mut buffer_frames: u32 = 0;
let mut size = mem::size_of::<u32>(); let mut size = mem::size_of::<u32>();
assert_eq!( assert_eq!(
audio_unit_get_property( audio_unit_get_property(unit, id, scope, element, &mut buffer_frames, &mut size),
unit,
id,
scope,
element,
&mut buffer_frames,
&mut size
),
0 0
); );
debug_println!("updated {} buffer frames: {}", debug_println!(
if element == IN_ELEMENT { "input" } else { "output" }, buffer_frames); "updated {} buffer frames: {}",
if element == IN_ELEMENT {
"input"
} else {
"output"
},
buffer_frames
);
let called = unsafe { let called = unsafe { &mut (*(data as *mut u32)) };
&mut (*(data as *mut u32))
};
*called += 1; *called += 1;
// It's ok to remove listener here. // It's ok to remove listener here.
@ -798,13 +721,18 @@ fn test_audio_unit_add_then_fire_then_remove_property_listener() {
} }
let default_device = get_default_input_or_output_device(); let default_device = get_default_input_or_output_device();
if default_device.id == sys::kAudioObjectUnknown || if default_device.id == sys::kAudioObjectUnknown
default_device.flags == device_flags::DEV_UNKNOWN { || default_device.flags == device_flags::DEV_UNKNOWN
{
return; return;
} }
assert!(default_device.flags.intersects(device_flags::DEV_INPUT | device_flags::DEV_OUTPUT)); assert!(default_device
assert!(!default_device.flags.contains(device_flags::DEV_INPUT | device_flags::DEV_OUTPUT)); .flags
.intersects(device_flags::DEV_INPUT | device_flags::DEV_OUTPUT));
assert!(!default_device
.flags
.contains(device_flags::DEV_INPUT | device_flags::DEV_OUTPUT));
let is_input = if default_device.flags.contains(device_flags::DEV_INPUT) { let is_input = if default_device.flags.contains(device_flags::DEV_INPUT) {
true true
@ -822,7 +750,11 @@ fn test_audio_unit_add_then_fire_then_remove_property_listener() {
audio_unit_get_property( audio_unit_get_property(
unit, unit,
sys::kAudioDevicePropertyBufferFrameSize, sys::kAudioDevicePropertyBufferFrameSize,
if is_input { sys::kAudioUnitScope_Output } else { sys::kAudioUnitScope_Input }, if is_input {
sys::kAudioUnitScope_Output
} else {
sys::kAudioUnitScope_Input
},
if is_input { IN_ELEMENT } else { OUT_ELEMENT }, if is_input { IN_ELEMENT } else { OUT_ELEMENT },
&mut buffer_frames, &mut buffer_frames,
&mut size &mut size
@ -830,8 +762,11 @@ fn test_audio_unit_add_then_fire_then_remove_property_listener() {
0 0
); );
debug_println!("current {} buffer frames: {}", debug_println!(
if is_input { "input" } else { "output" }, buffer_frames); "current {} buffer frames: {}",
if is_input { "input" } else { "output" },
buffer_frames
);
assert_eq!( assert_eq!(
audio_unit_add_property_listener( audio_unit_add_property_listener(
@ -846,14 +781,21 @@ fn test_audio_unit_add_then_fire_then_remove_property_listener() {
// Make sure buffer_frames will be set to a new value. // Make sure buffer_frames will be set to a new value.
assert_ne!(buffer_frames, 0); assert_ne!(buffer_frames, 0);
buffer_frames *= 2; buffer_frames *= 2;
debug_println!("target {} buffer frames: {}", debug_println!(
if is_input { "input" } else { "output" }, buffer_frames); "target {} buffer frames: {}",
if is_input { "input" } else { "output" },
buffer_frames
);
assert_eq!( assert_eq!(
audio_unit_set_property( audio_unit_set_property(
unit, unit,
sys::kAudioDevicePropertyBufferFrameSize, sys::kAudioDevicePropertyBufferFrameSize,
if is_input { sys::kAudioUnitScope_Output } else { sys::kAudioUnitScope_Input }, if is_input {
sys::kAudioUnitScope_Output
} else {
sys::kAudioUnitScope_Input
},
if is_input { IN_ELEMENT } else { OUT_ELEMENT }, if is_input { IN_ELEMENT } else { OUT_ELEMENT },
&buffer_frames, &buffer_frames,
size size
@ -861,7 +803,7 @@ fn test_audio_unit_add_then_fire_then_remove_property_listener() {
0 0
); );
while called < 2 {}; while called < 2 {}
assert_eq!( assert_eq!(
audio_unit_remove_property_listener_with_user_data( audio_unit_remove_property_listener_with_user_data(
@ -878,22 +820,11 @@ fn test_audio_unit_add_then_fire_then_remove_property_listener() {
#[cfg(test)] #[cfg(test)]
fn get_default_input_or_output_device() -> super::device_info { fn get_default_input_or_output_device() -> super::device_info {
use super::{ use super::{audiounit_get_default_device_id, device_flags, device_info, DeviceType};
audiounit_get_default_device_id,
device_flags,
device_info,
DeviceType,
};
let mut device = device_info::new(); let mut device = device_info::new();
assert_eq!( assert_eq!(device.id, sys::kAudioObjectUnknown);
device.id, assert_eq!(device.flags, device_flags::DEV_UNKNOWN);
sys::kAudioObjectUnknown
);
assert_eq!(
device.flags,
device_flags::DEV_UNKNOWN
);
// let default_output_id = audiounit_get_default_device_id(DeviceType::OUTPUT); // let default_output_id = audiounit_get_default_device_id(DeviceType::OUTPUT);
let default_output_id = sys::kAudioObjectUnknown; let default_output_id = sys::kAudioObjectUnknown;