Audiolatenzprobleme

8

In der Anwendung, die ich erstellen möchte, stehe ich vor technischen Hindernissen. Ich habe zwei Musiktitel in der Anwendung. Ein Benutzer importiert beispielsweise den Musikhintergrund als erste Spur. Der zweite Pfad ist eine Stimme, die vom Benutzer im Rhythmus des ersten vom Lautsprechergerät (oder Kopfhörer) wiedergegebenen Titels aufgezeichnet wird. In diesem Moment sind wir mit Latenz konfrontiert. Nach der Aufnahme und Wiedergabe in der App hört der Benutzer den Verlust der Synchronisation zwischen den Titeln, der aufgrund der Mikrofon- und Lautsprecherlatenzen auftritt.

Zunächst versuche ich, die Verzögerung durch Filterung des Eingangssignals zu erkennen. Ich benutze Androids AudioRecord-Klasse und die Methode read() . Diese Methode füllt mein kurzes Array mit Audiodaten. Ich habe festgestellt, dass die Anfangswerte dieses Arrays Nullen sind, also habe ich beschlossen, sie auszufiltern, bevor ich anfangen werde, sie in den Ausgabestrom zu schreiben. Also halte ich diese Nullen für eine "Aufwärm" -Latenz des Mikrofons. Ist dieser Ansatz richtig? Diese Operation liefert zwar einige Ergebnisse, löst das Problem jedoch nicht, und in diesem Stadium bin ich weit davon entfernt.

Aber der schlimmste Fall ist die Verzögerung zwischen dem Starten der Lautsprecher und dem Abspielen der Musik. Diese Verzögerung kann ich nicht filtern oder erkennen. Ich habe versucht, eine Kalibrierungsfunktion zu erstellen, die die Verzögerung zählt. Ich gebe einen Piepton über die Lautsprecher ab, und wenn ich anfange, es zu spielen, beginne ich auch, die Zeit zu messen. Dann beginne ich mit der Aufnahme und höre auf diesen Ton, der vom Mikrofon erkannt wird. Wenn ich diesen Ton in der App erkenne, höre ich auf, die Zeit zu messen. Ich wiederhole diesen Vorgang mehrmals, und der Endwert ist der Durchschnitt aus diesen Ergebnissen. So versuche ich die Latenz des Gerätes zu messen. Jetzt, wenn ich diesen Wert habe, kann ich einfach den zweiten Track rückwärts verschieben, um die Synchronisation beider Aufnahmen zu erreichen (ich werde einige Millisekunden der Aufnahme verlieren, aber ich überspringe diesen Fall, für den Moment gibt es einige Möglichkeiten, ihn zu beheben) . Ich dachte, dass dieser Ansatz das Problem lösen würde, aber es stellte sich heraus, dass dies nicht so einfach ist, wie ich dachte. Ich habe hier zwei Probleme gefunden:     1. Verzögerung während der Wiedergabe von zwei Spuren gleichzeitig     2. Zufällige Geräteaudiolatenz.

Der erste: Ich spiele zwei Tracks mit der AudioTrack-Klasse und führe die Methode play() so aus:

%Vor%

Dieser Code verursacht Verzögerungen bei der Wiedergabe von Tracks. Jetzt muss ich nicht einmal über Latenz beim Aufnehmen nachdenken; Ich kann nicht zwei Tracks gleichzeitig ohne Verzögerungen spielen. Ich habe das mit einer externen Audiodatei getestet (nicht in meiner App aufgenommen) - ich starte dieselbe Audiodatei mit dem obigen Code und sehe eine Verzögerung. Ich habe es auch mit der MediaPlayer-Klasse ausprobiert, und ich habe die gleichen Ergebnisse. In diesem Fall versuche ich sogar Tracks abzuspielen, wenn der Callback OnPreparedListener aufruft:

%Vor%

