AudioTrack滞后:obtainBuffer超时

我通过加载文件并通过FileInputStream> BufferedInputStream> DataInputStream方法将字节传送到AudioTrack.write()来在Android手机上播放WAV。 audio播放良好,当它是,我可以很容易地调整采样率,音量等性能不错。 然而,一首曲子开始播放大约需要两秒钟的时间。 我知道AudioTrack有一个不可避免的延迟,但这是荒谬的。 每当我弹奏曲目,我都会得到这个:

03-13 14:55:57.100: WARN/AudioTrack(3454): obtainBuffer timed out (is the CPU pegged?) 0x2e9348 user=00000960, server=00000000 03-13 14:55:57.340: WARN/AudioFlinger(72): write blocked for 233 msecs, 9 delayed writes, thread 0xba28 

我注意到,从打开手机的时间开始,每次播放音轨时,延迟的写入次数就会增加一次 – 即使在多次会话中也是如此。 块时间始终为230 – 240ms,考虑到此设备(9600/44100)上的最小缓冲区大小为9600,这是有意义的。 我在互联网上的无数次search中看到了这个消息,但通常似乎与播放audio或跳过audio有关。 就我而言,这只是一个延迟的开始。

我在高优先级的线程中运行我的所有代码。 这是我正在做的一个截断的function版本。 这是我的回放类中的线程callback。 再次,这个工作(现在只播放16位,44.1kHz,立体声文件),它只是需要永远启动,并获得缓冲区/延迟写入消息每一次。

 public void run() { // Load file FileInputStream mFileInputStream; try { // mFile is instance of custom file class -- this is correct, // so don't sweat this line mFileInputStream = new FileInputStream(mFile.path()); } catch (FileNotFoundException e) { // log } BufferedInputStream mBufferedInputStream = new BufferedInputStream(mFileInputStream, mBufferLength); DataInputStream mDataInputStream = new DataInputStream(mBufferedInputStream); // Skip header try { if (mDataInputStream.available() > 44) { mDataInputStream.skipBytes(44); } } catch (IOException e) { // log } // Initialize device mAudioTrack = new AudioTrack( AudioManager.STREAM_MUSIC, ConfigManager.SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT, ConfigManager.AUDIO_BUFFER_LENGTH, AudioTrack.MODE_STREAM ); mAudioTrack.play(); // Initialize buffer byte[] mByteArray = new byte[mBufferLength]; int mBytesToWrite = 0; int mBytesWritten = 0; // Loop to keep thread running while (mRun) { // This flag is turned on when the user presses "play" while (mPlaying) { try { // Check if data is available if (mDataInputStream.available() > 0) { // Read data from file and write to audio device mBytesToWrite = mDataInputStream.read(mByteArray, 0, mBufferLength); mBytesWritten += mAudioTrack.write(mByteArray, 0, mBytesToWrite); } } catch (IOException e){ // log } } } } 

如果我能经过人为的长时间延迟,我可以很容易地通过在稍后可预测的位置(即,当我开始播放文件时跳过最小缓冲区长度)开始我的写入来处理inheritance延迟。

Solutions Collecting From Web of "AudioTrack滞后:obtainBuffer超时"

我遇到了类似的问题,虽然我正在使用RandomAccessFile而不是BufferedInputStream来读取PCM数据。 问题是文件I / O太慢了。 我怀疑即使在缓冲stream的情况下也会遇到这个问题,因为I / O仍然在audio处理的同一线程上进行。

解决scheme是有两个线程:从文件读取缓冲区并将其排入内存的线程,以及从该队列读取并写入audio硬件的另一个线程。 我用了一个ConcurrentLinkedQueue来完成这个任务。

我使用相同的技术进行录制,使用AudioRecord,但方向相反。 关键是将文件I / O放在一个单独的线程上。

晚了一些回答这个问题,但万一它有助于任何人在未来 – 我遇到了这个问题的代码非常类似于问题中的代码,其中AudioTrack创build和设置为播放,但不写立即。

我发现,在开始写入之前立即创buildAudioTrack会使延迟消失。 出于某种原因,AudioTrack似乎不喜欢坐在一个空的缓冲区。

就上面的代码而言,你会想要做类似的事情

 mAudioTrack=null; while (mRun) { // This flag is turned on when the user presses "play" while (mPlaying) { try { if (mAudioTrack==null) { mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, ConfigManager.SAMPLE_RATE,AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT,ConfigManager.AUDIO_BUFFER_LENGTH,AudioTrack.MODE_STREAM); mAudioTrack.play(); } // Rest of the playback code here } } mAudioTrack=null; }