Enregistrer un multiplex de radio DAB+
Expérimentons la captation de stations de radio DAB+, voire directement d'un multiplex complet et regardons les outils logiciels et matériels nécessaires.
Le matériel
- Un ordinateur sous linux (ex: Raspberry Pi)
- Une antenne accordée sur les fréquences du DAB+ (VHF bande III, entre 180 MHz et 230 MHz)
- Un récepteur SDR de type clé RTL-SDR.
Un multiplex DAB+ faisant 1.536 MHz de bande passante, le récepteur et le CPU de l'ordinateur doivent supporter au moins cette largeur de bande.
Au milieu, une antenne adaptée à la réception DAB+
Une clé RTL-SDR pour faire de la radio logicielle, reliée à l'antenne DAB+
Les logiciels
L'OS est un Debian 11 (ou Raspberry Pi OS) fraichement installé.
Après avoir réglé un soucis de droit avec udev
, nous nous servirons des outils libres suivants que nous téléchargerons et compilerons :
- dabtools : un enregistreur de flux brut ETI du multiplex
- dablin : un lecteur de fichier ETI et démultiplexeur / extracteur d'audio
- welle-cli : issu du projet welle-io, permet également l'enregistrement d'un multiplex
Résolution d'un problème de droit
Sous Debian/Ubuntu
, pour utiliser notre périphérique rtl-sdr, il faut accorder certains droits à udev
sous peine d'avoir à l'usage le message d'erreur suivant :
1Please fix the device permissions, e.g. by installing the udev rules file rtl-sdr.rules
Récupérons l'identifiant constructeur de la clé RTL-SDR :
1$ lsusb
2Bus 003 Device 002: ID 0bda:2838 Realtek Semiconductor Corp. RTL2838 DVB-T
Note: sous CentOS
, lsusb
est installable via yum install usbutils
En root, créer un fichier /etc/udev/rules.d/20.rtlsdr.rules
avec le contenu suivant :
1SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", GROUP="adm", MODE="0666", SYMLINK+="rtl_sdr"
Note: adapter le nom du GROUP: adm
, admindl
...
Relancer udev (en root
)
Sous Debian :
1systemctl restart udev
Sous CentOS :
1udevadm control --reload-rules && udevadm trigger
Débrancher/rebrancher la clé usb
un lien /dev/rtl_sdr
doit maintenant être présent et le périphérique est désormais accessible à tous les users du groupe adm
Source: https://www.instructables.com/rtl-sdr-on-Ubuntu/
dabtools
Nous allons utiliser la commande dab2eti
issue du projet dabtools
Les dépendances requises sont installables en root
via la commande suivante :
1apt install git cmake librtlsdr-dev libfftw3-dev
Compilation
1git clone https://github.com/Opendigitalradio/dabtools
2cd dabtools
3mkdir build
4cd build
5cmake ..
6make
7sudo make install
Pour enregistrer le multiplex "towerCast" du Canal 9D (208.064 MHz) avec un gain de +29.7dB
1$ dab2eti 208064000 297 > 9D-towercast.eti
2Found 1 device(s):
3 0: Realtek, RTL2838UHIDIR, SN: 00000001
4
5Using device 0: Generic RTL2832U OEM
6Detached kernel driver
7Found Rafael Micro R820T tuner
8Supported gain values (29): 0.0 0.9 1.4 2.7 3.7 7.7 8.7 12.5 14.4 15.7 16.6 19.7 20.7 22.9 25.4 28.0 29.7 32.8 33.8 36.4 37.2 38.6 40.2 42.1 43.4 43.9 44.5 48.0 49.6
9[R82XX] PLL not locked!
10Tuned to 208064000 Hz.
11Tuner gain set to 29.70 dB.
12Waiting for sync...
13Allocating 32 zero-copy buffers
14startup_delay=1
15Locked
16ENSEMBLE_INFO: EId=0xf200, CIFCount = 12 228
17SubChId= 1, slForm=1, StartAddress=144, size= 72, bitrate= 96, ASCTy=0x3f
18SubChId= 2, slForm=1, StartAddress=216, size= 72, bitrate= 96, ASCTy=0x3f
19SubChId= 3, slForm=1, StartAddress=288, size= 72, bitrate= 96, ASCTy=0x3f
20SubChId= 4, slForm=1, StartAddress= 72, size= 72, bitrate= 96, ASCTy=0x3f
21SubChId= 6, slForm=1, StartAddress=360, size= 36, bitrate= 48, ASCTy=0x3f
22SubChId= 8, slForm=1, StartAddress= 0, size= 72, bitrate= 96, ASCTy=0x3f
(Ctrl+C pour arrêter)
Note: au 18/06/2022 je n'arrive plus à accrocher la synchronisation d'un mux ...
dablin
Également issu du projet Open Digital Radio, dablin
est un outil permettant de lire un fichier .eti
qui est un format conteneur de l'ensemble des données brutes (audio+metadata) d'un multiplex DAB+.
Compilation
1sudo apt install libsdl2-dev libmpg123-dev libfaad-dev
2git clone https://github.com/Opendigitalradio/dablin
3cd dablin
4mkdir build
5cd build
6cmake ..
7make
8sudo make install
Récupération de la liste des services à l'intérieur du multiplex
1$ dablin 9D-towercast.eti 2>&1 | grep "programme service label"
2FICDecoder: SId 0xF204: programme service label 'FIP' ('FIP')
3FICDecoder: SId 0xF208: programme service label 'Mouv'' ('Mouv'')
4FICDecoder: SId 0xF201: programme service label 'France Inter' ('Inter')
5FICDecoder: SId 0xF202: programme service label 'France Culture' ('Culture')
6FICDecoder: SId 0xF203: programme service label 'France Musique' ('Musique')
7FICDecoder: SId 0xF206: programme service label 'France Info' ('Info')
On veut par exemple extraire France Inter (serviceId 0xF204
), en gardant le codec audio d'origine sans réencodage (-u
) :
1dablin 9D-towercast.eti -u -s 0xf204 > france-inter.aac
Vérifions le format de fichier généré
1$ file france-inter.aac
20xf204.aac: MPEG-4 LOAS
On peut aussi décoder le flux audio pour avoir du pcm avec -p
:
1dablin 9D-towercast.eti -p -s 0xf204 > france-inter.pcm
Vérifions également le format de fichier généré
1$ file france-inter.pcm
2data
Attention, c'est un flux pcm
brut sans entête. welle-cli
nous a quand même donné quelques indications sur le format :
1PCMOutput: format set; samplerate: 48000, channels: 2, output: 32bit float
ajoutons les bonnes entêtes pour générer un .wav
valide :
1ffmpeg -f f32le -ar 48k -ac 2 -i france-inter.pcm france-inter.wav
Et voilà
welle-cli
Autre méthode d'enregistrement d'un multiplex DAB+ complet avec cette fois la commande welle-cli
issu du projet welle-io
.
Compilation sous Debian
:
1sudo apt install git cmake libfftw3-dev libmp3lame-dev libmpg123-dev librtlsdr-dev libfaad-dev libasound2-dev
2cd $HOME
3mkdir src && cd src
4git clone https://github.com/AlbrechtL/welle.io.git && cd welle.io
5mkdir build && cd build
6cmake .. -DRTLSDR=1 -DBUILD_WELLE_IO=OFF -DBUILD_WELLE_CLI=ON
7make
8sudo make install
Compilation sous CentOS7
:
cmake
non installé par défaut et la version proposée de base est la v2.x. welle-cli
nécessiste une v3 mini. cmake3
est disponible dans les dépôt epel
qu'il faut activer :
1yum install epel-release yum-utils
2yum install cmake3
3ln -s /usr/bin/cmake3 /usr/bin/cmake
Dépendances :
1yum install git gcc-c++ fftw-devel lame-devel mpg123-devel rtl-sdr-devel
faad2
est distribué via le dépot rpm fusion, activons le :
1yum install https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-7.noarch.rpm
2yum install faad2-devel
zut, à la compilation: unsupported gcc compiler 4.8.5 pour installer en parallèle une version + récente de gcc
1yum install centos-release-scl
2yum install devtoolset-7
3scl enable devtoolset-7 bash
4gcc --version
5gcc (GCC) 7.3.1
La compilation sous CentOS
peut alors se dérouler normalement.
Compilation sous Rock Linux 8
:
1yum install gcc-c++ # v 8.5.0 OK
2yum install cmake # v 3.20 OK
Activation des powertools pour ces dépendances :
1dnf config-manager --set-enabled powertools
2yum install git gcc-c++ fftw-devel lame-devel mpg123-devel rtl-sdr-devel
Activation de rpm-fusion-free pour cette dépendance :
1yum install rpm-fusion-free
2yum install faad2-devel
Exemple d'enregistrement du multiplex 11B (dans le répertoire courant) :
1$ welle-cli -c 11B -D
2$ ls
3-rw-r--r-- 1 pi pi 2310188 sept. 20 14:26 GENERATIONS.wav
4-rw-r--r-- 1 pi pi 2318380 sept. 20 14:26 'CHANTE FRANCE.wav'
5-rw-r--r-- 1 pi pi 2310188 sept. 20 14:26 FG.wav
6-rw-r--r-- 1 pi pi 2310188 sept. 20 14:26 EVASION.wav
7-rw-r--r-- 1 pi pi 2310188 sept. 20 14:26 'TSF JAZZ.wav'
8-rw-r--r-- 1 pi pi 2310188 sept. 20 14:26 Melody.wav
9-rw-r--r-- 1 pi pi 2318380 sept. 20 14:26 'BLEU PARIS.wav'
10-rw-r--r-- 1 pi pi 2318380 sept. 20 14:26 'SUD RADIO.wav'
11-rw-r--r-- 1 pi pi 2310188 sept. 20 14:26 'OUI FM.wav'
12-rw-r--r-- 1 pi pi 2310188 sept. 20 14:26 NOVA.wav
13-rw-r--r-- 1 pi pi 2310188 sept. 20 14:26 'J A Z Z Radio.wav'
14-rw-r--r-- 1 pi pi 2310188 sept. 20 14:26 VOLTAGE.wav
15-rw-r--r-- 1 pi pi 2310188 sept. 20 14:26 'Radio Notre Dame.wav'
Examinons le format généré :
1$ file BLEU\ PARIS.wav
2BLEU PARIS.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, stereo 48000 Hz
Quand on le lit avec mpv
un warning se produit
1[ffmpeg/demuxer] wav: Estimating duration from bitrate, this may be inaccurate
les compteurs dans les entêtes ne sont pas bons. On peut réparer ça avec ffmpeg
en le réencapsulant
1ffmpeg -i TEST2\ DAB+\ TFL.wav -c copy TEST2\ DAB+\ TFL\ fix.wav
Le fichier se lit mais ffmpeg
a ajouté un subchunk LIST-INFO
non essentiel. On peut demander à ce que ne soit pas ajouté avec l'option -bitexact
:
1ffmpeg -i TEST2\ DAB+\ TFL.wav -c copy -bitexact TEST2\ DAB+\ TFL\ fix2.wav
On aura alors un fichier .wav
valide, et de la même taille que le fichier avant réparation.
Note: avec un Raspberry Pi 2, je constate des drops audio. Peut être un cpu pas assez puissant pour décoder tout un multiplex ?
Patches sauvages pour welle-cli
Un fork est disponible ici https://github.com/aerogus/welle.io.git et va encore plus loin que les mini patchs suivants :
welle-cli
enregistre localement les flux en basant le nommage des fichiers sur le serviceLabel
. Si on veut plutôt se baser sur le serviceId
voici un patch (qui sette aussi le répertoire de stockage) :
1diff --git a/src/welle-cli/welle-cli.cpp b/src/welle-cli/welle-cli.cpp
2index dcd1019..6175973 100644
3--- a/src/welle-cli/welle-cli.cpp
4+++ b/src/welle-cli/welle-cli.cpp
5@@ -626,7 +626,15 @@ int main(int argc, char **argv)
6 }
7 cerr << endl;
8
9- string dumpFilePrefix = s.serviceLabel.utf8_label();
10+ // origine : nommage avec serviceLabel
11+ //string dumpFilePrefix = s.serviceLabel.utf8_label();
12+
13+ // hack: nommage avec le sid ex: 0xf00d dans un répertoire dédié
14+ std::stringstream stream;
15+ stream << "0x" << std::setfill('0') << std::hex << s.serviceId;
16+ string dumpFilePrefix = "/home/pi/rec/" + stream.str();
17+ //
18+
19 dumpFilePrefix.erase(std::find_if(dumpFilePrefix.rbegin(), dumpFilePrefix.rend(),
20 [](int ch) { return !std::isspace(ch); }).base(), dumpFilePrefix.end());
Si l'on choisit d'utiliser welle-cli
via son serveur web, il faut savoir que le flux DAB+ natif (AAC), sera décodé en linéaire puis réencodé en mp3. Pas l'idéal, alors autant setter l'encodeur pour perdre un minimum de qualité.
1diff --git a/src/welle-cli/webprogrammehandler.cpp b/src/welle-cli/webprogrammehandler.cpp
2index 6f4a977..b67648b 100644
3--- a/src/welle-cli/webprogrammehandler.cpp
4+++ b/src/welle-cli/webprogrammehandler.cpp
5@@ -226,8 +226,14 @@ void WebProgrammeHandler::onNewAudio(std::vector<int16_t>&& audioData,
6 if (not lame_initialised) {
7 lame_set_in_samplerate(lame.lame, rate);
8 lame_set_num_channels(lame.lame, channels);
9- lame_set_VBR(lame.lame, vbr_default);
10- lame_set_VBR_q(lame.lame, 2);
11+
12+ lame_set_brate(lame.lame, 320);
13+ lame_set_mode(lame.lame, STEREO);
14+ lame_set_quality(lame.lame, 2);
15+
16+ //lame_set_VBR(lame.lame, vbr_default);
17+ //lame_set_VBR_q(lame.lame, 2);
18+
19 lame_init_params(lame.lame);
20 lame_initialised = true;
21 }
Bilan
Ces méthodes sont encore un peu expérimentales. J'arrive bien à récupérer le flux audio brut sans réencodage mais j'aurai aimé un outil d'extraction direct en aac de l'ensemble des flux du multiplex (ça se scripte), voire de faire ça en temps réel. Deplus il serait bon d'avoir des découpes horaires propres "avec raccordement" et sans overlap. Bref encore beaucoup de choses à découvrir dans le domaine...