J’envoie régulièrement l’audio de mon ordinateur portable Thinkpad vers ma barre de son en bluetooth. Alors que celle-ci dispose de toutes les fonctionnalités audio surround, dolby, DTX, 5.1, etc, ça me désole d’envoyer simplement en stéréo alors que je pourrais faire mieux.
D’où mes recherches pour pouvoir envoyer un son plus qualitatif. Au fil de mes recherches je découvre qu’il existe principalement 2 technologies de diffusion audio bluetooth:
- L’A2DP (Advanced Audio Distribution Profile) est celle qu’on retrouve sur tous les périphériques bluetooth actuels. Elle permet une sortie audio stéréo (qu’on retrouve sous le terme sink). Elle utilise en natif le codec audio SBC qui fournit une qualité audio juste acceptable (références ici et là). Aussi d’autres codecs ont fait leur apparition, SBC XQ qui est une version améliorée de SBC, mais également LDAC, Aptx, AAC ou LC3. Cette page, celle là et cette dernière page expliquent très bien les subtilités qui peuvent exister entre eux. Cette technologie est associée à AVRCP (Audio Video Remote Control Profile) qui permet de gérer les commandes.
- LE Audio associé au Bluetooth Low Energy (BLE) est un mode basse consommation qui utilise le codec LC3 qui à terme devrait équiper tous les périphériques bluetooth. Ce mode permettra la diffusion vers plusieurs périphériques bluetooth et de pouvoir utiliser la diffusion multicanal 5.1 contrairement aux autres codecs précédemment cités qui sont limités au mono et au stéréo.
Or en connectant ma barre de son « Abri de jardin » (je sais, c’est bizarre…) avec blueman, je me rends compte que je n’ai accès qu’au codec standard SBC et à sa version améliorée SBC XQ. Pas moyen d’avoir un codec plus qualitatif.
Ni une, ni deux, je me lance dans l’installation du serveur audio pipewire car pulseaudio installé de base sur ma Mageia 9 ne gère que l’A2DP et ne gère pas le LE Audio.
Je bascule sous pipewire fourni sur mon système avec l’outil pa-switcher et je constate aucune évolution avec blueman et j’ai toujours les mêmes codecs, je choisis d’installer la dernière version de pipewire à partir des sources. Avant cela, j’ai installé les codecs supplémentaires. Tout d’abord LC3 qu’on récupérera ici. On tape ensuite les commandes suivantes:
tar xvfz liblc3-1.1.1.tar.gz
cd liblc3-1.1.1
meson setup build
cd build
et en tant que root
meson install
On passe à Aptx qu’on récupère sur ce site. On tape ensuite les commandes
tar xvfz libfreeaptx-0.1.1.tar.gz
libfreeaptx-0.1.1
make
Et en tant que root
make install
J’ai installé par ailleurs les packages suivants bluez-devel, sbc, lib64sbc-devel, lib64mysofa-devel et lib64ldac-devel. Pour pipewire, on le récupère sur ce site. On tape les commandes :
tar xvfj pipewire-1.2.6.tar.bz2
pipewire-1.2.6
./autogen.sh --prefix=/usr/local
Et voilà le résultat
pipewire 1.2.6
systemd conf data : YES
libsystemd : YES
logind : YES
libselinux : NO
intl support : YES
pipewire-alsa : YES
OpenSSL (for raop-sink) : YES
lilv (for lv2 plugins) : NO
ffado : NO
RLIMITs : with limits.d file affecting matching PAM users
PAM defaults : without limits.d file affecting all PAM users (not needed with modern systemd or kernel)
Documentation : NO
Man pages : NO
Misc dependencies
dbus (Bluetooth, rt, portal, pw-reserve): YES
SDL2 (video examples) : YES
opus (Bluetooth, RTP) : YES
readline (for pw-cli) : YES
X11 (x11-bell) : YES
libcanberra (x11-bell) : NO
GLib-2.0 (Flatpak support) : YES
GIO (GSettings) : YES
WebRTC Echo Canceling < 1.0 : NO
GLib-2.0 (Snap support) : YES
Gio-2.0 (Snap support) : YES
Apparmor (Snap support) : NO
Snapd-glib (Snap support) : NO
Vulkan : NO
pw-cat/pw-play/pw-dump/filter-chain
sndfile : YES
filter-chain
libmysofa : YES
Streaming between daemons
libpulse : YES
Avahi DNS-SD (Zeroconf) : NO
Opus with custom modes for NetJack2 : YES
ROC : NO
Backend
libusb (Bluetooth quirks) : YES
gstreamer-device-provider : YES
gstreamer DMA_DRM support : NO
JACK2 : NO
ALSA : YES
Bluetooth audio : YES
libcamera : NO
Compress-Offload : YES
Udev : YES
V4L2 kernel header : YES
V4L2 enabled : YES
GStreamer modules
glib-2.0 : YES
gobject-2.0 : YES
gmodule-2.0 : YES
gio-2.0 : YES
gio-unix-2.0 : YES
gstreamer-1.0 : YES
gstreamer-base-1.0 : YES
gstreamer-video-1.0 : YES
gstreamer-audio-1.0 : YES
gstreamer-allocators-1.0 : YES
Bluetooth audio codecs
SBC : YES
LDAC : YES
LDAC ABR : YES
aptX : YES
AAC : YES
LC3plus : NO
Opus : YES
LC3 : YES
Bluetooth backends
ModemManager : NO
Optional programs
find (for header testing) : YES
valgrind (test setup) : YES
Session managers
Build media-session : NO
Build wireplumber : YES
Default session-manager : wireplumber
pw-cat/pw-play/pw-dump tool
Build pw-cat tool : YES
Build pw-cat with FFmpeg integration : NO
Optional Modules
jack-tunnel : NO
ffado-driver : NO
rt : with RTKit
portal : YES
pulse-tunnel : YES
zeroconf-discover : NO
raop-discover (needs Avahi) : NO
snapcast-discover (needs Avahi) : NO
raop-sink (requires OpenSSL) : YES
roc-sink : NO
roc-source : NO
x11-bell : NO
avb : YES
Functional test programs
openal-info : NO
pactl : YES
Subprojects
lua : YES (from wireplumber)
wireplumber : YES
User defined options
prefix : /usr/local
J’avoue que je n’ai pas trouvé les sources de LC3plus, mais peu importe avec les autres codecs c’est déjà largement suffisant pour continuer. On tape ensuite make puis en tant que root make install. L’installation se fait sous /usr/local, ce qui évite d’écraser l’installation système. On stoppe déjà les processus pipewire système en tapant :
systemctl --user stop pipewire
systemctl --user stop pipewire.socket
systemctl --user stop pipewire-pulse
systemctl --user stop pipewire-pulse.socket
Et on lance maintenant les commandes ci-dessous, chacune dans un terminal distinct :
/usr/local/bin/pipewire
/usr/local/bin/pipewire-pulse
/usr/local/bin/wireplumber -c /usr/local/share/wireplumber/wireplumber.conf
Et voilà le résultat pour la dernière commande
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSource/ldac
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSink/aptx_hd
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSource/aptx_hd
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSink/aptx
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSource/aptx
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSink/aac
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSource/aac
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSink/opus_g
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSource/opus_g
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSink/sbc
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSource/sbc
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSource/aptx_ll_1
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSource/aptx_ll_0
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSource/aptx_ll_duplex_1
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSource/aptx_ll_duplex_0
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSource/faststream
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSource/faststream_duplex
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSink/opus_05
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSource/opus_05
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSink/opus_05_duplex
déc. 22 12:12:57 cilaos.kervao.fr bluetoothd[857]: Endpoint registered: sender=:1.197 path=/MediaEndpoint/A2DPSource/opus_05_duplex
C’est tout bon en ce qui concerne les nouveaux codecs. Et là je constate avec désappointement que blueman ne m’offre pas mieux, je recompile donc bluez qui fournit le daemon bluetoothd qu’on trouvera ici. Je l’installe en tapant les commandes:
tar xvf bluez-5.66.tar.xz
cd bluez-5.66/
./configure --enable-experimental
make
puis en tant que root make install. On modifie le fichier de configuration /etc/bluetooth/main.conf pour que LE Audio soit bien en compte, en modifiant les lignes suivantes :
# Enables D-Bus experimental interfaces
# Possible values: true or false
Experimental = true
# Enables kernel experimental features, alternatively a list of UUIDs
# can be given.
# Possible values: true,false,<UUID List>
# Possible UUIDS:
# d4992530-b9ec-469f-ab01-6c481c47da1c (BlueZ Experimental Debug)
# 671b10b5-42c0-4696-9227-eb28d1b049d6 (BlueZ Experimental Simultaneous Central and Peripheral)
# 15c0a148-c273-11ea-b3de-0242ac130004 (BlueZ Experimental LL privacy)
# 330859bc-7506-492d-9370-9a6f0614037f (BlueZ Experimental Bluetooth Quality Report)
# a6695ace-ee7f-4fb9-881a-5fac66c629af (BlueZ Experimental Offload Codecs)
6fbaf188-05e0-496a-9885-d6ddfdb4e03e (BlueZ Experimental ISO socket)
# Defaults to false.
KernelExperimental = true
Et là je me retrouve avec une installation hybride entre une installation système et local bluez et pipewire avec un mix de fichiers et les services systemd des versions locales qui ont écrasé les versions système. Au reboot du PC, c’est bien par défaut les binaires locaux qui sont lancés, pour vérifier cela il suffit de taper systemctl –user status pipewire et voilà le résultat
● pipewire.service - PipeWire Multimedia Service
Loaded: loaded (/usr/local/lib/systemd/user/pipewire.service; enabled; preset: disabled)
Active: active (running) since Sun 2024-12-22 12:20:23 CET; 1h 23min ago
TriggeredBy: ● pipewire.socket
Main PID: 6430 (pipewire)
Tasks: 3 (limit: 9205)
Memory: 9.9M
CPU: 6.371s
CGroup: /user.slice/user-5001.slice/user@5001.service/session.slice/pipewire.service
└─6430 /usr/local/bin/pipewire
déc. 22 12:20:23 cilaos.kervao.fr systemd[6414]: Started pipewire.service.
Et voilà ce que donne systemctl –user status wireplumber
● wireplumber.service - Multimedia Service Session Manager
Loaded: loaded (/usr/local/lib/systemd/user/wireplumber.service; enabled; preset: disabled)
Active: active (running) since Sun 2024-12-22 12:20:23 CET; 1h 24min ago
Main PID: 6431 (wireplumber)
Tasks: 6 (limit: 9205)
Memory: 7.1M
CPU: 38.317s
CGroup: /user.slice/user-5001.slice/user@5001.service/session.slice/wireplumber.service
└─6431 /usr/local/bin/wireplumber -c /usr/local/share/wireplumber/wireplumber.conf
déc. 22 12:20:23 cilaos.kervao.fr systemd[6414]: Started wireplumber.service.
déc. 22 12:20:23 cilaos.kervao.fr wireplumber[6431]: wp-internal-comp-loader: Loading profile 'main'
déc. 22 12:20:23 cilaos.kervao.fr wireplumber[6431]: wp-device: SPA handle 'api.libcamera.enum.manager' could not be loaded; is it installed?
déc. 22 12:20:23 cilaos.kervao.fr wireplumber[6431]: s-monitors-libcamera: PipeWire's libcamera SPA plugin is missing or broken. Some camera types may not be supported.
Je ne prête pas attention au dernier warning, car je n’ai pas compilé pipewire avec libcamera. Et en tant que root si je tape systemctl status bluetooth, j’obtiens :
● bluetooth.service - Bluetooth service
Loaded: loaded (/usr/lib/systemd/system/bluetooth.service; enabled; preset: enabled)
Active: active (running) since Sun 2024-12-22 12:19:47 CET; 1h 8min ago
Docs: man:bluetoothd(8)
Main PID: 850 (bluetoothd)
Status: "Running"
Tasks: 1 (limit: 9205)
Memory: 3.2M
CPU: 1.517s
CGroup: /system.slice/bluetooth.service
└─850 /usr/local/libexec/bluetooth/bluetoothd
Dans un premier temps j’avais erreur comme quoi wireplumber ne trouvait pas les codecs, j’ai dû en tant que root taper :
mv /usr/share/pipewire /usr/share/pipewire.system
ln -s /usr/local/share/pipeline /usr/share
Puis ensuite il me disait que ma barre de son était déjà connectée et pas moyen de l’utiliser, j’ai dû totalement réinitialisé la connexion avec la commande bluetoothctl avec mon périphérique qui a l’identité AC:F1:08:56:5C:DF en tapant au prompt les commandes suivantes:
untrust AC:F1:08:56:5C:DF
remove AC:F1:08:56:5C:DF
scan on
scan off
pair AC:F1:08:56:5C:DF
Au bout de toutes ces pérégrinations je connecte ma barre de son avec blueman et je constate avec dépit que j’en suis au même stade avec SBC et SBC XQ comme codecs. En dernier ressort, je compile blueman, mais ça ne change rien à l’affaire.
Je me tourne vers les spécifications de ma barre de son LG SL10YG et ce n’est qu’à ce moment là que je comprends que les modes multicanaux ne marchent que via l’interface HDMI et qu’elle se repose sur Bluetooth 4.2 qui ne prend pas en charge le LE Audio (qui arrive avec la version 5.2). J’aurais dû commencer par là !!
D’ailleurs la commande bluetoothctl info me renvoie :
UUID: Audio Sink (0000110b-0000-1000-8000-00805f9b34fb)
j’aurais du avoir quelque chose comme :
UUUUID: Published Audio Capabilities (00001850-0000-1000-8000-00805f9b34fb)
Fin du sketch qui m’aura pris quelques heures et qui m’a permis de passer à pipewire et de découvrir son fonctionnement.
Mon installation est stable dans cet état, mais pour revenir en arrière, il faut désinstaller les installations locales de pipewire et bluetooth (make uninstall dans les répertoires d’installation) et réinstaller les packages pipewire et bluetooth avec la commande urpmi –replacepkgs –force.