1use ffi;
7use std::ffi::CStr;
8use std::os::raw::c_void;
9use std::{ptr, str};
10use util::opt_bytes;
11use {
12 DeviceCollection, DeviceId, DeviceType, InputProcessingParams, Result, Stream, StreamParamsRef,
13};
14
15macro_rules! as_ptr {
16 ($e:expr) => {
17 $e.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut())
18 };
19}
20
21ffi_type_heap! {
22 type CType = ffi::cubeb;
23 fn drop = ffi::cubeb_destroy;
24 pub struct Context;
25 pub struct ContextRef;
26}
27
28impl Context {
29 pub fn init(context_name: Option<&CStr>, backend_name: Option<&CStr>) -> Result<Context> {
30 let mut context: *mut ffi::cubeb = ptr::null_mut();
31 let context_name = as_ptr!(context_name);
32 let backend_name = as_ptr!(backend_name);
33 unsafe {
34 call!(ffi::cubeb_init(&mut context, context_name, backend_name))?;
35 Ok(Context::from_ptr(context))
36 }
37 }
38}
39
40impl ContextRef {
41 pub fn backend_id(&self) -> &str {
42 str::from_utf8(self.backend_id_bytes()).unwrap()
43 }
44
45 pub fn backend_id_bytes(&self) -> &[u8] {
46 unsafe { opt_bytes(ffi::cubeb_get_backend_id(self.as_ptr())).unwrap() }
47 }
48
49 pub fn max_channel_count(&self) -> Result<u32> {
50 let mut channel_count = 0u32;
51 unsafe {
52 call!(ffi::cubeb_get_max_channel_count(
53 self.as_ptr(),
54 &mut channel_count
55 ))?;
56 }
57 Ok(channel_count)
58 }
59
60 pub fn min_latency(&self, params: &StreamParamsRef) -> Result<u32> {
61 let mut latency = 0u32;
62 unsafe {
63 call!(ffi::cubeb_get_min_latency(
64 self.as_ptr(),
65 params.as_ptr(),
66 &mut latency
67 ))?;
68 }
69 Ok(latency)
70 }
71
72 pub fn preferred_sample_rate(&self) -> Result<u32> {
73 let mut rate = 0u32;
74 unsafe {
75 call!(ffi::cubeb_get_preferred_sample_rate(
76 self.as_ptr(),
77 &mut rate
78 ))?;
79 }
80 Ok(rate)
81 }
82
83 pub fn supported_input_processing_params(&self) -> Result<InputProcessingParams> {
84 let mut params = ffi::CUBEB_INPUT_PROCESSING_PARAM_NONE;
85 unsafe {
86 call!(ffi::cubeb_get_supported_input_processing_params(
87 self.as_ptr(),
88 &mut params
89 ))?;
90 };
91 Ok(InputProcessingParams::from_bits_truncate(params))
92 }
93
94 #[allow(clippy::too_many_arguments)]
99 pub unsafe fn stream_init(
100 &self,
101 stream_name: Option<&CStr>,
102 input_device: DeviceId,
103 input_stream_params: Option<&StreamParamsRef>,
104 output_device: DeviceId,
105 output_stream_params: Option<&StreamParamsRef>,
106 latency_frames: u32,
107 data_callback: ffi::cubeb_data_callback,
108 state_callback: ffi::cubeb_state_callback,
109 user_ptr: *mut c_void,
110 ) -> Result<Stream> {
111 let mut stm: *mut ffi::cubeb_stream = ptr::null_mut();
112
113 let stream_name = as_ptr!(stream_name);
114 let input_stream_params = as_ptr!(input_stream_params);
115 let output_stream_params = as_ptr!(output_stream_params);
116
117 call!(ffi::cubeb_stream_init(
118 self.as_ptr(),
119 &mut stm,
120 stream_name,
121 input_device,
122 input_stream_params,
123 output_device,
124 output_stream_params,
125 latency_frames,
126 data_callback,
127 state_callback,
128 user_ptr
129 ))?;
130 Ok(Stream::from_ptr(stm))
131 }
132
133 pub fn enumerate_devices(&self, devtype: DeviceType) -> Result<DeviceCollection<'_>> {
134 let mut coll = ffi::cubeb_device_collection::default();
135 unsafe {
136 call!(ffi::cubeb_enumerate_devices(
137 self.as_ptr(),
138 devtype.bits(),
139 &mut coll
140 ))?;
141 }
142 Ok(DeviceCollection::init_with_ctx(self, coll))
143 }
144
145 pub unsafe fn register_device_collection_changed(
150 &self,
151 devtype: DeviceType,
152 callback: ffi::cubeb_device_collection_changed_callback,
153 user_ptr: *mut c_void,
154 ) -> Result<()> {
155 call!(ffi::cubeb_register_device_collection_changed(
156 self.as_ptr(),
157 devtype.bits(),
158 callback,
159 user_ptr
160 ))?;
161
162 Ok(())
163 }
164}