AudioTrack:通过WiFi播放声音

Tha*_*e90 10 audio android

我的应用程序中有一个AudioTrack,设置为Stream模式.我想写一些通过无线连接收到的音频.AudioTrack声明如下:

mPlayer = new AudioTrack(STREAM_TYPE,
                         FREQUENCY,
                         CHANNEL_CONFIG_OUT,
                         AUDIO_ENCODING,
                         PLAYER_CAPACITY,
                         PLAY_MODE);
Run Code Online (Sandbox Code Playgroud)

参数定义如下:

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;
Run Code Online (Sandbox Code Playgroud)

但是,当我使用write()将数据写入AudioTrack时,它将播放不稳定...调用

byte[] audio = packet.getData();
mPlayer.write(audio, 0, audio.length);
Run Code Online (Sandbox Code Playgroud)

只要通过网络连接接收到数据包就会生成.有没有人知道为什么它听起来不稳定?也许它与WiFi连接本身有关?我不这么认为,因为当我通过UDP将数据从Android手机发送到另一个来源时,声音听起来并不可怕.声音听起来完整而且根本没有波动......所以有人知道为什么会发生这种情况吗?

ASh*_*lly 7

您知道接收的每秒字节数,数据包之间的平均时间比较以及数据包之间的最大时间吗?如果没有,你可以添加代码来计算吗?

需要首先平均8000个样本/秒*2字节/采样= 每秒16000个字节,以保持填充流.

传入数据包之间的间隔超过2048字节/(16000字节/秒)= 128毫秒将导致您的流干运行并且音频断断续续.

防止它的一种方法是增加缓冲区大小(PLAYER_CAPACITY).较大的缓冲区将能够更好地处理传入数据包大小和速率的变化.额外稳定性的成本是在等待缓冲区初始填充时开始播放的较大延迟.


Tha*_*e90 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();
Run Code Online (Sandbox Code Playgroud)

只是有点匿名Thread,现在写作...

有人知道如何解决这个问题吗?


编辑:

经过一些进一步的检查和调试后,我注意到这是gainBuffer的一个问题.我查看了AudioTrackjava代码和AudioTrackC++代码.我注意到它只能出现在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;
}
Run Code Online (Sandbox Code Playgroud)

我注意到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");
Run Code Online (Sandbox Code Playgroud)

但是,我得到以下结果: Logcat Image http://img810.imageshack.us/img810/3453/logcatimage.png

这些表明滞后最初发生在开始,之后AudioTrack不断获取数据...我真的需要修复这个...