User Tools

Site Tools


tuto_icestream

IceStream

Icestream est un logiciel de stream audio qui permet de mixer, recevoir ou envoyer des flux audio à travers un réseau local ou Internet.

IceStream v2.1-2 : cooking - installation et utilisation

1 - La mise à jour du logiciel

Les nouvelles fonctionnalités et changements :

General

  • Les paramètres peuvent désormais être sauvegardé et chargé, ainsi qu'importé et exporté
  • Amélioration de la gestion des chemins

Lecteur

  • Ajout d'un vu-Mètre rudimentaire
  • Ajout d'une trackbar non interactive
  • Fix du contrôle de volume
  • Fix du comportement du lecteur
  • Amélioration général de la lisibilité générale

Client

  • Transition d'ices à Liquidsoap
  • Ajout du support pour le format mp3
  • Ajout d'une supervision des logs et statut du client
  • Ajout d'une option de sauvegarde du stream en local
  • Ajout d'une option de duplication du stream en basse qualité

Server

  • Mise à jour vers IceCast2
  • Ajout d'une vue Web vers le serveur
  • Ajout d'une supervision des logs et statut du client

2 - Installation How-To

[RECOMMENDÉ] Par package :

L'installation la plus facile se fait à partir du package (.deb) situé ici.

Double-clicker (ou click-droit → Installer logiciel) le fichier installera Icestream, ainsi que ces dépendances.

[ALTERNATIVE]

Vous pouvez également installer le package via dpkg, puis apt pour les dépendances :

dpkg -i ~/chemin/vers/icestream_x.x-x_x.deb
apt -f install
À partir des sources :

Si vous souhaitez compiler directement IceStream, vous trouverez ce dont vous avez besoin ici. N'oubliez pas d'installer les dépendances nécessaire :

apt install debhelper-compat, libvorbis-dev, libxml2-dev, libxslt1-dev, qt4-qmake, g++, libqt4-dev, libqtwebkit4

3 - Comment utiliser Icestream

L'interface consiste de trois onglets.
- Les lecteurs, pouvant jouer la majorité des formats audio et vidéo, que ce soit en local, ou en réseau.
- Le client, permettant de transmettre le flux vers un serveur.
- Le serveur, si vous souhaitez héberger votre propre serveur.

Pour lire un fichier/flux, il vous suffira d'insérer de cliquer sur le bouton représentant un dossier et de sélectionner votre audio, ou bien directement insérer le chemin/URL dans la barre de texte. Vous pourrez ensuite cliquer le bouton Play.

Pour envoyé votre flux vers un serveur, il vous suffira d'entrer les paramètres nécessaire à la connexion (adresse, port, mot de passe). Vous pouvez également modifier les paramètres audio à votre guise (Il est conseillé d'avoir un taux d’échantillonnage supérieur à 44100).
Il vous faudra ensuite, dans l'onglet “Connections” de qjackctl, lier les lecteurs (appelés “MPlayer”) au client “Liquidsoap”. Cette interface vous permettra de gérer quels flux sont envoyés au serveur, choisissant ainsi ce que l'auditeur peut entendre.

Pour héberger votre serveur, il vous suffira de rentrer les paramètres demandés.
Le mot de passe et port demandés sont bien ceux qu'il faudra transmettre au client.
Une fois le serveur démarré, une fenêtre s'ouvrira vers la page de gestion de votre serveur, vous permettant de contrôler sont statut.

[ FAQ ]

- Mon audio ne joue pas !
→ Assurez vous d'avoir démarré JACK, via qjackctl.

- J'héberge le serveur IceCast moi-même, mais je n'arrive pas à m'y connecter !
→ Assurez vous d'avoir correctement insérer l'adresse et le port de votre serveur. Il est également possible qu'IceCast tourne en fond. Pour régler cela, vous pouvez faire :

/etc/init.d/icecast2 stop

4 - Détails

[AVERTISSEMENT]
Les solutions présentées ci-dessous ne sont absolument pas les meilleures pratiques possible, mais les ébauches d'un débutant.
Une grande partie des ces méthodes pourraient être améliorées.
Veillez donc à rester critique, et à garder votre propre vision des choses. Merci.

Cette section consiste à expliquer en plus de détails les changements effectué au code
Note : IceStream à été conçu avec Qt Creator et Qt Designer, compilé sous qt4.8.

Fichiers de configurations Client/Serveur

Serveur
Un guide des plus complet peut être trouvé ici.
Client
La documentation du fichier de config Liquidsoap peut être trouvé ici.
Exemple :

