我通过 FileInputStream > BufferedInputStream > DataInputStream 方法加载文件并将字节送入 AudioTrack.write() 来在我的 Android 手机上播放 WAV。音频播放良好,当它播放时,我可以轻松地动态调整采样率、音量等,性能也不错。但是,轨道开始播放大约需要两秒。我知道 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 - 240 毫秒,考虑到此设备上的最小缓冲区大小为 9600 (9600/44100),这是有意义的。我在 Internet 上无数次搜索中看到过此消息,但它通常似乎与根本不播放音频或跳过音频有关。就我而言,这只是一个延迟的开始。
我在高优先级线程中运行所有代码。这是我正在做的事情的截断但功能的版本。这是我的播放类中的线程回调。同样,这有效(现在只播放 16 位、44.1kHz 的立体声文件),它只需要很长时间才能开始,并且每次都有 obtainBuffer/delayed write 消息。
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/