How do you determine the audio latency (AudioTrack) on Android?

微笑、不失礼 提交于 2019-11-30 13:57:47

问题


I have an app in which I use an AudioTrack in streaming mode to play dynamically generated audio. The app doesn't have to respond instantaneously to inputs, so the latency issues don't bother me for that side of the program.

The problem is that I have an animation that needs to be as precisely 'in-sync' as possible with the audio and it seems that different devices have different amounts of time between when the AudioTrack stops blocking the write() call and asks for more data, and when that audio is played from the speaker.

My current solution gets me most of the way there -- I count the number of frames I've passed in to the AudioTrack so far, and compare it to getPlaybackHeadPosition(). It looks basically like:

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

However, there's still some latency that getPlaybackHeadPosition() doesn't seem to account for that varies by device.

Is there a way to poll the system for the latency of the AudioTrack?


回答1:


Consider driver's latency. There's hidden function AudioManager.getOutputLatency(int) to get this.

Call it like this:

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

I get about 45 - 50 ms on different devices. Use the result in your calculations.




回答2:


API level 19 adds a method in AudioTrack called getTimeStamp(). From the documentation:

Poll for a timestamp on demand.

If you need to track timestamps during initial warmup or after a routing or mode change, you should request a new timestamp periodically until the reported timestamps show that the frame position is advancing, or until it becomes clear that timestamps are unavailable for this route.

You specify an AudioTimestamp object as the function's parameter and it will fill in the most recently "presented" frame position along with its "estimated" timestamp in nanoseconds. The nanosecond value corresponds to the millisecond value returned by SystemClock.uptimeMillis().

You can then determine the latency by figuring out when you wrote that particular frame to AudioTrack vs. when getTimestamp() thinks it actually presented. I have found this method to be more accurate than the other methods mentioned above.

You have to be careful though. The documentation says getTimeStamp() is not supported on all platforms or all routes. You can determine if the call was successful by checking the boolean return value. I have found with the devices I have tested that the function returns false until audio begins presenting, and then subsequent calls return true. I have only tested with AudioTrack in STREAM_MUSIC mode. Your mileage may vary.




回答3:


You should take into account the buffersize you passed along into the AudioTrack creation.

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;



回答4:


Okay, this is the key. First you need to extend the Audiotrack class, and then use the getNativeFrameCount to have an approximation on the latency involved in the native side of things.

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();
    }
}


来源:https://stackoverflow.com/questions/15802659/how-do-you-determine-the-audio-latency-audiotrack-on-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!