通过UDP数据包延迟音频提交

时间:2013-04-04 14:41:18

标签: android audio udp

我正在开发一个传输音频的应用程序。我有两个服务正在运行,一个用于接收,一个用于发送。发件人的重要内容如下:

            final DatagramSocket dSocket = new DatagramSocket();

            android.os.Process
                    .setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);

            Log.d(TAG, "Thread starting...");
            int buffersize = AudioRecord.getMinBufferSize(11025,
                    AudioFormat.CHANNEL_CONFIGURATION_MONO,
                    AudioFormat.ENCODING_PCM_16BIT);

            AudioRecord arec = new AudioRecord(
                    MediaRecorder.AudioSource.MIC, 11025,
                    AudioFormat.CHANNEL_CONFIGURATION_MONO,
                    AudioFormat.ENCODING_PCM_16BIT, buffersize);

            byte[] buffer = new byte[buffersize];
            Log.d(TAG, "Starting to record, buffersize=" + buffersize);
            arec.startRecording();

            while (isRunning && !isInterrupted()) {

                try {
                    Log.d(TAG, "Recording..");
                    arec.read(buffer, 0, buffersize);
                    DatagramPacket dPacket = new DatagramPacket(buffer,
                            buffersize);

                    for (Peer cur : mPeers) {
                        if(cur.isSelf) continue;

                        dPacket.setAddress(InetAddress
                                .getByName(cur.IP_ADDRESS));
                        dPacket.setPort(Config.UDP_PORT);
                        dSocket.send(dPacket);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

此代码可以工作并提交音频数据包。

接收器服务如下所示:

            // DatagramSocket dSocket = new DatagramSocket();
            DatagramChannel dChannel = DatagramChannel.open();
            DatagramSocket dSocket = dChannel.socket();

            dSocket.setReuseAddress(true);
            dSocket.setSoTimeout(2000);
            dSocket.bind(new InetSocketAddress(Config.UDP_PORT));

            Log.d(TAG, "DatagramSocket open.");

            android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);

            int buffersize = AudioRecord.getMinBufferSize(11025,
                    AudioFormat.CHANNEL_CONFIGURATION_MONO,
                    AudioFormat.ENCODING_PCM_16BIT);

            AudioTrack aTrack = new AudioTrack(
                    AudioManager.STREAM_VOICE_CALL, 11025,
                    AudioFormat.CHANNEL_CONFIGURATION_MONO,
                    AudioFormat.ENCODING_PCM_16BIT, buffersize,
                    AudioTrack.MODE_STREAM);

            DatagramPacket dPacket = new DatagramPacket(
                    new byte[buffersize], buffersize);
            Log.d(TAG, "Packet with buffersize=" + buffersize);
            aTrack.play();
            Log.d(TAG, "Playing track..");

            byte[] buffer = new byte[buffersize];

            while (isRunning && !isInterrupted()) {
                try {
                    dSocket.receive(dPacket);
                    buffer = dPacket.getData();

                    aTrack.setPlaybackRate(11025);
                    aTrack.write(buffer, 0, buffer.length);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            aTrack.stop();

这也有效,但是在发送超过几秒后,存在很大的延迟,数据包仍然存在但速度慢且音频播放只是“滞后” - 我该怎么做才能提高质量?这是一种直接的点对点连接,不涉及任何服务器。我应该增加缓冲区大小吗?当前缓冲区大小是我从Android获得的最小缓冲区大小,在我的设备上是1024(两个Galaxy Nexus)。 BTW,启动另一个线程的服务,其优先级设置为“URGENT”(我认为是最高的可用)。就我的目的而言,mPeers列表只有一个对等体,所以“for”循环并没有真正推迟这个我猜。

2 个答案:

答案 0 :(得分:2)

您是否检查过删除发送方循环中与网络相关的部分后会发生什么?即,来自麦克风的read() - 呼叫是否立即返回?此外,您描述了数据包缓慢到达,但是您是否检查过它们之间是否存在较长的延迟?

我问的原因是你描述的现象可能是由发送套接字阻塞引起的,因为它的缓冲区已满。如果套接字阻塞,send() - 调用将需要很长时间才能完成。除非你有非常高带宽的流量或非常慢的CPU,否则它不应该发生在UDP套接字上(它们通常会发生故障),但值得检查。

为了避免阻塞,请创建一个非阻塞套接字。我对Java网络不太熟悉,但似乎需要DatagramChannel才能做到这一点。

答案 1 :(得分:0)

好的,所以延迟消失了。我所做的是我只是增加了UDP数据包的缓冲区大小。我从Android收到的最小缓冲区大小是(在我的设备上)1024字节。现在我做这样的事情:

int maxBufferSize = 4096; // my value. see what's working best for you.
int minBufferSize = AudioRecord.getMinBufferSize(11025,
                AudioFormat.CHANNEL_CONFIGURATION_MONO,
                AudioFormat.ENCODING_PCM_16BIT);
int actualBufferSize = Math.max(minBufferSize, maxBufferSize);

使用4 KB缓冲区,音频传输非常好,绝对没有延迟。