// Copyright © 2017 Mozilla Foundation // // This program is made available under an ISC-style license. See the // accompanying file LICENSE for details #![cfg_attr(feature = "cargo-clippy", allow(clippy::float_cmp))] #[macro_use] extern crate cubeb_backend; use cubeb_backend::{ ffi, Context, ContextOps, DeviceCollectionRef, DeviceId, DeviceRef, DeviceType, InputProcessingParams, Ops, Result, Stream, StreamOps, StreamParams, StreamParamsRef, }; use std::ffi::CStr; use std::os::raw::c_void; use std::ptr; pub const OPS: Ops = capi_new!(TestContext, TestStream); struct TestContext { #[allow(dead_code)] pub ops: *const Ops, } impl ContextOps for TestContext { fn init(_context_name: Option<&CStr>) -> Result { let ctx = Box::new(TestContext { ops: &OPS as *const _, }); Ok(unsafe { Context::from_ptr(Box::into_raw(ctx) as *mut _) }) } fn backend_id(&mut self) -> &'static CStr { unsafe { CStr::from_ptr(b"remote\0".as_ptr() as *const _) } } fn max_channel_count(&mut self) -> Result { Ok(0u32) } fn min_latency(&mut self, _params: StreamParams) -> Result { Ok(0u32) } fn preferred_sample_rate(&mut self) -> Result { Ok(0u32) } fn supported_input_processing_params(&mut self) -> Result { Ok(InputProcessingParams::NONE) } fn enumerate_devices( &mut self, _devtype: DeviceType, collection: &DeviceCollectionRef, ) -> Result<()> { let coll = unsafe { &mut *collection.as_ptr() }; coll.device = 0xDEAD_BEEF as *mut _; coll.count = usize::max_value(); Ok(()) } fn device_collection_destroy(&mut self, collection: &mut DeviceCollectionRef) -> Result<()> { let coll = unsafe { &mut *collection.as_ptr() }; assert_eq!(coll.device, 0xDEAD_BEEF as *mut _); assert_eq!(coll.count, usize::max_value()); coll.device = ptr::null_mut(); coll.count = 0; Ok(()) } fn stream_init( &mut self, _stream_name: Option<&CStr>, _input_device: DeviceId, _input_stream_params: Option<&StreamParamsRef>, _output_device: DeviceId, _output_stream_params: Option<&StreamParamsRef>, _latency_frame: u32, _data_callback: ffi::cubeb_data_callback, _state_callback: ffi::cubeb_state_callback, _user_ptr: *mut c_void, ) -> Result { Ok(unsafe { Stream::from_ptr(0xDEAD_BEEF as *mut _) }) } fn register_device_collection_changed( &mut self, _dev_type: DeviceType, _collection_changed_callback: ffi::cubeb_device_collection_changed_callback, _user_ptr: *mut c_void, ) -> Result<()> { Ok(()) } } struct TestStream {} impl StreamOps for TestStream { fn start(&mut self) -> Result<()> { Ok(()) } fn stop(&mut self) -> Result<()> { Ok(()) } fn position(&mut self) -> Result { Ok(0u64) } fn latency(&mut self) -> Result { Ok(0u32) } fn input_latency(&mut self) -> Result { Ok(0u32) } fn set_volume(&mut self, volume: f32) -> Result<()> { assert_eq!(volume, 0.5); Ok(()) } fn set_name(&mut self, name: &CStr) -> Result<()> { assert_eq!(name, CStr::from_bytes_with_nul(b"test\0").unwrap()); Ok(()) } fn current_device(&mut self) -> Result<&DeviceRef> { Ok(unsafe { DeviceRef::from_ptr(0xDEAD_BEEF as *mut _) }) } fn set_input_mute(&mut self, mute: bool) -> Result<()> { assert_eq!(mute, true); Ok(()) } fn set_input_processing_params(&mut self, params: InputProcessingParams) -> Result<()> { assert_eq!(params, InputProcessingParams::ECHO_CANCELLATION); Ok(()) } fn device_destroy(&mut self, device: &DeviceRef) -> Result<()> { assert_eq!(device.as_ptr(), 0xDEAD_BEEF as *mut _); Ok(()) } fn register_device_changed_callback( &mut self, _: ffi::cubeb_device_changed_callback, ) -> Result<()> { Ok(()) } } #[test] fn test_ops_context_init() { let mut c: *mut ffi::cubeb = ptr::null_mut(); assert_eq!( unsafe { OPS.init.unwrap()(&mut c, ptr::null()) }, ffi::CUBEB_OK ); unsafe { OPS.destroy.unwrap()(c) } } #[test] fn test_ops_context_max_channel_count() { let c: *mut ffi::cubeb = ptr::null_mut(); let mut max_channel_count = u32::max_value(); assert_eq!( unsafe { OPS.get_max_channel_count.unwrap()(c, &mut max_channel_count) }, ffi::CUBEB_OK ); assert_eq!(max_channel_count, 0); } #[test] fn test_ops_context_min_latency() { let c: *mut ffi::cubeb = ptr::null_mut(); let params: ffi::cubeb_stream_params = unsafe { ::std::mem::zeroed() }; let mut latency = u32::max_value(); assert_eq!( unsafe { OPS.get_min_latency.unwrap()(c, params, &mut latency) }, ffi::CUBEB_OK ); assert_eq!(latency, 0); } #[test] fn test_ops_context_preferred_sample_rate() { let c: *mut ffi::cubeb = ptr::null_mut(); let mut rate = u32::max_value(); assert_eq!( unsafe { OPS.get_preferred_sample_rate.unwrap()(c, &mut rate) }, ffi::CUBEB_OK ); assert_eq!(rate, 0); } #[test] fn test_ops_context_supported_input_processing_params() { let c: *mut ffi::cubeb = ptr::null_mut(); let mut params: ffi::cubeb_input_processing_params = InputProcessingParams::all().bits(); assert_eq!( unsafe { OPS.get_supported_input_processing_params.unwrap()(c, &mut params) }, ffi::CUBEB_OK ); assert_eq!(params, ffi::CUBEB_INPUT_PROCESSING_PARAM_NONE); } #[test] fn test_ops_context_enumerate_devices() { let c: *mut ffi::cubeb = ptr::null_mut(); let mut coll = ffi::cubeb_device_collection { device: ptr::null_mut(), count: 0, }; assert_eq!( unsafe { OPS.enumerate_devices.unwrap()(c, 0, &mut coll) }, ffi::CUBEB_OK ); assert_eq!(coll.device, 0xDEAD_BEEF as *mut _); assert_eq!(coll.count, usize::max_value()) } #[test] fn test_ops_context_device_collection_destroy() { let c: *mut ffi::cubeb = ptr::null_mut(); let mut coll = ffi::cubeb_device_collection { device: 0xDEAD_BEEF as *mut _, count: usize::max_value(), }; assert_eq!( unsafe { OPS.device_collection_destroy.unwrap()(c, &mut coll) }, ffi::CUBEB_OK ); assert_eq!(coll.device, ptr::null_mut()); assert_eq!(coll.count, 0); } // stream_init: Some($crate::capi::capi_stream_init::<$ctx>), // stream_destroy: Some($crate::capi::capi_stream_destroy::<$stm>), // stream_start: Some($crate::capi::capi_stream_start::<$stm>), // stream_stop: Some($crate::capi::capi_stream_stop::<$stm>), // stream_get_position: Some($crate::capi::capi_stream_get_position::<$stm>), #[test] fn test_ops_stream_latency() { let s: *mut ffi::cubeb_stream = ptr::null_mut(); let mut latency = u32::max_value(); assert_eq!( unsafe { OPS.stream_get_latency.unwrap()(s, &mut latency) }, ffi::CUBEB_OK ); assert_eq!(latency, 0); } #[test] fn test_ops_stream_set_volume() { let s: *mut ffi::cubeb_stream = ptr::null_mut(); unsafe { OPS.stream_set_volume.unwrap()(s, 0.5); } } #[test] fn test_ops_stream_set_name() { let s: *mut ffi::cubeb_stream = ptr::null_mut(); unsafe { OPS.stream_set_name.unwrap()(s, CStr::from_bytes_with_nul(b"test\0").unwrap().as_ptr()); } } #[test] fn test_ops_stream_current_device() { let s: *mut ffi::cubeb_stream = ptr::null_mut(); let mut device: *mut ffi::cubeb_device = ptr::null_mut(); assert_eq!( unsafe { OPS.stream_get_current_device.unwrap()(s, &mut device) }, ffi::CUBEB_OK ); assert_eq!(device, 0xDEAD_BEEF as *mut _); } #[test] fn test_ops_stream_set_input_mute() { let s: *mut ffi::cubeb_stream = ptr::null_mut(); assert_eq!( unsafe { OPS.stream_set_input_mute.unwrap()(s, 1) }, ffi::CUBEB_OK ); } #[test] fn test_ops_stream_set_input_processing_params() { let s: *mut ffi::cubeb_stream = ptr::null_mut(); assert_eq!( unsafe { OPS.stream_set_input_processing_params.unwrap()( s, ffi::CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION, ) }, ffi::CUBEB_OK ); } #[test] fn test_ops_stream_device_destroy() { let s: *mut ffi::cubeb_stream = ptr::null_mut(); unsafe { OPS.stream_device_destroy.unwrap()(s, 0xDEAD_BEEF as *mut _); } }