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}