2013-04-04 11 views
9

Mam aplikację, w której korzystam z trybu AudioTrack w trybie strumieniowym, aby odtwarzać dynamicznie generowany dźwięk. Aplikacja nie musi natychmiast reagować na dane wejściowe, więc problemy z opóźnieniami nie przeszkadzają mi po tej stronie programu.Jak określić opóźnienie dźwięku (ścieżka dźwiękowa) w systemie Android?

Problem polega na tym, że mam animację, która musi być tak dokładnie „in-sync” jak to możliwe, z dźwiękiem i wydaje się, że różne urządzenia mają różne ilości czasu od kiedy AudioTrack przystanki blokowanie połączeń write() i prosi więcej danych i kiedy dźwięk jest odtwarzany z głośnika.

Moje obecne rozwiązanie daje mi najwięcej do zrobienia - Liczę liczbę ramek, które dotychczas przekazałem do AudioTrack i porównuję je z getPlaybackHeadPosition(). To wygląda w zasadzie jak:

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

Istnieje jednak jeszcze pewne opóźnienie, które getPlaybackHeadPosition() nie wydaje się stanowić, że różni się od urządzenia.

Czy istnieje sposób na odpytanie systemu o opóźnienie ścieżki dźwiękowej?

Odpowiedz

1

Rozważ opóźnienie kierowcy. Istnieje ukryta funkcja AudioManager.getOutputLatency (int), aby to uzyskać.

nazwać to tak:

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){ 
} 

uzyskać około 45 - 50 ms na różnych urządzeniach. Skorzystaj z wyniku w swoich obliczeniach.

+0

Należy zauważyć, że na niektórych urządzeniach zgłasza 'MethodNotFoundException' – zella

0

Powinieneś wziąć pod uwagę bufor, który przekazałeś do stworzenia AudioTrack.

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 .. teraz, że znowu o tym myślę. Byłoby dziwne, gdyby ten minimalny rozmiar bufora nie był uwzględniany w pozycji głowy. –

0

Okay, to jest klucz. Najpierw należy rozszerzyć klasę Audiotrack, a następnie użyć wartości getNativeFrameCount, aby uzyskać przybliżenie opóźnienia związanego z rodzimą stroną.

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

Poziom API 19 dodaje metodę w postaci AudioTrack o nazwie getTimeStamp(). Z dokumentacji:

Ankieta dla sygnatury czasowej na żądanie.

Jeśli chcesz śledzić znaczniki czasu podczas początkowej rozgrzewki lub po zmianie trasy lub trybu, powinieneś okresowo żądać nowego znacznika czasu, dopóki raportowane znaczniki czasu nie wskażą, że pozycja ramki się zbliża, lub dopóki nie stanie się jasne, że znaczniki czasu są niedostępne dla ta trasa.

określić przedmiot AudioTimestamp jako parametr funkcji i będzie wypełnienie ostatnio „prezentowanej pozycji” rama wraz z jego „przybliżony” datownik w nanosekund. Wartość nanosekundy odpowiada wartości milisekundy zwróconej przez SystemClock.uptimeMillis().

Następnie można określić opóźnienie, określając, kiedy napisano tę konkretną ramkę do AudioTrack, a kiedy getTimestamp() myśli, że faktycznie przedstawił. Stwierdziłem, że ta metoda jest dokładniejsza niż inne metody wspomniane powyżej.

Musisz być jednak ostrożny. Dokumentacja mówi, że getTimeStamp() nie jest obsługiwany na wszystkich platformach lub wszystkich trasach. Możesz sprawdzić, czy wywołanie zakończyło się pomyślnie, zwracając wartość zwracaną przez boolean. Znalazłem przy testowanych przeze mnie urządzeniach, że funkcja zwraca wartość false, dopóki audio nie rozpocznie prezentacji, a następnie kolejne wywołania zwracają wartość true. Testowałem tylko z AudioTrack w trybie . Twój przebieg może się różnić.

Powiązane problemy