1use ffi;
7use std::ffi::CStr;
8use std::os::raw::{c_int, c_void};
9use std::ptr;
10use {ChannelLayout, DeviceRef, Result, SampleFormat};
11
12#[derive(PartialEq, Eq, Clone, Debug, Copy)]
14pub enum State {
15 Started,
17 Stopped,
19 Drained,
21 Error,
23}
24
25impl From<ffi::cubeb_state> for State {
26 fn from(x: ffi::cubeb_state) -> Self {
27 use State::*;
28 match x {
29 ffi::CUBEB_STATE_STARTED => Started,
30 ffi::CUBEB_STATE_STOPPED => Stopped,
31 ffi::CUBEB_STATE_DRAINED => Drained,
32 _ => Error,
33 }
34 }
35}
36
37impl From<State> for ffi::cubeb_state {
38 fn from(x: State) -> Self {
39 use State::*;
40 match x {
41 Started => ffi::CUBEB_STATE_STARTED,
42 Stopped => ffi::CUBEB_STATE_STOPPED,
43 Drained => ffi::CUBEB_STATE_DRAINED,
44 Error => ffi::CUBEB_STATE_ERROR,
45 }
46 }
47}
48
49bitflags! {
50 pub struct StreamPrefs: ffi::cubeb_stream_prefs {
52 const LOOPBACK = ffi::CUBEB_STREAM_PREF_LOOPBACK;
53 const DISABLE_DEVICE_SWITCHING = ffi::CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING;
54 const VOICE = ffi::CUBEB_STREAM_PREF_VOICE;
55 }
56}
57
58impl StreamPrefs {
59 pub const NONE: Self = Self::empty();
60}
61
62bitflags! {
63 pub struct InputProcessingParams: ffi::cubeb_input_processing_params {
65 const ECHO_CANCELLATION = ffi::CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION;
66 const NOISE_SUPPRESSION = ffi::CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION;
67 const AUTOMATIC_GAIN_CONTROL = ffi::CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL;
68 const VOICE_ISOLATION = ffi::CUBEB_INPUT_PROCESSING_PARAM_VOICE_ISOLATION;
69 }
70}
71
72impl InputProcessingParams {
73 pub const NONE: Self = Self::empty();
74}
75
76ffi_type_stack! {
77 type CType = ffi::cubeb_stream_params;
79 #[derive(Debug)]
80 pub struct StreamParams;
81 pub struct StreamParamsRef;
82}
83
84impl StreamParamsRef {
85 fn get_ref(&self) -> &ffi::cubeb_stream_params {
86 unsafe { &*self.as_ptr() }
87 }
88
89 pub fn format(&self) -> SampleFormat {
90 use SampleFormat::*;
91 match self.get_ref().format {
92 ffi::CUBEB_SAMPLE_S16LE => S16LE,
93 ffi::CUBEB_SAMPLE_S16BE => S16BE,
94 ffi::CUBEB_SAMPLE_FLOAT32LE => Float32LE,
95 ffi::CUBEB_SAMPLE_FLOAT32BE => Float32BE,
96 x => panic!("unknown sample format: {}", x),
97 }
98 }
99
100 pub fn rate(&self) -> u32 {
101 self.get_ref().rate
102 }
103 pub fn channels(&self) -> u32 {
104 self.get_ref().channels
105 }
106
107 pub fn layout(&self) -> ChannelLayout {
108 ChannelLayout::from(self.get_ref().layout)
109 }
110
111 pub fn prefs(&self) -> StreamPrefs {
112 StreamPrefs::from_bits_truncate(self.get_ref().prefs)
113 }
114}
115
116unsafe fn wrapped_cubeb_stream_destroy(stream: *mut ffi::cubeb_stream) {
117 ffi::cubeb_stream_stop(stream);
118 ffi::cubeb_stream_destroy(stream);
119}
120
121ffi_type_heap! {
122 type CType = ffi::cubeb_stream;
123 fn drop = wrapped_cubeb_stream_destroy;
124 pub struct Stream;
125 pub struct StreamRef;
126}
127
128impl StreamRef {
129 pub fn start(&self) -> Result<()> {
131 unsafe { call!(ffi::cubeb_stream_start(self.as_ptr())) }
132 }
133
134 pub fn stop(&self) -> Result<()> {
136 unsafe { call!(ffi::cubeb_stream_stop(self.as_ptr())) }
137 }
138
139 pub fn position(&self) -> Result<u64> {
141 let mut position = 0u64;
142 unsafe {
143 call!(ffi::cubeb_stream_get_position(self.as_ptr(), &mut position))?;
144 }
145 Ok(position)
146 }
147
148 pub fn latency(&self) -> Result<u32> {
152 let mut latency = 0u32;
153 unsafe {
154 call!(ffi::cubeb_stream_get_latency(self.as_ptr(), &mut latency))?;
155 }
156 Ok(latency)
157 }
158
159 pub fn input_latency(&self) -> Result<u32> {
163 let mut latency = 0u32;
164 unsafe {
165 call!(ffi::cubeb_stream_get_input_latency(
166 self.as_ptr(),
167 &mut latency
168 ))?;
169 }
170 Ok(latency)
171 }
172
173 pub fn set_volume(&self, volume: f32) -> Result<()> {
175 unsafe { call!(ffi::cubeb_stream_set_volume(self.as_ptr(), volume)) }
176 }
177
178 pub fn set_name(&self, name: &CStr) -> Result<()> {
180 unsafe { call!(ffi::cubeb_stream_set_name(self.as_ptr(), name.as_ptr())) }
181 }
182
183 pub fn current_device(&self) -> Result<&DeviceRef> {
185 let mut device: *mut ffi::cubeb_device = ptr::null_mut();
186 unsafe {
187 call!(ffi::cubeb_stream_get_current_device(
188 self.as_ptr(),
189 &mut device
190 ))?;
191 Ok(DeviceRef::from_ptr(device))
192 }
193 }
194
195 pub fn set_input_mute(&self, mute: bool) -> Result<()> {
197 let mute: c_int = if mute { 1 } else { 0 };
198 unsafe { call!(ffi::cubeb_stream_set_input_mute(self.as_ptr(), mute)) }
199 }
200
201 pub fn set_input_processing_params(&self, params: InputProcessingParams) -> Result<()> {
203 unsafe {
204 call!(ffi::cubeb_stream_set_input_processing_params(
205 self.as_ptr(),
206 params.bits()
207 ))
208 }
209 }
210
211 pub fn device_destroy(&self, device: DeviceRef) -> Result<()> {
213 unsafe {
214 call!(ffi::cubeb_stream_device_destroy(
215 self.as_ptr(),
216 device.as_ptr()
217 ))
218 }
219 }
220
221 pub fn register_device_changed_callback(
223 &self,
224 callback: ffi::cubeb_device_changed_callback,
225 ) -> Result<()> {
226 unsafe {
227 call!(ffi::cubeb_stream_register_device_changed_callback(
228 self.as_ptr(),
229 callback
230 ))
231 }
232 }
233
234 pub fn user_ptr(&self) -> *mut c_void {
235 unsafe { ffi::cubeb_stream_user_ptr(self.as_ptr()) }
236 }
237}
238
239#[cfg(test)]
240mod tests {
241 use std::mem;
242 use {StreamParams, StreamParamsRef, StreamPrefs};
243
244 #[test]
245 fn stream_params_default() {
246 let params = StreamParams::default();
247 assert_eq!(params.channels(), 0);
248 }
249
250 #[test]
251 fn stream_params_raw_channels() {
252 let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
253 raw.channels = 2;
254 let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
255 assert_eq!(params.channels(), 2);
256 }
257
258 #[test]
259 fn stream_params_raw_format() {
260 let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
261 macro_rules! check(
262 ($($raw:ident => $real:ident),*) => (
263 $(raw.format = super::ffi::$raw;
264 let params = unsafe {
265 StreamParamsRef::from_ptr(&mut raw)
266 };
267 assert_eq!(params.format(), super::SampleFormat::$real);
268 )*
269 ) );
270
271 check!(CUBEB_SAMPLE_S16LE => S16LE,
272 CUBEB_SAMPLE_S16BE => S16BE,
273 CUBEB_SAMPLE_FLOAT32LE => Float32LE,
274 CUBEB_SAMPLE_FLOAT32BE => Float32BE);
275 }
276
277 #[test]
278 fn stream_params_raw_format_native_endian() {
279 let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
280 raw.format = super::ffi::CUBEB_SAMPLE_S16NE;
281 let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
282 assert_eq!(
283 params.format(),
284 if cfg!(target_endian = "little") {
285 super::SampleFormat::S16LE
286 } else {
287 super::SampleFormat::S16BE
288 }
289 );
290
291 raw.format = super::ffi::CUBEB_SAMPLE_FLOAT32NE;
292 let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
293 assert_eq!(
294 params.format(),
295 if cfg!(target_endian = "little") {
296 super::SampleFormat::Float32LE
297 } else {
298 super::SampleFormat::Float32BE
299 }
300 );
301 }
302
303 #[test]
304 fn stream_params_raw_layout() {
305 let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
306 macro_rules! check(
307 ($($raw:ident => $real:ident),*) => (
308 $(raw.layout = super::ffi::$raw;
309 let params = unsafe {
310 StreamParamsRef::from_ptr(&mut raw)
311 };
312 assert_eq!(params.layout(), super::ChannelLayout::$real);
313 )*
314 ) );
315
316 check!(CUBEB_LAYOUT_UNDEFINED => UNDEFINED,
317 CUBEB_LAYOUT_MONO => MONO,
318 CUBEB_LAYOUT_MONO_LFE => MONO_LFE,
319 CUBEB_LAYOUT_STEREO => STEREO,
320 CUBEB_LAYOUT_STEREO_LFE => STEREO_LFE,
321 CUBEB_LAYOUT_3F => _3F,
322 CUBEB_LAYOUT_3F_LFE => _3F_LFE,
323 CUBEB_LAYOUT_2F1 => _2F1,
324 CUBEB_LAYOUT_2F1_LFE => _2F1_LFE,
325 CUBEB_LAYOUT_3F1 => _3F1,
326 CUBEB_LAYOUT_3F1_LFE => _3F1_LFE,
327 CUBEB_LAYOUT_2F2 => _2F2,
328 CUBEB_LAYOUT_2F2_LFE => _2F2_LFE,
329 CUBEB_LAYOUT_QUAD => QUAD,
330 CUBEB_LAYOUT_QUAD_LFE => QUAD_LFE,
331 CUBEB_LAYOUT_3F2 => _3F2,
332 CUBEB_LAYOUT_3F2_LFE => _3F2_LFE,
333 CUBEB_LAYOUT_3F2_BACK => _3F2_BACK,
334 CUBEB_LAYOUT_3F2_LFE_BACK => _3F2_LFE_BACK,
335 CUBEB_LAYOUT_3F3R_LFE => _3F3R_LFE,
336 CUBEB_LAYOUT_3F4_LFE => _3F4_LFE);
337 }
338
339 #[test]
340 fn stream_params_raw_rate() {
341 let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
342 raw.rate = 44_100;
343 let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
344 assert_eq!(params.rate(), 44_100);
345 }
346
347 #[test]
348 fn stream_params_raw_prefs() {
349 let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
350 raw.prefs = super::ffi::CUBEB_STREAM_PREF_LOOPBACK;
351 let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
352 assert_eq!(params.prefs(), StreamPrefs::LOOPBACK);
353 }
354
355 #[test]
356 fn stream_params_stream_params_ref_ptr_match() {
357 let params = StreamParams::default();
358 assert_eq!(params.as_ptr(), params.as_ref().as_ptr());
359 }
360}