% % new 24 juillet 2014 - Mixart Myrys % \chapter{streaming} \label{chap:streaming} \index{streaming} Avertissement : pour le moment\footnote{En juillet 2014}, nous n'allons nous pencher que sur la diffusion de flux audios, avec des encodages libres comme \textsl{ogg} ou \textsl{speex}. Tout simplement parce que le monde de la vidéo est un gigantesque foutoir de codecs, de containers, de brevets logiciels et d'incompatiblités diverses et variées. Une notion importante à bien comprendre, c'est l'organisation du flux des sons immatériels au travers des intertubes. \textbf{insert picture here !}\index{XXX} %------------------------------------------------------------- \section{icecast2} \index{icecast2} \label{icecast2} Icecast est, semble-t-il, \textbf{le} serveur de streaming de référence. Il se configure facilement avec des fichiers en XML\index{XML}. Première approche d'une ergonomie différente, vous êtes avertis. \begin{quote} Icecast, the project, is a collection of programs and libraries for streaming audio over the Internet. This includes: Icecast, the program that streams audio data to listeners, libshout, a library for communicating with Icecast servers and Ices2\index{ices}, a program that sends audio data to Icecast servers \end{quote} Pour alimenter Icecast en son, il faut utiliser un \textsl{source-client} approprié. Le modèle recommandé est \textbf{ices2} qui est détaillé un peu plus loin, à la page \pageref{ices2}. Il peut envoyer depuis une entrée audio (alsa, jack, pulseaudio...) ou une playlistde fichiers \texttt{.ogg}\index{ogg}. \textsl{more to come...} %------------------------------------------------------------- \section{liquidsoap} \index{liquidsoap} Mais nous allonc commencer par un outil puissant, bien que délicat à comprendre au premier abord~: \texttt{https://www.liquidsoap.info/} \begin{quote} Liquidsoap is an extensible and flexible audio stream generator, mainly used for streaming to a shoutcast/icecast server. It is also possible to output in a file, to speakers or as raw PCM stream. liquidsoap can perform any audio processing, mixing streams together, applying filters, generating sound procedurally, there is no limit but your imagination. Input files can be accessed through the network, using samba, ftp or speech synthesis. The system features lots of programming operators, including user requests, time-based selection, sum... \end{quote} Un étonnant langage de script pour gérer tous ces octets musicaux en les promenant un peu dans tous les sens, la possibilité de commander Savonet avec un simple telnet\index{telnet}. Vite, un exemple d'utilisation, vous créez un fichier texte avec cez quelques lignes dedans et vous le sauvez sous le nom \texttt{savon.liq} : \begin{verbatim} set("log.file.path","/tmp/savon.log") set("log.stdout",true) output.icecast (%vorbis, host = "10.20.0.23", port = 1984, password = "hopla!", mount = "savon.ogg", single("loveme.ogg")) \end{verbatim} Avec ce petit programme, nous pouvons envoyer en boucle un fichier Ogg vers notre serveur. Les deux premières lignes permettent de voir et d'enregistrer les diverses actions. Et la grosse instruction \texttt{output.icecast} envoie la musique dans votre serveur Icecast2 en passant les paramètres nécessaires. \subsection{Logfile} \begin{verbatim} set("log.file.path", "/home/tth/Radio/log/takeover.log") set("log.stdout", false) set("log.level",3) \end{verbatim} Alors, la grande question est : « quelle valeur pour le loglevel ? », et la réponse n'est pas évidente à trouver dans la documentation, il y a même un ticker ouvert\dots \begin{itemize} \item{1 = critical} \item{2 = important} \item{3 = normal} \item{4 = information} \item{5 = debug} \end{itemize} \subsection{10.20.0.23} Maintenant, voyons un exemple plus complet et plus réaliste, largement inspiré d'un tutoriel de la documentation officielle, et qui deviendra un de ces jours la base de la nouvelle% \footnote{L'ancienne ayant été fermée pour des raisons incompréhensibles.} radio de Myrys~: \begin{verbatim} set("log.file.path", "/tmp/savon.log") set("log.stdout", false) default = single("loveme.ogg") openbsd = playlist(mode="random", "files/openbsd.pls") others = playlist(mode="random", "files/others.pls") jingles = playlist( "files/jingles.pls") radio = fallback([ switch([({ 5h-11h }, openbsd), ({ 11h-5h }, others)]), default]) radio = random(weights=[1,12],[ jingles, radio ]) output.icecast( %vorbis, host = "localhost", port = 1984, password = "hopla!", mount = "savon.ogg", radio) \end{verbatim} Ah bah oui, ça commence à être robuste, mais en fait c'est presque simple à comprendre, et un peu plus compliqué à mettre en œuvre. On se retrouve vite face à un problème classique : les différences de niveau sonore entre les divers morceaux. Et comme on veut avancer sur d'autres choses, on rache un petit bout de Bash avec de la poudre verte dedans : \begin{verbatim} #!/bin/bash/ echo "que faire ?" \end{verbatim} Cette poudre verte pourrait bien être \texttt{vorbisgain(1)}\dots \subsection{rotation des playlists} \begin{verbatim} pl2014 = playlist("2014") pl2013 = playlist("2013") ... jingles = playlist("jingles") s = rotate([pl2014, pl2013, ..., jingles]) output.icecast(..., s) \end{verbatim} \subsection{Take over the playlist} XXX\index{XXX} Il est également possible, avec liquidsoap, d'interrompre la diffusion d'une playlist à partir d'une autre source (fichier ou entrée audio), eventuellement externe. \lstinputlisting{code/takeover.liq} \subsection{trucs divers} Que signifie ce message : \textbf{That source is fallible.} ? Par exemple, que le fichier que vous aviez soigneusement désigné comme \texttt{default} n'existe plus sur le disque. Comment envoyer vers plusieurs icecasts ? Bah c'est très facile : il suffit de mettre plusieurs "blocs" \texttt{output.icecast} à la suite les uns des autres ;) %==================================================================== \section{Source clients} \label{sourceclients} Il existe une foultitude de clients source pour abreuver icecast2. %------------------------------------------------------------- \subsection{ices2} \index{ices2} \label{ices2} Premier mystère : comment faire le rapprochement entre la déclaration du périphérique d'entrée (\texttt{hw:1,0}) et l'équivalent dans le monde Alsa ? La commande \texttt{arecord -L} va nous donner quelques informations sur les « points d'entrée » utilisables. Liste dont nous extrayons (par la pure pensée logique) ce fameux nom de device~: \texttt{ plughw:CARD=Snowball,DEV=0} XXX\index{XXX} que nous pouvons mettre dans le XML. \textbf{Attention} si votre source est monophonique, comme le microphone USB \textsc{Snowball} utilisé dans cet exemple, il NE faut PAS mettre \textsl{downmix} à 1\dots Et si vous souhaitez dupliquer une entrée à un seul canal (genre un micro usb) por obtenir une sortie stéréo, ça ne semble pas possible fin 2020\index{2020}. Il serait temps de songer à écrire un patch\index{patch}. %------------------------------------------------------------- \subsection{Ezstream} \begin{quote} Ezstream is an audio and video streaming client which feeds any icecast server with audio data and metadata from a standard input without reencoding. It thus requires very little CPU resources. Some playlists can be looped and composed with MP3, Ogg Vorbis or Ogg Theora media files. \end{quote} %------------------------------------------------------------- \subsection{darkice} \index{darkice} \begin{quote} DarkIce as a live audio streamer. It records audio from an audio interface (e.g. sound card), encodes it and sends it to a streaming server. \end{quote} %------------------------------------------------------------- \subsection{VLC} \index{vlc} \label{streamvlc} VLC est le « cône de chantier » du multimédia. %------------------------------------------------------------- \subsection{butt} \index{butt} Du clickaconvi qui plante en X remote ;( mais sinon une interface graphique simple et facile d'emploi. Un bon choix pour qui aime les choses simples où juste brancher un microphone et causer dans le Ternet. %------------------------------------------------------------- \subsection{idjc} \index{idjc} \begin{quote} Internet DJ Console is an Internet radio application for making a live radio show or podcast. Features include two main media players with a crossfader, a jingle player, microphone signal processing (compressor and noise gate) \end{quote} %------------------------------------------------------------- \subsection{Android} \index{Android} Cool Mic \texttt{https://coolmic.net/} ? Mais il faut avoir quelques connaissances en \textsc{modernophone} pour arriver à tenter de comprendre pouquoi ça ne fonctionne pas, alors que tout semble correct. %==================================================================== \section{Gadgets} On peut aussi imaginer des \textsl{client sources} plus ésotériques. L'exemple classique étant l'utilisation de la synthèse vocale pour faire une horloge parlante. Mais comme tout vieux linuxien, j'attache un intérêt tout particulier à une valeur symbolique~: l'uptime de ma machine. En ces temps troublés\footnote{Début janvier 2021, le collectif d'artistes Mixart-Myrys, dont je fais partie depuis dix ans, est en train de se faire salement éjecter de son hangartistique. À cette occasion, j'ai remonté \textit{à la rache} un Icecast, et je l'ai voulu un peu surprenant pour le béotien, d'où l'uptime parlé.}, l'uptime, c'est important. \lstinputlisting{code/say-uptime.sh} L'option \texttt{-p} de la commande \texttt{uptime} permet d'obtenir une sortie de cette forme : \textsf{up 1 day, 1 hour, 37 minutes} qu'une micromagie \texttt{sed} change en une forme plus correcte syntaxiquement, bien qu'anglo-saxonne. La ligne suivante sert uniquement d'affichage de contrôle, et peut être supprimée sans vergogne. \label{say-uptime} Les trois lignes suivantes vont effectivement généré le son qui sera envoyé vers la radio\index{radio} de l'Internet. Premier élément du pipeline, \texttt{espeak-ng} reçoit le texte par son \textsl{stdin} et génère le flux de parole sur son \textsl{stdout}, à partir des options \texttt{-g 9 -s 150 -a 133}, réglant la voix synthétique. Ensuite, il faut que les échantillons sonores soient au format physique attendu par le diffuseur, d'où la conversion en 2$x$16 bits. Et pour finir, il est encodé/encapsulé dans du OggVorbis\index{ogg} que le \textsl{yuser} final ne pourra peut-être pas écouter sur son \textsf{iPhone}. Quand à la dernière ligne \texttt{~/bin/sender} c'est un programme, basé sur \texttt{libshout}, qui va gérer l'authentification et le transfert des données vers un point d'entrée du serveur icecast. Voilà, c'est tout pour le moment. %==================================================================== \section{Airtime} \index{Airtime} Cette partie est écrite pendant l'installation de Airtime dans \textsf{Radio-Parasite} en octobre 2021. Hélas, ça ne va pas être si simple que ça. Le logiciel original a été abandonné depuis plusieurs années (fin 2015 à la louche) par son éditeur \textsf{Sourcefabric}. Un remplaçant potentiel (un fork ?) existe~: \textsl{LibreTime} qui semble identique. \begin{quote} LibreTime est un système d'automatisation de station de radio qui prend en charge la diffusion Web. Il est construit à partir de la communauté du système d’automatisation de la station de radio Airtime de SourceFabric. \end{quote} \texttt{https://libretime.org/install} \texttt{https://libretime.org/docs/host-configuration} \texttt{https://progsoft.net/fr/software/libretime} %==================================================================== \section{libshout}\index{libshout}\label{libshout} Libshout c'est quoi ? Ah, chers amis de la radio en ligne, c'est une porte ouverte facilitant l'accès en direction du monde sonore extérieur, comme le précise clairement sa documentation~: \begin{quote} Libshout is a library for communicating with and sending data to an icecast server. It handles the socket connection, the timing of the data, and prevents bad data from getting to the icecast server. \end{quote} \lstinputlisting[language=c]{code/microcast.c} Mais il reste encore pas mal de chose importante à rajouter dans ce logiciel : par exemple la partie encodage. %==================================================================== %-------------------------------------------------------------