Ton mit einer Uhr synchronisieren, die nur einmal pro Sekunde tickt
Von JH
Wenn du ein Video über DLNA streamst, steckt der Ton im Stream und kommt aus dem Gerät, an das du sendest. Meistens ist das genau richtig. Manchmal möchtest du den Ton aber woanders haben: das Bild auf einem Bildschirm am anderen Ende des Zimmers und den Ton auf den Kopfhörern, damit du nicht das ganze Haus weckst. Oder einen Film direkt vor den Augen auf der Brille, ohne dass der Raum mithört. In beiden Fällen muss der Ton aus dem PC kommen, nicht aus dem Empfangsgerät.
GogglePlayer, meine App fürs Streaming über DLNA, kann das. Sie lässt das Video weiter ans Wiedergabegerät gehen und spielt den Ton stattdessen auf dem PC ab, über die Kopfhörerbuchse, einen USB-DAC, Bluetooth-Ohrhörer usw. Ich habe die App für Videobrillen entwickelt, aber als Wiedergabegerät funktioniert jeder DLNA-Empfänger im Netzwerk. Für die Trennung reicht ein Schalter. Dafür zu sorgen, dass es nicht furchtbar klingt, war der Großteil der Arbeit.
Das Problem: Nach der Trennung hast du zwei Uhren. Das Wiedergabegerät spielt das Video nach seiner Uhr ab, der PC den Ton nach seiner eigenen. Nichts hält die beiden zusammen. Ist die Abweichung groß genug, bewegen sich die Lippen einen Moment, bevor der Satz zu hören ist. Den ganzen Film lang. So ein Fehler, den du nicht mehr überhören kannst.
Einfach nach der Videoposition fragen reicht nicht
Naheliegend wäre, das Wiedergabegerät nach seiner Position in der Datei zu fragen und den Ton daran auszurichten. DLNA hat genau dafür einen Aufruf. Das Problem ist, dass viele Wiedergabegeräte nur ganze Sekunden zurückgeben: HH:MM:SS ohne Nachkommastellen. Bei der Tonsynchronisierung fallen schon etwa 40 ms auf. Eine sekundengenaue Antwort ist dafür unbrauchbar. Manche Geräte antworten bei einem Livestream gar nicht sinnvoll und melden die ganze Zeit null. Die Brille, mit der ich getestet habe, tat beides. So habe ich gelernt, der Anzeige nicht mehr zu vertrauen.
Der Wert führt nicht weiter. Die Übergänge schon.
Wenn die gemeldete Sekunde von 7 auf 8 springt, passiert das zu einem konkreten Zeitpunkt. Genau dann liegt die tatsächliche Position bei 8,000. Durch das Runden gehen die Nachkommastellen verloren, aber im Zeitpunkt des Zahlenwechsels stecken sie noch. Fragst du oft genug ab, um den Wechsel zu erfassen, bekommst du ein präzises Wertepaar: Dieser Zeitpunkt auf der Systemuhr entspricht genau dieser Medienzeit. Ein paar solche Paare reichen für die einzige Zahl, die du brauchst: den Zeitpunkt auf der Systemuhr, zu dem die Datei bei null war. Von da an ist die Position einfach die aktuelle Zeit minus dieser Referenzzeit, zwischen den Abfragen lokal auf die Millisekunde berechnet.
Das ist dasselbe Prinzip wie Taktrückgewinnung oder eine Software-PLL. Das Signal ist grob, aber sein Timing ist präzise. Also richtest du dich nach dem Timing und lässt den Rest weg. Etwas Glättung fängt Schwankungen bei den Abfragen ab. Der Kern der Idee sind aber die Übergänge.
Eine genaue Position reicht noch nicht
Die beiden Uhren laufen nicht gleich schnell. Eine PC-Soundkarte und der interne Takt eines Wiedergabegeräts haben beide nominell 44,1 kHz, so wie zwei billige Armbanduhren beide sechzig Sekunden pro Minute zählen: ungefähr gleich, aber nicht exakt. Der Fehler bleibt konstant und geht in dieselbe Richtung, summiert sich also. 0,5 % klingt nach nichts, bis daraus über einen zweistündigen Film 36 s Abweichung werden. Beim Vorspann noch synchron, im dritten Akt längst auseinander.
Du könntest ständig neu ausrichten: Abweichung erkennen, Ton zurücksetzen, wiederholen. Das funktioniert und klingt schlecht, weil jeder Sprung hörbar ist. Alle paar Minuten ein Knacken oder Stottern. Statt langsam auseinanderzulaufen, setzt der Ton jetzt alle paar Minuten kurz aus.
Ohne diese hörbaren Sprünge geht es, wenn du die Geschwindigkeit statt der Position korrigierst. Läuft der Ton etwas zu schnell, spiel ihn etwas langsamer ab. Durch Resampling passt du die Wiedergabegeschwindigkeit ganz leicht an und gleichst so die Taktabweichung aus. Laufend und behutsam gemacht ist das unhörbar, denn eine Tonhöhenänderung von 0,3 % hören die meisten von uns nicht, wenn sie nicht gezielt darauf achten. Und die Abweichung wächst nicht mit der Zeit, weil du die Geschwindigkeiten angleichst, statt erst den entstandenen Abstand einzuholen.
Die Taktabweichung kennst du vorher nicht. Sie hängt von der konkreten Hardware an beiden Enden ab. Du ermittelst sie also, während die Datei läuft, und misst weiter, weil ein Netzwerkaussetzer das Ziel verschieben kann. Das ist ein Regelungsproblem.
Der Regelkreis, der pendelt, und der, der hält
Ein Regelungsproblem löst man mit einer Rückkopplungsschleife: den Fehler zwischen Ton und Bild messen, an einen Regler geben und diesen die Wiedergabegeschwindigkeit einstellen lassen. Ein positiver Fehler bremst, ein negativer beschleunigt. Ein gewöhnlicher PI-Regler, wie er auch eine Temperatur auf einem bestimmten Wert hält, nur hier auf den Abstand angesetzt, um ihn auf null zu bringen.
Der erste, den ich gebaut habe, funktionierte und war unbrauchbar. Er fand die richtige Geschwindigkeit, schoss darüber hinaus, korrigierte zu heftig zurück, schoss in die andere Richtung und pendelte endlos weiter, von einer Begrenzung zur anderen. In einem hörbaren Zyklus von ungefähr 100 s: Der Ton driftete weg, wurde zurückgezogen, schoss vorbei, immer wieder. Ein korrekter Regelkreis, der das Problem hörbar verschlimmert. Da ist der Tag gelaufen.
Die Ursache: Die Regelstrecke ist selbst schon ein Integrator. Geschwindigkeit summiert sich zu Position. Ein Integralregler auf einer integrierenden Strecke schwingt. Die Lösung ist weniger Nachdruck. Du stimmst ihn so träge ab, dass er sich der konstanten Taktabweichung langsam nähert und dort bleibt, statt aufs Ziel zuzurennen und vorbeizuschießen. Er braucht länger, um einzurasten, beim ersten Start fast eine Minute. Das sah nach einem Rückschritt aus, bis er einmal eingerastet war und dann zwei Stunden lang völlig stabil blieb.
Zwei Details haben sich ausgezahlt. Der Regelkreis behält beim Spulen, was er gelernt hat. Ein Sprung kostet also nicht noch einmal eine Minute Einregelzeit. Und die ermittelte Taktabweichung wird pro Gerät gespeichert. Die nächste Datei mit demselben Wiedergabegerät und denselben Kopfhörern startet dadurch schon nah am richtigen Wert und rastet innerhalb von Sekunden ein. Unterdämpft pendelt, überdämpft hält. Der Großteil der Arbeit war der Weg vom einen zum anderen.
Wo Schluss ist
Die Regelung erfasst die konstante Abweichung zwischen zwei Uhren und gleicht sie aus. In einem ordentlichen Netzwerk stellst du den Bild-Ton-Versatz einmal ein und vergisst, dass da überhaupt etwas arbeitet. Kleine Abweichungen korrigiert sie über die Geschwindigkeit, wo du es nicht hörst. Einen Sprung, der für eine sanfte Korrektur zu groß ist, etwa nach erneutem Puffern wegen einer Netzwerkstörung, holt sie nicht langsam auf: Oberhalb eines Grenzwerts hört sie mit der Feinregelung auf und setzt den Ton selbstständig in einem Schritt zurück. Einen einzelnen Aussetzer fängt das ab. Eine Verbindung, die ständig stockt, aber nicht. Dann folgt ein Sprung auf den nächsten, und kein Regelkreis kommt gegen eine ausgelastete Verbindung an. Mit Resync kannst du Bild und Ton manuell neu synchronisieren; nach einem Aussetzer erscheint dafür ein Hinweis. Ab einem gewissen Punkt hilft aber nur noch ein Kabel.
Das ist alles. Aus einer Anzeige in ganzen Sekunden wird durch das Messen ihrer Übergänge eine gleichmäßig laufende Uhr. Und ein bewusst träger Regelkreis gleicht die Geschwindigkeiten zweier Uhren an, statt dem Abstand zwischen ihnen hinterherzulaufen. GogglePlayer erledigt das im Hintergrund, egal ob du auf einen Bildschirm am anderen Ende des Zimmers oder auf eine Brille streamst.