AudioTrack:通过WiFi播放声音

时间:2011-03-14 11:25:44

标签: android audio

我的应用程序中有一个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手机发送到另一个来源时,声音听起来并不可怕。声音听起来完整而且根本没有波动......所以有人知道为什么会发生这种情况吗?

2 个答案:

答案 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 AudioTrackC++ 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不断获取数据......我真的需要修复这个......