我正在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/