1

Is there a simple, application-independent way to record audio on given sound card?

Lets say I plug in USB headset, which appears as /dev/snd/foo.

I then use zoom or skype or any other application to make a call.

If the application does not allow recording natively, can I record the audio independently on the sound card level?

I am using alsa, and I imagine (naively) that there might be some infrastructure to attach to, or "mirror" the sound card and dump audio to file? I need to record both channels (microphone, speaker), so there might be some mixing necesary?

My OS is Debian 10, and I am using alsa (not pulseaudio)

8
  • Are you unable to use PulseAudio ? Can the solution use PulseAudio?
    – turtle
    Jan 23, 2022 at 1:40
  • @turtle - I am looking for a solution using ALSA. Jan 23, 2022 at 4:28
  • Well, PA uses Alsa too Jan 23, 2022 at 13:54
  • 1
    @Arkadiusz Drabczyk - I am using customized debian (without systemd and pulseaudio) Jan 23, 2022 at 16:04
  • 2
    Hopefully no one never needed to wait for pulseaudio to achieve that. Whoever downvoted this question for the reason OP would want to run pulseaudio-free is nothing but a quiche-eater. BTW +1 to the question, i'll work the answer.
    – MC68020
    Jan 23, 2022 at 16:30

1 Answer 1

9
+250

Is there a simple, application-independent way to record audio on given sound card?

Yes ! There is !

What you are looking for is to simply record the output of your sound card.

The easiest way would probably be to wire its outputs to its inputs… the aloop alsa driver will provide a wireless way.

A/ So first ensure the driver is loaded & appropriately initialized :

arecord -l can tell you this, displaying (on my system):

card 0: Loopback [Loopback], device 0: Loopback PCM [Loopback PCM]
  Subdevices: 8/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
  Subdevice #4: subdevice #4
  Subdevice #5: subdevice #5
  Subdevice #6: subdevice #6
  Subdevice #7: subdevice #7
card 0: Loopback [Loopback], device 1: Loopback PCM [Loopback PCM]
  Subdevices: 8/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
  Subdevice #4: subdevice #4
  Subdevice #5: subdevice #5
  Subdevice #6: subdevice #6
  Subdevice #7: subdevice #7

Of course depending on your implementation, the card id can differ from the above list.

If you don't obtain that output then it might be because the driver is not loaded therefore fire : modprobe snd-aloop.

In case you still don't succeed then ensure that the driver is selected in the kernel .config file (grep for CONFIG_SND_ALOOP)

B/ Basically ensure it works as expected

This driver provides a pair of cross-connected devices, forming a full-duplex loopback soundcard. The first application opening one device, will force the second application, trying to open the other device, to use its established parameters. Therefore no rate, format or channel number conversion is done. The consequence of this is, that you have to start the playback application first. So let's ensure it works as expected :

1/ Find whatever .wav file and play it to card 0 device 0 subdevice 0 : aplay -D hw:0,0,0 whatever.wav

2/ Record from associated cross-connected device card 0 device 1 subdevice 0: arecord -D hw:0,1,0 record.wav

Of course you might need to adapt the card id to your configuration.

3/ Ensure it just works by playing record.wav on your alsa default device : aplay record.wav . If you can't hear anything, this will probably be because of some basic alsa misconfiguration. (I can elaborate if needed)

