2013-04-04 2 views
9

私は、動的に生成されたオーディオを再生するためにストリーミングモードでAudioTrackを使用するアプリを持っています。アプリは入力に即座に反応する必要はないので、レイテンシーの問題はプログラムの面で気にならない。Androidのオーディオ待ち時間(AudioTrack)はどのようにして決まりますか?

問題は、私はオーディオの可能性として、「イン・シンク」のように正確である必要がアニメーションを持っているということであり、別のデバイスがAudioTrack停止しwrite()コールをブロックしたときの間の時間の異なる量を持っているようだと尋ねますより多くのデータとその音声がスピーカーから再生されるときに使用します。

私の現在の解決策は、私がここまでの道のりの大半を得ています。これまで渡したフレーム数をAudioTrackに数え、それをgetPlaybackHeadPosition()と比較してください。

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

しかし、getPlaybackHeadPosition()はそれはデバイスによって異なりを考慮していないようだという一部の待ち時間がまだあります:それは基本的にのように見えます。

AudioTrackのレイテンシをシステムにポーリングする方法はありますか?

答えて

1

ドライバの待ち時間を考慮してください。これを取得するには、隠された関数AudioManager.getOutputLatency(int)があります。

はこのようにそれを呼び出します。

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

私は約45取得 - 異なるデバイス上の50ミリ秒。 結果を計算に使用します。

+0

一部のデバイスでは 'MethodNotFoundException'がスローされることに注意してください – zella

0

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

ええと。もう一度やり直してください。その最小バッファサイズが頭の位置で考慮されていないのは変です。 –

0

これは重要なキーです。まず、Audiotrackクラスを拡張し、次にgetNativeFrameCountを使用して、ネイティブ側のレイテンシを近似する必要があります。

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

APIレベル19はと呼ばれるAudioTrackにメソッドを追加します。ドキュメントから:

オンデマンドでのタイムスタンプのポーリング。

初期ウォーミングアップ中またはルーティングまたはモード変更後にタイムスタンプを追跡する必要がある場合は、報告されたタイムスタンプにフレーム位置が進んでいることが示されるまで、またはタイムスタンプが使用できないことが明らかになるこのルート。

あなたは、関数のパラメータとしてAudioTimestampオブジェクトを指定し、それがナノ秒単位での「推定」のタイムスタンプと一緒に、最近「提示」フレーム位置に入力されます。ナノ秒の値は、SystemClock.uptimeMillis()によって返されるミリ秒の値に対応します。

getTimestamp()が実際に提示されたと考えるときに、その特定のフレームを書き込んだタイミングをAudioTrackに設定することで、待ち時間を判断できます。私は、この方法が上記の他の方法よりも正確であることを発見しました。

あなたは注意する必要があります。ドキュメントには、getTimeStamp()がすべてのプラットフォームまたはすべてのルートでサポートされていないと記載されています。 booleanの戻り値をチェックすることで、呼び出しが成功したかどうかを判断できます。私がテストしたデバイスでは、オーディオが提示され、その後の呼び出しがtrueを返すまで関数がfalseを返すことがわかりました。私は、AudioTrackSTREAM_MUSICモードでのみテストしました。あなたのマイレージは異なる場合があります。

関連する問題