我正在Android手机上播放WAV,方法是加载文件,然后通过FileInputStream> BufferedInputStream> DataInputStream方法将字节输入到AudioTrack.write()中。音频可以很好地播放,当它播放时,我可以轻松地以出色的性能即时调整采样率,音量等。但是,开始播放轨道大约需要整整两秒钟。我知道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

我注意到,从打开手机开始,每次播放轨道时(甚至跨多个 session ),延迟的写入计数都会增加一。块时间始终为230-240ms,考虑到此设备上的最小缓冲区大小为9600(9600/44100),这是有道理的。我在Internet上进行了无数次搜索时都看到了此消息,但通常似乎与根本不播放音频或跳过音频有关。就我而言,这只是一个延迟的开始。

我正在高优先级线程中运行所有代码。这是我正在做的功能截断的版本。这是我的回放类中的线程回调。再次,这是可行的(现在仅播放16位,44.1kHz,立体声文件),只是永久性地启动,并且每次都有该getBuffer/delayed写消息。
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
            }
        }
    }
}

如果可以克服人为的长时间延迟,则可以通过在较晚的可预测位置开始写操作来轻松地处理继承延迟(即,当我开始播放文件时跳过最小缓冲区长度)。

最佳答案

我遇到了一个类似的问题,尽管我使用的是RandomAccessFile而不是BufferedInputStream来读取PCM数据。问题是文件I/O太慢。我怀疑即使使用缓冲流,您也会遇到此问题,因为I/O仍在与音频处理相同的线程上进行。

解决方案是有两个线程:一个从文件读取缓冲区并将它们排队到内存中的线程,另一个从该队列读取并写入音频硬件的线程。我使用了ConcurrentLinkedQueue来完成此任务。

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

关于android - AudioTrack滞后: obtainBuffer timed out,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5293025/

10-12 02:33