Test du codec Speex dans Gstreamer

Speex (wiki / site officiel) est un codec audio libre (licence dérivée de BSD) dont les perfomances sont très intéressantes, surtout pour transporter un signal comme la voix humaine. Le but de ce billet est de tester ce codec dans le cadre d'une application de streaming audio.

Mise en place du test

Pour tester ce codec, j'utilise le framework GStreamer et deux scripts shell tournant sur deux machines différentes. Le script rtpserver.sh prend comme source le microphone par défaut de votre machine, encode le flux en Speex, puis le diffuse en RTP/UDP vers la seconde machine. Le script rtpclient.sh récupére le flux RTP/UDP venant de la première machine, le décode et le diffuse sur la sortie son par défaut.

Le script rtpserver.sh:

#!/bin/sh

SEND_TO_ADDR=192.168.29.111
SEND_TO_RTP_PORT=5003
SEND_TO_RTCP_PORT=5004
RECV_FROM_RTCP_PORT=5005

ENCODER=speexenc
PAYLOADER=rtpspeexpay

SPEEX_PARAMS="quality=4 vad=true dtx=true"
SPEEX_CAPS="audio/x-raw-int,rate=16000"

ENCODER_PARAMS=${SPEEX_PARAMS}
RTP_PARAMS="latency=200"
AUDIO_CAPS=${SPEEX_CAPS}

gst-launch -v  gstrtpbin name=rtpbin ${RTP_PARAMS}
alsasrc
! queue ! audioresample ! ${AUDIO_CAPS} ! ${ENCODER} ${ENCODER_PARAMS} ! ${PAYLOADER}
! rtpbin.send_rtp_sink_1
rtpbin.send_rtp_src_1 ! udpsink port=${SEND_TO_RTP_PORT} host=${SEND_TO_ADDR}
rtpbin.send_rtcp_src_1 ! udpsink port=${SEND_TO_RTCP_PORT} host=${SEND_TO_ADDR} sync=false async=false
udpsrc port=${RECV_FROM_RTCP_PORT} ! rtpbin.recv_rtcp_sink_1

Le script rtpclient.sh:

#!/bin/sh

SEND_TO_RTCP_PORT=5005
RECV_FROM_ADDR=192.168.29.146
RECV_FROM_RTP_PORT=5003
RECV_FROM_RTCP_PORT=5004
AUDIORATE=16000

gst-launch-0.10 -v gstrtpbin name=rtpbin latency=200
udpsrc caps="application/x-rtp, media=(string)audio, clock-rate=(int)${AUDIORATE}, encoding-name=(string)SPEEX, encoding-params=(string)1, ssrc=(guint)419764010, payload=(int)110, clock-base=(guint)3478167082, seqnum-base=(guint)57894" port=${RECV_FROM_RTP_PORT}
! rtpbin.recv_rtp_sink_1
rtpbin. ! rtpspeexdepay ! decodebin ! alsasink
udpsrc port=${RECV_FROM_RTCP_PORT} ! rtpbin.recv_rtcp_sink_1
rtpbin.send_rtcp_src_1 ! udpsink port=${SEND_TO_RTCP_PORT} host=${RECV_FROM_ADDR} sync=false async=false

Attention, il faut lancer le script rtpclient.sh avant le rtpserver.sh . Les variables suivantes sont modifiables dans les scripts:

Script rtpserver.sh:
SEND_TO_ADDR: Adresse IP du client
SEND_TO_RTP_PORT: Numéro de port sur lequel les paquets RTP seront envoyés
SEND_TO_RTCP_PORT: Numéro de port sur lequel les paquets RTCP seront envoyés
RECV_FROM_RTCP_PORT: Numéro de port sur lequel les paquets RTCP seront reçus
SPEEX_PARAMS: Paramètres du plugin d'encodage Speexenc
SPEEX_CAPS: Caps du flux audio (audio rate)

