Streaming audio haute qualité avec AAC
Le codec AAC (Advanced Audio Coding dont les fichiers portent souvent l'extension. MP4) est devenu au moins aussi populaire que le bon vieux MP3. Le fait que ce soit le codec audio utilisé par iTunes, le leader mondial de la vente en ligne, n'y est surement pas étranger.
Nous allons dans ce billet voir que l'on peut également utiliser ce codec lors de streaming. Je ne suis pas le premier à avoir cette idée car l'AAC est déjà utilisé pour la diffusion de la radio numérique Japonaise.
On ne change pas une équipe qui gagne, nous allons utiliser le framework GStreamer pour faire ce petit test de streaming audio entre deux machines. Pour ceux qui ne sont pas habitués à la notion de pipeline GStreamer, je vous conseille la lecture de ce billet.
Que cherche t'on à faire ?
Nous allons essayer de diffuser ("streamer") un flux audio (par exemple un .WAV non compressé pour être sûr d'avoir une source de bonne qualité) depuis une machine A vers une machine B (reliées par un réseau IP) en utilisant un encodage AAC-LC et une encapsulation MPEG-4 / RTP.
Création de la pipeline d'émission
Si vous avez bien suivi, la commande suivante doit être saisie sur la machine A:
gst-launch -tv \
gstrtpbin name=rtpbin latency=0 buffer-mode=0 \
filesrc location=\"samples/test.wav\" ! decodebin ! audioconvert \
! queue ! faac bitrate=128000 ! rtpmp4apay \
! rtpbin.send_rtp_sink_1 \
rtpbin.send_rtp_src_1 ! udpsink port=6969 host=$IP_B
Bien que fait cette commande:
- elle lance GStreamer (gst-launch)
- Elle produit un flux réseau RTP (gstrtpbin)
- La source audio du flux réseau RTP sera un fichier WAV (filesrc), qui sera décodé (decodebin)
- On encode en AAC en utilisant le plugin faac (basée sur FAAC l'implémentation libre du codec AAC) en fixant un débit réseau cible de 128Kbps (128000 bits). On utilisera ainsi un streaming de type CBR (constant bitrate), c'est à dire que l'on fixe le débit et que le codec s'arrange pour adapter la qualité
- On encapsule le résultat dans une trame RTP MP4 Audio (rtpmp4apay)
- On stream en UDP (udpsink) vers la machine $IP_B (à remplacer par l'adresse IP de la machine B) et sur le port 6969
Création de la pipeline de réception
A saisir sur la machine... B (bravo vous avez gagné une partie gratuite):
gst-launch -tv \
udpsrc port=6969 caps="application/x-rtp, media=(string)audio, clock-rate=(int)16000, encoding-name=(string)MP4A-LATM, cpresent=(string)0, payload=(int)96, config=(string)40002810" \
! gstrtpjitterbuffer latency=200 drop-on-latency=true ! rtpmp4adepay ! faad \
! audioconvert ! audioresample ! autoaudiosink
Que fait cette commande:
- Elle lance GStreamer (gst-launch)
- Elle écoute sur le port UDP port 6969 en filtrant les paquets RTP MP4A (udpsrc). La valeur a mettre dans la string config varie selon la fréquence d'échantillonnage de votre source. Elle est affichée lors du lancement de la pipeline A.
- Elle bufferise les paquets dans un buffer qui aura une taille maximale de 200ms (à adapter selon la qualité de votre réseau entre A et B). Si les paquets sortes de ce buffer avec plus de 200ms, ils seront dropés (donc perte de paquets, perte d'information, perte de son...).
- On décode le paquet RTP (rtpmp4adepay)
- On décode le flux audio AAC (faad)
- On joue le son sur le périphérique de sorti audio standard (autoaudiosink)
Résultat des tests
Après avoir fait mumuse avec des sources différentes (musique, voix...) et des débits plus ou moins importants (de 8 à 320 Kbps). On arrive à des résultats très intéressants.
Par exemple pour de la voix ("Pierre si tu m'entends "), on arrive à une qualité tout à fait acceptable en réglant un bitrate de 16bps pour un flux à 16KHz.
Pour la musique, point de salut en dessous de 128 Kbps (à moins de se contenter d'une qualité vraiment médiocre). A 256 Kbps, on a une qualité qui correspond à une écoute depuis un fichier .MP4 téléchargé sous iTunes Store. Au dessus de 256 Kbps, je n'ai pas noté d'amélioration (mais je n'avais pas un périphérique de sorti de très grande qualité).