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 pub fn input_params(&self) -> InputProcessingParams {
116 InputProcessingParams::from_bits_truncate(self.get_ref().input_params)
117 }
118}
119
120unsafe fn wrapped_cubeb_stream_destroy(stream: *mut ffi::cubeb_stream) {
121 ffi::cubeb_stream_stop(stream);
122 ffi::cubeb_stream_destroy(stream);
123}
124
125ffi_type_heap! {
126 type CType = ffi::cubeb_stream;
127 fn drop = wrapped_cubeb_stream_destroy;
128 pub struct Stream;
129 pub struct StreamRef;
130}
131
132impl StreamRef {
133 pub fn start(&self) -> Result<()> {
135 unsafe { call!(ffi::cubeb_stream_start(self.as_ptr())) }
136 }
137
138 pub fn stop(&self) -> Result<()> {
140 unsafe { call!(ffi::cubeb_stream_stop(self.as_ptr())) }
141 }
142
143 pub fn position(&self) -> Result<u64> {
145 let mut position = 0u64;
146 unsafe {
147 call!(ffi::cubeb_stream_get_position(self.as_ptr(), &mut position))?;
148 }
149 Ok(position)
150 }
151
152 pub fn latency(&self) -> Result<u32> {
156 let mut latency = 0u32;
157 unsafe {
158 call!(ffi::cubeb_stream_get_latency(self.as_ptr(), &mut latency))?;
159 }
160 Ok(latency)
161 }
162
163 pub fn input_latency(&self) -> Result<u32> {
167 let mut latency = 0u32;
168 unsafe {
169 call!(ffi::cubeb_stream_get_input_latency(
170 self.as_ptr(),
171 &mut latency
172 ))?;
173 }
174 Ok(latency)
175 }
176
177 pub fn set_volume(&self, volume: f32) -> Result<()> {
179 unsafe { call!(ffi::cubeb_stream_set_volume(self.as_ptr(), volume)) }
180 }
181
182 pub fn set_name(&self, name: &CStr) -> Result<()> {
184 unsafe { call!(ffi::cubeb_stream_set_name(self.as_ptr(), name.as_ptr())) }
185 }
186
187 pub fn current_device(&self) -> Result<&DeviceRef> {
189 let mut device: *mut ffi::cubeb_device = ptr::null_mut();
190 unsafe {
191 call!(ffi::cubeb_stream_get_current_device(
192 self.as_ptr(),
193 &mut device
194 ))?;
195 Ok(DeviceRef::from_ptr(device))
196 }
197 }
198
199 pub fn set_input_mute(&self, mute: bool) -> Result<()> {
201 let mute: c_int = if mute { 1 } else { 0 };
202 unsafe { call!(ffi::cubeb_stream_set_input_mute(self.as_ptr(), mute)) }
203 }
204
205 pub fn set_input_processing_params(&self, params: InputProcessingParams) -> Result<()> {
207 unsafe {
208 call!(ffi::cubeb_stream_set_input_processing_params(
209 self.as_ptr(),
210 params.bits()
211 ))
212 }
213 }
214
215 pub fn device_destroy(&self, device: DeviceRef) -> Result<()> {
217 unsafe {
218 call!(ffi::cubeb_stream_device_destroy(
219 self.as_ptr(),
220 device.as_ptr()
221 ))
222 }
223 }
224
225 pub fn register_device_changed_callback(
227 &self,
228 callback: ffi::cubeb_device_changed_callback,
229 ) -> Result<()> {
230 unsafe {
231 call!(ffi::cubeb_stream_register_device_changed_callback(
232 self.as_ptr(),
233 callback
234 ))
235 }
236 }
237
238 pub fn user_ptr(&self) -> *mut c_void {
239 unsafe { ffi::cubeb_stream_user_ptr(self.as_ptr()) }
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use std::mem;
246 use {InputProcessingParams, StreamParams, StreamParamsRef, StreamPrefs};
247
248 #[test]
249 fn stream_params_default() {
250 let params = StreamParams::default();
251 assert_eq!(params.channels(), 0);
252 }
253
254 #[test]
255 fn stream_params_raw_channels() {
256 let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
257 raw.channels = 2;
258 let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
259 assert_eq!(params.channels(), 2);
260 }
261
262 #[test]
263 fn stream_params_raw_format() {
264 let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
265 macro_rules! check(
266 ($($raw:ident => $real:ident),*) => (
267 $(raw.format = super::ffi::$raw;
268 let params = unsafe {
269 StreamParamsRef::from_ptr(&mut raw)
270 };
271 assert_eq!(params.format(), super::SampleFormat::$real);
272 )*
273 ) );
274
275 check!(CUBEB_SAMPLE_S16LE => S16LE,
276 CUBEB_SAMPLE_S16BE => S16BE,
277 CUBEB_SAMPLE_FLOAT32LE => Float32LE,
278 CUBEB_SAMPLE_FLOAT32BE => Float32BE);
279 }
280
281 #[test]
282 fn stream_params_raw_format_native_endian() {
283 let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
284 raw.format = super::ffi::CUBEB_SAMPLE_S16NE;
285 let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
286 assert_eq!(
287 params.format(),
288 if cfg!(target_endian = "little") {
289 super::SampleFormat::S16LE
290 } else {
291 super::SampleFormat::S16BE
292 }
293 );
294
295 raw.format = super::ffi::CUBEB_SAMPLE_FLOAT32NE;
296 let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
297 assert_eq!(
298 params.format(),
299 if cfg!(target_endian = "little") {
300 super::SampleFormat::Float32LE
301 } else {
302 super::SampleFormat::Float32BE
303 }
304 );
305 }
306
307 #[test]
308 fn stream_params_raw_layout() {
309 let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
310 macro_rules! check(
311 ($($raw:ident => $real:ident),*) => (
312 $(raw.layout = super::ffi::$raw;
313 let params = unsafe {
314 StreamParamsRef::from_ptr(&mut raw)
315 };
316 assert_eq!(params.layout(), super::ChannelLayout::$real);
317 )*
318 ) );
319
320 check!(CUBEB_LAYOUT_UNDEFINED => UNDEFINED,
321 CUBEB_LAYOUT_MONO => MONO,
322 CUBEB_LAYOUT_MONO_LFE => MONO_LFE,
323 CUBEB_LAYOUT_STEREO => STEREO,
324 CUBEB_LAYOUT_STEREO_LFE => STEREO_LFE,
325 CUBEB_LAYOUT_3F => _3F,
326 CUBEB_LAYOUT_3F_LFE => _3F_LFE,
327 CUBEB_LAYOUT_2F1 => _2F1,
328 CUBEB_LAYOUT_2F1_LFE => _2F1_LFE,
329 CUBEB_LAYOUT_3F1 => _3F1,
330 CUBEB_LAYOUT_3F1_LFE => _3F1_LFE,
331 CUBEB_LAYOUT_2F2 => _2F2,
332 CUBEB_LAYOUT_2F2_LFE => _2F2_LFE,
333 CUBEB_LAYOUT_QUAD => QUAD,
334 CUBEB_LAYOUT_QUAD_LFE => QUAD_LFE,
335 CUBEB_LAYOUT_3F2 => _3F2,
336 CUBEB_LAYOUT_3F2_LFE => _3F2_LFE,
337 CUBEB_LAYOUT_3F2_BACK => _3F2_BACK,
338 CUBEB_LAYOUT_3F2_LFE_BACK => _3F2_LFE_BACK,
339 CUBEB_LAYOUT_3F3R_LFE => _3F3R_LFE,
340 CUBEB_LAYOUT_3F4_LFE => _3F4_LFE);
341 }
342
343 #[test]
344 fn stream_params_raw_rate() {
345 let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
346 raw.rate = 44_100;
347 let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
348 assert_eq!(params.rate(), 44_100);
349 }
350
351 #[test]
352 fn stream_params_raw_prefs() {
353 let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
354 raw.prefs = super::ffi::CUBEB_STREAM_PREF_LOOPBACK;
355 let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
356 assert_eq!(params.prefs(), StreamPrefs::LOOPBACK);
357 }
358
359 #[test]
360 fn stream_params_raw_input_params() {
361 let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
362 raw.input_params = super::ffi::CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION;
363 let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
364 assert_eq!(
365 params.input_params(),
366 InputProcessingParams::ECHO_CANCELLATION
367 );
368 }
369
370 #[test]
371 fn stream_params_stream_params_ref_ptr_match() {
372 let params = StreamParams::default();
373 assert_eq!(params.as_ptr(), params.as_ref().as_ptr());
374 }
375}