2013-04-04 10 views
9

Ich habe eine App, in der ich einen AudioTrack im Streaming-Modus verwende, um dynamisch generiertes Audio wiederzugeben. Die App muss nicht sofort auf Eingaben reagieren, so dass die Latenzprobleme mich für diese Seite des Programms nicht stören.Wie bestimmen Sie die Audio-Latenz (AudioTrack) auf Android?

Das Problem ist, dass ich eine Animation, die so genau ‚in-sync‘ wie möglich mit dem Audio sein muss und es scheint, dass verschiedene Geräte unterschiedliche Mengen an Zeit zwischen, wenn die AudioTrack stoppt die write() Anrufblockierung und fragt für mehr Daten und wenn dieses Audio vom Lautsprecher gespielt wird.

Meine aktuelle Lösung bringt mich am meisten dorthin - ich zähle die Anzahl der Frames, die ich bisher an die AudioTrack übergeben habe, und vergleiche sie mit . Es sieht im Grunde wie:

long currentTimeInFrames = 0; 
while(playingAudio) { 
    currentTimeInFrames += numberOfFramesToWrite; 
    long delayInFrames = (currentTimeInFrames - audioTrack.getPlaybackHeadPosition()); 
    audioTrack.write(frameBuffer,0,sampleSize); 
    doAnimationAfterDelay(delayInFrames); 
} 

Allerdings gibt es noch einige Latenz dass getPlaybackHeadPosition() nicht zu berücksichtigen, scheint für die von der Vorrichtung variiert.

Gibt es eine Möglichkeit, das System auf die Latenz von AudioTrack abzufragen?

Antwort

1

Betrachten Sie die Latenz des Treibers. Es gibt versteckte Funktion AudioManager.getOutputLatency (int), um dies zu bekommen.

Nennen Sie es wie folgt aus:

AudioManager am = (AudioManager)getSystemService(Context.AUDIO_SERVICE); 
try{ 
    Method m = am.getClass().getMethod("getOutputLatency", int.class); 
    latency = (Integer)m.invoke(am, AudioManager.STREAM_MUSIC); 
}catch(Exception e){ 
} 

ich etwa 45 bis 50 ms auf verschiedenen Geräten. Verwenden Sie das Ergebnis in Ihren Berechnungen.

+0

Beachten Sie, dass auf einigen Geräten "MethodNotFoundException" ausgelöst wird – zella

0

Sie sollten die Puffergröße berücksichtigen, die Sie an die AudioTrack-Erstellung übergeben haben.

final int minBufSize = AudioTrack.getMinBufferSize(Application.PLAYRATE, 
AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT); 

out=new AudioTrack(AudioManager.STREAM_MUSIC, Application.PLAYRATE, 
AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT, minBufSize, 
AudioTrack.MODE_STREAM); 

extraLatencyFrames = minBufSize/4; 
+0

Hmm .. jetzt, dass ich wieder daran denke. Es wäre komisch, wenn diese minimale Puffergröße in der Kopfposition nicht berücksichtigt würde. –

0

Okay, das ist der Schlüssel. Zuerst müssen Sie die Audiotrack-Klasse erweitern und dann mit getNativeFrameCount eine Annäherung an die Latenzzeit der nativen Seite der Dinge erreichen.

class MyAudioTrack extends AudioTrack 
{ 
    public MyAudioTrack(int streamType, int sampleRateInHz, int channelConfig, 
      int audioFormat, int bufferSizeInBytes, int mode) 
      throws IllegalArgumentException { 
     super(streamType, sampleRateInHz, channelConfig, audioFormat, 
       bufferSizeInBytes, mode); 
     System.out.println("Native framecount "+getNativeFrameCount()); 
    } 
    public int getFrameCount() 
    { 
     return getNativeFrameCount(); 
    } 
} 
1

Die API-Ebene 19 fügt eine Methode in AudioTrack mit der Bezeichnung getTimeStamp() hinzu. Aus der Dokumentation:

Abfrage für einen Zeitstempel auf Anfrage.

Wenn Sie Zeitstempel während des ersten Aufwärmens oder nach einem Routing oder Moduswechsel verfolgen möchten, sollten Sie regelmäßig einen neuen Zeitstempel anfordern, bis die gemeldeten Zeitstempel anzeigen, dass die Rahmenposition vorrückt oder bis Zeitstempel nicht mehr verfügbar sind diese Route.

Sie geben ein AudioTimestamp Objekt als Parameter der Funktion und es wird zusammen mit seinen „geschätzten“ Zeitstempeln in Nanosekunden in der zuletzt „präsentiert“ Rahmenposition zu füllen. Der Wert für die Nanosekunde entspricht dem Millisekundenwert, der von SystemClock.uptimeMillis() zurückgegeben wird.

Sie können dann die Latenz ermitteln, indem Sie herausfinden, wann Sie diesen bestimmten Rahmen zu AudioTrack vs geschrieben haben, wenn getTimestamp() denkt, dass es tatsächlich präsentiert. Ich habe festgestellt, dass diese Methode genauer ist als die anderen oben genannten Methoden.

Sie müssen jedoch vorsichtig sein. Die Dokumentation sagt getTimeStamp() wird nicht auf allen Plattformen oder allen Routen unterstützt. Sie können feststellen, ob der Aufruf erfolgreich war, indem Sie den Rückgabewert boolean überprüfen. Ich habe mit den Geräten gefunden, die ich getestet habe, dass die Funktion false zurückgibt, bis Audio beginnt, darzustellen, und nachfolgende Aufrufe dann True zurückgeben. Ich habe nur mit AudioTrack in STREAM_MUSIC Modus getestet. Ihre Laufleistung kann variieren.