2013-04-04 48 views
1

我目前正在开发一个应用程序来传输音频。我有两个服务正在运行,一个接收它,一个发送它。发件人的重要内容如下所示:通过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(); 

这也适用,但发送超过几秒钟之后,有一个巨大的延迟,数据包仍旧arive,但是进展缓慢和音频播放只是“滞后” - 我能做些什么来提高质量?这是一个直接的点对点连接,不涉及服务器。我应该增加缓冲区大小吗?目前的缓冲区大小是我从Android获得的最小缓冲区大小,在我的设备上为1024(两个Galaxy Nexus)。顺便说一句,服务启动另一个线程,其优先级设置为“紧急”(我相信是最高可用)。为了我的目的,mPeers列表只有一个对等点,所以“for”循环并不是真的推迟了我猜测的。

回答

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缓冲区,音频传输是非常好的,绝对没有延迟。

1

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

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

为了避免阻塞,请创建一个非阻塞套接字。我对Java网络不太熟悉,但似乎需要使用DatagramChannel才能完成此操作。