我的应用程序中有一个AudioTrack,设置为Stream模式。我想写一些通过无线连接收到的音频。 AudioTrack声明如下:
mPlayer = new AudioTrack(STREAM_TYPE,
FREQUENCY,
CHANNEL_CONFIG_OUT,
AUDIO_ENCODING,
PLAYER_CAPACITY,
PLAY_MODE);
参数定义如下:
private static final int FREQUENCY = 8000,
CHANNEL_CONFIG_OUT = AudioFormat.CHANNEL_OUT_MONO,
AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT,
PLAYER_CAPACITY = 2048,
STREAM_TYPE = AudioManager.STREAM_MUSIC,
PLAY_MODE = AudioTrack.MODE_STREAM;
然而,当我使用write()将数据写入AudioTrack时,它将播放不稳定...通话
byte[] audio = packet.getData();
mPlayer.write(audio, 0, audio.length);
只要通过网络连接接收到数据包,就会生成。有没有人知道为什么它听起来不稳定?也许它与WiFi连接本身有关?我不这么认为,因为当我通过UDP将数据从Android手机发送到另一个来源时,声音听起来并不可怕。声音听起来完整而且根本没有波动......所以有人知道为什么会发生这种情况吗?
答案 0 :(得分:7)
您知道接收的每秒字节数,数据包之间的平均时间比较以及数据包之间的最长时间吗?如果没有,你可以添加代码来计算吗?
您需要平均8000个样本/秒* 2个字节/样本= 每秒16,000个字节,以便保持流的填充。
传入数据包之间的间隔超过2048字节/(16000字节/秒)= 128毫秒将导致您的数据流干涸,音频断断续续。
防止它的一种方法是增加缓冲区大小(PLAYER_CAPACITY)。较大的缓冲区将能够更好地处理传入数据包大小和速率的变化。额外稳定性的成本是在等待缓冲区最初填充时开始播放的较大延迟。
答案 1 :(得分:5)
我已将mPlayer.write(audio, 0, audio.length);
置于其自己的Thread
中,从而部分解决了这个问题。这确实消除了一些不稳定因素(由于写入是一个阻塞调用的事实),但是在一个好的秒或2之后它仍然听起来不稳定。它仍然有2-3秒的显着延迟。
new Thread(){
public void run(){
byte[] audio = packet.getData();
mPlayer.write(audio, 0, audio.length);
}
}.start();
只是一个匿名的Thread
现在正在写作......
有人知道如何解决这个问题吗?
编辑:
经过一些进一步的检查和调试后,我注意到这是一个与gainBuffer有关的问题。 我查看了java code of the AudioTrack和C++ code of AudioTrack我注意到它只能出现在C ++代码中。
if (__builtin_expect(result!=NO_ERROR, false)) {
LOGW( "obtainBuffer timed out (is the CPU pegged?) "
"user=%08x, server=%08x", u, s);
mAudioTrack->start(); // FIXME: Wake up audioflinger
timeout = 1;
}
我注意到这段代码中有一个FIXME
。 :其中但无论如何,任何人都可以解释这个C ++代码是如何工作的吗?我有过一些经验,但它从来没有这么复杂......
编辑2:
我现在尝试了一些不同,不同之处在于我缓冲了我收到的数据,然后当缓冲区充满了一些数据时,它被写入播放器。然而,玩家继续消耗几个周期,然后obtainBuffer timed out (is the CPU pegged?)
警告开始,并且没有任何数据写入玩家,直到它开始恢复生命......之后,它将继续将数据写入其中,直到清空缓冲区为止。
另一个细微差别是我现在将文件流式传输到播放器。也就是说,以块的形式读取它,将这些块写入缓冲区。这模拟了通过wifi接收的包裹......
我开始怀疑这是否只是Android的操作系统问题,而且我不能自己解决这个问题......有人对此有任何想法吗?
编辑3:
我做了更多测试,但这对我没有任何帮助。这个测试告诉我,当我第一次尝试写入AudioTrack时,我只会遇到延迟。这需要1到3秒才能完成。我通过使用以下代码来完成此操作:
long beforeTime = Utilities.getCurrentTimeMillis(), afterTime = 0;
mPlayer.write(data, 0, data.length);
afterTime = Utilities.getCurrentTimeMillis();
Log.e("WriteToPlayerThread", "Writing a package took " + (afterTime - beforeTime) + " milliseconds");
但是,我得到以下结果: Logcat Image http://img810.imageshack.us/img810/3453/logcatimage.png
这些表明滞后最初发生在开始,之后AudioTrack不断获取数据......我真的需要修复这个......