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

Links:

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. Ungetestet ist noch das Verhalten bei >2 Kanälen.

  • aes67.1545218704.txt.gz
  • Last modified: 2018/12/19 12:25
  • by mazdermind