Ceci est une mise à jour se rapportant à l’hébergement d’une radio sur votre propre serveur.
Logiciels utilisés
Après avoir fait des avant-arrière, voici ce avec quoi j’héberge ma radio. Ce ne fut pas sans mal, mais après plus d’un an en fonctionnel, il est content le monsieur!
- mpd est toujours utilisé pour créer le flux audio, et contrôlé avec mpc, qui est une commande qui va avec;
- ncmpc est l’éditeur de playlists que j’utilise en console. Il peut être remplacé par l’exécutable standalone ympc, qui crée une interface Web, mais ça me fout le bazar avec mes serveurs Web déjà tournant.
- icecast2 est finalement utilisé pour récupérer les informations genre titre, artiste, etc. qui m’intéressent; mpd permet théoriquement de le faire, mais je n’ai absolument jamais réussi à récupérer ça de manière fiable.
- nginx me permet de créer mon propre site Ouèbe, sur lequel j’ai bien entendu l’interface pour lancer/arrêter le flux audio en tant que client, mais aussi l’affichage des infos susnommées.
Configuration mpd
Voici les points-clés de la configuration de mpd dans /etc/mpd.conf :
music_directory "/media/Radio" # plusieurs sous-niveaux de dossiers, aucun problème
playlist_directory "/media/Radio" # les droits sont relou pour changer la playlist dans ncmpc, je dois passer par du 777 puis retour à 644
metadata_to_use "artist,album,title,name" # pour l'affichage sur la page web, requis!
follow_outside_symlinks "yes" # j'ai trouvé ça pratique mais c'est vous qui voyez
follow_inside_symlinks "yes" # idem
# Ci-après le truc le plus important : la description de la source audio
audio_output {
type "shout"
encoder "mp3"
name "Petit nom comme vous voulez"
host "localhost"
port "60099"
mount "/monstream" # SUPER important pour pointer vers le stream dans Icecast2
password "MonSuperMotDePasse" # Nécessaire pour Icecast2
bitrate "192"
format "44100:16:2"
protocol "icecast2"
user "source"
genre "VGM" #Tout sauf obligatoire
}
Le reste est par défaut.
Configuration Icecast2 (source)
Attention! La configuration d’Icecast que j’utilise est spécifique : comme je ne veux pas que ma radio tape directement sur le serveur qui est dans mon salon, j’utilise un VPS qui faire relais, c’est-à-dire que la radio tourne bien sur mon serveur, mais ne reçoit qu’un seul “client”, mon VPS.
Le VPS va ensuite servir de relais et encaisser le trafic issu d’Internet (nombre de clients mais aussi attaques potentielles).
Ceci nécessite d’avoir 2 Icecast 2 : un en source sur mon serveur, et un second en relais sur mon VPS.
Voyons donc la configuration Icecast2 “source”, sur mon serveur.
Points-clés de la configuration de Icecast2 dans /etc/icecast2/icecast.xml :
<authentication>
<source-password>IcecastSourceModpass</source-password>
<relay-password>IcecastRelayModpass</relay-password>
<admin-user>admin</admin-user>
<admin-password>IcecastAdminModpass</admin-password>
</authentication>
<hostname>domainesource.machin.com</hostname>
<listen-socket>
<port>60099</port>
</listen-socket>
<http-header>
<header name="Access-Control-Allow-Origin" value="*" />
<http-header>
Note : le hostname peut être [IP publique de votre serveur] OU [domaine genre domaine.machin.com] OU [localhost si vous tournez en local 100%].
Moi, comme je suis sur le Web, j’utilise un domaine tiers, qui ne sert QUE au VPS (qui est la “vraie” interface web) à accéder à la source et aux fichiers de statut (musique en cours).
Configuration Icecast2 (relais)
Maintenant, pour la partie relais (qui est sur le VPS), toujours dans /etc/icecast2/icecast.xml :
<authentication>
<source-password>IcecastSourceModpass</source-password>
<relay-password>IcecastRelayModpass</relay-password>
<admin-user>admin</admin-user>
<admin-password>IcecastAdminModpass</admin-password>
</authentication>
<hostname>radioweb.machin.com</hostname>
<listen-socket>
<port>60000</port>
</listen-socket>
<http-header>
<header name="Access-Control-Allow-Origin" value="*" />
<http-header>
<relay>
<server>[adresse IP serveur]</server>
<port>60099>/port>
<mount>/monstream</mount>
<localmount>/monstream</mount>
<on-demand>0</on-demand>
<relay-shoutcast-metadata>0</relay-shoutcast-metadata>
</relay>
Notes :
– source-password et relay-password sont évidemment les mêmes entre les deux instances d’Icecast2 (serveur et VPS).
– hostname devient celui du VPS, donc le “vrai domaine” via lequel votre radio sera accessible depuis le Web. D’ailleurs, il est aussi tout à fait possible de n’utiliser QUE des IP au lieu de domaines, si vous le souhaitez!
– port passe à 60000, question de choix personnel.
– dans la partie Relay :
> le server ne prend pas d’adresse HTTPS. Comme je refuse de débrayer le HTTPS pour mon domaine de serveur source, je rentre l’IP de chez moi.
> le port est celui que nous avons déclaré dans la partie source, donc 60099.
> mount est le chemin indiqué dans mpd.conf sur le serveur (ici monstream). Vous pouvez transformer ça entre mount et local-mount (genre /monstream en mount et /monputaindestream sur local-mount).
> relay-shoutcast-metadata semble être un levier intéressant pour plus tard, vu comment je m’emmerde pour la suite, vous verrez. Mais pour le moment, on reste sur un truc qui marche avant de partir sur de l’expérimental.
Fichiers statut et routines : source
Bien! Maintenant que nos source et relais sont configurés, nous allons passer à la configuration des prérequis pour que ça fonctionne. Sur notre serveur source, celui qui fait tourner MPD, nous allons donc avoir besoin de deux fichiers à récupérer par le VPS : status-json.xsl, et radio-track.json qui contient les informations courantes de la piste en cours.
status-json.xsl est géré automatiquement par Icecast2 et est généré selon la config de ce dernier dans /usr/share/icecast2/web/status-json.xsl . On se garde ça sous le coude pour plus tard.
radio-track.json : script de création
radio-track.json est issu d’un script maison qui va venir récupérer les informations ID3 (artiste, album…) et les mettre dans un fichier json, lequel sera affiché sur notre interface “officielle” de radio.
Pour la suite, nous partirons donc du principe que le script est /home/user/scripts/triggerradioupdate.sh, et dispose des droits +x.
Son contenu est le suivant :
#!/bin/bash
touch /run/radio/radio-track.json
while mpc idle player; do
OUT="/run/radio/radio-track.json"
artist=$(mpc -f %artist% current)
title=$(mpc -f %title% current)
album=$(mpc -f %album% current)
# Fallbacks
artist=${artist:-Inconnu}
title=${title:-Inconnu}
album=${album:-Inconnu}
cat > "$OUT" <<EOF
{
"artist": "$(printf '%s' "$artist" | sed 's/"/\\"/g')",
"title": "$(printf '%s' "$title" | sed 's/"/\\"/g')",
"album": "$(printf '%s' "$album" | sed 's/"/\\"/g')"
}
EOF
done
Notes :
– le fichier radio-track.json est créé dans /run/radio/, qui est un système de fichier volatile, en RAM, et disparaît donc à chaque reboot. Ceci permet à chaque mise à jour de ne pas “user” le support genre carte SD ou SSD.
– selon ce que vous voulez afficher niveau tags ID3, il faudra les changer dans la configuration de MPD, dans metadata_to_use.
– le script attend que mpc renvoie un état “idle” (entre deux chansons) pour appeler le script de mise à jour des infos liées à la piste courante. C’est la seule manière légère et un peu propre que j’ai trouvé…
radio-track.json : service d’appel
J’ai essayé sans passer par un service, genre bash script.sh & pour lancer en background, mais cela finit immanquablement par quitter le script. De dépit, ChatGPT m’a conseillé de passer par un service d’appel et de surveillance, qui relancera dès qu’il en aura besoin.
Il est recommandé d’ajouter votre utilisateur au groupe media, dont beaucoup d’applications se servent.
Notez qu’il est possible de passer par une tâche cron, mais l’unité est la minute. A vous de voir.
sudo usermod -aG media $USER
sudo nano /etc/systemd/system/radio-update.service
Contenu de radio-update.service :
[Unit]
Description=Radio Track Updater
After=network.target mpd.service
Requires=mpd.service
[Service]
ExecStart=/home/user/scripts/triggerradioupdate.sh
Restart=always
RestartSec=2
User=user
Group=media
RuntimeDirectory=radio
RuntimeDirectoryMode=0775
[Install]
WantedBy=multi-user.target
N’oubliez pas de mettre à jour ExecStart et User!
Assurez-vous que MPD fonctionne et tourne (via la simple commande mpc qui vous affichera le titre de la chanson en cours), sans quoi notre service ne démarrera pas.
Puis :
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable radio-update
sudo service radio-update start
Ensuite, vérifiez que ça fonctionne via :
cat /run/radio/radio-track.json
Normalement, vous devriez avoir un fichier vide : tout va bien! Il faudra patienter jusqu’au passage au prochain morceau pour que les informations soient écrites.
Si cependant vous avez un “No such file or directory”, c’est que le service ne s’est pas lancé. Vous pouvez voir pourquoi avec sudo service radio-update status.
Configuration Nginx : source
Maintenant que nos fichiers originaux sont préparés, nous allons donc passer à leur mise à disposition.
Notes :
– Pour l’exemple, j’utilise comme domaine qui pointe directement sur mon serveur “maison” le domaine domainesource.machin.com .
– Il est entendu que vous avez généré pour cela les certificats SSL comme des grands via certbot et qu’ils sont placés dans /etc/letsencrypt/live/ (le truc par défaut).
– Toujours pour l’exemple, la racine du site Web est /website/ (à la racine du système de fichiers).
– Les permissions pour les fichiers dans /website/ sont mises à 755 root:root (mais vous pouvez probablement mettre www-data:www-data en owner, moi, c’est en root et ça marche).
– Les ports 443 et 80 sont ouverts sur votre box, et le routage NAT est fait vers votre serveur maison.
– Vous savez activer/désactiver un site Web dans Nginx.
Fichier de configuration Nginx :
Globalement, dans /website/, vous n’aurez besoin que d’un seul fichier que nous allons créer par lien symbolique :
cd /website/
sudo ln -s /run/radio/radio-track.json ./radio-track.json
Vous pouvez créer un fichier index.php, histoire de dire, mais gardez en tête que dans mon exemple, ce serveur “source” n’est pas destiné à servir d’interface, juste de source de données.
Moi, par exemple, j’ai juste mis ça dans mon index.php :
<html><body>Present</body></html>
Histoire de savoir si ça marchait bien.
Mais vous me direz : attends, mais il devient quoi de radio-track.json et status-json.xsl?
Grâce au fichier de config nginx, nous avons fait en sorte qu’en tapant l’adresse https://domainesource.machin.com/status-json.xsl , on atterrisse sur le status-json produit par Icecast2 (grâce à un proxy-pass, dans nginx, donc), et que https://domainesource.machin.com/radio-track.json tombe sur le lien symbolique dans /website/radio-track.json, lui-même pointant sur /run/radio/radio-track.json.
Bien sûr, on a aussi fait en sorte de faire un proxy-pass sur https://domainesource.machin.com/monstream vers localhost:60099/monstream, soit l’adresse que nous avons défini pour notre stream dans MPD et Icecast2 🙂
Configuration Nginx : VPS (relais)
Allez, étape suivante : configurer notre frontend, notre véritable interface, celle qui est sur le VPS.
Notes :
– Notre site Web, le vrai, celui qui va servir l’interface officielle de notre radio, est toujours dans /website (mais sur le VPS, t’as pigé Roger)
– Le domaine bidon utilisé est ici radioweb.machin.com, en cohérence avec la config Icecast plus haut.
Les certificats SSL sont créés, et tout ça.
Site Web
Pour ce qui est de notre interface, je vais vous fournir celui qui me sert actuellement, ça sera plus simple.
Dans un premier temps, nous avons donc un répertoire /website/, lequel va contenir les fichiers suivants :
radio-info.php
<?php
header('Content-Type: application/json');
$trackfile = 'https://domainesource.machin.com/radio-track.json';
$statusfile = 'https://domainesource.machin.com/status-json.xsl';
$artist = $title = $album = 'Inconnu';
if ($json = @file_get_contents($trackfile))
{
$track_data = json_decode($json, true);
if (is_array($track_data))
{
$artist = $track_data['artist'] ?? 'Inconnu';
$title = $track_data['title'] ?? 'Inconnu';
$album = $track_data['album'] ?? 'Inconnu';
}
}
$listeners = 0;
if ($json = @file_get_contents($statusfile))
{
$data = json_decode($json, true);
if (isset($data['icestats']['source']))
{
$sources = $data['icestats']['source']
if (isset($sources[0]))
{
foreach ($sources as $src)
{
if (isset($src['listenurl']) && str_ends_with($src['listenurl'], '/monstream'))
{
$listeners = $src['listeners'] ?? 0;
break;
}
}
}
elseif (isset($sources['listenurl']) && str_ends_with($sources['listenurl'], '/monstream'))
{
$listeners = $sources['listeners'] ?? 0;
}
}
echo json_encode([
'artist' => $artist,
'title' => $title,
'album' => $album,
'listeners' => $listeners
]);
?>
(Désolé pour la mise en page, c’est vraiment daubé WordPress pour le code).
Notes : pensez bien à changer le /monstream dans l’URL (en gras dans le code) ainsi que les adresses des json en début de script.
index.php
Vu le côté pénible de la mise en page de WordPress, je vais donc vous inviter à tout simplement aller faire un clic droit -> voir le code source sur ma radio, ça sera plus simple, sur https://radio.nibelheim.fr .
Copiez donc ce code dans votre propre index.php, adaptez l’URL de votre stream, mettez-le dans /websites sur votre VPS, mettez à jour l’image de background, et vous voilà tout prêts pour votre propre radio!