1use cubeb_core::{
7 ffi, DeviceInfo, DeviceRef, DeviceType, InputProcessingParams, StreamParams, StreamParamsRef,
8};
9use std::ffi::CStr;
10use std::mem;
11use std::os::raw::{c_char, c_int, c_void};
12use {ContextOps, StreamOps};
13
14macro_rules! _try(
18 ($e:expr) => (match $e {
19 Ok(e) => e,
20 Err(e) => return e as c_int
21 })
22);
23
24macro_rules! as_opt_ref {
25 ($e:expr) => {
26 if $e.is_null() {
27 None
28 } else {
29 Some(StreamParamsRef::from_ptr($e))
30 }
31 };
32}
33
34#[macro_export]
35macro_rules! capi_new(
36 ($ctx:ident, $stm:ident) => (
37 Ops {
38 init: Some($crate::capi::capi_init::<$ctx>),
39 get_backend_id: Some($crate::capi::capi_get_backend_id::<$ctx>),
40 get_max_channel_count: Some($crate::capi::capi_get_max_channel_count::<$ctx>),
41 get_min_latency: Some($crate::capi::capi_get_min_latency::<$ctx>),
42 get_preferred_sample_rate: Some($crate::capi::capi_get_preferred_sample_rate::<$ctx>),
43 get_supported_input_processing_params:
44 Some($crate::capi::capi_get_supported_input_processing_params::<$ctx>),
45 enumerate_devices: Some($crate::capi::capi_enumerate_devices::<$ctx>),
46 device_collection_destroy: Some($crate::capi::capi_device_collection_destroy::<$ctx>),
47 destroy: Some($crate::capi::capi_destroy::<$ctx>),
48 stream_init: Some($crate::capi::capi_stream_init::<$ctx>),
49 stream_destroy: Some($crate::capi::capi_stream_destroy::<$stm>),
50 stream_start: Some($crate::capi::capi_stream_start::<$stm>),
51 stream_stop: Some($crate::capi::capi_stream_stop::<$stm>),
52 stream_get_position: Some($crate::capi::capi_stream_get_position::<$stm>),
53 stream_get_latency: Some($crate::capi::capi_stream_get_latency::<$stm>),
54 stream_get_input_latency: Some($crate::capi::capi_stream_get_input_latency::<$stm>),
55 stream_set_volume: Some($crate::capi::capi_stream_set_volume::<$stm>),
56 stream_set_name: Some($crate::capi::capi_stream_set_name::<$stm>),
57 stream_get_current_device: Some($crate::capi::capi_stream_get_current_device::<$stm>),
58 stream_set_input_mute: Some($crate::capi::capi_stream_set_input_mute::<$stm>),
59 stream_set_input_processing_params:
60 Some($crate::capi::capi_stream_set_input_processing_params::<$stm>),
61 stream_device_destroy: Some($crate::capi::capi_stream_device_destroy::<$stm>),
62 stream_register_device_changed_callback:
63 Some($crate::capi::capi_stream_register_device_changed_callback::<$stm>),
64 register_device_collection_changed:
65 Some($crate::capi::capi_register_device_collection_changed::<$ctx>)
66 }));
67
68pub unsafe extern "C" fn capi_init<CTX: ContextOps>(
75 c: *mut *mut ffi::cubeb,
76 context_name: *const c_char,
77) -> c_int {
78 let anchor = &();
79 let context_name = opt_cstr(anchor, context_name);
80 let context = _try!(CTX::init(context_name));
81 c.write(Box::into_raw(context) as *mut _);
82 ffi::CUBEB_OK
83}
84
85pub unsafe extern "C" fn capi_get_backend_id<CTX: ContextOps>(c: *mut ffi::cubeb) -> *const c_char {
92 let ctx = &mut *(c as *mut CTX);
93 ctx.backend_id().as_ptr()
94}
95
96pub unsafe extern "C" fn capi_get_max_channel_count<CTX: ContextOps>(
103 c: *mut ffi::cubeb,
104 max_channels: *mut u32,
105) -> c_int {
106 let ctx = &mut *(c as *mut CTX);
107
108 *max_channels = _try!(ctx.max_channel_count());
109 ffi::CUBEB_OK
110}
111
112pub unsafe extern "C" fn capi_get_min_latency<CTX: ContextOps>(
119 c: *mut ffi::cubeb,
120 param: ffi::cubeb_stream_params,
121 latency_frames: *mut u32,
122) -> c_int {
123 let ctx = &mut *(c as *mut CTX);
124 let param = StreamParams::from(param);
125 *latency_frames = _try!(ctx.min_latency(param));
126 ffi::CUBEB_OK
127}
128
129pub unsafe extern "C" fn capi_get_preferred_sample_rate<CTX: ContextOps>(
136 c: *mut ffi::cubeb,
137 rate: *mut u32,
138) -> c_int {
139 let ctx = &mut *(c as *mut CTX);
140
141 *rate = _try!(ctx.preferred_sample_rate());
142 ffi::CUBEB_OK
143}
144
145pub unsafe extern "C" fn capi_get_supported_input_processing_params<CTX: ContextOps>(
152 c: *mut ffi::cubeb,
153 params: *mut ffi::cubeb_input_processing_params,
154) -> c_int {
155 let ctx = &mut *(c as *mut CTX);
156 *params = _try!(ctx.supported_input_processing_params()).bits();
157 ffi::CUBEB_OK
158}
159
160pub unsafe extern "C" fn capi_enumerate_devices<CTX: ContextOps>(
167 c: *mut ffi::cubeb,
168 devtype: ffi::cubeb_device_type,
169 collection: *mut ffi::cubeb_device_collection,
170) -> c_int {
171 debug_assert!(!c.is_null());
172 debug_assert!(!collection.is_null());
173
174 let ctx = &mut *(c as *mut CTX);
175 let devtype = DeviceType::from_bits_truncate(devtype);
176
177 let coll = Box::into_raw(_try!(ctx.enumerate_devices(devtype)));
178 collection.write(ffi::cubeb_device_collection {
179 device: coll as *mut _,
180 count: coll.len(),
181 });
182 ffi::CUBEB_OK
183}
184
185pub unsafe extern "C" fn capi_device_collection_destroy<CTX: ContextOps>(
192 c: *mut ffi::cubeb,
193 collection: *mut ffi::cubeb_device_collection,
194) -> c_int {
195 debug_assert!(!c.is_null());
196 debug_assert!(!collection.is_null());
197
198 let ctx = &mut *(c as *mut CTX);
199 let collection = &mut *(collection);
200
201 let coll = Box::from_raw(std::ptr::slice_from_raw_parts_mut(
202 collection.device as *mut DeviceInfo,
203 collection.count,
204 ));
205 _try!(ctx.device_collection_destroy(coll));
206 collection.device = std::ptr::null_mut();
207 collection.count = 0;
208 ffi::CUBEB_OK
209}
210
211pub unsafe extern "C" fn capi_destroy<CTX>(c: *mut ffi::cubeb) {
218 let _: Box<CTX> = Box::from_raw(c as *mut _);
219}
220
221pub unsafe extern "C" fn capi_stream_init<CTX: ContextOps>(
229 c: *mut ffi::cubeb,
230 s: *mut *mut ffi::cubeb_stream,
231 stream_name: *const c_char,
232 input_device: ffi::cubeb_devid,
233 input_stream_params: *mut ffi::cubeb_stream_params,
234 output_device: ffi::cubeb_devid,
235 output_stream_params: *mut ffi::cubeb_stream_params,
236 latency_frames: u32,
237 data_callback: ffi::cubeb_data_callback,
238 state_callback: ffi::cubeb_state_callback,
239 user_ptr: *mut c_void,
240) -> c_int {
241 let ctx = &mut *(c as *mut CTX);
242 let anchor = &(); let input_stream_params = as_opt_ref!(input_stream_params);
245 let output_stream_params = as_opt_ref!(output_stream_params);
246
247 let stream = _try!(ctx.stream_init(
248 opt_cstr(anchor, stream_name),
249 input_device,
250 input_stream_params,
251 output_device,
252 output_stream_params,
253 latency_frames,
254 data_callback,
255 state_callback,
256 user_ptr
257 ));
258 *s = stream.as_ptr();
259 mem::forget(stream);
261 ffi::CUBEB_OK
262}
263
264pub unsafe extern "C" fn capi_stream_destroy<STM>(s: *mut ffi::cubeb_stream) {
271 let _ = Box::from_raw(s as *mut STM);
272}
273
274pub unsafe extern "C" fn capi_stream_start<STM: StreamOps>(s: *mut ffi::cubeb_stream) -> c_int {
281 let stm = &mut *(s as *mut STM);
282
283 _try!(stm.start());
284 ffi::CUBEB_OK
285}
286
287pub unsafe extern "C" fn capi_stream_stop<STM: StreamOps>(s: *mut ffi::cubeb_stream) -> c_int {
294 let stm = &mut *(s as *mut STM);
295
296 _try!(stm.stop());
297 ffi::CUBEB_OK
298}
299
300pub unsafe extern "C" fn capi_stream_get_position<STM: StreamOps>(
307 s: *mut ffi::cubeb_stream,
308 position: *mut u64,
309) -> c_int {
310 let stm = &mut *(s as *mut STM);
311
312 *position = _try!(stm.position());
313 ffi::CUBEB_OK
314}
315
316pub unsafe extern "C" fn capi_stream_get_latency<STM: StreamOps>(
323 s: *mut ffi::cubeb_stream,
324 latency: *mut u32,
325) -> c_int {
326 let stm = &mut *(s as *mut STM);
327
328 *latency = _try!(stm.latency());
329 ffi::CUBEB_OK
330}
331
332pub unsafe extern "C" fn capi_stream_get_input_latency<STM: StreamOps>(
339 s: *mut ffi::cubeb_stream,
340 latency: *mut u32,
341) -> c_int {
342 let stm = &mut *(s as *mut STM);
343
344 *latency = _try!(stm.input_latency());
345 ffi::CUBEB_OK
346}
347
348pub unsafe extern "C" fn capi_stream_set_volume<STM: StreamOps>(
355 s: *mut ffi::cubeb_stream,
356 volume: f32,
357) -> c_int {
358 let stm = &mut *(s as *mut STM);
359
360 _try!(stm.set_volume(volume));
361 ffi::CUBEB_OK
362}
363
364pub unsafe extern "C" fn capi_stream_set_name<STM: StreamOps>(
371 s: *mut ffi::cubeb_stream,
372 name: *const c_char,
373) -> c_int {
374 let stm = &mut *(s as *mut STM);
375 let anchor = &();
376 if let Some(name) = opt_cstr(anchor, name) {
377 _try!(stm.set_name(name));
378 ffi::CUBEB_OK
379 } else {
380 ffi::CUBEB_ERROR_INVALID_PARAMETER
381 }
382}
383
384pub unsafe extern "C" fn capi_stream_get_current_device<STM: StreamOps>(
391 s: *mut ffi::cubeb_stream,
392 device: *mut *mut ffi::cubeb_device,
393) -> i32 {
394 let stm = &mut *(s as *mut STM);
395
396 *device = _try!(stm.current_device()).as_ptr();
397 ffi::CUBEB_OK
398}
399
400pub unsafe extern "C" fn capi_stream_set_input_mute<STM: StreamOps>(
407 s: *mut ffi::cubeb_stream,
408 mute: c_int,
409) -> c_int {
410 let stm = &mut *(s as *mut STM);
411 _try!(stm.set_input_mute(mute != 0));
412 ffi::CUBEB_OK
413}
414
415pub unsafe extern "C" fn capi_stream_set_input_processing_params<STM: StreamOps>(
422 s: *mut ffi::cubeb_stream,
423 params: ffi::cubeb_input_processing_params,
424) -> c_int {
425 let stm = &mut *(s as *mut STM);
426 _try!(stm.set_input_processing_params(InputProcessingParams::from_bits_truncate(params)));
427 ffi::CUBEB_OK
428}
429
430pub unsafe extern "C" fn capi_stream_device_destroy<STM: StreamOps>(
437 s: *mut ffi::cubeb_stream,
438 device: *mut ffi::cubeb_device,
439) -> c_int {
440 let stm = &mut *(s as *mut STM);
441 if device.is_null() {
442 return ffi::CUBEB_ERROR_INVALID_PARAMETER;
443 }
444 let device = DeviceRef::from_ptr(device);
445 let _ = stm.device_destroy(device);
446 ffi::CUBEB_OK
447}
448
449pub unsafe extern "C" fn capi_stream_register_device_changed_callback<STM: StreamOps>(
456 s: *mut ffi::cubeb_stream,
457 device_changed_callback: ffi::cubeb_device_changed_callback,
458) -> c_int {
459 let stm = &mut *(s as *mut STM);
460
461 _try!(stm.register_device_changed_callback(device_changed_callback));
462 ffi::CUBEB_OK
463}
464
465pub unsafe extern "C" fn capi_register_device_collection_changed<CTX: ContextOps>(
473 c: *mut ffi::cubeb,
474 devtype: ffi::cubeb_device_type,
475 collection_changed_callback: ffi::cubeb_device_collection_changed_callback,
476 user_ptr: *mut c_void,
477) -> i32 {
478 let ctx = &mut *(c as *mut CTX);
479 let devtype = DeviceType::from_bits_truncate(devtype);
480 _try!(ctx.register_device_collection_changed(devtype, collection_changed_callback, user_ptr));
481 ffi::CUBEB_OK
482}
483
484fn opt_cstr<T>(_anchor: &T, ptr: *const c_char) -> Option<&CStr> {
485 if ptr.is_null() {
486 None
487 } else {
488 Some(unsafe { CStr::from_ptr(ptr) })
489 }
490}