cubeb_core/
device.rs

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
6use ffi;
7use std::str;
8use util::opt_bytes;
9
10/// The state of a device.
11#[derive(PartialEq, Eq, Clone, Debug, Copy)]
12pub enum DeviceState {
13    /// The device has been disabled at the system level.
14    Disabled,
15    /// The device is enabled, but nothing is plugged into it.
16    Unplugged,
17    /// The device is enabled.
18    Enabled,
19}
20
21bitflags! {
22    /// Architecture specific sample type.
23    pub struct DeviceFormat: ffi::cubeb_device_fmt {
24        const S16LE = ffi::CUBEB_DEVICE_FMT_S16LE;
25        const S16BE = ffi::CUBEB_DEVICE_FMT_S16BE;
26        const F32LE = ffi::CUBEB_DEVICE_FMT_F32LE;
27        const F32BE = ffi::CUBEB_DEVICE_FMT_F32BE;
28    }
29}
30
31bitflags! {
32    /// Channel type for a `cubeb_stream`. Depending on the backend and platform
33    /// used, this can control inter-stream interruption, ducking, and volume
34    /// control.
35    pub struct DevicePref: ffi::cubeb_device_pref {
36        const MULTIMEDIA = ffi::CUBEB_DEVICE_PREF_MULTIMEDIA;
37        const VOICE = ffi::CUBEB_DEVICE_PREF_VOICE;
38        const NOTIFICATION = ffi::CUBEB_DEVICE_PREF_NOTIFICATION;
39        const ALL = ffi::CUBEB_DEVICE_PREF_ALL;
40    }
41}
42
43impl DevicePref {
44    pub const NONE: Self = Self::empty();
45}
46
47bitflags! {
48    /// Whether a particular device is an input device (e.g. a microphone), or an
49    /// output device (e.g. headphones).
50    pub struct DeviceType: ffi::cubeb_device_type {
51        const INPUT = ffi::CUBEB_DEVICE_TYPE_INPUT as _;
52        const OUTPUT = ffi::CUBEB_DEVICE_TYPE_OUTPUT as _;
53    }
54}
55
56impl DeviceType {
57    pub const UNKNOWN: Self = Self::empty();
58}
59
60/// An opaque handle used to refer to a particular input or output device
61/// across calls.
62pub type DeviceId = ffi::cubeb_devid;
63
64ffi_type_heap! {
65    /// Audio device description
66    type CType = ffi::cubeb_device;
67    #[derive(Debug)]
68    pub struct Device;
69    pub struct DeviceRef;
70}
71
72impl DeviceRef {
73    fn get_ref(&self) -> &ffi::cubeb_device {
74        unsafe { &*self.as_ptr() }
75    }
76
77    /// Gets the output device name.
78    ///
79    /// May return `None` if there is no output device.
80    pub fn output_name(&self) -> Option<&str> {
81        self.output_name_bytes().map(|b| str::from_utf8(b).unwrap())
82    }
83
84    pub fn output_name_bytes(&self) -> Option<&[u8]> {
85        unsafe { opt_bytes(self.get_ref().output_name) }
86    }
87
88    /// Gets the input device name.
89    ///
90    /// May return `None` if there is no input device.
91    pub fn input_name(&self) -> Option<&str> {
92        self.input_name_bytes().map(|b| str::from_utf8(b).unwrap())
93    }
94
95    pub fn input_name_bytes(&self) -> Option<&[u8]> {
96        unsafe { opt_bytes(self.get_ref().input_name) }
97    }
98}
99
100ffi_type_stack! {
101    /// This structure holds the characteristics of an input or output
102    /// audio device. It is obtained using `enumerate_devices`, which
103    /// returns these structures via `device_collection` and must be
104    /// destroyed via `device_collection_destroy`.
105    type CType = ffi::cubeb_device_info;
106    pub struct DeviceInfo;
107    pub struct DeviceInfoRef;
108}
109
110impl DeviceInfoRef {
111    fn get_ref(&self) -> &ffi::cubeb_device_info {
112        unsafe { &*self.as_ptr() }
113    }
114
115    /// Device identifier handle.
116    pub fn devid(&self) -> DeviceId {
117        self.get_ref().devid
118    }
119
120    /// Device identifier which might be presented in a UI.
121    pub fn device_id(&self) -> Option<&str> {
122        self.device_id_bytes().map(|b| str::from_utf8(b).unwrap())
123    }
124
125    pub fn device_id_bytes(&self) -> Option<&[u8]> {
126        unsafe { opt_bytes(self.get_ref().device_id) }
127    }
128
129    /// Friendly device name which might be presented in a UI.
130    pub fn friendly_name(&self) -> Option<&str> {
131        self.friendly_name_bytes()
132            .map(|b| str::from_utf8(b).unwrap())
133    }
134
135    pub fn friendly_name_bytes(&self) -> Option<&[u8]> {
136        unsafe { opt_bytes(self.get_ref().friendly_name) }
137    }
138
139    /// Two devices have the same group identifier if they belong to
140    /// the same physical device; for example a headset and
141    /// microphone.
142    pub fn group_id(&self) -> Option<&str> {
143        self.group_id_bytes().map(|b| str::from_utf8(b).unwrap())
144    }
145
146    pub fn group_id_bytes(&self) -> Option<&[u8]> {
147        unsafe { opt_bytes(self.get_ref().group_id) }
148    }
149
150    /// Optional vendor name, may be None.
151    pub fn vendor_name(&self) -> Option<&str> {
152        self.vendor_name_bytes().map(|b| str::from_utf8(b).unwrap())
153    }
154
155    pub fn vendor_name_bytes(&self) -> Option<&[u8]> {
156        unsafe { opt_bytes(self.get_ref().vendor_name) }
157    }
158
159    /// Type of device (Input/Output).
160    pub fn device_type(&self) -> DeviceType {
161        DeviceType::from_bits_truncate(self.get_ref().device_type)
162    }
163
164    /// State of device disabled/enabled/unplugged.
165    pub fn state(&self) -> DeviceState {
166        let state = self.get_ref().state;
167        macro_rules! check( ($($raw:ident => $real:ident),*) => (
168            $(if state == ffi::$raw {
169                DeviceState::$real
170            }) else *
171            else {
172                panic!("unknown device state: {}", state)
173            }
174        ));
175
176        check!(CUBEB_DEVICE_STATE_DISABLED => Disabled,
177               CUBEB_DEVICE_STATE_UNPLUGGED => Unplugged,
178               CUBEB_DEVICE_STATE_ENABLED => Enabled)
179    }
180
181    /// Preferred device.
182    pub fn preferred(&self) -> DevicePref {
183        DevicePref::from_bits(self.get_ref().preferred).unwrap()
184    }
185
186    /// Sample format supported.
187    pub fn format(&self) -> DeviceFormat {
188        DeviceFormat::from_bits(self.get_ref().format).unwrap()
189    }
190
191    /// The default sample format for this device.
192    pub fn default_format(&self) -> DeviceFormat {
193        DeviceFormat::from_bits(self.get_ref().default_format).unwrap()
194    }
195
196    /// Channels.
197    pub fn max_channels(&self) -> u32 {
198        self.get_ref().max_channels
199    }
200
201    /// Default/Preferred sample rate.
202    pub fn default_rate(&self) -> u32 {
203        self.get_ref().default_rate
204    }
205
206    /// Maximum sample rate supported.
207    pub fn max_rate(&self) -> u32 {
208        self.get_ref().max_rate
209    }
210
211    /// Minimum sample rate supported.
212    pub fn min_rate(&self) -> u32 {
213        self.get_ref().min_rate
214    }
215
216    /// Lowest possible latency in frames.
217    pub fn latency_lo(&self) -> u32 {
218        self.get_ref().latency_lo
219    }
220
221    /// Higest possible latency in frames.
222    pub fn latency_hi(&self) -> u32 {
223        self.get_ref().latency_hi
224    }
225}
226
227#[cfg(test)]
228mod tests {
229    use ffi::cubeb_device;
230    use Device;
231
232    #[test]
233    fn device_device_ref_same_ptr() {
234        let ptr: *mut cubeb_device = 0xDEAD_BEEF as *mut _;
235        let device = unsafe { Device::from_ptr(ptr) };
236        assert_eq!(device.as_ptr(), ptr);
237        assert_eq!(device.as_ptr(), device.as_ref().as_ptr());
238    }
239}