Skip to content

ALSA: Capture fails from certain devices: snd_pcm_sw_params returns EINVAL, triggered by MONOTONIC_RAW timestamps #606

@ssssam

Description

@ssssam

Hello, thanks for creating 'cpal'. I have an issue with v0.13.4 on Fedora 34.

Here is what happens when I run the feedback.rs example, from the v0.13.4 tag:

> cargo run --example feedback  -- 'sysdefault:CARD=PCH' 'sysdefault:CARD=PCH'

Using input device: "sysdefault:CARD=PCH"
Using output device: "sysdefault:CARD=PCH"
Attempting to build both streams with f32 samples and `StreamConfig { channels: 2, sample_rate: SampleRate(44100), buffer_size: Default }`.
Error: A backend-specific error has occurred: ALSA function 'snd_pcm_sw_params' failed with error 'EINVAL: Invalid argument'

Caused by:
    A backend-specific error has occurred: ALSA function 'snd_pcm_sw_params' failed with error 'EINVAL: Invalid argument'

If I use the default audio outputs, then the 'feedback' example works as expected. It breaks when I specify a device.

I can recreate the 'feedback' example with this ALSA command, and it successfully connects the two devices I used above:

> arecord -D 'sysdefault:CARD=PCH' --disable-softvol --rate 48000 --format S32_LE --verbose | aplay -D 'sysdefault:CARD=PCH'  --disable-softvol
Recording WAVE 'stdin' : Signed 32 bit Little Endian, Rate 48000 Hz, Mono
Plug PCM: Route conversion PCM (sformat=S32_LE)
  Transformation table:
    0 <- 0
Its setup is:
  stream       : CAPTURE
  access       : RW_INTERLEAVED
  format       : S32_LE
  subformat    : STD
  channels     : 1
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 32
  buffer_size  : 16384
  period_size  : 1024
  period_time  : 21333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 1024
  period_event : 0
  start_threshold  : 1
  stop_threshold   : 16384
  silence_threshold: 0
  silence_size : 0
  boundary     : 4611686018427387904
<... snip long log...>
Playing WAVE 'stdin' : Signed 32 bit Little Endian, Rate 48000 Hz, Mono

The problem looks related to the struct we pass to the snd_pcm_sw_params() function. I am running Linux 5.11.20-300.fc34; here's that function in Linux v5.11: https://github.com/torvalds/linux/blob/v5.11/sound/core/pcm_native.c

I can see a few ways to trigger EINVAL. I added some debug prints to cpal:

diff --git a/src/host/alsa/mod.rs b/src/host/alsa/mod.rs
index 908d63c..29c78a9 100644
--- a/src/host/alsa/mod.rs
+++ b/src/host/alsa/mod.rs
@@ -1017,6 +1017,7 @@ fn set_sw_params_from_format(
 
     let period_len = {
         let (buffer, period) = pcm_handle.get_params()?;
+        println!("buffer {}, period {}", buffer, period);
         if buffer == 0 {
             return Err(BackendSpecificError {
                 description: "initialization resulted in a null buffer".to_string(),
@@ -1036,6 +1037,10 @@ fn set_sw_params_from_format(
     sw_params.set_tstamp_mode(true)?;
     sw_params.set_tstamp_type(alsa::pcm::TstampType::MonotonicRaw)?;
 
+    println!("{:?}", sw_params);
+    let mut output = alsa::Output::buffer_open().unwrap();
+    sw_params.dump(&mut output).unwrap();
+    println!("{}", output);
     pcm_handle.sw_params(&sw_params)?;
 
     Ok(period_len)

Here's the output:

> cargo run --example feedback  -- 'sysdefault:CARD=PCH' 'sysdefault:CARD=PCH'
    Finished dev [unoptimized + debuginfo] target(s) in 1.55s
     Running `target/debug/examples/feedback 'sysdefault:CARD=PCH' 'sysdefault:CARD=PCH'`
Using input device: "sysdefault:CARD=PCH"
Using output device: "sysdefault:CARD=PCH"
Attempting to build both streams with f32 samples and `StreamConfig { channels: 2, sample_rate: SampleRate(44100), buffer_size: Default }`.
buffer 4704, period 940
SwParams(avail_min: Ok(940) frames, start_threshold: Ok(1) frames, stop_threshold: Ok(4704) frames)
tstamp_mode: ENABLE
tstamp_type: MONOTONIC_RAW
period_step: 1
avail_min: 940
start_threshold: 1
stop_threshold: 4704
silence_threshold: 0
silence_size: 0
boundary: 5296233161787703296

set swparams
Error: A backend-specific error has occurred: ALSA function 'snd_pcm_sw_params' failed with error 'EINVAL: Invalid argument'

Caused by:
    A backend-specific error has occurred: ALSA function 'snd_pcm_sw_params' failed with error 'EINVAL: Invalid argument'

Nothing in that sw_params info seems like it would trigger the EINVAL error that I am seeing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions