Je suis récemment tombé sur des projets similaires, je les liste ici :
- Sonoriser les cookies : https://vimeo.com/502348796
- Bip à chaque paquet envoyé à un tracker : https://berthub.eu/articles/posts/tracker-beeper/
But et outillage
Une fois n’est pas coutume, faisons quelque chose qui n’implique pas que du texte. Quelque chose d’un peu plus fun : de la supervision de serveurs web avec du son. Cette expérimentation n’a pas vocation à se substituer à ce que serait de la supervision plus sérieuse. Elle a pour but :
- d’être un moyen ludique de garder un œil (ou une oreille huhu) sur l’activité des sites du serveur
- de favoriser les interactions avec les utilisateur·ices
- d’être un outil pédagogique autour du web
- apprendre quelques trucs au sujet du son sur linux
J’ai décidé dans cet article d’utiliser principalement ffmpeg, souvent présenté comme le couteau suisse du son et de la vidéo. Cette décision est principalement motivée par le fait que je ne connais pas vraiment d’outil similaire et que celui-ci est fait pour être utilisé en ligne de commande, ce que j’apprécie. Cela dit ce ne veut pas pour autant dire que son utilisation est facile. ffmpeg est connu pour sa quantité d’options absolument gigantesque, ce qui est un atout en cela que la commande “sait tout faire”, mais est un gros désavantage à sa prise en main, sa découvrabilité, son utilisation lors des phases exploratoires. Ce passage du site de l’outil :
Converting video and audio has never been so easy.
$ ffmpeg -i input.mp4 output.avi
Est vrai mais une fois sortie des cas d’usages les plus simples ça part vite en cacahuète. Comme beaucoup d’outils en ligne de commande passé une certaine quantité et complexité de paramétrage.
Cet article ne sera pas un cours de ffmpeg. Pour tout avouer je n’y comprends pas grand chose et j’en suis malheureusement encore à l’étape “copier/coller des trucs de stackoverflow et me plaindre de la documentation un peu nulle sans vraiment l’avoir lu ni vouloir investir le temps nécessaire à comprendre les principes fondamentaux” de ma relation avec cet outil. Avant lui le shell, gnuplot, sed etc.
Créer du son
Avant de se demander comment lier les logs à du son, demandons nous comment en créer. Il y aurait mille façons de le faire, mille sources à utiliser et mille sons à créer. Nous allons ici utiliser ffmpeg mais tout le reste de l’article peu se dérouler avec n’importe quel fichier audio, il n’est pas nécessaire d’en générer un de zéro.
Dans ffmpeg il existe un concept de
“device”. Un device est… bah je sais
pas bien. Ils semblent
pouvoir être en entrée ou en sortie. En entrée un device semble être un élément
configurable qui permet d’accéder à une source d’audio. Par exemple si vous êtes
sur un linux, que vous utilisez
alsa et que vous avez un micro
sur votre ordinateur alors vous pouvez probablement y accéder via le device
“alsa”. Pour choisir un device il faut utiliser l’option -f
de ffmpeg.
Il se trouve qu’il existe un device nommé lavfi qui permet de générer une entrée “virtuelle”. Il semble possible de faire pleins de choses avec mais sans bien comprendre comment cela fonctionne je me suis contenté de trouver ça sur les internet :
$ ffplay -f lavfi -i "sine=frequency=440:duration=1"
ffplay ?
ffplay est un lecteur audio/vidéo qui utilise ffmpeg sous le capot. Cette commande a les mêmes arguments que si l’on avait voulu enregistrer l’audio généré dans un fichier avec ffmpeg plutôt que de directement le lire.
Cette commande utilise de device lavfi
et prend en argument des commandes
comprises par lavfi qui ici génèrent une fréquence de 440Hz pendant une seconde.
sine
est un “filtre” documenté
ici. Il est un peu
particulier puisque contrairement à la plupart des filtres il n’a pas pour objet
de modifier une source mais d’un créer une. Il n’a donc pas d’entrée.
du bruit lovecraftien horrifique avec anoisesrc
Au passage je joue avec d’autres filtres et du bruit marron avec un sample rate très bas donne un côté “bruit qui vient du tréfond des océans” assez flippant et lovecraftien. Essayez
$ ffplay -f lavfi -i "anoisesrc=c=brown:r=1000:a=1"
Le visuel généré par ffplay donne une dimension encore plus angoissante.
Le saviez vous ? Lovecraft était très raciste et antisémite
Plutôt que de directement jouer le son nous pouvons utiliser ffmpeg pour le stocker dans un fichier (ogg par exemple) :
ffmpeg -f lavfi -i "sine=frequency=440:duration=1" bip.ogg
On peut rejouer le fichier avec ffplay ou tout autre lecteur :
mpv bip.ogg
Pour l’article crééons quatre sons différents, quatre bip de fréquences différentes :
ffmpeg -f lavfi -i "sine=frequency=440:duration=1" bip.ogg
ffmpeg -f lavfi -i "sine=frequency=640:duration=1" bip-640.ogg
ffmpeg -f lavfi -i "sine=frequency=240:duration=1" bip-240.ogg
ffmpeg -f lavfi -i "sine=frequency=540:duration=1" bip-540.ogg
faire des bips à la fréquence aléatoire
$ seq N M | shuf | head -n1
Par exemple :
$ seq 200 1000 | shuf | head -n1
529
Si l’on veut générer quatre bip aléatoires on peut donc faire :
seq 200 1000 |
shuf |
head -n4 |
xargs -I {} -r ffmpeg -f lavfi -i "sine=frequency={}:duration=1" bip-{}.ogg
qui exécutera :
ffmpeg -f lavfi -i sine=frequency=479:duration=1 bip-479.ogg
ffmpeg -f lavfi -i sine=frequency=812:duration=1 bip-812.ogg
ffmpeg -f lavfi -i sine=frequency=281:duration=1 bip-281.ogg
ffmpeg -f lavfi -i sine=frequency=624:duration=1 bip-624.ogg
Déclencher du son au bon moment
L’idée d’origine est de déclencher un son à chaque visite du site. On commence d’abord par récupérer les logs du serveur en local :
$ ssh host "tail -f /chemin/vers/logs"
130.79.96.42 - - [11/Jun/2024:15:48:23 +0200] "GET /style.css HTTP/1.1" 200 170 "http://zinzine.bebou.netlib.re/" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0"
130.79.96.42 - - [11/Jun/2024:15:48:23 +0200] "GET /cssVarFilledCookies.css HTTP/1.1" 200 975 "http://zinzine.bebou.netlib.re/" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0"
213.16.110.236 - - [11/Jun/2024:16:05:20 +0200] "GET / HTTP/1.0" 200 1068 "-" "-"
[...]
On peut boucler dessus avec un while
:
ssh host "tail -f /chemin/vers/logs" |
while read line;do
[...]
done
ssh, les commandes et les pipes
Si vous êtes étonné·es de voir ssh utilisé de la sorte j’explique. L’usage
“habituel” d’ssh est de ssh host
ce qui permet de récupérer un shell
interactif sur la machine distant. En réalité on peut passer n’importe quelle
commande en argument d’ssh. Celle-ci s’exécutera sur la machine distante. Ici
on récupère donc les logs du serveur à l’aide d’un tail
. Deuxième surprise
éventuelle, le fait de piper le résultat de la commande ssh dans la suite de
notre script. Ca peut paraître un peu magique (ou au contraire tout à fait
logique selon les personnes) mais ssh “connecte” les entrées et sorties des
commandes locales et distantes. Ainsi dans :
$ seq 10 | ssh host "paste -s -d '+'" | bc -l
seq 10
est exécuté sur la machine locale, sa sortie est branchée à l’entrée de la commandessh
ssh
est exécuté en local et lancepaste -s -d '+'
sur la machine distante. Au passage ssh branche son entrée (la sortie deseq
) sur l’entrée de la commandepaste
sur la machine distante. ssh récupère également la sortie du paste sur la machine distante pour la transmettre au pipe sur la machine locale.bc -l
est exécuté en local, son entrée étant la sortie de la commande ssh qui est la sortie de la commande paste distante.
Tout ça pour dire qu’ssh branche les pipes les un avec les autres pour qu’ils se comportent comme si la commande distante était exécutée en local.
En se basant sur le contenu de la variable $line
on devrait pouvoir détecter
(à la va vite on fait simple) quel site est visité :
ssh host "tail -f /chemin/vers/logs" |
while read line;do
site=$(echo "$line" | grep -oE '/(arthur|doublezip|zinzine)\.')
case "$site" in
(/arthur.) [...] ;;
(/doublezip.) [...] ;;
(/zinzine.) [...] ;;
(*) [...] ;;
esac
done
Et jouer un son différent selon le site avec deux dixième de seconde entre chacun :
ssh host "tail -f /chemin/vers/logs" |
while read line;do
site=$(echo "$line" | grep -oE '/(arthur|doublezip|zinzine)\.')
case "$site" in
(/arthur.)
ffplay -autoexit -nodisp -loglevel panic -i bip-281.ogg & ;;
(/doublezip.)
ffplay -autoexit -nodisp -loglevel panic -i bip-624.ogg & ;;
(/zinzine.)
ffplay -autoexit -nodisp -loglevel panic -i bip-812.ogg & ;;
(*)
ffplay -autoexit -nodisp -loglevel panic -i bip-479.ogg & ;;
esac
sleep 0.2
done
On emballe tout ça dans un script et on le lance ! On peut ajuster le sleep pour
accélérer ou ralentir la lecture. On peut également retirer les &
des lignes
ffplay pour que chaque son soit joué l’un après l’autre de manière strictement
séquentiel. Si un très grand nombre de requêtes arrivent dans un petit laps de
temps ça risque de prendre un long moment pour tout dépiler.
Des idées
- Streamer le son sur une radio. Parfois c’est live sur la radio sup-sonore
- Demander à chaque personne qui rejoint le serveur un fichier audio d’une seconde pour que ce soit le son associé à leur site
- L’explication de ce script en atelier CESAR démontre que pour une personne avec un niveau moyen en Unix c’est un projet assez pédagogique
- On pourrait utiliser ce système pour créer des pièces sonores basées sur l’interaction avec un public lors d’un concert par exemple. On peut imaginer des interactions plus sobres (et accessibles, pleins de personnes n’ont pas de smartphone) que de sortir son smartphone et spammer un site mais plus facile à mettre en place sans matériel dédié je suis pas sûr.
- On peut imaginer n’importe quel truc à la place de balancer du son. Des idées en vrac : générer ou dévoiler une image (merci Miguel), générer une mosaïque, que les sons soient des notes…