cpal icon indicating copy to clipboard operation
cpal copied to clipboard

[ALSA] using default device on linux fails

Open vim-zz opened this issue 7 years ago • 7 comments

I am using a x86 Linux machine, when trying to use the default device, e.g. using examples/recorder_wav.rs it fails with this output

     Running `target/debug/examples/record_wav`
Default input device: default
ALSA lib confmisc.c:767:(parse_card) cannot find card '0'
ALSA lib conf.c:4528:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
ALSA lib conf.c:4528:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib confmisc.c:1246:(snd_func_refer) error evaluating name
ALSA lib conf.c:4528:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5007:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM default
thread 'main' panicked at 'Failed to get default input format: DeviceNotAvailable', libcore/result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

The enumerate example works, this is the first few lines of output:

     Running `target/debug/examples/enumerate`
Default Input Device:
  Some("default")
Default Output Device:
  Some("default")
Devices: 
1. "default:CARD=AT2020USB"
  Default input stream format:
    Format { channels: 2, sample_rate: SampleRate(44100), data_type: F32 }
  All supported input stream formats:
    1.1. SupportedFormat { channels: 1, min_sample_rate: SampleRate(4000), max_sample_rate: SampleRate(4294967295), data_type: I16 }

As a workaround changing the record example to use the first input device and not the default device (which are the same device...), solves this issue, as following:

fn main() {
    // Setup the default input device and stream with the default input format.
    // ORIGINAL API:
    // let device = cpal::default_input_device().expect("Failed to get default input device");
    // WORKAROUND:
    let device = cpal::devices().nth(0).unwrap();
    println!("Default input device: {}", device.name());
    let format = device.default_input_format().expect("Failed to get default input format");

vim-zz avatar Jun 07 '18 08:06 vim-zz

I'm similarly seeing a segfault when attempting the recording demo on the Pi 3B+ with multiple USB mics. Recording on the device works with other programs.

paulirotta avatar Nov 22 '18 15:11 paulirotta

While writing #286 I noticed that the ALSA backend currently just assumes that there are "default" devices available in the backend without actually checking the API:

#[inline]
pub fn default_input_device() -> Option<Device> {
    Some(Device("default".to_owned()))
}

#[inline]
pub fn default_output_device() -> Option<Device> {
    Some(Device("default".to_owned()))
}

While I believe using the "default" name is the approach recommended for working with ALSA, we should actually check that it exists. Maybe a better approach would be to enumerate all devices, check if one of the devices is named "default", if so return it, otherwise return the first device that was yielded?

mitchmindtree avatar Jun 20 '19 21:06 mitchmindtree

That is odd. What does arecord -lL list? And can you record sound using arecord without specifying the device? The existence of the name "default:CARD=AT2020USB" suggests that the name default exists as well (At least that is the case on my systems). Now I think "failing to open" is a perfectly acceptable response to the missing default device.

Falling back to the first device is completely inappropriate imho. You go from "default" to something that is poorly defined and may result in sound appearing from a source it shouldn't or not at all while it seems to be working otherwise. It only works if it is guaranteed that what should be "default" is the first device. If that guarantee is given, go for it, but otherwise erroring out is just better.

EDIT: Even for devices that do not have a corresponding friendly named device listed it still works to just use the friendly prefix. Apparently aplay and arecord use the same binary, so aplay would work just as well.

Given the trace, this file seems relevant: https://git.alsa-project.org/?p=alsa-lib.git;a=blob_plain;f=src/conf/pcm/default.conf;hb=HEAD

Looks like the defaults.pcm.card is set to 0 while this card does not actually exist. Which suggests the USB device of the OP is not card 0 even though it is the only card present. Now I am even more curious whether arecord is actually able to record.

I was able to confirm that setting defaults.pcm.card to a nonexistent card has two effects: It removes the (sys)default device hints and it causes aplay to throw the exact same trace.

sniperrifle2004 avatar Jun 18 '20 23:06 sniperrifle2004

Encountered this issue today.

arecord -lL shows the following:

null
    Discard all samples (playback) or generate zero samples (capture)
pipewire
    PipeWire Sound Server
sysdefault:CARD=sofhdadsp
    sof-hda-dsp,
    Default Audio Device
**** List of CAPTURE Hardware Devices ****
card 0: sofhdadsp [sof-hda-dsp], device 0: HDA Analog (*) []
  Subdevices: 0/1
  Subdevice #0: subdevice #0
card 0: sofhdadsp [sof-hda-dsp], device 6: DMIC (*) []
  Subdevices: 0/1
  Subdevice #0: subdevice #0
card 0: sofhdadsp [sof-hda-dsp], device 7: DMIC16kHz (*) []
  Subdevices: 1/1
  Subdevice #0: subdevice #0

fooker avatar Sep 27 '24 22:09 fooker

Try with https://github.com/RustAudio/cpal/pull/917

abique avatar Sep 29 '24 12:09 abique

Try with #917

Same behavior.

fooker avatar Oct 11 '24 17:10 fooker

Looks like it is this: https://github.com/RustAudio/cpal/blob/f43d36e55494993bbbde3299af0c53e5cdf4d4cf/src/host/alsa/enumerate.rs#L88 whereas the assumption that "default" exists, does not hold (any more). Could be related to pipewire.

fooker avatar Oct 11 '24 17:10 fooker

I don't know of any way to programmatically query ALSA for a default device that isn't called "default". This reply is relevant: that'd be a system configuration issue.

If you wish to point your ALSA default to PipeWire, then put this in your ~/.asoundrc:

pcm.!default {
    type pipewire
}
ctl.!default {
    type pipewire
}

roderickvd avatar Dec 11 '25 08:12 roderickvd