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