Alsa: how to duplicate a stream on 2 outputs and save system configs?
Asked Answered
A

1

8

My sound card is Audigy SE [SB0570].

I want to play the same stereo stream not only on speakers but on headphones too, simultaneously.

I try this config on my empty ~/.asoundrc

pcm.quad {
    type multi

    slaves.a.pcm "hw:0,0" #green hole
    slaves.a.channels 2
    slaves.b.pcm "hw:0,2" #black hole
    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
}

pcm.!default quad

and it works just as I want. But sharing channel between many streams is broken now and I can't play 2 mp3 files at the same time.

By the way /etc/asound.conf is empty too. I don't know where is the real system alsa configs are, may be this /var/lib/alsa/asound.state fat extremely hard understandable with 4705 lines and hundreds of control.## blocks.

Aerie answered 12/5, 2017 at 13:38 Comment(0)
I
15

Your idea is correct. You can use "type multi" alsa module to play sound to two different devices. You just need to extend it a little to build full chain.

Card name. It's usually better to use card names instead of indexes: "hw:CardName,2" instead of "hw:0,2" because card index may change on reboot, and names usually don't change. You can see card names in cat /proc/asound/cards and aplay -l output. For your card the name is probably "CA0106".

Dmix. To allow several apps playing simultaneously put "type dmix" between "type multi" and "hw" in your playback chain. The "type dmix" module mixes multiple apps into the same hardware buffer.

Route. Your "type multi" module maps input channels 0,1,2,3 to output channels 0,1 of slave "a" and channels 0,1 of slave "b", which implies that you have 4 input channels, while you have just 2 channels (stereo). To convert 2 channels stereo into 4 channels for "type multi" precede it with "type route" pcm duplicating channels 0,1 both to 0,1 and 2,3.

Plug. Different applications may try playing formats/rates, not directly supported by your hardware. So it's a good practice to put "type plug" autoconversion module first in the playback chain chain — it will convert whatever input format/rate into a supported output.

Overall the playback chain would be like:

default = plug -> route -> multi -> (dmix->hw:CA0106,0 + dmix->hw:CA0106,2)

Asym: But that's just playback chain. It's not enough if you want to point "default" pcm to it, because "default" is a pcm used by default both for playback and capture. To allow apps recording from "default" you need to define different playback and capture chains for it using "type asym" module. Capture chain can look like:

default = plug <- dsnoop <- hw

("type dsnoop" is a dmix-like module for capture — it allows multiple apps capturing from the same device)

You can define each of those pcms by hand, but I suggest to take a shortcut and reuse predefined "plug", "dmix" and "dsnoop" pcms (defined in /usr/share/alsa/alsa.conf, /usr/share/alsa/pcm/dmix.conf, /usr/share/alsa/pcm/dsnoop.conf). Then the whole config would be:

pcm.quad {
    type multi
    slaves.a.pcm "dmix:CA0106,0"
    slaves.a.channels 2
    slaves.b.pcm "dmix:CA0106,2"
    slaves.b.channels 2
    bindings.0 { slave a; channel 0; }
    bindings.1 { slave a; channel 1; }
    bindings.2 { slave b; channel 0; }
    bindings.3 { slave b; channel 1; }
}
pcm.stereo2quad {
    type route
    slave.pcm "quad"
    ttable.0.0 1
    ttable.1.1 1
    ttable.0.2 1
    ttable.1.3 1
}
pcm.!default {
    type asym
    playback.pcm "plug:stereo2quad"
    capture.pcm "plug:dsnoop:CA0106"
}

Put this in ~/.asoundrc (your user only) or /etc/asound.conf (all users).

PS: People often want their volumes to be preserved across reboot. So many distros run alsactl store on shutdown to save current volume controls and alsactl restore on startup to load those volume controls back. By default alsactl saves those volume controls in /var/lib/alsa/asound.state. That's the only purpose of that file.

Links:

Indicative answered 27/5, 2017 at 14:18 Comment(4)
I can not understand the concept of "slaves" and plugin chains. Which must be slave for which, the order of them? What must be in minimum set and what is optional? When I need a plug type and when I don't? And many other questions not described in this two links.Aerie
@Kroll, "Slave" is the next module in chain. Alsa-lib is modular: type dmix mixes multiple apps, type route modifies/duplicates channels, type plug autoconverts formats/rates, etc. So to do multiple things you chain those modules together. This way each module does its one thing and passes the output to its slave, which does some other thing and passes the output to its slave, and so on. That's the concept of "slaves".Indicative
About order of modules. The type hw module passes the output to hardware, it has no slaves, so it's always the last one in the chain. Also type hw is the only accepted slave for type dmix, so dmix is always next to last. The type plug autoconvertion module accepts almost all possible inputs, so it's placed first in chain to allow apps to play any format they want to it. Other modules in chain and their order depend on what you want them to do. The type multi is added if you need different channels passed to different slaves. And type route perform additional channels manipulations.Indicative
I've got an issue related to this. I have two devices but they accept different formats, one is S32_LE and the other S24_3LE. My guess is that if plug is early on the chain, it cannot convert to a common format and it fails. If I put it at the end, or use plughw, then I cannot use dmix and I cannot have multiple apps playing to multiple devices. Is there any solution for this?Sheer

© 2022 - 2024 — McMap. All rights reserved.