-
Notifications
You must be signed in to change notification settings - Fork 189
Using bluealsa‐aplay with dsnoop
A bluealsa PCM permits only one process to capture from it at a time. For hardware sound cards ALSA provides a plugin, dsnoop
, that permits multiple processes to open a single capture PCM simultaneously. Unfortunately no such plugin exists for software PCMs such as bluealsa. We must find an indirect method, introducing a virtual hardware device as a proxy for bluealsa. This is analogous to the dmix
playback issue which is discussed in another wiki article here: Using bluealsa with dmix; and we can use that same ALSA Loopback virtual sound card as the proxy for capture. See that article for an introduction to the Loopback card if you are not already familiar with it.
In this article, we describe a method that uses bluealsa-aplay
to perform the bluealsa capture and to feed the stream to a Loopback PCM; applications can then capture from the Loopback using dsnoop
. You will need to ensure that the snd_aloop
kernel module is loaded for the Loopback, again see the Using bluealsa with dmix article for some hints on how to do that.
When creating an ALSA configuration for this method, the most important points to consider are:
-
the Loopback device takes its stream parameters from the first process that opens it, no matter if that process opens the capture side or the playback side. All other processes must accept those parameters. Therefore it is essential to force an agreed configuration. We achieve this by pre-defining format, channels and rate and using this within our PCM definitions. In order to avoid unnecessary format conversions it irs recommended to choose values that are used by the bluetooth device (or the majority of your devices if, for example, some use a sample rate of 48000Hz whereas others use 44100Hz).
-
bluealsa-aplay opens a fresh playback connection for each bluetooth device. Therefore we need to mix these streams together when feeding them to the Loopback. For this reason we use a dmix plugin in the Loopback interface to bluealsa-aplay.
defaults.bluealsa_aplay.a2dp {
format "s16_le"
rate 48000
channels 2
loopback 0
}
defaults.bluealsa_aplay.sco {
format "s16_le"
rate 8000
channels 1
loopback 1
}
pcm_slave.bluetooth_capture {
@args [ PROFILE ]
@args.PROFILE {
type string
}
pcm {
type dsnoop
ipc_key 1026
ipc_perm 0666
slave {
pcm {
type hw
card Loopback
device 0
subdevice {
@func refer
name {
@func concat
strings [
"defaults.bluealsa_aplay."
$PROFILE
".loopback"
]
}
}
}
channels {
@func refer
name {
@func concat
strings [
"defaults.bluealsa_aplay."
$PROFILE
".channels"
]
}
}
rate {
@func refer
name {
@func concat
strings [
"defaults.bluealsa_aplay."
$PROFILE
".rate"
]
}
}
format {
@func refer
name {
@func concat
strings [
"defaults.bluealsa_aplay."
$PROFILE
".format"
]
}
}
}
}
}
pcm.bluetooth_a2dp_capture {
type plug
slave "bluetooth_capture:PROFILE=a2dp"
hint {
show {
@func refer
name defaults.namehint.basic
}
description "Bluetooth audio A2DP sources"
}
}
pcm.bluetooth_sco_capture {
type plug
slave "bluetooth_capture:PROFILE=sco"
hint {
show {
@func refer
name defaults.namehint.basic
}
description "Bluetooth audio HFP/HSP sources"
}
}
pcm.bluealsa-aplay {
@args [ PROFILE ]
@args.PROFILE {
type string
default {
@func refer
name defaults.bluealsa.profile
}
}
type plug
slave.pcm {
type dmix
ipc_key 1025
ipc_perm 0600
slave {
pcm {
type hw
card Loopback
device 1
subdevice {
@func refer
name {
@func concat
strings [
"defaults.bluealsa_aplay."
$PROFILE
".loopback"
]
}
}
}
channels {
@func refer
name {
@func concat
strings [
"defaults.bluealsa_aplay."
$PROFILE
".channels"
]
}
}
rate {
@func refer
name {
@func concat
strings [
"defaults.bluealsa_aplay."
$PROFILE
".rate"
]
}
}
format {
@func refer
name {
@func concat
strings [
"defaults.bluealsa_aplay."
$PROFILE
".format"
]
}
}
}
}
hint.show off
}
An instance of bluealsa-aplay
can be used to capture from multiple connected bluealsa A2DP devices and send each stream to a playback device. Similarly, a second bluealsa-aplay
instance can do the same for bluealsa SCO capture devices. In this solution we want the playback device to be our virtual Loopback PCM. With the above ALSA configuration we can achieve this simply with:
bluealsa-aplay --profile-a2dp --pcm=bluealsa-aplay:PROFILE=a2dp 00:00:00:00:00:00
Similarly, for HFP/HSP devices we can use:
bluealsa-aplay --profile-sco --pcm=bluealsa-aplay:PROFILE=sco 00:00:00:00:00:00
The A2DP and SCO streams are available to applications as devices bluetooth_a2dp_capture
and bluetooth_sco_capture
respectively. Each can be captured by multiple applications simultaneously. So for example, it is possible to record using arecord
with:
arecord -D bluetooth_a2dp_capture -f dat recording.wav
while at the same time playing the stream to the default playback device with:
alsaloop -C bluetooth_a2dp_capture -P default -t 100000
-
To make this configuration available to all users, install the above config file into the alsa configuration directory.
For alsa versions 1.1.7 and later, this file should be saved as:
/etc/alsa/conf.d/22-bluealsa-aplay.conf
and for alsa versions 1.1.6 and earlier:
/usr/share/alsa/alsa.conf.d/22-bluealsa-aplay.conf
-
If using this method in combination with the "bmix" playback method described in Using bluealsa with dmix then you must reserve the Loopback substream(s) for use by bluealsa-aplay. In the file
/etc/default/bmix
include the lineBMIX_LOOPBACK=2
This will ensure that substreams 0 and 1 are reserved for use by bluealsa-aplay.