AES67 Audio Network

AES67 ist ein offener Standard für ein Audio-Netzwerk, ähnlich zu Dante. Technisch sind AES67 und Dante sehr nahe beieinander.

In AES67 werden (bis zu?) 8 Audio-Kanäle im L24 (“24-bit Linear Sampled Audio”, https://tools.ietf.org/html/rfc3190) Format mit 48000 Samples/s via Multicast-RTP übertragen.

Parallel dazu wird eine System-Clock im PTP-Protokoll benutzt (https://en.wikipedia.org/wiki/Precision_Time_Protocol).

AES67 mit GStreamer empfangen

Für unsere Anwendungsfälle (Audio nur empfangen, keine Wiedergabe) ist es nicht unbedingt nötig, PTP zu implementieren. Man kann die Daten einfach so schnell verarbeiten, wie sie reinkommen.

Beim experimentieren habe ich festgestellt, dass sich die Hardware-AES67-Sender in diesem Fall anders verhalten als die meisten VirtualSoundcards. Die RTP-Pakete der Hardware-Sender enthalten keine Zeitstempel-Angaben. Daher ist auch die Empfangspipeline leicht anders. Ich vermute, dass dieser Unterschied verschwinden würde, wenn wir PTP korrekt implementieren würden.

Basis-Empfangspipeline für Hardware-Sender

Eine Einfache GStreamer-Pipeline zum Empfang von AES67 von Hardware-Controllern schaut so aus:

gst-launch-1.0 udpsrc multicast-iface=enp0s25.2342 address=239.192.42.42 port=5004 !\
application/x-rtp, clock-rate=48000, channels=8 !\
rtpL24depay !\
audioconvert !\
wavenc !\
filesink location=/tmp/lala.wav

Als multicast-iface muss das Interface des ausführenden Rechners angegeben werden, auf welchem die Multicast-Pakete empfangen werden sollen. Insbesondere wenn das Mutlicast-Netz als VLAN ankommt, muss hier das korrekte VLAN-Interface benannt werden.

Als address muss die korrekte Multicast-Gruppe benannt werden. Diese wird beim Einrichten des AES67-Streams im Hardware-Controller bestimmt

Falls weniger als 8 Kanäle gesendet werden, muss channels=8 entsprechend angepasst werden.

Basis-Empfangspipeline für Software-Sender

Die beiden VirtualSoundcards die ich getestet habe, übermitteln in ihren RTP-Paketen Zeitstempel mit. In der GStreamer-Pipeline muss dann ein rtpjitterbuffer-Element hinzugefügt werden, welches GStreamer erlaubt den Netzwerk-Jitter auszugleichen:<code>gst-launch-1.0 udpsrc multicast-iface=enp0s25.2342 address=239.192.42.42 port=5004 !\ application/x-rtp, clock-rate=48000, channels=8 !\ rtpjitterbuffer latency=2000 !\ rtpL24depay !\ audioconvert !\ wavenc !\ filesink location=/tmp/lala.wav</code>

PTP

Es gibt eine fertige PTP-Implementierung für GStreamer, diese muss nur korrekt initialisiert und die Pipeline damit konfiguriert werden. Das geht nicht mit gst-launch-1.0 sondern nur mit einer Host-Applikation (z.B: in Python).

Links:

https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstPtpClock.html

https://coaxion.net/blog/2015/05/ptp-network-clock-support-in-gstreamer/

AES67 Loudness-Meter

Für das Loudness-Meter in der ACR benutzen wir eine Pipeline aus drei Komponenten:

Eine GStreamer-Pipeline zum empfangen und dekodieren des AES67-Datenstroms, gibt ein wav aller Kanäle aus

Ein ffmpeg41-Prozess, der das wav auf den ebur128-Filter wirft und dadurch die visuelle Anzeige der Loudness über die Zeit hinweg generiert, gibt raw-Video- und Audio in matroska verpackt aus

Ein ffplay-Prozess, der das Video anzeigt

Das sieht dann ungefähr so aus:<code>gst-launch-1.0 -q udpsrc multicast-iface=enp0s25.2342 address=239.192.42.42 port=5004 !\ application/x-rtp, clock-rate=48000, channels=2 !\ rtpL24depay !\ audioconvert !\ wavenc !\ fdsink |\ /opt/ffmpeg-4.1-64bit-static/ffmpeg -i - -filtercomplex ' [0] pan=2c|c0=c0|c1=c1, ebur128=video=1:target=-16:gauge=shortterm:scale=relative [v][a] ' -map '[v]' -map '[a]' \ -pixfmt yuv420p -c:v rawvideo \

c:a pcm_s16le -f matroska - |\

ffplay -v 0 -autoexit -</code>Angepasst werden muss hier ebenfalls das Interface und die Multicast-Gruppe. Ungetestet ist noch das Verhalten bei >2 Kanälen.