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