set("log.stdout", false)
set("log.file", true)
set("log.file.path", "/tmp/liquidsoap.log")
set("log.level", 3)
set("frame.audio.size", 2048)
full = input.jack(id="liquidsoap")
output.icecast(%vorbis(samplerate=96000, channels=1 , quality=0.5),
host="monhost.com",
port=XXXX,
password="monpass",
mount="monnomdestream",
name="test",
description="test stream",
genre="Etcetera",
full)

Creation d'un fichier de config Client/Server La création d'un fichier de config ce sont en utilisant QFile.
La configuration d'IceCast devant être sous format XML, il est sage d'utiliser QXmlStreamWriter, qui permet l'écriture de contenu XML très simplement.
La configuration de Liquidsoap devant être en Plain Text, QTextStream sera utiliser.

void CreateLiquidConfig()
{
    QFile file(clientFilePath);

    file.open(QFile::WriteOnly | QFile::Text);
    QTextStream stream(&file);
    stream.setCodec("ISO 8859-1");

    stream << "set(\"log.stdout\", false)" << endl;
    ...
file.close();
----------------------------------------------------------------------
    QXmlStreamWriter writer(&file);
    writer.setCodec("ISO 8859-1");

    writer.setAutoFormatting(true);
    writer.writeStartDocument();
    writer.writeStartElement("icecast");
    writer.writeEndElement();
    ...
file.close();
Mise à jour IceCast2

IceCast(1) étant obsolète, il a fallu passer à IceCast2.
Au niveau code, il a simplement fallu remplacer un mot-clef. Le fichier de configuration est lui resté le même.

void launchIceCast()
{
[...]
    serverStreamCommande = "icecast2";
[...]
}
La vue Web

Une vue Web (comme un explorateur internet) vers la page d'admin du serveur à été ajouté.

Pour cela on utilise un objet QWebView, placé dans l'UI via Qt Designer.
À la confirmation du bon lancement du serveur, on ouvre la vue, en lui donnant l'adresse vers où pointé :
Ici un timer est utilisé pour donner un peu de temps au serveur de s'initialiser correctement. Tenter d'afficher la vue trop rapidement est voué à l'échec.

[ Après lancement ]
QTimer::singleShot(1000, this, SLOT(slotOpenAdminView()));

void slotOpenAdminView(){
    ui->iceWebView->load(iceAdminUrl);
    ui->iceWebView->show();
}
Supervision des logs et statut d'un QProcess

Le but était d'avoir un œil sur le statut d'IceCast et de LiquidSoap

Les fichiers de logs se trouvent dans /tmp/ (voir configuration server/client)
Un QFileSystemWatcher est utilisé ici afin d'obtenir un signal à chaque écriture dans le fichier

liquidsoap_watcher = new QFileSystemWatcher(this);
liquidsoap_watcher->addPath("/tmp/liquidsoap.log");
connect(liquidsoap_watcher,SIGNAL(fileChanged(QString)),SLOT(slotLiquidlog(QString)));

slotLiquidlog(QString filepath)
{
    QString log = getLogs(filepath);
    if((log != lastLiquidlog) && !(log.contains(lastLiquidlog))){
        ui->liquidsoap_logWindow->append(log);
        lastLiquidlog = log ;
    }
}

Avec une fonction permettant de parser les nouvelles lignes ajoutées

getLogs(QString path){
    QFile file(path);
    QString log;
    QString lastlog[3];
    if (file.open(QIODevice::ReadOnly | QIODevice::Text)){
        file.seek(file.size()-1);
        for (int i=0;(i<=1) && (file.pos() > 0);) {
            QString token = file.read(1);
            file.seek(file.pos()-2);
            if (token == "\n"){
                i++;
            }
        }
        log = file.readAll();
        file.close();
        log.remove(0, 2); log.remove(log.size()-1, 1);  // Fix pour une erreur dans la lecture
    } return log; }

Note : Cette méthode complète est loin d'être parfaite, et devrait être amélioré si vous étiez à vous inspirer des ces snippets.

Les applications étant lancées en tant que QProcess, le statut (ON/OFF) est obtenue grâce aux changements du QProcess::ProcessState tel que :

connect(streamProcess,SIGNAL(stateChanged(QProcess::ProcessState)),SLOT(slotstreamProcess_StateChanged(QProcess::ProcessState)));

void slotstreamProcess_StateChanged(QProcess::ProcessState i)
{
    if(i == 0){ ui->streamStatus->setIcon(QIcon(ledred)); }  // OFF
    else { ui->streamStatus->setIcon(QIcon(ledgreen)); }     // ON
}
Ajout d'un format audio (ici mp3)

La documentation sur les formats audio se trouve ici.
La configuration ayant besoin d'être donné à Liquidsoap concernant le format diffère de format à format.

// Exemple avec ogg
output_setting = "output.icecast(%vorbis(samplerate=" + ui->comboBox_SampleRate_ogg->currentText() + ", channels=" + ui->comboBox_Channels_ogg->currentText() + " , quality=" + ui->comboBox_Quality_ogg->currentText() + "),";

La ligne correspondante au format doit pouvoir être interchangeable si l'on veut pouvoir utiliser plusieurs formats.

void audioFormatSettingsPicker(int i){
    QString output_setting;
    switch (i) {
        case 0: // ogg
        output_setting = "output.icecast(%vorbis(samplerate=" + ui->comboBox_SampleRate_ogg->currentText() + ", channels=" + ui->comboBox_Channels_ogg->currentText() + " , quality=" + ui->comboBox_Quality_ogg->currentText() + "),";
        break;
        case 1: // mp3
        output_setting = "output.icecast(%mp3.vbr(samplerate=" + ui->comboBox_SampleRate_mp3->currentText() + ", quality=" + ui->comboBox_Quality_mp3->currentText() + ", " + ui->comboBox_StereoMode_mp3->currentText() + "),";
        break;

Il faut également que l'utilisateur puisse sélectionner ce format et ses paramètres. Dans le cas d'IceStream, les paramètres de chaque formats sont contenu dans leurs propres QFrame.
C'est frame sont ensuite cachées et affichées selon le format sélectionné.

connect(ui->comboBox_Format, SIGNAL(currentIndexChanged(int)),SLOT(audioFormatFrameHandler(int)));

void audioFormatFrameHandler(int i){
    switch (i) {
    case 0:
        ui->audioFrame_mp3->hide();
        ui->audioFrame_mp3->setEnabled(0);
        ui->audioFrame_ogg->setEnabled(1);
        ui->audioFrame_ogg->show();
        break;
    case 1:
        ui->audioFrame_ogg->hide();
        ui->audioFrame_ogg->setEnabled(0);
        ui->audioFrame_mp3->setEnabled(1);
        ui->audioFrame_mp3->show();
        break;
Ajout d'une option Liquidsoap

Liquidsoap est un client puissant, offrant plus que la possibilité d'envoyer un flux.
Lors de la création du fichier de configuration, on utilisera “checkState()” de QCheckBox afin de savoir si l'utilisateur à choisi cette option.

void createLiquidConfig()
{
    QFile file(clientFilePath);
    // Ouverture du fichier en écriture et en texte.
    file.open(QFile::WriteOnly | QFile::Text);
    QTextStream stream(&file);
    [...]
    if(ui->optionStreamDump->checkState()){
    stream << "output.file(%wav(stereo=true, channels=2, samplesize=16, header=false)," << endl;
    stream << "'dump/%d-%m-%Y-%Hh%M.wav'," << endl;
    stream << "fallible=true," << endl;
    stream << "reopen_on_metadata=false," << endl;
    stream << "on_stop=shutdown," << endl;
    stream << "dump)" << endl;
    }
Utilisation de QProcess

Un QProcess permet de lancer une application/commande, et de lui attacher un objet.
L'exemple ci-dessous correspond à une version simplifié au lancement du vu-mètre d'IceStream.
QProcess à besoin du nom de l'application/commande quand une QString, ainsi qu'une QStringList contenant tout possible argument que désirez passer à votre application/commande.

void startVuMeter(){
    QStringList arguments;
    QString output = "MPlayer [%1]";
    arguments << "-t" << "dpm" << output_one.arg(playaProcess->pid()));
    vuMeterProcess->start("meterbridge", arguments);
}

Note : Ici est également démontré l'utilisation de la fonction .arg de QString, remplacant “%1”, par la valeur donnée.

Le stdin & stdout de MPlayer

Exemple : La trackbar
Elle consiste d'une simple QProgressBar, personnalisé pour mieux s'accorder au concept d'une trackbar.
Le snippet si dessous correspond à la stylesheet utilisé pour IceStream. La syntax est dans l'esprit du CSS.

QProgressBar::chunk {
	background-color:rgb(57, 119, 163);
	margin-left: 1px;
	margin-right: 1px;
    border: 1px solid rgb(110, 95, 100);
    border-radius: 3px;
}

La position de la piste est obtenu en envoyant à MPlayer la commande “get_time_pos” toutes les secondes.

poller = new QTimer(this);
poller->start(1000);       
               
connect(poller, SIGNAL(timeout()), this, SLOT(slotpollCurrentTime()));

La réponse d'MPlayer est alors “ANS_TIME_POSITION=XX.x”. Il suffit donc d'extraire cette valeur et de mettre à jour la barre.

connect(lecteurProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(slotprocessMessage()));

void slotprocessMessage(){
    while (lecteurProcess->canReadLine())
    {
        buffer.remove(0, 18); // Retire "ANS_TIME_POSITION="
        currentTime = buffer.toFloat();
        trackBar->setValue(static_cast<int>(currentTime));
    }
}

Exemple : Le volume
Le principe est le même que pour la trackbar, mais cet fois-ci pas besoin de lire le stdout.
Le petit détail ennuyant avec MPlayer est qu'il est impossible de lui donner une valeur à affecter au volume.
Il faut donc lui envoyer la commande “volume +” ou “volume -” le nombre de fois correspondant au volume désiré.
Lorsque le volume est modifié par l'utilisateur, une fonction doit être appelé, qui gère quelle instructions donner à MPlayer.

void setVolume(int i)
{
    int val = (i-volumeAncienneValeur);
    QString lecteurVolume;
    if((i-volAncienneValeur) >= 0){
        for (int n=0;n<=val;n++) {
            lecteurVolume= "volume +1\n";
            char *volumeProc=playerVolume.toAscii().data();
            lecteurProcess->write(volumeProc);
        }
    }
    else {
        for (int n=0;n>=val;val++) {
            playerVolume = "volume -1\n";
            char *volumeProc=playerVolume.toAscii().data();
            lecteurProcess->write(volumeProc);
        }
    }
    volAncienneValeur=slider->sliderPosition();
La sauvegarde des paramètres de l'UI (save, load)

Pour éviter que l'utilisateur ait à remplir les champs de l'UI à chaque démarrage du logiciel, il est totalement possible de sauvegarder les valeurs de ces champs pendant une session, et de les réutiliser.

Pour créer le fichier de config, on utilise le même principe que pour la config de Liquidsoap, c'est-à-dire avec QXmlStreamWriter.

void makeConfig(QString chemin){
    QFile file(chemin);
    file.open(QFile::WriteOnly | QFile::Text);
    QTextStream outStream(&file);

    outStream << "server_port = " << ui->Line_Local_Port->text() << endl;
    outStream << "server_pass = " << ui->Line_Local_Pass->text() << endl;
    [...]
    file.close;

Cela produira un fichier contenant, ligne par ligne, les nom & valeurs que vous lui avez donné.
Note: N'oubliez pas de convertir vos types speciaux, tel qu'un Booléan, car ils pourraient mal se traduire en valeur brut.

Maintenant, il faut lire ces valeurs, et les réattribués à leurs champs respectifs.
Ici, une QMap composé de deux QString nous simplifie grandement la tâche.
Le but est de lire l'intégralité du fichier, et dans ranger dans la QMap, chaque nom et sa valeur, ligne par ligne.
Puis on finit par remplir les champs en utilisant “settingsMap[”nomdemavaleur“]”.

QMap<QString, QString> settingsMap;

void getConfig(QString chemin)
{
    QFile file(chemin);
    QString current_line;
    file.open(QFile::ReadOnly | QFile::Text);
    QTextStream outStream(&file);

    while(!outStream.atEnd()){
        std::string a = outStream.readLine().toStdString();
        size_t pos = a.find('=');
        QString key = QString::fromStdString(a.substr(0, pos - 1));
        QString value = QString::fromStdString(a.substr(pos + 2));
        settingsMap[key] = value;
    }

    ui->Line_Local_Port->setText(settingsMap["server_port"]);
    ui->Line_Local_Pass->setText(settingsMap["server_pass"]);
    [...]
    file.close;

Installation Icestream v1.2 :

Pour l'installer télécharger les sources : IceStream

Les dépendances :

sudo apt-get install mplayer qjackctl libvorbis-dev libxml2-dev libxslt1-dev qt4-qmake g++ libqt4-dev

Puis les paquets en root :

sudo su
tar xvzf IceStream.tar.gz 
cd IceStream/
dpkg -i libshout_2.2-1_i386.deb 
dpkg -i libtheora_1.2-1_i386.deb
dpkg -i icecast-2.3.2_3-1_i386.deb
dpkg -i ices-2.0_4-1_i386.deb
cd IHMB/
qmake -project
qmake .
make
sudo cp IHMB /usr/local/bin/icestream

Utilisation :

Vous le lancer comme ceci en utilisateur simple (id NOT sudo):

icestream

Pour l'utilisation vous pouvez suivre ce tuto Enjoy !

tuto_icestream.txt · Last modified: 2020/03/03 09:12 by raven14