1 // Copyright © 2017-2018 Mozilla Foundation
2 //
3 // This program is made available under an ISC-style license.  See the
4 // accompanying file LICENSE for details.
5 
6 use {DeviceCollection, DeviceId, DeviceType, Result, Stream, StreamParamsRef};
7 use ffi;
8 use std::{ptr, str};
9 use std::ffi::CStr;
10 use std::os::raw::c_void;
11 use util::opt_bytes;
12 
13 macro_rules! as_ptr {
14     ($e:expr) => { $e.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()) }
15 }
16 
17 ffi_type_heap! {
18     type CType = ffi::cubeb;
19     fn drop = ffi::cubeb_destroy;
20     pub struct Context;
21     pub struct ContextRef;
22 }
23 
24 impl Context {
init(context_name: Option<&CStr>, backend_name: Option<&CStr>) -> Result<Context>25     pub fn init(context_name: Option<&CStr>, backend_name: Option<&CStr>) -> Result<Context> {
26         let mut context: *mut ffi::cubeb = ptr::null_mut();
27         let context_name = as_ptr!(context_name);
28         let backend_name = as_ptr!(backend_name);
29         unsafe {
30             try_call!(ffi::cubeb_init(&mut context, context_name, backend_name));
31             Ok(Context::from_ptr(context))
32         }
33     }
34 }
35 
36 impl ContextRef {
backend_id(&self) -> &str37     pub fn backend_id(&self) -> &str {
38         str::from_utf8(self.backend_id_bytes()).unwrap()
39     }
40 
backend_id_bytes(&self) -> &[u8]41     pub fn backend_id_bytes(&self) -> &[u8] {
42         unsafe { opt_bytes(ffi::cubeb_get_backend_id(self.as_ptr())).unwrap() }
43     }
44 
max_channel_count(&self) -> Result<u32>45     pub fn max_channel_count(&self) -> Result<u32> {
46         let mut channel_count = 0u32;
47         unsafe {
48             let _ = try_call!(ffi::cubeb_get_max_channel_count(
49                 self.as_ptr(),
50                 &mut channel_count
51             ));
52         }
53         Ok(channel_count)
54     }
55 
min_latency(&self, params: &StreamParamsRef) -> Result<u32>56     pub fn min_latency(&self, params: &StreamParamsRef) -> Result<u32> {
57         let mut latency = 0u32;
58         unsafe {
59             let _ = try_call!(ffi::cubeb_get_min_latency(
60                 self.as_ptr(),
61                 params.as_ptr(),
62                 &mut latency
63             ));
64         }
65         Ok(latency)
66     }
67 
preferred_sample_rate(&self) -> Result<u32>68     pub fn preferred_sample_rate(&self) -> Result<u32> {
69         let mut rate = 0u32;
70         unsafe {
71             let _ = try_call!(ffi::cubeb_get_preferred_sample_rate(
72                 self.as_ptr(),
73                 &mut rate
74             ));
75         }
76         Ok(rate)
77     }
78 
79     #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
stream_init( &self, stream_name: Option<&CStr>, input_device: DeviceId, input_stream_params: Option<&StreamParamsRef>, output_device: DeviceId, output_stream_params: Option<&StreamParamsRef>, latency_frames: u32, data_callback: ffi::cubeb_data_callback, state_callback: ffi::cubeb_state_callback, user_ptr: *mut c_void, ) -> Result<Stream>80     pub unsafe fn stream_init(
81         &self,
82         stream_name: Option<&CStr>,
83         input_device: DeviceId,
84         input_stream_params: Option<&StreamParamsRef>,
85         output_device: DeviceId,
86         output_stream_params: Option<&StreamParamsRef>,
87         latency_frames: u32,
88         data_callback: ffi::cubeb_data_callback,
89         state_callback: ffi::cubeb_state_callback,
90         user_ptr: *mut c_void,
91     ) -> Result<Stream> {
92         let mut stm: *mut ffi::cubeb_stream = ptr::null_mut();
93 
94         let stream_name = as_ptr!(stream_name);
95         let input_stream_params = as_ptr!(input_stream_params);
96         let output_stream_params = as_ptr!(output_stream_params);
97 
98         let _ = try_call!(ffi::cubeb_stream_init(
99             self.as_ptr(),
100             &mut stm,
101             stream_name,
102             input_device,
103             input_stream_params,
104             output_device,
105             output_stream_params,
106             latency_frames,
107             data_callback,
108             state_callback,
109             user_ptr
110         ));
111         Ok(Stream::from_ptr(stm))
112     }
113 
enumerate_devices(&self, devtype: DeviceType) -> Result<DeviceCollection>114     pub fn enumerate_devices(&self, devtype: DeviceType) -> Result<DeviceCollection> {
115         let mut coll = ffi::cubeb_device_collection::default();
116         unsafe {
117             let _ = try_call!(ffi::cubeb_enumerate_devices(
118                 self.as_ptr(),
119                 devtype.bits(),
120                 &mut coll
121             ));
122         }
123         Ok(DeviceCollection::init_with_ctx(self, coll))
124     }
125 
register_device_collection_changed( &self, devtype: DeviceType, callback: ffi::cubeb_device_collection_changed_callback, user_ptr: *mut c_void, ) -> Result<()>126     pub unsafe fn register_device_collection_changed(
127         &self,
128         devtype: DeviceType,
129         callback: ffi::cubeb_device_collection_changed_callback,
130         user_ptr: *mut c_void,
131     ) -> Result<()> {
132         let _ = try_call!(ffi::cubeb_register_device_collection_changed(
133             self.as_ptr(),
134             devtype.bits(),
135             callback,
136             user_ptr
137         ));
138 
139         Ok(())
140     }
141 }
142