Of course, working like this (directing playback to the loopback, output won't be sent to your default playback device, so you won't be able to hear anything while recording. This is anyhow possible via some particular alsa configuration.

C/ Get both audio playing in your ears and enable recording

Warning! : This will be the hardest part of the work since alsa configuration files have always needed an appreciable part of… magic.

For this, you'll need to conceive from scratch either the /etc/asound.conf file (if your config is meant system-wide) or $HOME/.asoundrc (if the config is meant for your sole user) in order to create a couple of virtual sound devices.

1/ Start defining quasi aliases

pcm.MAUDIO{
    type hw
    card M2496
    device 0
    subdevice 0
    nonblock true}

ctl.MAUDIO{
    type hw
    card M2496}

This example being related to my own system with :

  • MAUDIO (choose whatever you want instead) acting as an alias for future reference to the hardware sound device,
  • M2496 coming from the CARD=M2496 associated to my preferred hardware device for sound playback (you should adapt according to your output of aplay -L)
  • nonblock true because you don't want Alsa to lock the character special file (/dev/snd/pcmwhatever) associated to the device driver of your sound card. (So than any other application can also open it if needed)

Then going on with the loopback device :

pcm.loopin {
    type plug
    slave.pcm "hw:Loopback,0,0"
}

pcm.loopout {
    type plug
    slave.pcm "hw:Loopback,1,0"
}

2/ Of course you want a mixer

pcm.dmixer{
    type dmix
    ipc_key 219345
    slave{
        pcm MAUDIO
        format S32_LE
        period_size 1024
        buffer_size 4096 }}

For the ipc_key choose whatever unique shared memory key (check using ipcs -ma that the one you choose is not used). period_size and buffer_size values depend on your expectations in terms of latency (lower the values, lower the latency) and the performances of your system (lower the values, higher the probability of XRuns)

3/ Of course you want everything to work as before (without conf)

pcm.!default{
    type plug
    slave.pcm "dmixer"
    hint{
        show on
        description "Alsa Default Device"}}

This will define the alsa default device described as such on all apps enabling the selection of audio output devices.

All we need now is to define a pseudo device able to duplicate it's input to both, the hardware sound device and the loopback device. This will be achieved thanks to alsa's multi plugin.

4/ Routing audio to hardware sound device and duplicate to loopback

pcm.multi {
    type route;
    slave.pcm {
        type multi;
        slaves.a.pcm "MAUDIO";
        slaves.b.pcm "loopin";
        slaves.a.channels 2;
        slaves.b.channels 2;
        bindings.0.slave a;
        bindings.0.channel 0;
        bindings.1.slave a;
        bindings.1.channel 1;
        bindings.2.slave b;
        bindings.2.channel 0;
        bindings.3.slave b;
        bindings.3.channel 1;
    }

    ttable.0.0 1;
    ttable.1.1 1;
    ttable.0.2 1;
    ttable.1.3 1;
}

Note that instead of slaves.a.pcm "MAUDIO", you may prefer slaves.a.pcm "dmixer"

For commodity, define an alias :

pcm.pbnrec {
    type plug
    slave.pcm "multi"
    hint{
        show on
        description "Alsa Playback & Record"}}

D/ Let's GO!

Shutdown & Reboot if you chose configuring system wide or logout login if you chose configuring user's own .asoundrc. From then, under any honest audio app enabling you to select the preferred audio output device, you should be able to choose the "Alsa Playback & Record" device, start playing then, on the command line, either :

  • arecord on the "loopout" device
  • ffmpeg on the "loopout" device if wishing resampling / other file formats.
  • Fire whatever more convenient audio recording desktop utility like audacity.

E/ Ha! This works as it should with players A,B,C but not with D,E,F apps

Unfortunately, many suboptimal apps won't enable you to select the desired output device. Browsers in particular. Because they will output to alsa default pcm, you'll need to adapt your configuration file and change the pcm.!default description as detailed above for something looking like :

pcm.!default {
    type plug
    slave.pcm "pbnrec"
}

F/ FTS! That still doesn't work with Firefox and Chrome.

1/ Chrome

To be honest… I cannot tell since I use chromium. Chromium will default to pulseaudio output unless specifying the --alsa-output-device option. So, one should try launching chrome --alsa-output-device='default' and hear if it works, it does indeed up to my current chromium 96

2/ Firefox

For whatever somber reason, Firefox decided to privilege pluseaudio so there is AFAIK no way to workaround this… with the official binary. However, building Firefox from sources, there is some make option which enables the build of an alsa backend. I can't tell how to achieve this under Debian, but this is almost certainly possible. All I can tell is that it works for me up to my current 91.4.0 version.


CREDITS : Since OP wanted authoritative sources, everything in this answer was elaborated from :


ALTERNATIVE

A sound server can stand as a viable alternative to the alsa fiddlings described here above. (to the cost of some processing power) The sound server of choice has, for decades, always be the Jack Audio Connection Kit. Pulseaudio never managed to compete.

But… this is another story.


ADDITIONAL INFORMATION FOLLOWING COMMENTS

1/ Sample rate

The snd-aloop driver is, in itself, not constrained to whatever fixed sample rate. Any of its subdevices can operate at a different sample rate if desired.
However, the application that will be the first to open a subdevice will determine the sample rate (since no conversion is done) for the cross-paired subdevice.

In practice, this means that the playback application outputing at PBSource Hz, the recording application will capture samples at PBSource Hz sample rate.
In case this is not convenient, resampling needs to be done, it will be on behalf of the recording app.
ffmpeg can achieve this on the fly, as would desktop recording apps (most likely thanks to ffmpeg)

In practice, this also means that the pseudo device used to push sound to the hardware sound device will have its input sampled at PBSource Hz.
There can indeed be a mismatch with the sound device (fixed) HW hz sample rate, this leading to bad sound.
Alsa provides two ways to overcome this, either by :

  • Using the rate plugin which will force the resampling to a given frequency. This is somehow suboptimal since alsa will then resample systematically. (even if the sample rate of the source and the given sample rate are identical)
  • Using the dmix plugin (cf. above §C-2,3) which will automatically resample but only when needed.

One can even select the preferred resampling algo via the definition of defaults.pcm.rate_converter.

8
  • 2
    Upvote for effort! Yet I still think "use pulseaudio" is a valid recommendation for the more average desktop user.
    – Hermann
    Jan 23, 2022 at 23:55
  • 1
    Thank you @Hermann. I fully agree with you and even more than fully in case of a gnome desktop user. But... well... since OP is systemd-free debian… I have assumed that they were not an average desktop user. ;-)
    – MC68020
    Jan 24, 2022 at 0:20
  • @MC68020 - I had to compile new kernel, with CONFIG_SND_ALOOP enabled. But now, my sound cards are "shifted", my soundcard is now device 1. So, sound does not work now by default, unless I specify device 1,0,0. Jan 24, 2022 at 10:35
  • @400theCat : Great ! I presume that the loopback device will have stolen card id #0. Normal. In order to have alsa default on your hardware sound device then proceed to C 1,2,3 steps. (test before going further)
    – MC68020
    Jan 24, 2022 at 12:01
  • 1
    +1 Defiantly a great answer. Well done
    – turtle
    Jan 24, 2022 at 20:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .