我正在我的Android手机上播放WAV,方法是加载文件并通过FileInputStream>将字节输入AudioTrack.write()。 BufferedInputStream> DataInputStream方法。音频播放效果很好,如果是,我可以轻松调整采样率,音量等,性能良好。然而,一首曲目开始播放大约需要两秒钟。我知道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(9600/44100),这是有意义的。我在互联网上的无数次搜索中看到了这个消息,但它通常似乎与不播放音频或跳过音频有关。就我而言,这只是一个延迟的开始。
我正在高优先级线程中运行所有代码。这是我正在做的截断但功能正常的版本。这是我的播放类中的线程回调。再次,这是有效的(现在只播放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
}
}
}
}
如果我能够超越人为的长时滞,我可以通过在稍后的可预测位置开始写入来轻松处理继承延迟(即,当我开始播放文件时跳过最小缓冲区长度)。
答案 0 :(得分:2)
我遇到了类似的问题,虽然我使用RandomAccessFile而不是BufferedInputStream来读取PCM数据。问题是文件I / O太慢了。我怀疑即使使用缓冲流也会出现此问题,因为I / O仍然在与音频处理相同的线程上进行。
解决方案是拥有两个线程:一个从文件读取缓冲区并将它们排入内存的线程,另一个线程从该队列读取并写入音频硬件。我使用了ConcurrentLinkedQueue来实现这一目标。
我使用相同的技术进行录音,使用AudioRecord,但反方向。关键是将文件I / O放在一个单独的线程上。
答案 1 :(得分:1)
派对回答这个问题有点晚了,但万一它会帮助将来的任何人 - 我遇到了这个问题的代码非常类似于问题中的代码,其中AudioTrack被创建并设置为播放,但是不是立刻写的。
我发现在开始写入之前立即创建AudioTrack会导致延迟消失。出于某种原因,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;
}