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 * ::std::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 
46 use libc::{c_int, c_uint, c_void, ssize_t, c_short, timespec, pollfd};
47 use crate::alsa;
48 use std::marker::PhantomData;
49 use std::mem::size_of;
50 use std::ffi::{CStr, CString};
51 use std::{io, fmt, ptr, cell};
52 use super::error::*;
53 use super::{Direction, Output, poll, ValueOr, chmap};
54 
55 pub use super::chmap::{Chmap, ChmapPosition, ChmapType, ChmapsQuery};
56 
57 /// [snd_pcm_sframes_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html)
58 pub type Frames = alsa::snd_pcm_sframes_t;
59 
60 pub struct Info(*mut alsa::snd_pcm_info_t);
61 
62 impl Info {
new() -> Result<Info>63     pub fn new() -> Result<Info> {
64         let mut p = ptr::null_mut();
65         acheck!(snd_pcm_info_malloc(&mut p)).map(|_| Info(p))
66     }
67 
get_card(&self) -> i3268     pub fn get_card(&self) -> i32 {
69         unsafe { alsa::snd_pcm_info_get_card(self.0) }
70     }
71 
get_device(&self) -> u3272     pub fn get_device(&self) -> u32 {
73         unsafe { alsa::snd_pcm_info_get_device(self.0) }
74     }
75 
get_subdevice(&self) -> u3276     pub fn get_subdevice(&self) -> u32 {
77         unsafe { alsa::snd_pcm_info_get_subdevice(self.0) }
78     }
79 
get_id(&self) -> Result<&str>80     pub fn get_id(&self) -> Result<&str> {
81         let c = unsafe { alsa::snd_pcm_info_get_id(self.0) };
82         from_const("snd_pcm_info_get_id", c)
83     }
84 
get_name(&self) -> Result<&str>85     pub fn get_name(&self) -> Result<&str> {
86         let c = unsafe { alsa::snd_pcm_info_get_name(self.0) };
87         from_const("snd_pcm_info_get_name", c)
88     }
89 
get_subdevice_name(&self) -> Result<&str>90     pub fn get_subdevice_name(&self) -> Result<&str> {
91         let c = unsafe { alsa::snd_pcm_info_get_subdevice_name(self.0) };
92         from_const("snd_pcm_info_get_subdevice_name", c)
93     }
94 
get_stream(&self) -> Direction95     pub fn get_stream(&self) -> Direction {
96         match unsafe { alsa::snd_pcm_info_get_stream(self.0) } {
97             alsa::SND_PCM_STREAM_CAPTURE => Direction::Capture,
98             alsa::SND_PCM_STREAM_PLAYBACK => Direction::Playback,
99             n @ _ => panic!("snd_pcm_info_get_stream invalid direction '{}'", n),
100         }
101     }
102 }
103 
104 impl Drop for Info {
drop(&mut self)105     fn drop(&mut self) { unsafe { alsa::snd_pcm_info_free(self.0) }; }
106 }
107 
108 /// [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
109 pub struct PCM(*mut alsa::snd_pcm_t, cell::Cell<bool>);
110 
111 unsafe impl Send for PCM {}
112 
113 impl PCM {
check_has_io(&self)114     fn check_has_io(&self) {
115         if self.1.get() { panic!("No hw_params call or additional IO objects allowed") }
116     }
117 
118     /// Wrapper around open that takes a &str instead of a &CStr
new(name: &str, dir: Direction, nonblock: bool) -> Result<PCM>119     pub fn new(name: &str, dir: Direction, nonblock: bool) -> Result<PCM> {
120         Self::open(&CString::new(name).unwrap(), dir, nonblock)
121     }
122 
123     // Does not offer async mode (it's not very Rustic anyway)
open(name: &CStr, dir: Direction, nonblock: bool) -> Result<PCM>124     pub fn open(name: &CStr, dir: Direction, nonblock: bool) -> Result<PCM> {
125         let mut r = ptr::null_mut();
126         let stream = match dir {
127             Direction::Capture => alsa::SND_PCM_STREAM_CAPTURE,
128             Direction::Playback => alsa::SND_PCM_STREAM_PLAYBACK
129         };
130         let flags = if nonblock { alsa::SND_PCM_NONBLOCK } else { 0 };
131         acheck!(snd_pcm_open(&mut r, name.as_ptr(), stream, flags)).map(|_| PCM(r, cell::Cell::new(false)))
132     }
133 
start(&self) -> Result<()>134     pub fn start(&self) -> Result<()> { acheck!(snd_pcm_start(self.0)).map(|_| ()) }
drop(&self) -> Result<()>135     pub fn drop(&self) -> Result<()> { acheck!(snd_pcm_drop(self.0)).map(|_| ()) }
pause(&self, pause: bool) -> Result<()>136     pub fn pause(&self, pause: bool) -> Result<()> {
137         acheck!(snd_pcm_pause(self.0, if pause { 1 } else { 0 })).map(|_| ()) }
resume(&self) -> Result<()>138     pub fn resume(&self) -> Result<()> { acheck!(snd_pcm_resume(self.0)).map(|_| ()) }
drain(&self) -> Result<()>139     pub fn drain(&self) -> Result<()> { acheck!(snd_pcm_drain(self.0)).map(|_| ()) }
prepare(&self) -> Result<()>140     pub fn prepare(&self) -> Result<()> { acheck!(snd_pcm_prepare(self.0)).map(|_| ()) }
reset(&self) -> Result<()>141     pub fn reset(&self) -> Result<()> { acheck!(snd_pcm_reset(self.0)).map(|_| ()) }
recover(&self, err: c_int, silent: bool) -> Result<()>142     pub fn recover(&self, err: c_int, silent: bool) -> Result<()> {
143         acheck!(snd_pcm_recover(self.0, err, if silent { 1 } else { 0 })).map(|_| ()) }
144 
145     /// Wrapper around snd_pcm_recover.
146     ///
147     /// Returns Ok if the error was successfully recovered from, or the original
148     /// error if the error was unhandled.
try_recover(&self, err: Error, silent: bool) -> Result<()>149     pub fn try_recover(&self, err: Error, silent: bool) -> Result<()> {
150         if let Some(e) = err.errno() {
151             self.recover(e as c_int, silent)
152         } else { Err(err) }
153     }
154 
wait(&self, timeout_ms: Option<u32>) -> Result<bool>155     pub fn wait(&self, timeout_ms: Option<u32>) -> Result<bool> {
156         acheck!(snd_pcm_wait(self.0, timeout_ms.map(|x| x as c_int).unwrap_or(-1))).map(|i| i == 1) }
157 
state(&self) -> State158     pub fn state(&self) -> State { State::from_c_int(
159         unsafe { alsa::snd_pcm_state(self.0) } as c_int, "snd_pcm_state").unwrap() }
160 
bytes_to_frames(&self, i: isize) -> Frames161     pub fn bytes_to_frames(&self, i: isize) -> Frames { unsafe { alsa::snd_pcm_bytes_to_frames(self.0, i as ssize_t) }}
frames_to_bytes(&self, i: Frames) -> isize162     pub fn frames_to_bytes(&self, i: Frames) -> isize { unsafe { alsa::snd_pcm_frames_to_bytes(self.0, i) as isize }}
163 
avail_update(&self) -> Result<Frames>164     pub fn avail_update(&self) -> Result<Frames> { acheck!(snd_pcm_avail_update(self.0)) }
avail(&self) -> Result<Frames>165     pub fn avail(&self) -> Result<Frames> { acheck!(snd_pcm_avail(self.0)) }
166 
avail_delay(&self) -> Result<(Frames, Frames)>167     pub fn avail_delay(&self) -> Result<(Frames, Frames)> {
168         let (mut a, mut d) = (0, 0);
169         acheck!(snd_pcm_avail_delay(self.0, &mut a, &mut d)).map(|_| (a, d))
170     }
delay(&self) -> Result<Frames>171     pub fn delay(&self) -> Result<Frames> {
172         let mut d = 0;
173         acheck!(snd_pcm_delay(self.0, &mut d)).map(|_| d)
174     }
175 
status(&self) -> Result<Status>176     pub fn status(&self) -> Result<Status> {
177         let z = Status::new();
178         acheck!(snd_pcm_status(self.0, z.ptr())).map(|_| z)
179     }
180 
verify_format(&self, f: Format) -> Result<()>181     fn verify_format(&self, f: Format) -> Result<()> {
182         let ff = self.hw_params_current().and_then(|h| h.get_format())?;
183         if ff == f { Ok(()) }
184         else {
185             // let s = format!("Invalid sample format ({:?}, expected {:?})", ff, f);
186             Err(Error::unsupported("io_xx"))
187         }
188     }
189 
io_i8<'a>(&'a self) -> Result<IO<'a, i8>>190     pub fn io_i8<'a>(&'a self) -> Result<IO<'a, i8>> { self.io_checked() }
io_u8<'a>(&'a self) -> Result<IO<'a, u8>>191     pub fn io_u8<'a>(&'a self) -> Result<IO<'a, u8>> { self.io_checked() }
io_i16<'a>(&'a self) -> Result<IO<'a, i16>>192     pub fn io_i16<'a>(&'a self) -> Result<IO<'a, i16>> { self.io_checked() }
io_u16<'a>(&'a self) -> Result<IO<'a, u16>>193     pub fn io_u16<'a>(&'a self) -> Result<IO<'a, u16>> { self.io_checked() }
io_i32<'a>(&'a self) -> Result<IO<'a, i32>>194     pub fn io_i32<'a>(&'a self) -> Result<IO<'a, i32>> { self.io_checked() }
io_u32<'a>(&'a self) -> Result<IO<'a, u32>>195     pub fn io_u32<'a>(&'a self) -> Result<IO<'a, u32>> { self.io_checked() }
io_f32<'a>(&'a self) -> Result<IO<'a, f32>>196     pub fn io_f32<'a>(&'a self) -> Result<IO<'a, f32>> { self.io_checked() }
io_f64<'a>(&'a self) -> Result<IO<'a, f64>>197     pub fn io_f64<'a>(&'a self) -> Result<IO<'a, f64>> { self.io_checked() }
198 
io_checked<'a, S: IoFormat>(&'a self) -> Result<IO<'a, S>>199     pub fn io_checked<'a, S: IoFormat>(&'a self) -> Result<IO<'a, S>> {
200         self.verify_format(S::FORMAT).map(|_| IO::new(&self))
201     }
202 
203     #[deprecated(note = "renamed to io_bytes")]
io<'a>(&'a self) -> IO<'a, u8>204     pub fn io<'a>(&'a self) -> IO<'a, u8> { IO::new(&self) }
io_bytes<'a>(&'a self) -> IO<'a, u8>205     pub fn io_bytes<'a>(&'a self) -> IO<'a, u8> { IO::new(&self) }
206 
207     /// Read buffers by talking to the kernel directly, bypassing alsa-lib.
direct_mmap_capture<S>(&self) -> Result<crate::direct::pcm::MmapCapture<S>>208     pub fn direct_mmap_capture<S>(&self) -> Result<crate::direct::pcm::MmapCapture<S>> {
209         self.check_has_io();
210         crate::direct::pcm::new_mmap(self)
211     }
212 
213     /// Write buffers by talking to the kernel directly, bypassing alsa-lib.
direct_mmap_playback<S>(&self) -> Result<crate::direct::pcm::MmapPlayback<S>>214     pub fn direct_mmap_playback<S>(&self) -> Result<crate::direct::pcm::MmapPlayback<S>> {
215         self.check_has_io();
216         crate::direct::pcm::new_mmap(self)
217     }
218 
219     /// Sets hw parameters. Note: No IO object can exist for this PCM
220     /// when hw parameters are set.
hw_params(&self, h: &HwParams) -> Result<()>221     pub fn hw_params(&self, h: &HwParams) -> Result<()> {
222         self.check_has_io();
223         acheck!(snd_pcm_hw_params(self.0, h.0)).map(|_| ())
224     }
225 
226     /// Retreive current PCM hardware configuration.
hw_params_current<'a>(&'a self) -> Result<HwParams<'a>>227     pub fn hw_params_current<'a>(&'a self) -> Result<HwParams<'a>> {
228         HwParams::new(&self).and_then(|h|
229             acheck!(snd_pcm_hw_params_current(self.0, h.0)).map(|_| h))
230     }
231 
sw_params(&self, h: &SwParams) -> Result<()>232     pub fn sw_params(&self, h: &SwParams) -> Result<()> {
233         acheck!(snd_pcm_sw_params(self.0, h.0)).map(|_| ())
234     }
235 
sw_params_current<'a>(&'a self) -> Result<SwParams<'a>>236     pub fn sw_params_current<'a>(&'a self) -> Result<SwParams<'a>> {
237         SwParams::new(&self).and_then(|h|
238             acheck!(snd_pcm_sw_params_current(self.0, h.0)).map(|_| h))
239     }
240 
241     /// Wraps `snd_pcm_get_params`, returns `(buffer_size, period_size)`.
get_params(&self) -> Result<(u64, u64)>242     pub fn get_params(&self) -> Result<(u64, u64)> {
243         let mut buffer_size = 0;
244         let mut period_size = 0;
245         acheck!(snd_pcm_get_params(self.0, &mut buffer_size, &mut period_size))
246             .map(|_| (buffer_size as u64, period_size as u64))
247 
248     }
249 
info(&self) -> Result<Info>250     pub fn info(&self) -> Result<Info> {
251         Info::new().and_then(|info|
252             acheck!(snd_pcm_info(self.0, info.0)).map(|_| info ))
253     }
254 
dump(&self, o: &mut Output) -> Result<()>255     pub fn dump(&self, o: &mut Output) -> Result<()> {
256         acheck!(snd_pcm_dump(self.0, super::io::output_handle(o))).map(|_| ())
257     }
258 
dump_hw_setup(&self, o: &mut Output) -> Result<()>259     pub fn dump_hw_setup(&self, o: &mut Output) -> Result<()> {
260         acheck!(snd_pcm_dump_hw_setup(self.0, super::io::output_handle(o))).map(|_| ())
261     }
262 
dump_sw_setup(&self, o: &mut Output) -> Result<()>263     pub fn dump_sw_setup(&self, o: &mut Output) -> Result<()> {
264         acheck!(snd_pcm_dump_sw_setup(self.0, super::io::output_handle(o))).map(|_| ())
265     }
266 
query_chmaps(&self) -> ChmapsQuery267     pub fn query_chmaps(&self) -> ChmapsQuery {
268         chmap::chmaps_query_new(unsafe { alsa::snd_pcm_query_chmaps(self.0) })
269     }
270 
set_chmap(&self, c: &Chmap) -> Result<()>271     pub fn set_chmap(&self, c: &Chmap) -> Result<()> {
272         acheck!(snd_pcm_set_chmap(self.0, chmap::chmap_handle(c))).map(|_| ())
273     }
274 
get_chmap(&self) -> Result<Chmap>275     pub fn get_chmap(&self) -> Result<Chmap> {
276         let p = unsafe { alsa::snd_pcm_get_chmap(self.0) };
277         if p == ptr::null_mut() { Err(Error::unsupported("snd_pcm_get_chmap")) }
278         else { Ok(chmap::chmap_new(p)) }
279     }
280 
link(&self, other: &PCM) -> Result<()>281     pub fn link(&self, other: &PCM) -> Result<()> {
282         acheck!(snd_pcm_link(self.0, other.0)).map(|_| ())
283     }
284 
unlink(&self) -> Result<()>285     pub fn unlink(&self) -> Result<()> {
286         acheck!(snd_pcm_unlink(self.0)).map(|_| ())
287     }
288 }
289 
290 impl Drop for PCM {
drop(&mut self)291     fn drop(&mut self) { unsafe { alsa::snd_pcm_close(self.0) }; }
292 }
293 
294 
295 impl poll::Descriptors for PCM {
count(&self) -> usize296     fn count(&self) -> usize {
297         unsafe { alsa::snd_pcm_poll_descriptors_count(self.0) as usize }
298     }
fill(&self, p: &mut [pollfd]) -> Result<usize>299     fn fill(&self, p: &mut [pollfd]) -> Result<usize> {
300         let z = unsafe { alsa::snd_pcm_poll_descriptors(self.0, p.as_mut_ptr(), p.len() as c_uint) };
301         from_code("snd_pcm_poll_descriptors", z).map(|_| z as usize)
302     }
revents(&self, p: &[pollfd]) -> Result<poll::Flags>303     fn revents(&self, p: &[pollfd]) -> Result<poll::Flags> {
304         let mut r = 0;
305         let z = unsafe { alsa::snd_pcm_poll_descriptors_revents(self.0, p.as_ptr() as *mut pollfd, p.len() as c_uint, &mut r) };
306         from_code("snd_pcm_poll_descriptors_revents", z).map(|_| poll::Flags::from_bits_truncate(r as c_short))
307     }
308 }
309 
310 /// Sample format dependent struct for reading from and writing data to a `PCM`.
311 /// Also implements `std::io::Read` and `std::io::Write`.
312 ///
313 /// Note: Only one IO object is allowed in scope at a time (for mmap safety).
314 pub struct IO<'a, S: Copy>(&'a PCM, PhantomData<S>);
315 
316 impl<'a, S: Copy> Drop for IO<'a, S> {
drop(&mut self)317     fn drop(&mut self) { (self.0).1.set(false) }
318 }
319 
320 impl<'a, S: Copy> IO<'a, S> {
321 
new(a: &'a PCM) -> IO<'a, S>322     fn new(a: &'a PCM) -> IO<'a, S> {
323         a.check_has_io();
324         a.1.set(true);
325         IO(a, PhantomData)
326     }
327 
to_frames(&self, b: usize) -> alsa::snd_pcm_uframes_t328     fn to_frames(&self, b: usize) -> alsa::snd_pcm_uframes_t {
329         // TODO: Do we need to check for overflow here?
330         self.0.bytes_to_frames((b * size_of::<S>()) as isize) as alsa::snd_pcm_uframes_t
331     }
332 
from_frames(&self, b: alsa::snd_pcm_uframes_t) -> usize333     fn from_frames(&self, b: alsa::snd_pcm_uframes_t) -> usize {
334         // TODO: Do we need to check for overflow here?
335         (self.0.frames_to_bytes(b as Frames) as usize) / size_of::<S>()
336     }
337 
338     /// On success, returns number of *frames* written.
339     /// (Multiply with number of channels to get number of items in buf successfully written.)
writei(&self, buf: &[S]) -> Result<usize>340     pub fn writei(&self, buf: &[S]) -> Result<usize> {
341         acheck!(snd_pcm_writei((self.0).0, buf.as_ptr() as *const c_void, self.to_frames(buf.len()))).map(|r| r as usize)
342     }
343 
344     /// On success, returns number of *frames* read.
345     /// (Multiply with number of channels to get number of items in buf successfully read.)
readi(&self, buf: &mut [S]) -> Result<usize>346     pub fn readi(&self, buf: &mut [S]) -> Result<usize> {
347         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)
348     }
349 
350     /// Wrapper around snd_pcm_mmap_begin and snd_pcm_mmap_commit.
351     ///
352     /// You can read/write into the sound card's buffer during the call to the closure.
353     /// According to alsa-lib docs, you should call avail_update before calling this function.
354     ///
355     /// All calculations are in *frames*, i e, the closure should return number of frames processed.
356     /// Also, there might not be as many frames to read/write as requested, and there can even be
357     /// an empty buffer supplied to the closure.
358     ///
359     /// Note: This function works only with interleaved access mode.
mmap<F: FnOnce(&mut [S]) -> usize>(&self, frames: usize, func: F) -> Result<usize>360     pub fn mmap<F: FnOnce(&mut [S]) -> usize>(&self, frames: usize, func: F) -> Result<usize> {
361         let mut f = frames as alsa::snd_pcm_uframes_t;
362         let mut offs: alsa::snd_pcm_uframes_t = 0;
363         let mut areas = ptr::null();
364         acheck!(snd_pcm_mmap_begin((self.0).0, &mut areas, &mut offs, &mut f))?;
365 
366         let (first, step) = unsafe { ((*areas).first, (*areas).step) };
367         if first != 0 || step as isize != self.0.frames_to_bytes(1) * 8 {
368             unsafe { alsa::snd_pcm_mmap_commit((self.0).0, offs, 0) };
369             // let s = format!("Can only mmap a single interleaved buffer (first = {:?}, step = {:?})", first, step);
370             return Err(Error::unsupported("snd_pcm_mmap_begin"));
371         }
372 
373         let buf = unsafe {
374             let p = ((*areas).addr as *mut S).offset(self.from_frames(offs) as isize);
375             ::std::slice::from_raw_parts_mut(p, self.from_frames(f))
376         };
377         let fres = func(buf);
378         debug_assert!(fres <= f as usize);
379         acheck!(snd_pcm_mmap_commit((self.0).0, offs, fres as alsa::snd_pcm_uframes_t)).map(|r| r as usize)
380     }
381 }
382 
383 impl<'a, S: Copy> io::Read for IO<'a, S> {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>384     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
385         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?
386         let r = unsafe { alsa::snd_pcm_readi((self.0).0, buf.as_mut_ptr() as *mut c_void, size) };
387         if r < 0 { Err(io::Error::from_raw_os_error(r as i32)) }
388         else { Ok(self.0.frames_to_bytes(r) as usize) }
389     }
390 }
391 
392 impl<'a, S: Copy> io::Write for IO<'a, S> {
write(&mut self, buf: &[u8]) -> io::Result<usize>393     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
394         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?
395         let r = unsafe { alsa::snd_pcm_writei((self.0).0, buf.as_ptr() as *const c_void, size) };
396         if r < 0 { Err(io::Error::from_raw_os_error(r as i32)) }
397         else { Ok(self.0.frames_to_bytes(r) as usize) }
398     }
flush(&mut self) -> io::Result<()>399     fn flush(&mut self) -> io::Result<()> { Ok(()) }
400 }
401 
402 
403 alsa_enum!(
404     /// [SND_PCM_STATE_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) constants
405     State, ALL_STATES[9],
406 
407     Open = SND_PCM_STATE_OPEN,
408     Setup = SND_PCM_STATE_SETUP,
409     Prepared = SND_PCM_STATE_PREPARED,
410     Running = SND_PCM_STATE_RUNNING,
411     XRun = SND_PCM_STATE_XRUN,
412     Draining = SND_PCM_STATE_DRAINING,
413     Paused = SND_PCM_STATE_PAUSED,
414     Suspended = SND_PCM_STATE_SUSPENDED,
415     Disconnected = SND_PCM_STATE_DISCONNECTED,
416 );
417 
418 alsa_enum!(
419     /// [SND_PCM_FORMAT_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) constants
420     Format, ALL_FORMATS[48],
421 
422     Unknown = SND_PCM_FORMAT_UNKNOWN,
423     S8 = SND_PCM_FORMAT_S8,
424     U8 = SND_PCM_FORMAT_U8,
425     S16LE = SND_PCM_FORMAT_S16_LE,
426     S16BE = SND_PCM_FORMAT_S16_BE,
427     U16LE = SND_PCM_FORMAT_U16_LE,
428     U16BE = SND_PCM_FORMAT_U16_BE,
429     S24LE = SND_PCM_FORMAT_S24_LE,
430     S24BE = SND_PCM_FORMAT_S24_BE,
431     U24LE = SND_PCM_FORMAT_U24_LE,
432     U24BE = SND_PCM_FORMAT_U24_BE,
433     S32LE = SND_PCM_FORMAT_S32_LE,
434     S32BE = SND_PCM_FORMAT_S32_BE,
435     U32LE = SND_PCM_FORMAT_U32_LE,
436     U32BE = SND_PCM_FORMAT_U32_BE,
437     FloatLE = SND_PCM_FORMAT_FLOAT_LE,
438     FloatBE = SND_PCM_FORMAT_FLOAT_BE,
439     Float64LE = SND_PCM_FORMAT_FLOAT64_LE,
440     Float64BE = SND_PCM_FORMAT_FLOAT64_BE,
441     IEC958SubframeLE = SND_PCM_FORMAT_IEC958_SUBFRAME_LE,
442     IEC958SubframeBE = SND_PCM_FORMAT_IEC958_SUBFRAME_BE,
443     MuLaw = SND_PCM_FORMAT_MU_LAW,
444     ALaw = SND_PCM_FORMAT_A_LAW,
445     ImaAdPCM = SND_PCM_FORMAT_IMA_ADPCM,
446     MPEG = SND_PCM_FORMAT_MPEG,
447     GSM = SND_PCM_FORMAT_GSM,
448     Special = SND_PCM_FORMAT_SPECIAL,
449     S243LE = SND_PCM_FORMAT_S24_3LE,
450     S243BE = SND_PCM_FORMAT_S24_3BE,
451     U243LE = SND_PCM_FORMAT_U24_3LE,
452     U243BE = SND_PCM_FORMAT_U24_3BE,
453     S203LE = SND_PCM_FORMAT_S20_3LE,
454     S203BE = SND_PCM_FORMAT_S20_3BE,
455     U203LE = SND_PCM_FORMAT_U20_3LE,
456     U203BE = SND_PCM_FORMAT_U20_3BE,
457     S183LE = SND_PCM_FORMAT_S18_3LE,
458     S183BE = SND_PCM_FORMAT_S18_3BE,
459     U183LE = SND_PCM_FORMAT_U18_3LE,
460     U183BE = SND_PCM_FORMAT_U18_3BE,
461     G72324 = SND_PCM_FORMAT_G723_24,
462     G723241B = SND_PCM_FORMAT_G723_24_1B,
463     G72340 = SND_PCM_FORMAT_G723_40,
464     G723401B = SND_PCM_FORMAT_G723_40_1B,
465     DSDU8 = SND_PCM_FORMAT_DSD_U8,
466     DSDU16LE = SND_PCM_FORMAT_DSD_U16_LE,
467     DSDU32LE = SND_PCM_FORMAT_DSD_U32_LE,
468     DSDU16BE = SND_PCM_FORMAT_DSD_U16_BE,
469     DSDU32BE = SND_PCM_FORMAT_DSD_U32_BE,
470 );
471 
472 impl Format {
s16() -> Format473     pub fn s16() -> Format { <i16 as IoFormat>::FORMAT }
u16() -> Format474     pub fn u16() -> Format { <u16 as IoFormat>::FORMAT }
s32() -> Format475     pub fn s32() -> Format { <i32 as IoFormat>::FORMAT }
u32() -> Format476     pub fn u32() -> Format { <u32 as IoFormat>::FORMAT }
float() -> Format477     pub fn float() -> Format { <f32 as IoFormat>::FORMAT }
float64() -> Format478     pub fn float64() -> Format { <f64 as IoFormat>::FORMAT }
479 
s24() -> Format480     #[cfg(target_endian = "little")] pub fn s24() -> Format { Format::S24LE }
s24() -> Format481     #[cfg(target_endian = "big")] pub fn s24() -> Format { Format::S24BE }
482 
u24() -> Format483     #[cfg(target_endian = "little")] pub fn u24() -> Format { Format::U24LE }
u24() -> Format484     #[cfg(target_endian = "big")] pub fn u24() -> Format { Format::U24BE }
485 
iec958_subframe() -> Format486     #[cfg(target_endian = "little")] pub fn iec958_subframe() -> Format { Format::IEC958SubframeLE }
iec958_subframe() -> Format487     #[cfg(target_endian = "big")] pub fn iec958_subframe() -> Format { Format::IEC958SubframeBE }
488 }
489 
490 
491 pub trait IoFormat: Copy {
492     const FORMAT: Format;
493 }
494 
495 impl IoFormat for i8 { const FORMAT: Format = Format::S8; }
496 impl IoFormat for u8 { const FORMAT: Format = Format::U8; }
497 
498 impl IoFormat for i16 {
499     #[cfg(target_endian = "little")]
500     const FORMAT: Format = Format::S16LE;
501     #[cfg(target_endian = "big")]
502     const FORMAT: Format = Format::S16BE;
503 }
504 impl IoFormat for u16 {
505     #[cfg(target_endian = "little")]
506     const FORMAT: Format = Format::U16LE;
507     #[cfg(target_endian = "big")]
508     const FORMAT: Format = Format::U16BE;
509 }
510 impl IoFormat for i32 {
511     #[cfg(target_endian = "little")]
512     const FORMAT: Format = Format::S32LE;
513     #[cfg(target_endian = "big")]
514     const FORMAT: Format = Format::S32BE;
515 }
516 impl IoFormat for u32 {
517     #[cfg(target_endian = "little")]
518     const FORMAT: Format = Format::U32LE;
519     #[cfg(target_endian = "big")]
520     const FORMAT: Format = Format::U32BE;
521 }
522 impl IoFormat for f32 {
523     #[cfg(target_endian = "little")]
524     const FORMAT: Format = Format::FloatLE;
525     #[cfg(target_endian = "big")]
526     const FORMAT: Format = Format::FloatBE;
527 }
528 impl IoFormat for f64 {
529     #[cfg(target_endian = "little")]
530     const FORMAT: Format = Format::Float64LE;
531     #[cfg(target_endian = "big")]
532     const FORMAT: Format = Format::Float64BE;
533 }
534 
535 
536 alsa_enum!(
537     /// [SND_PCM_ACCESS_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) constants
538     Access, ALL_ACCESSES[5],
539 
540     MMapInterleaved = SND_PCM_ACCESS_MMAP_INTERLEAVED,
541     MMapNonInterleaved = SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
542     MMapComplex = SND_PCM_ACCESS_MMAP_COMPLEX,
543     RWInterleaved = SND_PCM_ACCESS_RW_INTERLEAVED,
544     RWNonInterleaved = SND_PCM_ACCESS_RW_NONINTERLEAVED,
545 );
546 
547 alsa_enum!(
548     /// [SND_PCM_TSTAMP_TYPE_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) constants
549     TstampType, ALL_TSTAMP_TYPES[3],
550 
551     Gettimeofday = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY,
552     Monotonic = SND_PCM_TSTAMP_TYPE_MONOTONIC,
553     MonotonicRaw = SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW,
554 );
555 
556 /// [snd_pcm_hw_params_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m___h_w___params.html) wrapper
557 pub struct HwParams<'a>(*mut alsa::snd_pcm_hw_params_t, &'a PCM);
558 
559 impl<'a> Drop for HwParams<'a> {
drop(&mut self)560     fn drop(&mut self) { unsafe { alsa::snd_pcm_hw_params_free(self.0) }; }
561 }
562 
563 impl<'a> HwParams<'a> {
new(a: &'a PCM) -> Result<HwParams<'a>>564     fn new(a: &'a PCM) -> Result<HwParams<'a>> {
565         let mut p = ptr::null_mut();
566         acheck!(snd_pcm_hw_params_malloc(&mut p)).map(|_| HwParams(p, a))
567     }
568 
any(a: &'a PCM) -> Result<HwParams<'a>>569     pub fn any(a: &'a PCM) -> Result<HwParams<'a>> { HwParams::new(a).and_then(|p|
570         acheck!(snd_pcm_hw_params_any(a.0, p.0)).map(|_| p)
571     )}
572 
get_rate_resample(&self) -> Result<bool>573     pub fn get_rate_resample(&self) -> Result<bool> {
574         let mut v = 0;
575         acheck!(snd_pcm_hw_params_get_rate_resample((self.1).0, self.0, &mut v)).map(|_| v != 0)
576     }
577 
set_rate_resample(&self, resample: bool) -> Result<()>578     pub fn set_rate_resample(&self, resample: bool) -> Result<()> {
579         acheck!(snd_pcm_hw_params_set_rate_resample((self.1).0, self.0, if resample {1} else {0})).map(|_| ())
580     }
581 
set_channels_near(&self, v: u32) -> Result<u32>582     pub fn set_channels_near(&self, v: u32) -> Result<u32> {
583         let mut r = v as c_uint;
584         acheck!(snd_pcm_hw_params_set_channels_near((self.1).0, self.0, &mut r)).map(|_| r)
585     }
586 
set_channels(&self, v: u32) -> Result<()>587     pub fn set_channels(&self, v: u32) -> Result<()> {
588         acheck!(snd_pcm_hw_params_set_channels((self.1).0, self.0, v as c_uint)).map(|_| ())
589     }
590 
get_channels(&self) -> Result<u32>591     pub fn get_channels(&self) -> Result<u32> {
592         let mut v = 0;
593         acheck!(snd_pcm_hw_params_get_channels(self.0, &mut v)).map(|_| v as u32)
594     }
595 
get_channels_max(&self) -> Result<u32>596     pub fn get_channels_max(&self) -> Result<u32> {
597         let mut v = 0;
598         acheck!(snd_pcm_hw_params_get_channels_max(self.0, &mut v)).map(|_| v as u32)
599     }
600 
get_channels_min(&self) -> Result<u32>601     pub fn get_channels_min(&self) -> Result<u32> {
602         let mut v = 0;
603         acheck!(snd_pcm_hw_params_get_channels_min(self.0, &mut v)).map(|_| v as u32)
604     }
605 
test_channels(&self, v: u32) -> Result<()>606     pub fn test_channels(&self, v: u32) -> Result<()> {
607         acheck!(snd_pcm_hw_params_test_channels((self.1).0, self.0, v as c_uint)).map(|_| ())
608     }
609 
set_rate_near(&self, v: u32, dir: ValueOr) -> Result<u32>610     pub fn set_rate_near(&self, v: u32, dir: ValueOr) -> Result<u32> {
611         let mut d = dir as c_int;
612         let mut r = v as c_uint;
613         acheck!(snd_pcm_hw_params_set_rate_near((self.1).0, self.0, &mut r, &mut d)).map(|_| r)
614     }
615 
set_rate(&self, v: u32, dir: ValueOr) -> Result<()>616     pub fn set_rate(&self, v: u32, dir: ValueOr) -> Result<()> {
617         acheck!(snd_pcm_hw_params_set_rate((self.1).0, self.0, v as c_uint, dir as c_int)).map(|_| ())
618     }
619 
get_rate(&self) -> Result<u32>620     pub fn get_rate(&self) -> Result<u32> {
621         let (mut v, mut d) = (0,0);
622         acheck!(snd_pcm_hw_params_get_rate(self.0, &mut v, &mut d)).map(|_| v as u32)
623     }
624 
get_rate_max(&self) -> Result<u32>625     pub fn get_rate_max(&self) -> Result<u32> {
626         let mut v = 0;
627         // Note on the null ptr: if this ptr is not null, then the value behind it is replaced with
628         // -1 if the suprenum is not in the set (i.e. it's an open range), 0 otherwise. This could
629         // be returned along with the value, but it's safe to pass a null ptr in, in which case the
630         // pointer is not dereferenced.
631         acheck!(snd_pcm_hw_params_get_rate_max(self.0, &mut v, ptr::null_mut())).map(|_| v as u32)
632     }
633 
get_rate_min(&self) -> Result<u32>634     pub fn get_rate_min(&self) -> Result<u32> {
635         let mut v = 0;
636         // Note on the null ptr: see get_rate_max but read +1 and infinum instead of -1 and
637         // suprenum.
638         acheck!(snd_pcm_hw_params_get_rate_min(self.0, &mut v, ptr::null_mut())).map(|_| v as u32)
639     }
640 
test_rate(&self, rate: u32) -> Result<()>641     pub fn test_rate(&self, rate: u32) -> Result<()> {
642         acheck!(snd_pcm_hw_params_test_rate((self.1).0, self.0, rate as c_uint, 0)).map(|_| ())
643     }
644 
set_format(&self, v: Format) -> Result<()>645     pub fn set_format(&self, v: Format) -> Result<()> {
646         acheck!(snd_pcm_hw_params_set_format((self.1).0, self.0, v as c_int)).map(|_| ())
647     }
648 
get_format(&self) -> Result<Format>649     pub fn get_format(&self) -> Result<Format> {
650         let mut v = 0;
651         acheck!(snd_pcm_hw_params_get_format(self.0, &mut v))
652             .and_then(|_| Format::from_c_int(v, "snd_pcm_hw_params_get_format"))
653     }
654 
test_format(&self, v: Format) -> Result<()>655     pub fn test_format(&self, v: Format) -> Result<()> {
656         acheck!(snd_pcm_hw_params_test_format((self.1).0, self.0, v as c_int)).map(|_| ())
657     }
658 
set_access(&self, v: Access) -> Result<()>659     pub fn set_access(&self, v: Access) -> Result<()> {
660         acheck!(snd_pcm_hw_params_set_access((self.1).0, self.0, v as c_uint)).map(|_| ())
661     }
662 
get_access(&self) -> Result<Access>663     pub fn get_access(&self) -> Result<Access> {
664         let mut v = 0;
665         acheck!(snd_pcm_hw_params_get_access(self.0, &mut v))
666             .and_then(|_| Access::from_c_int(v as c_int, "snd_pcm_hw_params_get_access"))
667     }
668 
set_period_size_near(&self, v: Frames, dir: ValueOr) -> Result<Frames>669     pub fn set_period_size_near(&self, v: Frames, dir: ValueOr) -> Result<Frames> {
670         let mut d = dir as c_int;
671         let mut r = v as alsa::snd_pcm_uframes_t;
672         acheck!(snd_pcm_hw_params_set_period_size_near((self.1).0, self.0, &mut r, &mut d)).map(|_| r as Frames)
673     }
674 
set_period_size(&self, v: Frames, dir: ValueOr) -> Result<()>675     pub fn set_period_size(&self, v: Frames, dir: ValueOr) -> Result<()> {
676         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(|_| ())
677     }
678 
set_period_time_near(&self, v: u32, dir: ValueOr) -> Result<u32>679     pub fn set_period_time_near(&self, v: u32, dir: ValueOr) -> Result<u32> {
680         let mut d = dir as c_int;
681         let mut r = v as c_uint;
682         acheck!(snd_pcm_hw_params_set_period_time_near((self.1).0, self.0, &mut r, &mut d)).map(|_| r as u32)
683     }
684 
get_period_size(&self) -> Result<Frames>685     pub fn get_period_size(&self) -> Result<Frames> {
686         let (mut v, mut d) = (0,0);
687         acheck!(snd_pcm_hw_params_get_period_size(self.0, &mut v, &mut d)).map(|_| v as Frames)
688     }
689 
get_period_size_min(&self) -> Result<Frames>690     pub fn get_period_size_min(&self) -> Result<Frames> {
691         let (mut v, mut d) = (0,0);
692         acheck!(snd_pcm_hw_params_get_period_size_min(self.0, &mut v, &mut d)).map(|_| v as Frames)
693     }
694 
get_period_size_max(&self) -> Result<Frames>695     pub fn get_period_size_max(&self) -> Result<Frames> {
696         let (mut v, mut d) = (0,0);
697         acheck!(snd_pcm_hw_params_get_period_size_max(self.0, &mut v, &mut d)).map(|_| v as Frames)
698     }
699 
set_periods(&self, v: u32, dir: ValueOr) -> Result<()>700     pub fn set_periods(&self, v: u32, dir: ValueOr) -> Result<()> {
701         acheck!(snd_pcm_hw_params_set_periods((self.1).0, self.0, v as c_uint, dir as c_int)).map(|_| ())
702     }
703 
get_periods(&self) -> Result<u32>704     pub fn get_periods(&self) -> Result<u32> {
705         let (mut v, mut d) = (0,0);
706         acheck!(snd_pcm_hw_params_get_periods(self.0, &mut v, &mut d)).map(|_| v as u32)
707     }
708 
set_buffer_size_near(&self, v: Frames) -> Result<Frames>709     pub fn set_buffer_size_near(&self, v: Frames) -> Result<Frames> {
710         let mut r = v as alsa::snd_pcm_uframes_t;
711         acheck!(snd_pcm_hw_params_set_buffer_size_near((self.1).0, self.0, &mut r)).map(|_| r as Frames)
712     }
713 
set_buffer_size_max(&self, v: Frames) -> Result<Frames>714     pub fn set_buffer_size_max(&self, v: Frames) -> Result<Frames> {
715         let mut r = v as alsa::snd_pcm_uframes_t;
716         acheck!(snd_pcm_hw_params_set_buffer_size_max((self.1).0, self.0, &mut r)).map(|_| r as Frames)
717     }
718 
set_buffer_size_min(&self, v: Frames) -> Result<Frames>719     pub fn set_buffer_size_min(&self, v: Frames) -> Result<Frames> {
720         let mut r = v as alsa::snd_pcm_uframes_t;
721         acheck!(snd_pcm_hw_params_set_buffer_size_min((self.1).0, self.0, &mut r)).map(|_| r as Frames)
722     }
723 
set_buffer_size(&self, v: Frames) -> Result<()>724     pub fn set_buffer_size(&self, v: Frames) -> Result<()> {
725         acheck!(snd_pcm_hw_params_set_buffer_size((self.1).0, self.0, v as alsa::snd_pcm_uframes_t)).map(|_| ())
726     }
727 
set_buffer_time_near(&self, v: u32, dir: ValueOr) -> Result<u32>728     pub fn set_buffer_time_near(&self, v: u32, dir: ValueOr) -> Result<u32> {
729         let mut d = dir as c_int;
730         let mut r = v as c_uint;
731         acheck!(snd_pcm_hw_params_set_buffer_time_near((self.1).0, self.0, &mut r, &mut d)).map(|_| r as u32)
732     }
733 
get_buffer_size(&self) -> Result<Frames>734     pub fn get_buffer_size(&self) -> Result<Frames> {
735         let mut v = 0;
736         acheck!(snd_pcm_hw_params_get_buffer_size(self.0, &mut v)).map(|_| v as Frames)
737     }
738 
get_buffer_size_min(&self) -> Result<Frames>739     pub fn get_buffer_size_min(&self) -> Result<Frames> {
740         let mut v = 0;
741         acheck!(snd_pcm_hw_params_get_buffer_size_min(self.0, &mut v)).map(|_| v as Frames)
742     }
743 
get_buffer_size_max(&self) -> Result<Frames>744     pub fn get_buffer_size_max(&self) -> Result<Frames> {
745         let mut v = 0;
746         acheck!(snd_pcm_hw_params_get_buffer_size_max(self.0, &mut v)).map(|_| v as Frames)
747     }
748 
get_buffer_time_max(&self) -> Result<u32>749     pub fn get_buffer_time_max(&self) -> Result<u32> {
750         let (mut v, mut d) = (0,0);
751         acheck!(snd_pcm_hw_params_get_buffer_time_max(self.0, &mut v, &mut d)).map(|_| v as u32)
752     }
753 
754     /// Returns true if the alsa stream can be paused, false if not.
755     ///
756     /// This function should only be called when the configuration space contains a single
757     /// configuration. Call `PCM::hw_params` to choose a single configuration from the
758     /// configuration space.
can_pause(&self) -> bool759     pub fn can_pause(&self) -> bool {
760         unsafe { alsa::snd_pcm_hw_params_can_pause(self.0) != 0 }
761     }
762 
763     /// Returns true if the alsa stream can be resumed, false if not.
764     ///
765     /// This function should only be called when the configuration space contains a single
766     /// configuration. Call `PCM::hw_params` to choose a single configuration from the
767     /// configuration space.
can_resume(&self) -> bool768     pub fn can_resume(&self) -> bool {
769         unsafe { alsa::snd_pcm_hw_params_can_resume(self.0) != 0 }
770     }
771 
dump(&self, o: &mut Output) -> Result<()>772     pub fn dump(&self, o: &mut Output) -> Result<()> {
773         acheck!(snd_pcm_hw_params_dump(self.0, super::io::output_handle(o))).map(|_| ())
774     }
775 
copy_from(&mut self, other: &HwParams<'a>)776     pub fn copy_from(&mut self, other: &HwParams<'a>) {
777         self.1 = other.1;
778         unsafe { alsa::snd_pcm_hw_params_copy(self.0, other.0) };
779     }
780 }
781 
782 impl<'a> Clone for HwParams<'a> {
clone(&self) -> HwParams<'a>783     fn clone(&self) -> HwParams<'a> {
784         let mut r = HwParams::new(self.1).unwrap();
785         r.copy_from(&self);
786         r
787     }
788 }
789 
790 impl<'a> fmt::Debug for HwParams<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result791     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
792         f.debug_struct("HwParams")
793             .field("channels", &self.get_channels())
794             .field("rate", &format!("{:?} Hz", self.get_rate()))
795             .field("format", &self.get_format())
796             .field("access", &self.get_access())
797             .field("period_size", &format!("{:?} frames", self.get_period_size()))
798             .field("buffer_size", &format!("{:?} frames", self.get_buffer_size()))
799             .finish()
800     }
801 }
802 
803 /// [snd_pcm_sw_params_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m___s_w___params.html) wrapper
804 pub struct SwParams<'a>(*mut alsa::snd_pcm_sw_params_t, &'a PCM);
805 
806 impl<'a> Drop for SwParams<'a> {
drop(&mut self)807     fn drop(&mut self) { unsafe { alsa::snd_pcm_sw_params_free(self.0) }; }
808 }
809 
810 impl<'a> SwParams<'a> {
811 
new(a: &'a PCM) -> Result<SwParams<'a>>812     fn new(a: &'a PCM) -> Result<SwParams<'a>> {
813         let mut p = ptr::null_mut();
814         acheck!(snd_pcm_sw_params_malloc(&mut p)).map(|_| SwParams(p, a))
815     }
816 
set_avail_min(&self, v: Frames) -> Result<()>817     pub fn set_avail_min(&self, v: Frames) -> Result<()> {
818         acheck!(snd_pcm_sw_params_set_avail_min((self.1).0, self.0, v as alsa::snd_pcm_uframes_t)).map(|_| ())
819     }
820 
get_avail_min(&self) -> Result<Frames>821     pub fn get_avail_min(&self) -> Result<Frames> {
822         let mut v = 0;
823         acheck!(snd_pcm_sw_params_get_avail_min(self.0, &mut v)).map(|_| v as Frames)
824     }
825 
get_boundary(&self) -> Result<Frames>826     pub fn get_boundary(&self) -> Result<Frames> {
827         let mut v = 0;
828         acheck!(snd_pcm_sw_params_get_boundary(self.0, &mut v)).map(|_| v as Frames)
829     }
830 
set_start_threshold(&self, v: Frames) -> Result<()>831     pub fn set_start_threshold(&self, v: Frames) -> Result<()> {
832         acheck!(snd_pcm_sw_params_set_start_threshold((self.1).0, self.0, v as alsa::snd_pcm_uframes_t)).map(|_| ())
833     }
834 
get_start_threshold(&self) -> Result<Frames>835     pub fn get_start_threshold(&self) -> Result<Frames> {
836         let mut v = 0;
837         acheck!(snd_pcm_sw_params_get_start_threshold(self.0, &mut v)).map(|_| v as Frames)
838     }
839 
set_stop_threshold(&self, v: Frames) -> Result<()>840     pub fn set_stop_threshold(&self, v: Frames) -> Result<()> {
841         acheck!(snd_pcm_sw_params_set_stop_threshold((self.1).0, self.0, v as alsa::snd_pcm_uframes_t)).map(|_| ())
842     }
843 
get_stop_threshold(&self) -> Result<Frames>844     pub fn get_stop_threshold(&self) -> Result<Frames> {
845         let mut v = 0;
846         acheck!(snd_pcm_sw_params_get_stop_threshold(self.0, &mut v)).map(|_| v as Frames)
847     }
848 
set_tstamp_mode(&self, v: bool) -> Result<()>849     pub fn set_tstamp_mode(&self, v: bool) -> Result<()> {
850         let z = if v { alsa::SND_PCM_TSTAMP_ENABLE } else { alsa::SND_PCM_TSTAMP_NONE };
851         acheck!(snd_pcm_sw_params_set_tstamp_mode((self.1).0, self.0, z)).map(|_| ())
852     }
853 
get_tstamp_mode(&self) -> Result<bool>854     pub fn get_tstamp_mode(&self) -> Result<bool> {
855         let mut v = 0;
856         acheck!(snd_pcm_sw_params_get_tstamp_mode(self.0, &mut v)).map(|_| v != 0)
857     }
858 
set_tstamp_type(&self, v: TstampType) -> Result<()>859     pub fn set_tstamp_type(&self, v: TstampType) -> Result<()> {
860         acheck!(snd_pcm_sw_params_set_tstamp_type((self.1).0, self.0, v as u32)).map(|_| ())
861     }
862 
get_tstamp_type(&self) -> Result<TstampType>863     pub fn get_tstamp_type(&self) -> Result<TstampType> {
864         let mut v = 0;
865         acheck!(snd_pcm_sw_params_get_tstamp_type(self.0, &mut v))?;
866         TstampType::from_c_int(v as c_int, "snd_pcm_sw_params_get_tstamp_type")
867     }
868 
dump(&self, o: &mut Output) -> Result<()>869     pub fn dump(&self, o: &mut Output) -> Result<()> {
870         acheck!(snd_pcm_sw_params_dump(self.0, super::io::output_handle(o))).map(|_| ())
871     }
872 }
873 
874 impl<'a> fmt::Debug for SwParams<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result875     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
876         write!(f,
877            "SwParams(avail_min: {:?} frames, start_threshold: {:?} frames, stop_threshold: {:?} frames)",
878            self.get_avail_min(), self.get_start_threshold(), self.get_stop_threshold())
879     }
880 }
881 
882 const STATUS_SIZE: usize = 152;
883 
884 /// [snd_pcm_status_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m___status.html) wrapper
885 pub struct Status([u8; STATUS_SIZE]);
886 
887 impl Status {
new() -> Status888     fn new() -> Status {
889         assert!(unsafe { alsa::snd_pcm_status_sizeof() } as usize <= STATUS_SIZE);
890         Status([0; STATUS_SIZE])
891     }
892 
ptr(&self) -> *mut alsa::snd_pcm_status_t893     fn ptr(&self) -> *mut alsa::snd_pcm_status_t { self.0.as_ptr() as *const _ as *mut alsa::snd_pcm_status_t }
894 
get_htstamp(&self) -> timespec895     pub fn get_htstamp(&self) -> timespec {
896         let mut h = timespec {tv_sec: 0, tv_nsec: 0};
897         unsafe { alsa::snd_pcm_status_get_htstamp(self.ptr(), &mut h) };
898         h
899     }
900 
get_trigger_htstamp(&self) -> timespec901     pub fn get_trigger_htstamp(&self) -> timespec {
902         let mut h = timespec {tv_sec: 0, tv_nsec: 0};
903         unsafe { alsa::snd_pcm_status_get_trigger_htstamp(self.ptr(), &mut h) };
904         h
905     }
906 
get_audio_htstamp(&self) -> timespec907     pub fn get_audio_htstamp(&self) -> timespec {
908         let mut h = timespec {tv_sec: 0, tv_nsec: 0};
909         unsafe { alsa::snd_pcm_status_get_audio_htstamp(self.ptr(), &mut h) };
910         h
911     }
912 
get_state(&self) -> State913     pub fn get_state(&self) -> State { State::from_c_int(
914         unsafe { alsa::snd_pcm_status_get_state(self.ptr()) } as c_int, "snd_pcm_status_get_state").unwrap() }
915 
get_avail(&self) -> Frames916     pub fn get_avail(&self) -> Frames { unsafe { alsa::snd_pcm_status_get_avail(self.ptr()) as Frames }}
get_delay(&self) -> Frames917     pub fn get_delay(&self) -> Frames { unsafe { alsa::snd_pcm_status_get_delay(self.ptr()) }}
get_avail_max(&self) -> Frames918     pub fn get_avail_max(&self) -> Frames { unsafe { alsa::snd_pcm_status_get_avail_max(self.ptr()) as Frames }}
get_overrange(&self) -> Frames919     pub fn get_overrange(&self) -> Frames { unsafe { alsa::snd_pcm_status_get_overrange(self.ptr()) as Frames }}
920 
dump(&self, o: &mut Output) -> Result<()>921     pub fn dump(&self, o: &mut Output) -> Result<()> {
922         acheck!(snd_pcm_status_dump(self.ptr(), super::io::output_handle(o))).map(|_| ())
923     }
924 }
925 
926 #[test]
info_from_default()927 fn info_from_default() {
928     use std::ffi::CString;
929     let pcm = PCM::open(&*CString::new("default").unwrap(), Direction::Capture, false).unwrap();
930     let info = pcm.info().unwrap();
931     println!("PCM Info:");
932     println!("\tCard: {}", info.get_card());
933     println!("\tDevice: {}", info.get_device());
934     println!("\tSubdevice: {}", info.get_subdevice());
935     println!("\tId: {}", info.get_id().unwrap());
936     println!("\tName: {}", info.get_name().unwrap());
937     println!("\tSubdevice Name: {}", info.get_subdevice_name().unwrap());
938 }
939 
940 #[test]
drop()941 fn drop() {
942     use std::ffi::CString;
943     let pcm = PCM::open(&*CString::new("default").unwrap(), Direction::Capture, false).unwrap();
944     // Verify that this does not cause a naming conflict (issue #14)
945     let _ = pcm.drop();
946 }
947 
948 #[test]
record_from_default()949 fn record_from_default() {
950     use std::ffi::CString;
951     let pcm = PCM::open(&*CString::new("default").unwrap(), Direction::Capture, false).unwrap();
952     let hwp = HwParams::any(&pcm).unwrap();
953     hwp.set_channels(2).unwrap();
954     hwp.set_rate(44100, ValueOr::Nearest).unwrap();
955     hwp.set_format(Format::s16()).unwrap();
956     hwp.set_access(Access::RWInterleaved).unwrap();
957     pcm.hw_params(&hwp).unwrap();
958     pcm.start().unwrap();
959     let mut buf = [0i16; 1024];
960     assert_eq!(pcm.io_i16().unwrap().readi(&mut buf).unwrap(), 1024/2);
961 }
962 
963 #[test]
playback_to_default()964 fn playback_to_default() {
965     use std::ffi::CString;
966     let pcm = PCM::open(&*CString::new("default").unwrap(), Direction::Playback, false).unwrap();
967     let hwp = HwParams::any(&pcm).unwrap();
968     hwp.set_channels(1).unwrap();
969     hwp.set_rate(44100, ValueOr::Nearest).unwrap();
970     hwp.set_format(Format::s16()).unwrap();
971     hwp.set_access(Access::RWInterleaved).unwrap();
972     pcm.hw_params(&hwp).unwrap();
973 
974     let hwp = pcm.hw_params_current().unwrap();
975     let swp = pcm.sw_params_current().unwrap();
976     swp.set_start_threshold(hwp.get_buffer_size().unwrap()).unwrap();
977     pcm.sw_params(&swp).unwrap();
978 
979     println!("PCM status: {:?}, {:?}", pcm.state(), pcm.hw_params_current().unwrap());
980     let mut outp = Output::buffer_open().unwrap();
981     pcm.dump(&mut outp).unwrap();
982     println!("== PCM dump ==\n{}", outp);
983 
984     let mut buf = [0i16; 1024];
985     for (i, a) in buf.iter_mut().enumerate() {
986         *a = ((i as f32 * 2.0 * ::std::f32::consts::PI / 128.0).sin() * 8192.0) as i16
987     }
988     let io = pcm.io_i16().unwrap();
989     for _ in 0..2*44100/1024 { // 2 seconds of playback
990         println!("PCM state: {:?}", pcm.state());
991         assert_eq!(io.writei(&buf[..]).unwrap(), 1024);
992     }
993     if pcm.state() != State::Running { pcm.start().unwrap() };
994 
995     let mut outp2 = Output::buffer_open().unwrap();
996     pcm.status().unwrap().dump(&mut outp2).unwrap();
997     println!("== PCM status dump ==\n{}", outp2);
998 
999     pcm.drain().unwrap();
1000 }
1001 
1002 #[test]
print_sizeof()1003 fn print_sizeof() {
1004     let s = unsafe { alsa::snd_pcm_status_sizeof() } as usize;
1005     println!("Status size: {}", s);
1006 
1007     assert!(s <= STATUS_SIZE);
1008 }
1009