Skip to main content

alsa/
pcm.rs

1//! Audio playback and capture
2//!
3//! # Example
4//! Playback a sine wave through the "default" device.
5//!
6//! ```
7//! use alsa::{Direction, ValueOr};
8//! use alsa::pcm::{PCM, HwParams, Format, Access, State};
9//!
10//! // Open default playback device
11//! let pcm = PCM::new("default", Direction::Playback, false).unwrap();
12//!
13//! // Set hardware parameters: 44100 Hz / Mono / 16 bit
14//! let hwp = HwParams::any(&pcm).unwrap();
15//! hwp.set_channels(1).unwrap();
16//! hwp.set_rate(44100, ValueOr::Nearest).unwrap();
17//! hwp.set_format(Format::s16()).unwrap();
18//! hwp.set_access(Access::RWInterleaved).unwrap();
19//! pcm.hw_params(&hwp).unwrap();
20//! let io = pcm.io_i16().unwrap();
21//!
22//! // Make sure we don't start the stream too early
23//! let hwp = pcm.hw_params_current().unwrap();
24//! let swp = pcm.sw_params_current().unwrap();
25//! swp.set_start_threshold(hwp.get_buffer_size().unwrap()).unwrap();
26//! pcm.sw_params(&swp).unwrap();
27//!
28//! // Make a sine wave
29//! let mut buf = [0i16; 1024];
30//! for (i, a) in buf.iter_mut().enumerate() {
31//!     *a = ((i as f32 * 2.0 * ::core::f32::consts::PI / 128.0).sin() * 8192.0) as i16
32//! }
33//!
34//! // Play it back for 2 seconds.
35//! for _ in 0..2*44100/1024 {
36//!     assert_eq!(io.writei(&buf[..]).unwrap(), 1024);
37//! }
38//!
39//! // In case the buffer was larger than 2 seconds, start the stream manually.
40//! if pcm.state() != State::Running { pcm.start().unwrap() };
41//! // Wait for the stream to finish playback.
42//! pcm.drain().unwrap();
43//! ```
44
45
46use libc::{c_int, c_uint, c_void, ssize_t, c_short, timespec, pollfd};
47use crate::alsa;
48use core::convert::Infallible;
49use core::marker::PhantomData;
50use core::mem::size_of;
51use core::ffi::CStr;
52use core::str::FromStr;
53use ::alloc::ffi::CString;
54use ::alloc::format;
55use core::{fmt, ptr, cell};
56use super::error::*;
57use super::{Direction, Output, poll, ValueOr, chmap};
58
59pub use super::chmap::{Chmap, ChmapPosition, ChmapType, ChmapsQuery};
60
61/// [snd_pcm_sframes_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html)
62pub type Frames = alsa::snd_pcm_sframes_t;
63
64/// [snd_pcm_info_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) wrapper - PCM generic info container
65#[derive(Debug)]
66pub struct Info(pub(crate) *mut alsa::snd_pcm_info_t);
67
68impl Info {
69    pub fn new() -> Result<Info> {
70        let mut p = ptr::null_mut();
71        acheck!(snd_pcm_info_malloc(&mut p)).map(|_| Info(p))
72    }
73
74    pub fn get_card(&self) -> i32 {
75        unsafe { alsa::snd_pcm_info_get_card(self.0) }
76    }
77
78    pub fn get_device(&self) -> u32 {
79        unsafe { alsa::snd_pcm_info_get_device(self.0) }
80    }
81
82    pub fn get_subdevice(&self) -> u32 {
83        unsafe { alsa::snd_pcm_info_get_subdevice(self.0) }
84    }
85
86    pub fn get_id(&self) -> Result<&str> {
87        let c = unsafe { alsa::snd_pcm_info_get_id(self.0) };
88        from_const("snd_pcm_info_get_id", c)
89    }
90
91    pub fn get_name(&self) -> Result<&str> {
92        let c = unsafe { alsa::snd_pcm_info_get_name(self.0) };
93        from_const("snd_pcm_info_get_name", c)
94    }
95
96    pub fn get_subdevice_name(&self) -> Result<&str> {
97        let c = unsafe { alsa::snd_pcm_info_get_subdevice_name(self.0) };
98        from_const("snd_pcm_info_get_subdevice_name", c)
99    }
100
101    pub fn get_stream(&self) -> Direction {
102        match unsafe { alsa::snd_pcm_info_get_stream(self.0) } {
103            alsa::SND_PCM_STREAM_CAPTURE => Direction::Capture,
104            alsa::SND_PCM_STREAM_PLAYBACK => Direction::Playback,
105            n @ _ => panic!("snd_pcm_info_get_stream invalid direction '{}'", n),
106        }
107    }
108
109    pub fn get_subdevices_count(&self) -> u32 {
110        unsafe { alsa::snd_pcm_info_get_subdevices_count(self.0) }
111    }
112
113    pub fn get_subdevices_avail(&self) -> u32 {
114        unsafe { alsa::snd_pcm_info_get_subdevices_avail(self.0) }
115    }
116
117    pub(crate) fn set_device(&mut self, device: u32) {
118        unsafe { alsa::snd_pcm_info_set_device(self.0, device) }
119    }
120
121    pub(crate) fn set_stream(&mut self, direction: Direction) {
122        let stream = match direction {
123            Direction::Capture => alsa::SND_PCM_STREAM_CAPTURE,
124            Direction::Playback => alsa::SND_PCM_STREAM_PLAYBACK,
125        };
126        unsafe { alsa::snd_pcm_info_set_stream(self.0, stream) }
127    }
128
129    pub(crate) fn set_subdevice(&mut self, subdevice: u32) {
130        unsafe { alsa::snd_pcm_info_set_subdevice(self.0, subdevice) }
131    }
132}
133
134impl Drop for Info {
135    fn drop(&mut self) { unsafe { alsa::snd_pcm_info_free(self.0) }; }
136}
137
138/// [snd_pcm_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) wrapper - start here for audio playback and recording
139#[derive(Debug)]
140pub struct PCM(*mut alsa::snd_pcm_t, cell::Cell<bool>);
141
142unsafe impl Send for PCM {}
143
144impl PCM {
145    fn check_has_io(&self) {
146        if self.1.get() { panic!("No hw_params call or additional IO objects allowed") }
147    }
148
149    /// Wrapper around open that takes a &str instead of a &CStr
150    pub fn new(name: &str, dir: Direction, nonblock: bool) -> Result<PCM> {
151        Self::open(&CString::new(name).unwrap(), dir, nonblock)
152    }
153
154    // Does not offer async mode (it's not very Rustic anyway)
155    pub fn open(name: &CStr, dir: Direction, nonblock: bool) -> Result<PCM> {
156        let mut r = ptr::null_mut();
157        let stream = match dir {
158            Direction::Capture => alsa::SND_PCM_STREAM_CAPTURE,
159            Direction::Playback => alsa::SND_PCM_STREAM_PLAYBACK
160        };
161        let flags = if nonblock { alsa::SND_PCM_NONBLOCK } else { 0 };
162        acheck!(snd_pcm_open(&mut r, name.as_ptr(), stream, flags)).map(|_| PCM(r, cell::Cell::new(false)))
163    }
164
165    pub fn start(&self) -> Result<()> { acheck!(snd_pcm_start(self.0)).map(|_| ()) }
166    pub fn drop(&self) -> Result<()> { acheck!(snd_pcm_drop(self.0)).map(|_| ()) }
167    pub fn pause(&self, pause: bool) -> Result<()> {
168        acheck!(snd_pcm_pause(self.0, if pause { 1 } else { 0 })).map(|_| ()) }
169    pub fn resume(&self) -> Result<()> { acheck!(snd_pcm_resume(self.0)).map(|_| ()) }
170    pub fn drain(&self) -> Result<()> { acheck!(snd_pcm_drain(self.0)).map(|_| ()) }
171    pub fn prepare(&self) -> Result<()> { acheck!(snd_pcm_prepare(self.0)).map(|_| ()) }
172    pub fn reset(&self) -> Result<()> { acheck!(snd_pcm_reset(self.0)).map(|_| ()) }
173    pub fn recover(&self, err: c_int, silent: bool) -> Result<()> {
174        acheck!(snd_pcm_recover(self.0, err, if silent { 1 } else { 0 })).map(|_| ()) }
175
176    /// Wrapper around snd_pcm_recover.
177    ///
178    /// Returns Ok if the error was successfully recovered from, or the original
179    /// error if the error was unhandled.
180    pub fn try_recover(&self, err: Error, silent: bool) -> Result<()> {
181        self.recover(err.errno() as c_int, silent)
182    }
183
184    pub fn wait(&self, timeout_ms: Option<u32>) -> Result<bool> {
185        acheck!(snd_pcm_wait(self.0, timeout_ms.map(|x| x as c_int).unwrap_or(-1))).map(|i| i == 1) }
186
187    pub fn state(&self) -> State {
188        let rawstate = self.state_raw();
189        if let Ok(state) = State::from_c_int(rawstate, "snd_pcm_state") {
190            state
191        }
192        else {
193            panic!("snd_pcm_state returned an invalid value of {}", rawstate);
194        }
195    }
196
197    /// Only used internally, and for debugging the alsa library. Please use the "state" function instead.
198    pub fn state_raw(&self) -> c_int { unsafe { alsa::snd_pcm_state(self.0) as c_int } }
199
200    pub fn bytes_to_frames(&self, i: isize) -> Frames { unsafe { alsa::snd_pcm_bytes_to_frames(self.0, i as ssize_t) }}
201    pub fn frames_to_bytes(&self, i: Frames) -> isize { unsafe { alsa::snd_pcm_frames_to_bytes(self.0, i) as isize }}
202
203    pub fn avail_update(&self) -> Result<Frames> { acheck!(snd_pcm_avail_update(self.0)) }
204    pub fn avail(&self) -> Result<Frames> { acheck!(snd_pcm_avail(self.0)) }
205
206    pub fn avail_delay(&self) -> Result<(Frames, Frames)> {
207        let (mut a, mut d) = (0, 0);
208        acheck!(snd_pcm_avail_delay(self.0, &mut a, &mut d)).map(|_| (a, d))
209    }
210    pub fn delay(&self) -> Result<Frames> {
211        let mut d = 0;
212        acheck!(snd_pcm_delay(self.0, &mut d)).map(|_| d)
213    }
214
215    pub fn status(&self) -> Result<Status> {
216        StatusBuilder::new().build(self)
217    }
218
219    fn verify_format(&self, f: Format) -> Result<()> {
220        let ff = self.hw_params_current().and_then(|h| h.get_format())?;
221        if ff == f { Ok(()) }
222        else {
223            // let s = format!("Invalid sample format ({:?}, expected {:?})", ff, f);
224            Err(Error::unsupported("io_xx"))
225        }
226    }
227
228    pub fn io_i8(&self) -> Result<IO<'_, i8>> { self.io_checked() }
229    pub fn io_u8(&self) -> Result<IO<'_, u8>> { self.io_checked() }
230    pub fn io_i16(&self) -> Result<IO<'_, i16>> { self.io_checked() }
231    pub fn io_u16(&self) -> Result<IO<'_, u16>> { self.io_checked() }
232    pub fn io_i32(&self) -> Result<IO<'_, i32>> { self.io_checked() }
233    pub fn io_u32(&self) -> Result<IO<'_, u32>> { self.io_checked() }
234    pub fn io_f32(&self) -> Result<IO<'_, f32>> { self.io_checked() }
235    pub fn io_f64(&self) -> Result<IO<'_, f64>> { self.io_checked() }
236
237    /// For the `s24` format, represented by i32
238    pub fn io_i32_s24(&self) -> Result<IO<'_, i32>> { self.verify_format(Format::s24()).map(|_| IO::new(self)) }
239    /// For the `u24` format, represented by u32
240    pub fn io_u32_u24(&self) -> Result<IO<'_, u32>> { self.verify_format(Format::u24()).map(|_| IO::new(self)) }
241
242    pub fn io_checked<S: IoFormat>(&self) -> Result<IO<'_, S>> {
243        self.verify_format(S::FORMAT).map(|_| IO::new(self))
244    }
245
246    /// Creates IO without checking `S` is valid type.
247    ///
248    /// SAFETY: Caller must guarantee `S` is valid type for this PCM stream
249    /// and that no other IO objects exist at the same time for the same stream
250    /// (or in some other way guarantee mmap safety)
251    pub unsafe fn io_unchecked<S: IoFormat>(&self) -> IO<'_, S> {
252        IO::new_unchecked(self)
253    }
254
255    #[deprecated(note = "renamed to io_bytes")]
256    pub fn io(&self) -> IO<'_, u8> { IO::new(self) }
257
258    /// Call this if you have an unusual format, not supported by the regular access methods
259    /// (io_i16 etc). It will succeed regardless of the sample format, but conversion to and from
260    /// bytes to your format is up to you.
261    pub fn io_bytes(&self) -> IO<'_, u8> { IO::new(self) }
262
263    /// Read buffers by talking to the kernel directly, bypassing alsa-lib.
264    pub fn direct_mmap_capture<S>(&self) -> Result<crate::direct::pcm::MmapCapture<S>> {
265        self.check_has_io();
266        crate::direct::pcm::new_mmap(self)
267    }
268
269    /// Write buffers by talking to the kernel directly, bypassing alsa-lib.
270    pub fn direct_mmap_playback<S>(&self) -> Result<crate::direct::pcm::MmapPlayback<S>> {
271        self.check_has_io();
272        crate::direct::pcm::new_mmap(self)
273    }
274
275    /// Sets hw parameters. Note: No IO object can exist for this PCM
276    /// when hw parameters are set.
277    pub fn hw_params(&self, h: &HwParams) -> Result<()> {
278        self.check_has_io();
279        acheck!(snd_pcm_hw_params(self.0, h.0)).map(|_| ())
280    }
281
282    /// Retreive current PCM hardware configuration.
283    pub fn hw_params_current(&self) -> Result<HwParams<'_>> {
284        HwParams::new(self).and_then(|h|
285            acheck!(snd_pcm_hw_params_current(self.0, h.0)).map(|_| h))
286    }
287
288    pub fn sw_params(&self, h: &SwParams) -> Result<()> {
289        acheck!(snd_pcm_sw_params(self.0, h.0)).map(|_| ())
290    }
291
292    pub fn sw_params_current(&self) -> Result<SwParams<'_>> {
293        SwParams::new(self).and_then(|h|
294            acheck!(snd_pcm_sw_params_current(self.0, h.0)).map(|_| h))
295    }
296
297    /// Wraps `snd_pcm_get_params`, returns `(buffer_size, period_size)`.
298    pub fn get_params(&self) -> Result<(u64, u64)> {
299        let mut buffer_size = 0;
300        let mut period_size = 0;
301        acheck!(snd_pcm_get_params(self.0, &mut buffer_size, &mut period_size))
302            .map(|_| (buffer_size as u64, period_size as u64))
303
304    }
305
306    pub fn info(&self) -> Result<Info> {
307        Info::new().and_then(|info|
308            acheck!(snd_pcm_info(self.0, info.0)).map(|_| info ))
309    }
310
311    pub fn dump(&self, o: &mut Output) -> Result<()> {
312        acheck!(snd_pcm_dump(self.0, super::io::output_handle(o))).map(|_| ())
313    }
314
315    pub fn dump_hw_setup(&self, o: &mut Output) -> Result<()> {
316        acheck!(snd_pcm_dump_hw_setup(self.0, super::io::output_handle(o))).map(|_| ())
317    }
318
319    pub fn dump_sw_setup(&self, o: &mut Output) -> Result<()> {
320        acheck!(snd_pcm_dump_sw_setup(self.0, super::io::output_handle(o))).map(|_| ())
321    }
322
323    pub fn query_chmaps(&self) -> ChmapsQuery {
324        chmap::chmaps_query_new(unsafe { alsa::snd_pcm_query_chmaps(self.0) })
325    }
326
327    pub fn set_chmap(&self, c: &Chmap) -> Result<()> {
328        acheck!(snd_pcm_set_chmap(self.0, chmap::chmap_handle(c))).map(|_| ())
329    }
330
331    pub fn get_chmap(&self) -> Result<Chmap> {
332        let p = unsafe { alsa::snd_pcm_get_chmap(self.0) };
333        if p.is_null() { Err(Error::unsupported("snd_pcm_get_chmap")) }
334        else { Ok(chmap::chmap_new(p)) }
335    }
336
337    pub fn link(&self, other: &PCM) -> Result<()> {
338        acheck!(snd_pcm_link(self.0, other.0)).map(|_| ())
339    }
340
341    pub fn unlink(&self) -> Result<()> {
342        acheck!(snd_pcm_unlink(self.0)).map(|_| ())
343    }
344}
345
346impl Drop for PCM {
347    fn drop(&mut self) { unsafe { alsa::snd_pcm_close(self.0) }; }
348}
349
350
351impl poll::Descriptors for PCM {
352    fn count(&self) -> usize {
353        unsafe { alsa::snd_pcm_poll_descriptors_count(self.0) as usize }
354    }
355    fn fill(&self, p: &mut [pollfd]) -> Result<usize> {
356        let z = unsafe { alsa::snd_pcm_poll_descriptors(self.0, p.as_mut_ptr(), p.len() as c_uint) };
357        from_code("snd_pcm_poll_descriptors", z).map(|_| z as usize)
358    }
359    fn revents(&self, p: &[pollfd]) -> Result<poll::Flags> {
360        let mut r = 0;
361        let z = unsafe { alsa::snd_pcm_poll_descriptors_revents(self.0, p.as_ptr() as *mut pollfd, p.len() as c_uint, &mut r) };
362        from_code("snd_pcm_poll_descriptors_revents", z).map(|_| poll::Flags::from_bits_truncate(r as c_short))
363    }
364}
365
366/// Sample format dependent struct for reading from and writing data to a `PCM`.
367/// Also implements `std::io::Read` and `std::io::Write`.
368///
369/// Note: Only one IO object is allowed in scope at a time (for mmap safety).
370#[derive(Debug)]
371pub struct IO<'a, S: Copy>(&'a PCM, PhantomData<S>);
372
373impl<'a, S: Copy> Drop for IO<'a, S> {
374    fn drop(&mut self) { (self.0).1.set(false) }
375}
376
377impl<'a, S: Copy> IO<'a, S> {
378
379    fn new(a: &'a PCM) -> IO<'a, S> {
380        a.check_has_io();
381        a.1.set(true);
382        IO(a, PhantomData)
383    }
384
385    unsafe fn new_unchecked(a: &'a PCM) -> IO<'a, S> {
386        a.1.set(true);
387        IO(a, PhantomData)
388    }
389
390    fn to_frames(&self, b: usize) -> alsa::snd_pcm_uframes_t {
391        // TODO: Do we need to check for overflow here?
392        self.0.bytes_to_frames((b * size_of::<S>()) as isize) as alsa::snd_pcm_uframes_t
393    }
394
395    fn from_frames(&self, b: alsa::snd_pcm_uframes_t) -> usize {
396        // TODO: Do we need to check for overflow here?
397        (self.0.frames_to_bytes(b as Frames) as usize) / size_of::<S>()
398    }
399
400    /// On success, returns number of *frames* written.
401    /// (Multiply with number of channels to get number of items in buf successfully written.)
402    pub fn writei(&self, buf: &[S]) -> Result<usize> {
403        acheck!(snd_pcm_writei((self.0).0, buf.as_ptr() as *const c_void, self.to_frames(buf.len()))).map(|r| r as usize)
404    }
405
406    /// On success, returns number of *frames* read.
407    /// (Multiply with number of channels to get number of items in buf successfully read.)
408    pub fn readi(&self, buf: &mut [S]) -> Result<usize> {
409        acheck!(snd_pcm_readi((self.0).0, buf.as_mut_ptr() as *mut c_void, self.to_frames(buf.len()))).map(|r| r as usize)
410    }
411
412    /// Write non-interleaved frames to pcm. On success, returns number of frames written.
413    ///
414    /// # Safety
415    ///
416    /// Caller must ensure that the length of `bufs` is at least the number of
417    /// channels, and that each element of bufs is a valid pointer to an array
418    /// of at least `frames` length.
419    pub unsafe fn writen(&self, bufs: &[*const S], frames: usize) -> Result<usize> {
420        let frames = frames as alsa::snd_pcm_uframes_t;
421        acheck!(snd_pcm_writen((self.0).0, bufs.as_ptr() as *mut *mut c_void, frames)).map(|r| r as usize)
422    }
423
424    /// Read non-interleaved frames to pcm. On success, returns number of frames read.
425    ///
426    /// # Safety
427    ///
428    /// Caller must ensure that the length of `bufs` is at least the number of
429    /// channels, and that each element of bufs is a valid pointer to an array
430    /// of at least `frames` length.
431    pub unsafe fn readn(&self, bufs: &mut [*mut S], frames: usize) -> Result<usize> {
432        let frames = frames as alsa::snd_pcm_uframes_t;
433        acheck!(snd_pcm_readn((self.0).0, bufs.as_mut_ptr() as *mut *mut c_void, frames)).map(|r| r as usize)
434    }
435
436    /// Wrapper around snd_pcm_mmap_begin and snd_pcm_mmap_commit.
437    ///
438    /// You can read/write into the sound card's buffer during the call to the closure.
439    /// According to alsa-lib docs, you should call avail_update before calling this function.
440    ///
441    /// All calculations are in *frames*, i e, the closure should return number of frames processed.
442    /// Also, there might not be as many frames to read/write as requested, and there can even be
443    /// an empty buffer supplied to the closure.
444    ///
445    /// Note: This function works only with interleaved access mode.
446    pub fn mmap<F: FnOnce(&mut [S]) -> usize>(&self, frames: usize, func: F) -> Result<usize> {
447        let mut f = frames as alsa::snd_pcm_uframes_t;
448        let mut offs: alsa::snd_pcm_uframes_t = 0;
449        let mut areas = ptr::null();
450        acheck!(snd_pcm_mmap_begin((self.0).0, &mut areas, &mut offs, &mut f))?;
451
452        let (first, step) = unsafe { ((*areas).first, (*areas).step) };
453        if first != 0 || step as isize != self.0.frames_to_bytes(1) * 8 {
454            unsafe { alsa::snd_pcm_mmap_commit((self.0).0, offs, 0) };
455            // let s = format!("Can only mmap a single interleaved buffer (first = {:?}, step = {:?})", first, step);
456            return Err(Error::unsupported("snd_pcm_mmap_begin"));
457        }
458
459        let buf = unsafe {
460            let p = ((*areas).addr as *mut S).add(self.from_frames(offs));
461            ::core::slice::from_raw_parts_mut(p, self.from_frames(f))
462        };
463        let fres = func(buf);
464        debug_assert!(fres <= f as usize);
465        acheck!(snd_pcm_mmap_commit((self.0).0, offs, fres as alsa::snd_pcm_uframes_t)).map(|r| r as usize)
466    }
467}
468
469#[cfg(feature = "std")]
470impl<'a, S: Copy> std::io::Read for IO<'a, S> {
471    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
472        let size = self.0.bytes_to_frames(buf.len() as isize) as alsa::snd_pcm_uframes_t; // TODO: Do we need to check for overflow here?
473        let r = unsafe { alsa::snd_pcm_readi((self.0).0, buf.as_mut_ptr() as *mut c_void, size) };
474        if r < 0 { Err(std::io::Error::from_raw_os_error(-r as i32)) }
475        else { Ok(self.0.frames_to_bytes(r) as usize) }
476    }
477}
478
479#[cfg(feature = "std")]
480impl<'a, S: Copy> std::io::Write for IO<'a, S> {
481    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
482        let size = self.0.bytes_to_frames(buf.len() as isize) as alsa::snd_pcm_uframes_t; // TODO: Do we need to check for overflow here?
483        let r = unsafe { alsa::snd_pcm_writei((self.0).0, buf.as_ptr() as *const c_void, size) };
484        if r < 0 { Err(std::io::Error::from_raw_os_error(r as i32)) }
485        else { Ok(self.0.frames_to_bytes(r) as usize) }
486    }
487    fn flush(&mut self) -> std::io::Result<()> { Ok(()) }
488}
489
490
491alsa_enum!(
492    /// [SND_PCM_STATE_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) constants
493    State, ALL_STATES[9],
494
495    Open = SND_PCM_STATE_OPEN,
496    Setup = SND_PCM_STATE_SETUP,
497    Prepared = SND_PCM_STATE_PREPARED,
498    Running = SND_PCM_STATE_RUNNING,
499    XRun = SND_PCM_STATE_XRUN,
500    Draining = SND_PCM_STATE_DRAINING,
501    Paused = SND_PCM_STATE_PAUSED,
502    Suspended = SND_PCM_STATE_SUSPENDED,
503    Disconnected = SND_PCM_STATE_DISCONNECTED,
504);
505
506alsa_enum!(
507    #[non_exhaustive]
508    /// [SND_PCM_FORMAT_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) constants
509    Format, ALL_FORMATS[52],
510
511    Unknown = SND_PCM_FORMAT_UNKNOWN,
512    S8 = SND_PCM_FORMAT_S8,
513    U8 = SND_PCM_FORMAT_U8,
514    S16LE = SND_PCM_FORMAT_S16_LE,
515    S16BE = SND_PCM_FORMAT_S16_BE,
516    U16LE = SND_PCM_FORMAT_U16_LE,
517    U16BE = SND_PCM_FORMAT_U16_BE,
518    S24LE = SND_PCM_FORMAT_S24_LE,
519    S24BE = SND_PCM_FORMAT_S24_BE,
520    U24LE = SND_PCM_FORMAT_U24_LE,
521    U24BE = SND_PCM_FORMAT_U24_BE,
522    S32LE = SND_PCM_FORMAT_S32_LE,
523    S32BE = SND_PCM_FORMAT_S32_BE,
524    U32LE = SND_PCM_FORMAT_U32_LE,
525    U32BE = SND_PCM_FORMAT_U32_BE,
526    FloatLE = SND_PCM_FORMAT_FLOAT_LE,
527    FloatBE = SND_PCM_FORMAT_FLOAT_BE,
528    Float64LE = SND_PCM_FORMAT_FLOAT64_LE,
529    Float64BE = SND_PCM_FORMAT_FLOAT64_BE,
530    IEC958SubframeLE = SND_PCM_FORMAT_IEC958_SUBFRAME_LE,
531    IEC958SubframeBE = SND_PCM_FORMAT_IEC958_SUBFRAME_BE,
532    MuLaw = SND_PCM_FORMAT_MU_LAW,
533    ALaw = SND_PCM_FORMAT_A_LAW,
534    ImaAdPCM = SND_PCM_FORMAT_IMA_ADPCM,
535    MPEG = SND_PCM_FORMAT_MPEG,
536    GSM = SND_PCM_FORMAT_GSM,
537    S20LE = SND_PCM_FORMAT_S20_LE,
538    S20BE = SND_PCM_FORMAT_S20_BE,
539    U20LE = SND_PCM_FORMAT_U20_LE,
540    U20BE = SND_PCM_FORMAT_U20_BE,
541    Special = SND_PCM_FORMAT_SPECIAL,
542    S243LE = SND_PCM_FORMAT_S24_3LE,
543    S243BE = SND_PCM_FORMAT_S24_3BE,
544    U243LE = SND_PCM_FORMAT_U24_3LE,
545    U243BE = SND_PCM_FORMAT_U24_3BE,
546    S203LE = SND_PCM_FORMAT_S20_3LE,
547    S203BE = SND_PCM_FORMAT_S20_3BE,
548    U203LE = SND_PCM_FORMAT_U20_3LE,
549    U203BE = SND_PCM_FORMAT_U20_3BE,
550    S183LE = SND_PCM_FORMAT_S18_3LE,
551    S183BE = SND_PCM_FORMAT_S18_3BE,
552    U183LE = SND_PCM_FORMAT_U18_3LE,
553    U183BE = SND_PCM_FORMAT_U18_3BE,
554    G72324 = SND_PCM_FORMAT_G723_24,
555    G723241B = SND_PCM_FORMAT_G723_24_1B,
556    G72340 = SND_PCM_FORMAT_G723_40,
557    G723401B = SND_PCM_FORMAT_G723_40_1B,
558    DSDU8 = SND_PCM_FORMAT_DSD_U8,
559    DSDU16LE = SND_PCM_FORMAT_DSD_U16_LE,
560    DSDU32LE = SND_PCM_FORMAT_DSD_U32_LE,
561    DSDU16BE = SND_PCM_FORMAT_DSD_U16_BE,
562    DSDU32BE = SND_PCM_FORMAT_DSD_U32_BE,
563);
564
565impl fmt::Display for Format {
566    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
567        use Format::*;
568        match *self {
569            S8 => write!(f, "S8"),
570            U8 => write!(f, "U8"),
571            S16LE => write!(f, "S16_LE"),
572            S16BE => write!(f, "S16_BE"),
573            U16LE => write!(f, "U16_LE"),
574            U16BE => write!(f, "U16_BE"),
575            S24LE => write!(f, "S24_LE"),
576            S24BE => write!(f, "S24_BE"),
577            U24LE => write!(f, "U24_LE"),
578            U24BE => write!(f, "U24_BE"),
579            S32LE => write!(f, "S32_LE"),
580            S32BE => write!(f, "S32_BE"),
581            U32LE => write!(f, "U32_LE"),
582            U32BE => write!(f, "U32_BE"),
583            FloatLE => write!(f, "FLOAT_LE"),
584            FloatBE => write!(f, "FLOAT_BE"),
585            Float64LE => write!(f, "FLOAT64_LE"),
586            Float64BE => write!(f, "FLOAT64_BE"),
587            IEC958SubframeLE => write!(f, "IEC958_SUBFRAME_LE"),
588            IEC958SubframeBE => write!(f, "IEC958_SUBFRAME_BE"),
589            MuLaw => write!(f, "MU_LAW"),
590            ALaw => write!(f, "A_LAW"),
591            ImaAdPCM => write!(f, "IMA_ADPCM"),
592            MPEG => write!(f, "MPEG"),
593            GSM => write!(f, "GSM"),
594            S20LE => write!(f, "S20_LE"),
595            S20BE => write!(f, "S20_BE"),
596            U20LE => write!(f, "U20_LE"),
597            U20BE => write!(f, "U20_BE"),
598            Special => write!(f, "SPECIAL"),
599            S243LE => write!(f, "S24_3LE"),
600            S243BE => write!(f, "S24_3BE"),
601            U243LE => write!(f, "U24_3LE"),
602            U243BE => write!(f, "U24_3BE"),
603            S203LE => write!(f, "S20_3LE"),
604            S203BE => write!(f, "S20_3BE"),
605            U203LE => write!(f, "U20_3LE"),
606            U203BE => write!(f, "U20_3BE"),
607            S183LE => write!(f, "S18_3LE"),
608            S183BE => write!(f, "S18_3BE"),
609            U183LE => write!(f, "U18_3LE"),
610            U183BE => write!(f, "U18_3BE"),
611            G72324 => write!(f, "G723_24"),
612            G723241B => write!(f, "G723_24_1B"),
613            G72340 => write!(f, "G723_40"),
614            G723401B => write!(f, "G723_40_1B"),
615            DSDU8 => write!(f, "DSD_U8"),
616            DSDU16LE => write!(f, "DSD_U16_LE"),
617            DSDU32LE => write!(f, "DSD_U32_LE"),
618            DSDU16BE => write!(f, "DSD_U16_BE"),
619            DSDU32BE => write!(f, "DSD_U32_BE"),
620            _ => write!(f, "UNKNOWN"),
621        }
622    }
623}
624
625impl FromStr for Format {
626    type Err = Infallible;
627
628    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
629        use Format::*;
630        Ok(match s.to_ascii_uppercase().as_str() {
631            "S8" => S8,
632            "U8" => U8,
633            "S16_LE" => S16LE,
634            "S16_BE" => S16BE,
635            "U16_LE" => U16LE,
636            "U16_BE" => U16BE,
637            "S24_LE" => S24LE,
638            "S24_BE" => S24BE,
639            "U24_LE" => U24LE,
640            "U24_BE" => U24BE,
641            "S32_LE" => S32LE,
642            "S32_BE" => S32BE,
643            "U32_LE" => U32LE,
644            "U32_BE" => U32BE,
645            "FLOAT_LE" => FloatLE,
646            "FLOAT_BE" => FloatBE,
647            "FLOAT64_LE" => Float64LE,
648            "FLOAT64_BE" => Float64BE,
649            "IEC958_SUBFRAME_LE" => IEC958SubframeLE,
650            "IEC958_SUBFRAME_BE" => IEC958SubframeBE,
651            "MU_LAW" => MuLaw,
652            "A_LAW" => ALaw,
653            "IMA_ADPCM" => ImaAdPCM,
654            "MPEG" => MPEG,
655            "GSM" => GSM,
656            "S20_LE" => S20LE,
657            "S20_BE" => S20BE,
658            "U20_LE" => U20LE,
659            "U20_BE" => U20BE,
660            "SPECIAL" => Special,
661            "S24_3LE" => S243LE,
662            "S24_3BE" => S243BE,
663            "U24_3LE" => U243LE,
664            "U24_3BE" => U243BE,
665            "S20_3LE" => S203LE,
666            "S20_3BE" => S203BE,
667            "U20_3LE" => U203LE,
668            "U20_3BE" => U203BE,
669            "S18_3LE" => S183LE,
670            "S18_3BE" => S183BE,
671            "U18_3LE" => U183LE,
672            "U18_3BE" => U183BE,
673            "G723_24" => G72324,
674            "G723_24_1B" => G723241B,
675            "G723_40" => G72340,
676            "G723_40_1B" => G723401B,
677            "DSD_U8" => DSDU8,
678            "DSD_U16_LE" => DSDU16LE,
679            "DSD_U32_LE" => DSDU32LE,
680            "DSD_U16_BE" => DSDU16BE,
681            "DSD_U32_BE" => DSDU32BE,
682            _ => Unknown,
683        })
684    }
685}
686
687impl Format {
688    pub const fn s16() -> Format { <i16 as IoFormat>::FORMAT }
689    pub const fn u16() -> Format { <u16 as IoFormat>::FORMAT }
690    pub const fn s32() -> Format { <i32 as IoFormat>::FORMAT }
691    pub const fn u32() -> Format { <u32 as IoFormat>::FORMAT }
692    pub const fn float() -> Format { <f32 as IoFormat>::FORMAT }
693    pub const fn float64() -> Format { <f64 as IoFormat>::FORMAT }
694
695    #[cfg(target_endian = "little")] pub const fn s24() -> Format { Format::S24LE }
696    #[cfg(target_endian = "big")] pub const fn s24() -> Format { Format::S24BE }
697
698    #[cfg(target_endian = "little")] pub const fn s24_3() -> Format { Format::S243LE }
699    #[cfg(target_endian = "big")] pub const fn s24_3() -> Format { Format::S243BE }
700
701    #[cfg(target_endian = "little")] pub const fn u24() -> Format { Format::U24LE }
702    #[cfg(target_endian = "big")] pub const fn u24() -> Format { Format::U24BE }
703
704    #[cfg(target_endian = "little")] pub const fn u24_3() -> Format { Format::U243LE }
705    #[cfg(target_endian = "big")] pub const fn u24_3() -> Format { Format::U243BE }
706
707    #[cfg(target_endian = "little")] pub const fn s20() -> Format { Format::S20LE }
708    #[cfg(target_endian = "big")] pub const fn s20() -> Format { Format::S20BE }
709
710    #[cfg(target_endian = "little")] pub const fn s20_3() -> Format { Format::S203LE }
711    #[cfg(target_endian = "big")] pub const fn s20_3() -> Format { Format::S203BE }
712
713    #[cfg(target_endian = "little")] pub const fn u20() -> Format { Format::U20LE }
714    #[cfg(target_endian = "big")] pub const fn u20() -> Format { Format::U20BE }
715
716    #[cfg(target_endian = "little")] pub const fn u20_3() -> Format { Format::U203LE }
717    #[cfg(target_endian = "big")] pub const fn u20_3() -> Format { Format::U203BE }
718
719    #[cfg(target_endian = "little")] pub const fn s18_3() -> Format { Format::S183LE }
720    #[cfg(target_endian = "big")] pub const fn s18_3() -> Format { Format::S183BE }
721
722    #[cfg(target_endian = "little")] pub const fn u18_3() -> Format { Format::U183LE }
723    #[cfg(target_endian = "big")] pub const fn u18_3() -> Format { Format::U183BE }
724
725    #[cfg(target_endian = "little")] pub const fn dsd_u16() -> Format { Format::DSDU16LE }
726    #[cfg(target_endian = "big")] pub const fn dsd_u16() -> Format { Format::DSDU16BE }
727
728    #[cfg(target_endian = "little")] pub const fn dsd_u32() -> Format { Format::DSDU32LE }
729    #[cfg(target_endian = "big")] pub const fn dsd_u32() -> Format { Format::DSDU32BE }
730
731    #[cfg(target_endian = "little")] pub const fn iec958_subframe() -> Format { Format::IEC958SubframeLE }
732    #[cfg(target_endian = "big")] pub const fn iec958_subframe() -> Format { Format::IEC958SubframeBE }
733
734    pub fn physical_width(&self) -> Result<i32> {
735        acheck!(snd_pcm_format_physical_width(self.to_c_int()))
736    }
737
738    pub fn width(&self) -> Result<i32> {
739        acheck!(snd_pcm_format_width(self.to_c_int()))
740    }
741
742    pub fn silence_16(&self) -> u16 {
743        unsafe { alsa::snd_pcm_format_silence_16(self.to_c_int()) }
744    }
745
746    pub fn little_endian(&self) -> Result<bool> {
747        acheck!(snd_pcm_format_little_endian(self.to_c_int())).map(|v| v != 0)
748    }
749}
750
751
752pub trait IoFormat: Copy {
753    const FORMAT: Format;
754}
755
756impl IoFormat for i8 { const FORMAT: Format = Format::S8; }
757impl IoFormat for u8 { const FORMAT: Format = Format::U8; }
758
759impl IoFormat for i16 {
760    #[cfg(target_endian = "little")]
761    const FORMAT: Format = Format::S16LE;
762    #[cfg(target_endian = "big")]
763    const FORMAT: Format = Format::S16BE;
764}
765impl IoFormat for u16 {
766    #[cfg(target_endian = "little")]
767    const FORMAT: Format = Format::U16LE;
768    #[cfg(target_endian = "big")]
769    const FORMAT: Format = Format::U16BE;
770}
771impl IoFormat for i32 {
772    #[cfg(target_endian = "little")]
773    const FORMAT: Format = Format::S32LE;
774    #[cfg(target_endian = "big")]
775    const FORMAT: Format = Format::S32BE;
776}
777impl IoFormat for u32 {
778    #[cfg(target_endian = "little")]
779    const FORMAT: Format = Format::U32LE;
780    #[cfg(target_endian = "big")]
781    const FORMAT: Format = Format::U32BE;
782}
783impl IoFormat for f32 {
784    #[cfg(target_endian = "little")]
785    const FORMAT: Format = Format::FloatLE;
786    #[cfg(target_endian = "big")]
787    const FORMAT: Format = Format::FloatBE;
788}
789impl IoFormat for f64 {
790    #[cfg(target_endian = "little")]
791    const FORMAT: Format = Format::Float64LE;
792    #[cfg(target_endian = "big")]
793    const FORMAT: Format = Format::Float64BE;
794}
795
796
797alsa_enum!(
798    /// [SND_PCM_ACCESS_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) constants
799    Access, ALL_ACCESSES[5],
800
801    MMapInterleaved = SND_PCM_ACCESS_MMAP_INTERLEAVED,
802    MMapNonInterleaved = SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
803    MMapComplex = SND_PCM_ACCESS_MMAP_COMPLEX,
804    RWInterleaved = SND_PCM_ACCESS_RW_INTERLEAVED,
805    RWNonInterleaved = SND_PCM_ACCESS_RW_NONINTERLEAVED,
806);
807
808alsa_enum!(
809    /// [SND_PCM_TSTAMP_TYPE_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) constants
810    TstampType, ALL_TSTAMP_TYPES[3],
811
812    Gettimeofday = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY,
813    Monotonic = SND_PCM_TSTAMP_TYPE_MONOTONIC,
814    MonotonicRaw = SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW,
815);
816
817/// [snd_pcm_hw_params_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m___h_w___params.html) wrapper
818pub struct HwParams<'a>(*mut alsa::snd_pcm_hw_params_t, &'a PCM);
819
820impl<'a> Drop for HwParams<'a> {
821    fn drop(&mut self) { unsafe { alsa::snd_pcm_hw_params_free(self.0) }; }
822}
823
824impl<'a> HwParams<'a> {
825    fn new(a: &'a PCM) -> Result<HwParams<'a>> {
826        let mut p = ptr::null_mut();
827        acheck!(snd_pcm_hw_params_malloc(&mut p)).map(|_| HwParams(p, a))
828    }
829
830    pub fn any(a: &'a PCM) -> Result<HwParams<'a>> { HwParams::new(a).and_then(|p|
831        acheck!(snd_pcm_hw_params_any(a.0, p.0)).map(|_| p)
832    )}
833
834    pub fn get_rate_resample(&self) -> Result<bool> {
835        let mut v = 0;
836        acheck!(snd_pcm_hw_params_get_rate_resample((self.1).0, self.0, &mut v)).map(|_| v != 0)
837    }
838
839    pub fn set_rate_resample(&self, resample: bool) -> Result<()> {
840        acheck!(snd_pcm_hw_params_set_rate_resample((self.1).0, self.0, if resample {1} else {0})).map(|_| ())
841    }
842
843    pub fn set_channels_near(&self, v: u32) -> Result<u32> {
844        let mut r = v as c_uint;
845        acheck!(snd_pcm_hw_params_set_channels_near((self.1).0, self.0, &mut r)).map(|_| r)
846    }
847
848    pub fn set_channels(&self, v: u32) -> Result<()> {
849        acheck!(snd_pcm_hw_params_set_channels((self.1).0, self.0, v as c_uint)).map(|_| ())
850    }
851
852    pub fn get_channels(&self) -> Result<u32> {
853        let mut v = 0;
854        acheck!(snd_pcm_hw_params_get_channels(self.0, &mut v)).map(|_| v as u32)
855    }
856
857    pub fn get_channels_max(&self) -> Result<u32> {
858        let mut v = 0;
859        acheck!(snd_pcm_hw_params_get_channels_max(self.0, &mut v)).map(|_| v as u32)
860    }
861
862    pub fn get_channels_min(&self) -> Result<u32> {
863        let mut v = 0;
864        acheck!(snd_pcm_hw_params_get_channels_min(self.0, &mut v)).map(|_| v as u32)
865    }
866
867    pub fn test_channels(&self, v: u32) -> Result<()> {
868        acheck!(snd_pcm_hw_params_test_channels((self.1).0, self.0, v as c_uint)).map(|_| ())
869    }
870
871    pub fn set_rate_near(&self, v: u32, dir: ValueOr) -> Result<u32> {
872        let mut d = dir as c_int;
873        let mut r = v as c_uint;
874        acheck!(snd_pcm_hw_params_set_rate_near((self.1).0, self.0, &mut r, &mut d)).map(|_| r)
875    }
876
877    pub fn set_rate(&self, v: u32, dir: ValueOr) -> Result<()> {
878        acheck!(snd_pcm_hw_params_set_rate((self.1).0, self.0, v as c_uint, dir as c_int)).map(|_| ())
879    }
880
881    pub fn get_rate(&self) -> Result<u32> {
882        let (mut v, mut d) = (0,0);
883        acheck!(snd_pcm_hw_params_get_rate(self.0, &mut v, &mut d)).map(|_| v as u32)
884    }
885
886    pub fn get_rate_max(&self) -> Result<u32> {
887        let mut v = 0;
888        // Note on the null ptr: if this ptr is not null, then the value behind it is replaced with
889        // -1 if the suprenum is not in the set (i.e. it's an open range), 0 otherwise. This could
890        // be returned along with the value, but it's safe to pass a null ptr in, in which case the
891        // pointer is not dereferenced.
892        acheck!(snd_pcm_hw_params_get_rate_max(self.0, &mut v, ptr::null_mut())).map(|_| v as u32)
893    }
894
895    pub fn get_rate_min(&self) -> Result<u32> {
896        let mut v = 0;
897        // Note on the null ptr: see get_rate_max but read +1 and infinum instead of -1 and
898        // suprenum.
899        acheck!(snd_pcm_hw_params_get_rate_min(self.0, &mut v, ptr::null_mut())).map(|_| v as u32)
900    }
901
902    pub fn test_rate(&self, rate: u32) -> Result<()> {
903        acheck!(snd_pcm_hw_params_test_rate((self.1).0, self.0, rate as c_uint, 0)).map(|_| ())
904    }
905
906    pub fn set_format(&self, v: Format) -> Result<()> {
907        acheck!(snd_pcm_hw_params_set_format((self.1).0, self.0, v as c_int)).map(|_| ())
908    }
909
910    pub fn get_format(&self) -> Result<Format> {
911        let mut v = 0;
912        acheck!(snd_pcm_hw_params_get_format(self.0, &mut v))
913            .and_then(|_| Format::from_c_int(v, "snd_pcm_hw_params_get_format"))
914    }
915
916    pub fn test_format(&self, v: Format) -> Result<()> {
917        acheck!(snd_pcm_hw_params_test_format((self.1).0, self.0, v as c_int)).map(|_| ())
918    }
919
920    pub fn test_access(&self, v: Access) -> Result<()> {
921        acheck!(snd_pcm_hw_params_test_access((self.1).0, self.0, v as c_uint)).map(|_| ())
922    }
923
924    pub fn set_access(&self, v: Access) -> Result<()> {
925        acheck!(snd_pcm_hw_params_set_access((self.1).0, self.0, v as c_uint)).map(|_| ())
926    }
927
928    pub fn get_access(&self) -> Result<Access> {
929        let mut v = 0;
930        acheck!(snd_pcm_hw_params_get_access(self.0, &mut v))
931            .and_then(|_| Access::from_c_int(v as c_int, "snd_pcm_hw_params_get_access"))
932    }
933
934    pub fn set_period_size_near(&self, v: Frames, dir: ValueOr) -> Result<Frames> {
935        let mut d = dir as c_int;
936        let mut r = v as alsa::snd_pcm_uframes_t;
937        acheck!(snd_pcm_hw_params_set_period_size_near((self.1).0, self.0, &mut r, &mut d)).map(|_| r as Frames)
938    }
939
940    pub fn set_period_size(&self, v: Frames, dir: ValueOr) -> Result<()> {
941        acheck!(snd_pcm_hw_params_set_period_size((self.1).0, self.0, v as alsa::snd_pcm_uframes_t, dir as c_int)).map(|_| ())
942    }
943
944    pub fn set_period_time_near(&self, v: u32, dir: ValueOr) -> Result<u32> {
945        let mut d = dir as c_int;
946        let mut r = v as c_uint;
947        acheck!(snd_pcm_hw_params_set_period_time_near((self.1).0, self.0, &mut r, &mut d)).map(|_| r as u32)
948    }
949
950    pub fn set_period_size_min(&self, v: Frames, dir: ValueOr) -> Result<Frames> {
951        let mut d = dir as c_int;
952        let mut r = v as alsa::snd_pcm_uframes_t;
953        acheck!(snd_pcm_hw_params_set_period_size_min((self.1).0, self.0, &mut r, &mut d)).map(|_| r as Frames)
954    }
955
956    pub fn set_period_size_max(&self, v: Frames, dir: ValueOr) -> Result<Frames> {
957        let mut d = dir as c_int;
958        let mut r = v as alsa::snd_pcm_uframes_t;
959        acheck!(snd_pcm_hw_params_set_period_size_max((self.1).0, self.0, &mut r, &mut d)).map(|_| r as Frames)
960    }
961
962    pub fn set_period_time(&self, v: u32, dir: ValueOr) -> Result<()> {
963        acheck!(snd_pcm_hw_params_set_period_time((self.1).0, self.0, v as c_uint, dir as c_int)).map(|_| ())
964    }
965
966    pub fn set_period_time_min(&self, v: u32, dir: ValueOr) -> Result<u32> {
967        let mut d = dir as c_int;
968        let mut r = v as c_uint;
969        acheck!(snd_pcm_hw_params_set_period_time_min((self.1).0, self.0, &mut r, &mut d)).map(|_| r as u32)
970    }
971
972    pub fn set_period_time_max(&self, v: u32, dir: ValueOr) -> Result<u32> {
973        let mut d = dir as c_int;
974        let mut r = v as c_uint;
975        acheck!(snd_pcm_hw_params_set_period_time_max((self.1).0, self.0, &mut r, &mut d)).map(|_| r as u32)
976    }
977
978    pub fn get_period_time(&self) -> Result<u32> {
979        let (mut v, mut d) = (0,0);
980        acheck!(snd_pcm_hw_params_get_period_time(self.0, &mut v, &mut d)).map(|_| v as u32)
981    }
982
983    pub fn get_period_time_min(&self) -> Result<u32> {
984        let (mut v, mut d) = (0,0);
985        acheck!(snd_pcm_hw_params_get_period_time_min(self.0, &mut v, &mut d)).map(|_| v as u32)
986    }
987
988    pub fn get_period_time_max(&self) -> Result<u32> {
989        let (mut v, mut d) = (0,0);
990        acheck!(snd_pcm_hw_params_get_period_time_max(self.0, &mut v, &mut d)).map(|_| v as u32)
991    }
992
993    pub fn get_period_size(&self) -> Result<Frames> {
994        let (mut v, mut d) = (0,0);
995        acheck!(snd_pcm_hw_params_get_period_size(self.0, &mut v, &mut d)).map(|_| v as Frames)
996    }
997
998    pub fn get_period_size_min(&self) -> Result<Frames> {
999        let (mut v, mut d) = (0,0);
1000        acheck!(snd_pcm_hw_params_get_period_size_min(self.0, &mut v, &mut d)).map(|_| v as Frames)
1001    }
1002
1003    pub fn get_period_size_max(&self) -> Result<Frames> {
1004        let (mut v, mut d) = (0,0);
1005        acheck!(snd_pcm_hw_params_get_period_size_max(self.0, &mut v, &mut d)).map(|_| v as Frames)
1006    }
1007
1008    pub fn set_periods_near(&self, v: u32, dir: ValueOr) -> Result<u32> {
1009        let mut d = dir as c_int;
1010        let mut r = v as c_uint;
1011        acheck!(snd_pcm_hw_params_set_periods_near((self.1).0, self.0, &mut r, &mut d)).map(|_| r as u32)
1012    }
1013
1014    pub fn set_periods(&self, v: u32, dir: ValueOr) -> Result<()> {
1015        acheck!(snd_pcm_hw_params_set_periods((self.1).0, self.0, v as c_uint, dir as c_int)).map(|_| ())
1016    }
1017
1018    pub fn set_periods_min(&self, v: u32, dir: ValueOr) -> Result<u32> {
1019        let mut d = dir as c_int;
1020        let mut r = v as c_uint;
1021        acheck!(snd_pcm_hw_params_set_periods_min((self.1).0, self.0, &mut r, &mut d)).map(|_| r as u32)
1022    }
1023
1024    pub fn set_periods_max(&self, v: u32, dir: ValueOr) -> Result<u32> {
1025        let mut d = dir as c_int;
1026        let mut r = v as c_uint;
1027        acheck!(snd_pcm_hw_params_set_periods_max((self.1).0, self.0, &mut r, &mut d)).map(|_| r as u32)
1028    }
1029
1030    pub fn get_periods(&self) -> Result<u32> {
1031        let (mut v, mut d) = (0,0);
1032        acheck!(snd_pcm_hw_params_get_periods(self.0, &mut v, &mut d)).map(|_| v as u32)
1033    }
1034
1035    pub fn get_periods_min(&self) -> Result<u32> {
1036        let (mut v, mut d) = (0,0);
1037        acheck!(snd_pcm_hw_params_get_periods_min(self.0, &mut v, &mut d)).map(|_| v as u32)
1038    }
1039
1040    pub fn get_periods_max(&self) -> Result<u32> {
1041        let (mut v, mut d) = (0,0);
1042        acheck!(snd_pcm_hw_params_get_periods_max(self.0, &mut v, &mut d)).map(|_| v as u32)
1043    }
1044
1045    pub fn set_buffer_size_near(&self, v: Frames) -> Result<Frames> {
1046        let mut r = v as alsa::snd_pcm_uframes_t;
1047        acheck!(snd_pcm_hw_params_set_buffer_size_near((self.1).0, self.0, &mut r)).map(|_| r as Frames)
1048    }
1049
1050    pub fn set_buffer_size_max(&self, v: Frames) -> Result<Frames> {
1051        let mut r = v as alsa::snd_pcm_uframes_t;
1052        acheck!(snd_pcm_hw_params_set_buffer_size_max((self.1).0, self.0, &mut r)).map(|_| r as Frames)
1053    }
1054
1055    pub fn set_buffer_size_min(&self, v: Frames) -> Result<Frames> {
1056        let mut r = v as alsa::snd_pcm_uframes_t;
1057        acheck!(snd_pcm_hw_params_set_buffer_size_min((self.1).0, self.0, &mut r)).map(|_| r as Frames)
1058    }
1059
1060    pub fn set_buffer_size(&self, v: Frames) -> Result<()> {
1061        acheck!(snd_pcm_hw_params_set_buffer_size((self.1).0, self.0, v as alsa::snd_pcm_uframes_t)).map(|_| ())
1062    }
1063
1064    pub fn set_buffer_time_near(&self, v: u32, dir: ValueOr) -> Result<u32> {
1065        let mut d = dir as c_int;
1066        let mut r = v as c_uint;
1067        acheck!(snd_pcm_hw_params_set_buffer_time_near((self.1).0, self.0, &mut r, &mut d)).map(|_| r as u32)
1068    }
1069
1070    pub fn set_buffer_time(&self, v: u32, dir: ValueOr) -> Result<()> {
1071        acheck!(snd_pcm_hw_params_set_buffer_time((self.1).0, self.0, v as c_uint, dir as c_int)).map(|_| ())
1072    }
1073
1074    pub fn set_buffer_time_min(&self, v: u32, dir: ValueOr) -> Result<u32> {
1075        let mut d = dir as c_int;
1076        let mut r = v as c_uint;
1077        acheck!(snd_pcm_hw_params_set_buffer_time_min((self.1).0, self.0, &mut r, &mut d)).map(|_| r as u32)
1078    }
1079
1080    pub fn set_buffer_time_max(&self, v: u32, dir: ValueOr) -> Result<u32> {
1081        let mut d = dir as c_int;
1082        let mut r = v as c_uint;
1083        acheck!(snd_pcm_hw_params_set_buffer_time_max((self.1).0, self.0, &mut r, &mut d)).map(|_| r as u32)
1084    }
1085
1086    pub fn get_buffer_size(&self) -> Result<Frames> {
1087        let mut v = 0;
1088        acheck!(snd_pcm_hw_params_get_buffer_size(self.0, &mut v)).map(|_| v as Frames)
1089    }
1090
1091    pub fn get_buffer_size_min(&self) -> Result<Frames> {
1092        let mut v = 0;
1093        acheck!(snd_pcm_hw_params_get_buffer_size_min(self.0, &mut v)).map(|_| v as Frames)
1094    }
1095
1096    pub fn get_buffer_size_max(&self) -> Result<Frames> {
1097        let mut v = 0;
1098        acheck!(snd_pcm_hw_params_get_buffer_size_max(self.0, &mut v)).map(|_| v as Frames)
1099    }
1100
1101    pub fn get_buffer_time(&self) -> Result<u32> {
1102        let (mut v, mut d) = (0,0);
1103        acheck!(snd_pcm_hw_params_get_buffer_time(self.0, &mut v, &mut d)).map(|_| v as u32)
1104    }
1105
1106    pub fn get_buffer_time_min(&self) -> Result<u32> {
1107        let (mut v, mut d) = (0,0);
1108        acheck!(snd_pcm_hw_params_get_buffer_time_min(self.0, &mut v, &mut d)).map(|_| v as u32)
1109    }
1110
1111    pub fn get_buffer_time_max(&self) -> Result<u32> {
1112        let (mut v, mut d) = (0,0);
1113        acheck!(snd_pcm_hw_params_get_buffer_time_max(self.0, &mut v, &mut d)).map(|_| v as u32)
1114    }
1115
1116    /// Returns true if the alsa stream can be paused, false if not.
1117    ///
1118    /// This function should only be called when the configuration space contains a single
1119    /// configuration. Call `PCM::hw_params` to choose a single configuration from the
1120    /// configuration space.
1121    pub fn can_pause(&self) -> bool {
1122        unsafe { alsa::snd_pcm_hw_params_can_pause(self.0) != 0 }
1123    }
1124
1125    /// Returns true if the alsa stream can be resumed, false if not.
1126    ///
1127    /// This function should only be called when the configuration space contains a single
1128    /// configuration. Call `PCM::hw_params` to choose a single configuration from the
1129    /// configuration space.
1130    pub fn can_resume(&self) -> bool {
1131        unsafe { alsa::snd_pcm_hw_params_can_resume(self.0) != 0 }
1132    }
1133
1134    /// Returns true if the alsa stream supports the provided `AudioTstampType`, false if not.
1135    ///
1136    /// This function should only be called when the configuration space contains a single
1137    /// configuration. Call `PCM::hw_params` to choose a single configuration from the
1138    /// configuration space.
1139    pub fn supports_audio_ts_type(&self, type_: AudioTstampType) -> bool {
1140        unsafe { alsa::snd_pcm_hw_params_supports_audio_ts_type(self.0, type_ as libc::c_int) != 0 }
1141    }
1142
1143    pub fn dump(&self, o: &mut Output) -> Result<()> {
1144        acheck!(snd_pcm_hw_params_dump(self.0, super::io::output_handle(o))).map(|_| ())
1145    }
1146
1147    pub fn copy_from(&mut self, other: &HwParams<'a>) {
1148        self.1 = other.1;
1149        unsafe { alsa::snd_pcm_hw_params_copy(self.0, other.0) };
1150    }
1151}
1152
1153impl<'a> Clone for HwParams<'a> {
1154    fn clone(&self) -> HwParams<'a> {
1155        let mut r = HwParams::new(self.1).unwrap();
1156        r.copy_from(self);
1157        r
1158    }
1159}
1160
1161impl<'a> fmt::Debug for HwParams<'a> {
1162    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1163        f.debug_struct("HwParams")
1164            .field("channels", &self.get_channels())
1165            .field("rate", &format!("{:?} Hz", self.get_rate()))
1166            .field("format", &self.get_format())
1167            .field("access", &self.get_access())
1168            .field("period_size", &format!("{:?} frames", self.get_period_size()))
1169            .field("buffer_size", &format!("{:?} frames", self.get_buffer_size()))
1170            .finish()
1171    }
1172}
1173
1174/// [snd_pcm_sw_params_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m___s_w___params.html) wrapper
1175pub struct SwParams<'a>(*mut alsa::snd_pcm_sw_params_t, &'a PCM);
1176
1177impl<'a> Drop for SwParams<'a> {
1178    fn drop(&mut self) { unsafe { alsa::snd_pcm_sw_params_free(self.0) }; }
1179}
1180
1181impl<'a> SwParams<'a> {
1182
1183    fn new(a: &'a PCM) -> Result<SwParams<'a>> {
1184        let mut p = ptr::null_mut();
1185        acheck!(snd_pcm_sw_params_malloc(&mut p)).map(|_| SwParams(p, a))
1186    }
1187
1188    pub fn set_avail_min(&self, v: Frames) -> Result<()> {
1189        acheck!(snd_pcm_sw_params_set_avail_min((self.1).0, self.0, v as alsa::snd_pcm_uframes_t)).map(|_| ())
1190    }
1191
1192    pub fn get_avail_min(&self) -> Result<Frames> {
1193        let mut v = 0;
1194        acheck!(snd_pcm_sw_params_get_avail_min(self.0, &mut v)).map(|_| v as Frames)
1195    }
1196
1197    pub fn get_boundary(&self) -> Result<Frames> {
1198        let mut v = 0;
1199        acheck!(snd_pcm_sw_params_get_boundary(self.0, &mut v)).map(|_| v as Frames)
1200    }
1201
1202    pub fn set_start_threshold(&self, v: Frames) -> Result<()> {
1203        acheck!(snd_pcm_sw_params_set_start_threshold((self.1).0, self.0, v as alsa::snd_pcm_uframes_t)).map(|_| ())
1204    }
1205
1206    pub fn get_start_threshold(&self) -> Result<Frames> {
1207        let mut v = 0;
1208        acheck!(snd_pcm_sw_params_get_start_threshold(self.0, &mut v)).map(|_| v as Frames)
1209    }
1210
1211    pub fn set_stop_threshold(&self, v: Frames) -> Result<()> {
1212        acheck!(snd_pcm_sw_params_set_stop_threshold((self.1).0, self.0, v as alsa::snd_pcm_uframes_t)).map(|_| ())
1213    }
1214
1215    pub fn get_stop_threshold(&self) -> Result<Frames> {
1216        let mut v = 0;
1217        acheck!(snd_pcm_sw_params_get_stop_threshold(self.0, &mut v)).map(|_| v as Frames)
1218    }
1219
1220    pub fn set_tstamp_mode(&self, v: bool) -> Result<()> {
1221        let z = if v { alsa::SND_PCM_TSTAMP_ENABLE } else { alsa::SND_PCM_TSTAMP_NONE };
1222        acheck!(snd_pcm_sw_params_set_tstamp_mode((self.1).0, self.0, z)).map(|_| ())
1223    }
1224
1225    pub fn get_tstamp_mode(&self) -> Result<bool> {
1226        let mut v = 0;
1227        acheck!(snd_pcm_sw_params_get_tstamp_mode(self.0, &mut v)).map(|_| v != 0)
1228    }
1229
1230    pub fn set_tstamp_type(&self, v: TstampType) -> Result<()> {
1231        acheck!(snd_pcm_sw_params_set_tstamp_type((self.1).0, self.0, v as u32)).map(|_| ())
1232    }
1233
1234    pub fn get_tstamp_type(&self) -> Result<TstampType> {
1235        let mut v = 0;
1236        acheck!(snd_pcm_sw_params_get_tstamp_type(self.0, &mut v))?;
1237        TstampType::from_c_int(v as c_int, "snd_pcm_sw_params_get_tstamp_type")
1238    }
1239
1240    pub fn dump(&self, o: &mut Output) -> Result<()> {
1241        acheck!(snd_pcm_sw_params_dump(self.0, super::io::output_handle(o))).map(|_| ())
1242    }
1243}
1244
1245impl<'a> fmt::Debug for SwParams<'a> {
1246    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1247        write!(f,
1248           "SwParams(avail_min: {:?} frames, start_threshold: {:?} frames, stop_threshold: {:?} frames)",
1249           self.get_avail_min(), self.get_start_threshold(), self.get_stop_threshold())
1250    }
1251}
1252
1253const STATUS_SIZE: usize = 152;
1254
1255/// [snd_pcm_status_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m___status.html) wrapper
1256#[derive(Debug)]
1257pub struct Status([u64; (STATUS_SIZE+7)/8]);
1258
1259impl Status {
1260    fn new() -> Status {
1261        assert!(unsafe { alsa::snd_pcm_status_sizeof() } as usize <= STATUS_SIZE);
1262        Status([0; (STATUS_SIZE+7)/8])
1263    }
1264
1265    fn ptr(&self) -> *mut alsa::snd_pcm_status_t { self.0.as_ptr() as *const _ as *mut alsa::snd_pcm_status_t }
1266
1267    pub fn get_htstamp(&self) -> timespec {
1268        let mut h = timespec {tv_sec: 0, tv_nsec: 0};
1269        unsafe { alsa::snd_pcm_status_get_htstamp(self.ptr(), &mut h) };
1270        h
1271    }
1272
1273    pub fn get_trigger_htstamp(&self) -> timespec {
1274        let mut h = timespec {tv_sec: 0, tv_nsec: 0};
1275        unsafe { alsa::snd_pcm_status_get_trigger_htstamp(self.ptr(), &mut h) };
1276        h
1277    }
1278
1279    pub fn get_audio_htstamp(&self) -> timespec {
1280        let mut h = timespec {tv_sec: 0, tv_nsec: 0};
1281        unsafe { alsa::snd_pcm_status_get_audio_htstamp(self.ptr(), &mut h) };
1282        h
1283    }
1284
1285    pub fn get_state(&self) -> State { State::from_c_int(
1286        unsafe { alsa::snd_pcm_status_get_state(self.ptr()) } as c_int, "snd_pcm_status_get_state").unwrap() }
1287
1288    pub fn get_avail(&self) -> Frames { unsafe { alsa::snd_pcm_status_get_avail(self.ptr()) as Frames }}
1289    pub fn get_delay(&self) -> Frames { unsafe { alsa::snd_pcm_status_get_delay(self.ptr()) }}
1290    pub fn get_avail_max(&self) -> Frames { unsafe { alsa::snd_pcm_status_get_avail_max(self.ptr()) as Frames }}
1291    pub fn get_overrange(&self) -> Frames { unsafe { alsa::snd_pcm_status_get_overrange(self.ptr()) as Frames }}
1292
1293    pub fn dump(&self, o: &mut Output) -> Result<()> {
1294        acheck!(snd_pcm_status_dump(self.ptr(), super::io::output_handle(o))).map(|_| ())
1295    }
1296}
1297
1298/// Builder for [`Status`].
1299///
1300/// Allows setting the audio timestamp configuration before retrieving the
1301/// status from the stream.
1302#[derive(Debug)]
1303pub struct StatusBuilder(Status);
1304
1305impl StatusBuilder {
1306    pub fn new() -> Self {
1307        StatusBuilder(Status::new())
1308    }
1309
1310    pub fn audio_htstamp_config(
1311        self,
1312        type_requested: AudioTstampType,
1313        report_delay: bool,
1314    ) -> Self {
1315        let mut cfg: alsa::snd_pcm_audio_tstamp_config_t = unsafe { core::mem::zeroed() };
1316        cfg.set_type_requested(type_requested as _);
1317        cfg.set_report_delay(report_delay as _);
1318        unsafe { alsa::snd_pcm_status_set_audio_htstamp_config(self.0.ptr(), &mut cfg) };
1319        self
1320    }
1321
1322    pub fn build(mut self, pcm: &PCM) -> Result<Status> {
1323        let p = self.0.0.as_mut_ptr() as *mut alsa::snd_pcm_status_t;
1324        acheck!(snd_pcm_status(pcm.0, p)).map(|_| self.0)
1325    }
1326}
1327
1328alsa_enum!(
1329    #[non_exhaustive]
1330    /// [SND_PCM_AUDIO_TSTAMP_TYPE_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) constants
1331    AudioTstampType, ALL_AUDIO_TSTAMP_TYPES[6],
1332
1333    Compat = SND_PCM_AUDIO_TSTAMP_TYPE_COMPAT,
1334    Default = SND_PCM_AUDIO_TSTAMP_TYPE_DEFAULT,
1335    Link = SND_PCM_AUDIO_TSTAMP_TYPE_LINK,
1336    LinkAbsolute = SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE,
1337    LinkEstimated = SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED,
1338    LinkSynchronized = SND_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED,
1339);
1340
1341#[test]
1342fn info_from_default() {
1343    extern crate std;
1344    use ::alloc::ffi::CString;
1345    let pcm = PCM::open(&*CString::new("default").unwrap(), Direction::Capture, false).unwrap();
1346    let info = pcm.info().unwrap();
1347    std::println!("PCM Info:");
1348    std::println!("\tCard: {}", info.get_card());
1349    std::println!("\tDevice: {}", info.get_device());
1350    std::println!("\tSubdevice: {}", info.get_subdevice());
1351    std::println!("\tId: {}", info.get_id().unwrap());
1352    std::println!("\tName: {}", info.get_name().unwrap());
1353    std::println!("\tSubdevice Name: {}", info.get_subdevice_name().unwrap());
1354}
1355
1356#[test]
1357fn drop() {
1358    use ::alloc::ffi::CString;
1359    let pcm = PCM::open(&*CString::new("default").unwrap(), Direction::Capture, false).unwrap();
1360    // Verify that this does not cause a naming conflict (issue #14)
1361    let _ = pcm.drop();
1362}
1363
1364#[test]
1365fn record_from_default() {
1366    use ::alloc::ffi::CString;
1367    let pcm = PCM::open(&*CString::new("default").unwrap(), Direction::Capture, false).unwrap();
1368    let hwp = HwParams::any(&pcm).unwrap();
1369    hwp.set_channels(2).unwrap();
1370    hwp.set_rate(44100, ValueOr::Nearest).unwrap();
1371    hwp.set_format(Format::s16()).unwrap();
1372    hwp.set_access(Access::RWInterleaved).unwrap();
1373    pcm.hw_params(&hwp).unwrap();
1374    pcm.start().unwrap();
1375    let mut buf = [0i16; 1024];
1376    assert_eq!(pcm.io_i16().unwrap().readi(&mut buf).unwrap(), 1024/2);
1377}
1378
1379#[test]
1380fn open_s24() {
1381    let pcm = PCM::open(c"default", Direction::Playback, false).unwrap();
1382    let hwp = HwParams::any(&pcm).unwrap();
1383    hwp.set_channels(1).unwrap();
1384    hwp.set_rate(44100, ValueOr::Nearest).unwrap();
1385    hwp.set_format(Format::s24()).unwrap();
1386    hwp.set_access(Access::RWInterleaved).unwrap();
1387    pcm.hw_params(&hwp).unwrap();
1388    assert_eq!(Format::s24().physical_width(), Ok(32));
1389    let _io = pcm.io_i32_s24().unwrap();
1390}
1391
1392#[test]
1393fn playback_to_default() {
1394    extern crate std;
1395
1396    use ::alloc::ffi::CString;
1397    let pcm = PCM::open(&*CString::new("default").unwrap(), Direction::Playback, false).unwrap();
1398    let hwp = HwParams::any(&pcm).unwrap();
1399    hwp.set_channels(1).unwrap();
1400    hwp.set_rate(44100, ValueOr::Nearest).unwrap();
1401    hwp.set_format(Format::s16()).unwrap();
1402    hwp.set_access(Access::RWInterleaved).unwrap();
1403    pcm.hw_params(&hwp).unwrap();
1404
1405    let hwp = pcm.hw_params_current().unwrap();
1406    let swp = pcm.sw_params_current().unwrap();
1407    swp.set_start_threshold(hwp.get_buffer_size().unwrap()).unwrap();
1408    pcm.sw_params(&swp).unwrap();
1409
1410    std::println!("PCM status: {:?}, {:?}", pcm.state(), pcm.hw_params_current().unwrap());
1411    let mut outp = Output::buffer_open().unwrap();
1412    pcm.dump(&mut outp).unwrap();
1413    std::println!("== PCM dump ==\n{}", outp);
1414
1415    let mut buf = [0i16; 1024];
1416    for (i, a) in buf.iter_mut().enumerate() {
1417        *a = ((i as f32 * 2.0 * ::core::f32::consts::PI / 128.0).sin() * 8192.0) as i16
1418    }
1419    let io = pcm.io_i16().unwrap();
1420    for _ in 0..2*44100/1024 { // 2 seconds of playback
1421        std::println!("PCM state: {:?}", pcm.state());
1422        assert_eq!(io.writei(&buf[..]).unwrap(), 1024);
1423    }
1424    if pcm.state() != State::Running { pcm.start().unwrap() };
1425
1426    let mut outp2 = Output::buffer_open().unwrap();
1427    pcm.status().unwrap().dump(&mut outp2).unwrap();
1428    std::println!("== PCM status dump ==\n{}", outp2);
1429
1430    pcm.drain().unwrap();
1431}
1432
1433#[test]
1434fn print_sizeof() {
1435    extern crate std;
1436
1437    let s = unsafe { alsa::snd_pcm_status_sizeof() } as usize;
1438    std::println!("Status size: {}", s);
1439
1440    assert!(s <= STATUS_SIZE);
1441}
1442
1443#[test]
1444fn format_display_from_str() {
1445    use ::alloc::string::ToString;
1446
1447    for format in ALL_FORMATS {
1448        assert_eq!(format, format.to_string().parse().unwrap());
1449    }
1450}