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