audio_device/alsa/software_parameters.rs
1use crate::alsa::{Error, Result, Timestamp, TimestampType};
2use crate::libc as c;
3use alsa_sys as alsa;
4use std::mem;
5use std::ops;
6use std::ptr;
7
8/// Collection of software parameters being configured for a [Pcm][super::Pcm]
9/// handle.
10///
11/// See
12/// [Pcm::software_parameters][super::Pcm::software_parameters].
13pub struct SoftwareParameters {
14 handle: ptr::NonNull<alsa::snd_pcm_sw_params_t>,
15}
16
17impl SoftwareParameters {
18 /// Open current software parameters for the current device for reading.
19 pub(super) unsafe fn new(pcm: &mut ptr::NonNull<alsa::snd_pcm_t>) -> Result<Self> {
20 let mut handle = mem::MaybeUninit::uninit();
21
22 errno!(alsa::snd_pcm_sw_params_malloc(handle.as_mut_ptr()))?;
23
24 let mut handle = ptr::NonNull::new_unchecked(handle.assume_init());
25
26 if let Err(e) = errno!(alsa::snd_pcm_sw_params_current(
27 pcm.as_ptr(),
28 handle.as_mut()
29 )) {
30 alsa::snd_pcm_sw_params_free(handle.as_mut());
31 return Err(e.into());
32 }
33
34 Ok(SoftwareParameters { handle })
35 }
36
37 /// Copy one set of software parameters to another.
38 ///
39 /// # Examples
40 ///
41 /// ```rust,no_run
42 /// use audio_device::alsa;
43 ///
44 /// # fn main() -> anyhow::Result<()> {
45 /// let mut a = alsa::Pcm::open_default(alsa::Stream::Playback)?;
46 /// let mut b = alsa::Pcm::open_default(alsa::Stream::Playback)?;
47 ///
48 /// let a = a.software_parameters()?;
49 /// let mut b = b.software_parameters()?;
50 ///
51 /// b.copy(&a);
52 /// # Ok(()) }
53 /// ```
54 pub fn copy(&mut self, other: &SoftwareParameters) {
55 unsafe { alsa::snd_pcm_sw_params_copy(self.handle.as_mut(), other.handle.as_ptr()) };
56 }
57
58 /// Get boundary for ring pointers from a software configuration container.
59 ///
60 /// # Examples
61 ///
62 /// ```rust,no_run
63 /// use audio_device::alsa;
64 ///
65 /// # fn main() -> anyhow::Result<()> {
66 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
67 /// let sw = pcm.software_parameters()?;
68 ///
69 /// let boundary = sw.boundary()?;
70 /// dbg!(boundary);
71 /// # Ok(()) }
72 /// ```
73 pub fn boundary(&self) -> Result<c::c_ulong> {
74 unsafe {
75 let mut boundary = mem::MaybeUninit::uninit();
76 errno!(alsa::snd_pcm_sw_params_get_boundary(
77 self.handle.as_ptr(),
78 boundary.as_mut_ptr()
79 ))?;
80 Ok(boundary.assume_init())
81 }
82 }
83
84 /// Get timestamp mode from a software configuration container.
85 ///
86 /// # Examples
87 ///
88 /// ```rust,no_run
89 /// use audio_device::alsa;
90 ///
91 /// # fn main() -> anyhow::Result<()> {
92 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
93 /// let sw = pcm.software_parameters()?;
94 ///
95 /// let timestamp_mode = sw.timestamp_mode()?;
96 /// dbg!(timestamp_mode);
97 /// # Ok(()) }
98 /// ```
99 pub fn timestamp_mode(&self) -> Result<Timestamp> {
100 unsafe {
101 let mut timestamp_mode = mem::MaybeUninit::uninit();
102 alsa::snd_pcm_sw_params_get_tstamp_mode(
103 self.handle.as_ptr(),
104 timestamp_mode.as_mut_ptr(),
105 );
106 let timestamp_mode = timestamp_mode.assume_init();
107 let timestamp_mode = Timestamp::from_value(timestamp_mode)
108 .ok_or_else(|| Error::BadTimestamp(timestamp_mode))?;
109 Ok(timestamp_mode)
110 }
111 }
112
113 /// Get timestamp type from a software configuration container.
114 ///
115 /// # Examples
116 ///
117 /// ```rust,no_run
118 /// use audio_device::alsa;
119 ///
120 /// # fn main() -> anyhow::Result<()> {
121 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
122 /// let sw = pcm.software_parameters()?;
123 ///
124 /// let value = sw.timestamp_type()?;
125 /// dbg!(value);
126 /// # Ok(()) }
127 /// ```
128 pub fn timestamp_type(&self) -> Result<TimestampType> {
129 unsafe {
130 let mut timestamp_type = mem::MaybeUninit::uninit();
131 alsa::snd_pcm_sw_params_get_tstamp_type(
132 self.handle.as_ptr(),
133 timestamp_type.as_mut_ptr(),
134 );
135 let timestamp_type = timestamp_type.assume_init();
136 let timestamp_type = TimestampType::from_value(timestamp_type)
137 .ok_or_else(|| Error::BadTimestampType(timestamp_type))?;
138 Ok(timestamp_type)
139 }
140 }
141
142 /// Get avail min from a software configuration container.
143 ///
144 /// # Examples
145 ///
146 /// ```rust,no_run
147 /// use audio_device::alsa;
148 ///
149 /// # fn main() -> anyhow::Result<()> {
150 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
151 /// let sw = pcm.software_parameters()?;
152 ///
153 /// let available_min = sw.available_min()?;
154 /// dbg!(available_min);
155 /// # Ok(()) }
156 /// ```
157 pub fn available_min(&self) -> Result<c::c_ulong> {
158 unsafe {
159 let mut available_min = mem::MaybeUninit::uninit();
160 alsa::snd_pcm_sw_params_get_avail_min(self.handle.as_ptr(), available_min.as_mut_ptr());
161 Ok(available_min.assume_init())
162 }
163 }
164
165 /// Get period event from a software configuration container.
166 ///
167 /// # Examples
168 ///
169 /// ```rust,no_run
170 /// use audio_device::alsa;
171 ///
172 /// # fn main() -> anyhow::Result<()> {
173 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
174 /// let sw = pcm.software_parameters()?;
175 ///
176 /// let value = sw.period_event()?;
177 /// # Ok(()) }
178 /// ```
179 pub fn period_event(&self) -> Result<c::c_int> {
180 unsafe {
181 let mut value = mem::MaybeUninit::uninit();
182 alsa::snd_pcm_sw_params_get_period_event(self.handle.as_ptr(), value.as_mut_ptr());
183 Ok(value.assume_init())
184 }
185 }
186
187 /// Get start threshold from a software configuration container.
188 ///
189 /// # Examples
190 ///
191 /// ```rust,no_run
192 /// use audio_device::alsa;
193 ///
194 /// # fn main() -> anyhow::Result<()> {
195 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
196 /// let sw = pcm.software_parameters()?;
197 ///
198 /// let value = sw.start_threshold()?;
199 /// # Ok(()) }
200 /// ```
201 pub fn start_threshold(&self) -> Result<c::c_ulong> {
202 unsafe {
203 let mut value = mem::MaybeUninit::uninit();
204 alsa::snd_pcm_sw_params_get_start_threshold(self.handle.as_ptr(), value.as_mut_ptr());
205 Ok(value.assume_init())
206 }
207 }
208
209 /// Get stop threshold from a software configuration container.
210 ///
211 /// # Examples
212 ///
213 /// ```rust,no_run
214 /// use audio_device::alsa;
215 ///
216 /// # fn main() -> anyhow::Result<()> {
217 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
218 /// let sw = pcm.software_parameters()?;
219 ///
220 /// let value = sw.stop_threshold()?;
221 /// # Ok(()) }
222 /// ```
223 pub fn stop_threshold(&self) -> Result<c::c_ulong> {
224 unsafe {
225 let mut value = mem::MaybeUninit::uninit();
226 alsa::snd_pcm_sw_params_get_stop_threshold(self.handle.as_ptr(), value.as_mut_ptr());
227 Ok(value.assume_init())
228 }
229 }
230
231 /// Get silence threshold from a software configuration container.
232 ///
233 /// A portion of playback buffer is overwritten with silence (see
234 /// [set_silence_size][SoftwareParametersMut::set_silence_size]) when
235 /// playback underrun is nearer than silence threshold.
236 ///
237 /// # Examples
238 ///
239 /// ```rust,no_run
240 /// use audio_device::alsa;
241 ///
242 /// # fn main() -> anyhow::Result<()> {
243 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
244 /// let sw = pcm.software_parameters()?;
245 ///
246 /// let value = sw.silence_threshold()?;
247 /// # Ok(()) }
248 /// ```
249 pub fn silence_threshold(&self) -> Result<c::c_ulong> {
250 unsafe {
251 let mut value = mem::MaybeUninit::uninit();
252 alsa::snd_pcm_sw_params_get_silence_threshold(self.handle.as_ptr(), value.as_mut_ptr());
253 Ok(value.assume_init())
254 }
255 }
256
257 /// Get silence size from a software configuration container.
258 ///
259 /// # Examples
260 ///
261 /// ```rust,no_run
262 /// use audio_device::alsa;
263 ///
264 /// # fn main() -> anyhow::Result<()> {
265 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
266 /// let sw = pcm.software_parameters()?;
267 ///
268 /// let value = sw.silence_size()?;
269 /// # Ok(()) }
270 /// ```
271 pub fn silence_size(&self) -> Result<c::c_ulong> {
272 unsafe {
273 let mut value = mem::MaybeUninit::uninit();
274 alsa::snd_pcm_sw_params_get_silence_size(self.handle.as_ptr(), value.as_mut_ptr());
275 Ok(value.assume_init())
276 }
277 }
278}
279
280impl Drop for SoftwareParameters {
281 fn drop(&mut self) {
282 unsafe {
283 alsa::snd_pcm_sw_params_free(self.handle.as_mut());
284 }
285 }
286}
287
288/// Collection of mutable software parameters being configured for a
289/// [Pcm][super::Pcm] handle.
290///
291/// See
292/// [Pcm::software_parameters_mut][super::Pcm::software_parameters_mut].
293pub struct SoftwareParametersMut<'a> {
294 pcm: &'a mut ptr::NonNull<alsa::snd_pcm_t>,
295 base: SoftwareParameters,
296}
297
298impl<'a> SoftwareParametersMut<'a> {
299 /// Open current software parameters for the current device for writing.
300 pub(super) unsafe fn new(pcm: &'a mut ptr::NonNull<alsa::snd_pcm_t>) -> Result<Self> {
301 let base = SoftwareParameters::new(pcm)?;
302
303 Ok(Self { pcm, base })
304 }
305
306 /// Install PCM software configuration defined by params.
307 ///
308 /// # Examples
309 ///
310 /// ```rust,no_run
311 /// use audio_device::alsa;
312 ///
313 /// # fn main() -> anyhow::Result<()> {
314 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
315 /// let mut sw = pcm.software_parameters_mut()?;
316 ///
317 /// sw.set_timestamp_mode(alsa::Timestamp::Enable)?;
318 /// sw.install()?;
319 /// # Ok(()) }
320 /// ```
321 pub fn install(mut self) -> Result<()> {
322 unsafe {
323 errno!(alsa::snd_pcm_sw_params(
324 self.pcm.as_mut(),
325 self.base.handle.as_mut()
326 ))?;
327 Ok(())
328 }
329 }
330
331 /// Set timestamp mode inside a software configuration container.
332 ///
333 /// # Examples
334 ///
335 /// ```rust,no_run
336 /// use audio_device::alsa;
337 ///
338 /// # fn main() -> anyhow::Result<()> {
339 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
340 /// let mut sw = pcm.software_parameters_mut()?;
341 ///
342 /// sw.set_timestamp_mode(alsa::Timestamp::Enable)?;
343 /// # Ok(()) }
344 /// ```
345 pub fn set_timestamp_mode(&mut self, timestamp_mode: Timestamp) -> Result<()> {
346 unsafe {
347 errno!(alsa::snd_pcm_sw_params_set_tstamp_mode(
348 self.pcm.as_mut(),
349 self.base.handle.as_mut(),
350 timestamp_mode as c::c_uint,
351 ))?;
352 Ok(())
353 }
354 }
355
356 /// Set timestamp type inside a software configuration container.
357 ///
358 /// # Examples
359 ///
360 /// ```rust,no_run
361 /// use audio_device::alsa;
362 ///
363 /// # fn main() -> anyhow::Result<()> {
364 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
365 /// let mut sw = pcm.software_parameters_mut()?;
366 ///
367 /// sw.set_timestamp_type(alsa::TimestampType::Monotonic)?;
368 /// # Ok(()) }
369 /// ```
370 pub fn set_timestamp_type(&mut self, timestamp_type: TimestampType) -> Result<()> {
371 unsafe {
372 errno!(alsa::snd_pcm_sw_params_set_tstamp_type(
373 self.pcm.as_mut(),
374 self.base.handle.as_mut(),
375 timestamp_type as c::c_uint,
376 ))?;
377 Ok(())
378 }
379 }
380
381 /// Set avail min inside a software configuration container.
382 ///
383 /// This is similar to setting an OSS wakeup point. The valid values for
384 /// 'val' are determined by the specific hardware. Most PC sound cards can
385 /// only accept power of 2 frame counts (i.e. 512, 1024, 2048). You cannot
386 /// use this as a high resolution timer - it is limited to how often the
387 /// sound card hardware raises an interrupt.
388 ///
389 /// # Examples
390 ///
391 /// ```rust,no_run
392 /// use audio_device::alsa;
393 ///
394 /// # fn main() -> anyhow::Result<()> {
395 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
396 /// let mut sw = pcm.software_parameters_mut()?;
397 ///
398 /// sw.set_available_min(1000)?;
399 /// # Ok(()) }
400 /// ```
401 pub fn set_available_min(&mut self, available_min: c::c_ulong) -> Result<()> {
402 unsafe {
403 errno!(alsa::snd_pcm_sw_params_set_avail_min(
404 self.pcm.as_mut(),
405 self.base.handle.as_mut(),
406 available_min
407 ))?;
408 Ok(())
409 }
410 }
411
412 /// Set period event inside a software configuration container.
413 ///
414 /// An poll (select) wakeup event is raised if enabled.
415 ///
416 /// # Examples
417 ///
418 /// ```rust,no_run
419 /// use audio_device::alsa;
420 ///
421 /// # fn main() -> anyhow::Result<()> {
422 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
423 /// let mut sw = pcm.software_parameters_mut()?;
424 ///
425 /// sw.set_period_event(0)?;
426 /// # Ok(()) }
427 /// ```
428 pub fn set_period_event(&mut self, period_event: c::c_int) -> Result<()> {
429 unsafe {
430 errno!(alsa::snd_pcm_sw_params_set_period_event(
431 self.pcm.as_mut(),
432 self.base.handle.as_mut(),
433 period_event
434 ))?;
435 Ok(())
436 }
437 }
438
439 /// Set start threshold inside a software configuration container.
440 ///
441 /// # Examples
442 ///
443 /// ```rust,no_run
444 /// use audio_device::alsa;
445 ///
446 /// # fn main() -> anyhow::Result<()> {
447 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
448 /// let mut sw = pcm.software_parameters_mut()?;
449 ///
450 /// sw.set_start_threshold(0)?;
451 /// # Ok(()) }
452 /// ```
453 pub fn set_start_threshold(&mut self, start_threshold: c::c_ulong) -> Result<()> {
454 unsafe {
455 errno!(alsa::snd_pcm_sw_params_set_start_threshold(
456 self.pcm.as_mut(),
457 self.base.handle.as_mut(),
458 start_threshold
459 ))?;
460 Ok(())
461 }
462 }
463
464 /// Set stop threshold inside a software configuration container.
465 ///
466 /// # Examples
467 ///
468 /// ```rust,no_run
469 /// use audio_device::alsa;
470 ///
471 /// # fn main() -> anyhow::Result<()> {
472 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
473 /// let mut sw = pcm.software_parameters_mut()?;
474 ///
475 /// sw.set_stop_threshold(0)?;
476 /// # Ok(()) }
477 /// ```
478 pub fn set_stop_threshold(&mut self, stop_threshold: c::c_ulong) -> Result<()> {
479 unsafe {
480 errno!(alsa::snd_pcm_sw_params_set_stop_threshold(
481 self.pcm.as_mut(),
482 self.base.handle.as_mut(),
483 stop_threshold
484 ))?;
485 Ok(())
486 }
487 }
488
489 /// Set silence threshold inside a software configuration container.
490 ///
491 /// # Examples
492 ///
493 /// ```rust,no_run
494 /// use audio_device::alsa;
495 ///
496 /// # fn main() -> anyhow::Result<()> {
497 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
498 /// let mut sw = pcm.software_parameters_mut()?;
499 ///
500 /// sw.set_silence_threshold(0)?;
501 /// # Ok(()) }
502 /// ```
503 pub fn set_silence_threshold(&mut self, silence_threshold: c::c_ulong) -> Result<()> {
504 unsafe {
505 errno!(alsa::snd_pcm_sw_params_set_silence_threshold(
506 self.pcm.as_mut(),
507 self.base.handle.as_mut(),
508 silence_threshold
509 ))?;
510 Ok(())
511 }
512 }
513
514 /// Set silence size inside a software configuration container.
515 ///
516 /// A portion of playback buffer is overwritten with silence when playback
517 /// underrun is nearer than silence threshold (see
518 /// snd_pcm_sw_params_set_silence_threshold)
519 ///
520 /// The special case is when silence size value is equal or greater than
521 /// boundary. The unused portion of the ring buffer (initial written samples
522 /// are untouched) is filled with silence at start. Later, only just
523 /// processed sample area is filled with silence. Note: silence_threshold
524 /// must be set to zero.
525 ///
526 /// # Examples
527 ///
528 /// ```rust,no_run
529 /// use audio_device::alsa;
530 ///
531 /// # fn main() -> anyhow::Result<()> {
532 /// let mut pcm = alsa::Pcm::open_default(alsa::Stream::Playback)?;
533 /// let mut sw = pcm.software_parameters_mut()?;
534 ///
535 /// sw.set_silence_size(0)?;
536 /// # Ok(()) }
537 /// ```
538 pub fn set_silence_size(&mut self, silence_size: c::c_ulong) -> Result<()> {
539 unsafe {
540 errno!(alsa::snd_pcm_sw_params_set_silence_size(
541 self.pcm.as_mut(),
542 self.base.handle.as_mut(),
543 silence_size
544 ))?;
545 Ok(())
546 }
547 }
548}
549
550impl ops::Deref for SoftwareParametersMut<'_> {
551 type Target = SoftwareParameters;
552
553 fn deref(&self) -> &Self::Target {
554 &self.base
555 }
556}