Script rtpclient.sh:
SEND_TO_RTCP_PORT: Numéro de port sur lequel les paquets RTCP seront envoyés
RECV_FROM_ADDR:  Adresse IP du serveur
RECV_FROM_RTP_PORT: Numéro de port sur lequel les paquets RTP seront reçus
RECV_FROM_RTCP_PORT: Numéro de port sur lequel les paquets RTCP seront reçus
AUDIORATE: Audio rate, mettre la même valeur que celle dans le caps du serveur

Résultats des tests

Le premier test a été effectué avec un audio rate de 44000 (bref un taux d'échantillonnage proche de celui d'un CD audio).

Paramètres:
rate=44000 / vad=false / dtx=false
Tests:
En jouant sur l'option quality, on obtient
quality=10 -> bande passante de 80 Kbps
quality=8 -> bande passante de 60 Kbps
quality=6 -> bande passante de 50 Kbps
quality=4 -> bande passante de 40 Kbps
quality=3 -> bande passante de 36 Kbps
quality=2 -> bande passante de 35 Kbps
Conclusion:
On obtient une dégradation de la qualité de réception de la voix en dessous d'une valeur de quality de 4. Il est clairement dit dans la documentation que la qualité > 4 son a réserver pour les sources audio plus complexes que la voix humaine (musique, film...). Par contre la consommation de CPU est plus importante (rapport de 5 contre 1 entre quality=10 et quality=1).
La bande passante est constante (à quelques Kbps) que l'on parle ou que l'on ne parle pas.

Paramètres:
En jouant sur les paramètres vad et dtx, on va essayer d'optimiser la bande passante en gardant la même qualité.
VAD (dixit Wiki): "Quand cette option est activé, le VAD détecte quand l'audio encodé est du dialogue ou du silence/bruit de fond. VAD est toujours implicitement activé en encodage VBR, donc cette option est utile uniquement en mode non VBR. Dans ce cas Speex détecte les périodes sans dialogue et les encode avec le strict minimum de bits pour reproduire le bruit de fond. Cette fonction est appelée Comfort Noise Generation (CNG)."
DTX (dixit Wiki): "la transmission discontinue est une fonctionnalité qui s'ajoute aux
opérations de VAD et de VBR, qui permet de couper la transmission
complètement quand le bruit de fond est stationnaire. Dans un fichier,
5 bits sont utilisés pour chaque frame manquante (correspondant à 250 bits/s)"

Tests:
On ajoute les paramètres vad=true et dtx=true au niveau du serveur (SPEEX_PARAMS)
La bande passante reste la même (40 Kbps) quand on parle, par contre elle passe à 23 Kbps quand on ne parle pas.
Conclusion:
Les algorithmes VAD et DTX fonctionnent très bien. Ils permettent de gagner de la bande passante quand l'activité au niveau sonore est faible (ce qui est le cas dans une conversation ou, normalement, une seule personne parle à un instant t).

En conservant les paramètres du premier test (quality=4, vad=true, dtx=true), on change seulement l'audio rate (au niveau du serveur et du client).

Paramètres:
rate=16000
Tests:
Bande passante de 28 Kbps lorsque l'on parle, 17 Kbps pendant les silences.
Conclusion:
La qualité reste excellente. Sur une conversation (voix humaine), on ne voit pas la différence avec un rate de 44000 (44 KHz).

Paramètres:
rate=8000
Tests:

Bande passante de 23 Kbps lorsque l'on parle, 16 Kbps pendant les silences.

Conclusion:
La qualité est dégradée mais la conversation reste compréhensible. On gagne seulement 5 Kbps par rapport au test précédant.

Pour conclure

D'après les tests effectués, le meilleur compromis bande passante qualité est:

  • audio rate = 16000 (16 Khz)
  • quality = 4
  • vad = true
  • dtx = true

Vus : 328
Publié par Nicolargo : 402