aes67

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).

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.

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.

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:

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

Warning: Sowohl die Lösung mit jitterbuffer als auch die ohne funktionieren nur, weil es uns eigentlich fast egal ist, mit wie viel Verzögerung das Audio-Signal bei uns ankommt. Für jeder Art von Live-Wiedergabe oder -Processing ist die Implementierung von PTP unumgänglich.

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).

Die GStreamer PTP-Clock konnte sich nicht mit dem Nexus syncen, daher haben wir den 35C3 mit der internen Free-Running Clock gefahren.

Links:

Da das Audio-Backup am Ende vor allem in Sync zum Video sein muss, wäre es vermutlich gut, es mit dem Video-Recording zu syncen.

13:52 <       MaZderMind > https://coaxion.net/blog/2014/12/improved-gstreamer-support-for-blackmagic-decklink-cards/
13:54 <       MaZderMind > man könnte voctomix über den reference-in der duo2 karten mit einer worldclock versehen
13:54 <       MaZderMind > vmtl. würde das sogar automatisch passieren, wenn wir da mal was dran stecken würden
13:55 <       MaZderMind > The clock of the hardware is now exposed to the pipeline as a GstClock and even if the pipeline chooses a different clock, the elements will slave their internal clock to the 
                           master clock of the pipeline and make sure that synchronization is even kept if the pipeline clock and the Decklink hardware clock are drifting apart. Thanks to GStreamer’s 
                           extensive synchronization model and all the 
13:55 <       MaZderMind > functionality that already exists in the GstClock class, this was much easier than it sounds.
13:56 <       MaZderMind > da die audio-backup-recorder auch eine decklink karte hatten würden die einfach die selbe clock bekommen und schon wäre alles schön in sync
13:56 <       MaZderMind > die decklink-karten können blackburst und trisync
13:57 <       MaZderMind > hhelenav Simpel ^
14:00 <       MaZderMind > jup, GstDecklinkClock ist verfügbar

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:

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 -y -nostdin -i - -filter_complex '
			[0] pan=2c|c0=c0|c1=c1, ebur128=video=1:target=-16:gauge=shortterm:scale=relative [v][a]
		' -map '[v]' -map '[a]' \
		-pix_fmt yuv420p -c:v rawvideo \
		-c:a pcm_s16le -f matroska - |\
			ffplay -v 0 -autoexit -exitonkeydown -exitonmousedown -window_title "ebur128 Loudness" -

Angepasst werden muss hier ebenfalls das Interface und die Multicast-Gruppe. Mit dem pan-Filter werden die beiden Kanäle aus den eingehenden 8 ausgewählt, die für die Loudness-Analyse verwendet werden. Um beispielsweise die Kanäle 4 und 5 (0123_45_67) benutzt werden, sieht der Filter so aus: pan=2c|c0=c4|c1=c5.

  • aes67.txt
  • Last modified: 2018/12/31 14:09
  • by mazdermind