Und es hilft nicht. Ich weiß, dass es eine weitere von Android angebotene Klasse namens SoundPool gibt. Laut der Dokumentation kann es besser sein, Tracks gleichzeitig abzuspielen, aber ich kann es nicht verwenden, weil es nur kleine Audiodateien unterstützt und das kann mich nicht einschränken. Wie kann ich dieses Problem lösen? Wie kann ich genau zwei Tracks gleichzeitig spielen?

Die zweite: Die Audio-Latenz ist nicht deterministisch - manchmal ist sie kleiner und manchmal ist sie riesig und liegt nicht in meiner Hand. Die Latenz des Messgeräts kann also wieder helfen - das Problem kann nicht gelöst werden.

Zusammenfassend: Gibt es eine Lösung, die mir genaue Latenz pro Gerät (oder App-Session?) oder andere Trigger, die tatsächliche Verzögerung erkennen, geben kann, um die beste Synchronisation bei gleichzeitiger Wiedergabe von zwei Tracks zu bieten?

Vielen Dank im Voraus!

    
andrdev 08.02.2018, 14:09
quelle

2 Antworten

4

Das Synchronisieren von Audio für Karaoke-Apps ist schwierig. Das Hauptproblem, mit dem Sie konfrontiert sind, ist die variable Latenz im Ausgabestream.

Dies wird mit ziemlicher Sicherheit durch die "Warm-up" Latenz verursacht: die Zeit, die man braucht, um "Play" auf der Backing-Spur zu dem ersten Frame von Audiodaten zu schlagen, die vom Audiogerät gerendert werden (z.B. Kopfhörer). Dies kann große Abweichungen haben und ist schwer zu messen.

Die erste (und einfachste) Aufgabe ist es, MODE_STREAM zu verwenden, wenn Sie Ihre AudioTrack erstellen und sie mit bufferSizeInBytes der Daten vor dem Aufruf von play ( mehr hier ). Dies sollte zu einer niedrigeren, konsistenteren "Aufwärm" -Latenz führen.

Ein besserer Weg ist es, den Android NDK zu verwenden, um einen kontinuierlich laufenden Audio-Stream zu haben gibt nur Stille aus, bis Sie die Wiedergabe starten, und beginnt sofort mit dem Senden von Audiorahmen. Die einzige Latenz, die Sie hier haben, ist die kontinuierliche Ausgangslatenz .

Wenn Sie sich für diese Route entscheiden, sollten Sie sich die Oboebibliothek ansehen (vollständige Beschreibung: Ich gehöre zu die Autoren).

Um eine Ihrer spezifischen Fragen zu beantworten ...

Gibt es eine Möglichkeit, die Latenz des Audio-Ausgangsstroms programmatisch zu berechnen?

Ja. Der einfachste Weg, dies zu erklären, ist ein Codebeispiel (dies ist C ++ für die AAudio-API, aber das Prinzip ist dasselbe mit Java AudioTrack):

%Vor%

Vorbehalt: Diese Methode beruht auf genauen Zeitstempeln, die von der Audio-Hardware gemeldet werden. Ich weiß, das funktioniert auf Google Pixel-Geräten, habe aber Berichte gehört, dass es auf anderen Geräten nicht so genau ist, also YMMV.

    
donturner 13.02.2018 18:16
quelle
1

Die Androide MediaPlayer-Klasse ist notorisch langsam, um mit der Audiowiedergabe zu beginnen. Ich hatte ein Problem in einer App, die ich erstellt habe, wo es eine Verzögerung von mehr als einer Sekunde gab, um mit der Wiedergabe eines Audioclips zu beginnen. Ich habe es gelöst, indem ich zum ExoPlayer wechselte, was dazu führte, dass die Wiedergabe innerhalb von 100ms begann. Ich habe auch gelesen, dass ffmpeg sogar schneller startet als der ExoPlayer, aber ich habe es nicht benutzt, damit ich es kann Versprechen Sie nicht.

    
Jacob Applin 15.02.2018 20:34
quelle

Tags und Links