2010-09-26 92 views
8

我试图创建一个Speex Voip客户端和服务器。我通过UDP了解了基础知识,并在本地机器上正常工作。我使用JSpeex来实现可移植性。我正在寻找关于创建客户端和服务器的提示。你怎么看?帮助创建一个Speex Voip服务器和客户端

的JSpeex库只能编码每次调用320个字节,因此向服务器发送数据包是微小的(在我的情况〜244个字节)。客户端在发送之前等待大约1或2 KB的编码数据是否准备就绪,或者让服务器处理缓冲数据包会更好吗?

此外,在如何实现缓冲数据的任何帮助将是不错的。

一些什么,我有一个在本地计算机上工作。

客户:

public void run() { 
    int nBytesToRead = (m_inputAudioFormat.getFrameSize() * 160); 
    int nAvailable = 0; 
    byte[] abPCMData = new byte[nBytesToRead]; 
    byte[] abSpeexData = null; 
    UserSpeexPacket userSpeexPacket = new UserSpeexPacket("Xiphias3", "TheLounge", null, 0); 

    while (m_captureThread != null) { 
     nAvailable = m_line.available(); 
     if (nAvailable >= nBytesToRead) { 
      int nBytesRead = m_line.read(abPCMData, 0, nBytesToRead); 
      if (nBytesRead == -1) break; 
      if (nBytesRead < nBytesToRead) 
       Arrays.fill(abPCMData, nBytesRead, abPCMData.length, (byte) 0); 
      abSpeexData = createSpeexPacketFromPCM(abPCMData, 0, abPCMData.length); 
      //DatagramPacket packet = new DatagramPacket(abSpeexData, 0, abSpeexData.length, m_connection.getInetAddress(), m_nServerPort); 
      userSpeexPacket.setSpeexData(abSpeexData); 
      userSpeexPacket.incrementPacketNumber(); 
      DatagramPacket packet = UserSpeexPacket.userSpeexPacketToDatagramPacket(m_connection.getInetAddress(), m_connection.getPort(), userSpeexPacket); 
      try { 
       m_connection.send(packet); 
      } 
      catch(IOException iox) { 
       System.out.println("Connection to server lost: " + iox.getMessage()); 
       break; 
      } 
     } 
    } 
    closeLine(); 
    disconnect(); 
} 

public byte[] createSpeexPacketFromPCM(byte[] abPCMData, int nOffset, int nLength) 
{ 
    byte[] abEncodedData = null; 
    m_speexEncoder.processData(abPCMData, nOffset, nLength); 
    abEncodedData = new byte[m_speexEncoder.getProcessedDataByteSize()]; 
    m_speexEncoder.getProcessedData(abEncodedData, 0); 
    return abEncodedData; 
} 

服务器:

DatagramPacket packet = new DatagramPacket(new byte[2048], 0, 2048); 
    byte[] abPCMData = null; 
    long lPrevVolPrintTime = 0; 

    while (m_bServerRunning) { 
     try { 
      m_serverSocket.receive(packet); 
      //System.out.println("Packet size is " + packet.getData().length); 
      //System.out.println("Got packet from " + packet.getAddress().getHostAddress()); 
      //abPCMData = decodeSpeexPacket(packet.getData(), 0, packet.getLength()); 
      UserSpeexPacket usp = UserSpeexPacket.datagramPacketToUserSpeexPacket(packet); 
      abPCMData = decodeSpeexPacket(usp.getSpeexData(), 0, usp.getSpeexData().length); 
      m_srcDataLine.write(abPCMData, 0, abPCMData.length); 

      if (System.currentTimeMillis() >= (lPrevVolPrintTime + 500)) { 
       //System.out.println("Current volume: " + AudioUtil.getVolumeLevelForPCM22050Hz16Bit1Channel(abPCMData, 0, abPCMData.length)); 
       lPrevVolPrintTime = System.currentTimeMillis(); 
      } 
     } 
     catch (IOException iox) { 
      if (m_bServerRunning) { 
       System.out.println("Server socket broke: " + iox.getMessage()); 
       stopServer(); 
      } 
     } 
    } 

回答

5

我在一个类似的项目工作。从我阅读的所有内容以及个人经验来看,最好的选择是使用少量的数据并尽快发送。您希望在接收器侧面完成任何抖动缓冲。

这是典型的VoIP应用每秒发送的数据包50-100。对于8000Hz的uLaw编码,这将导致80-160字节的分组大小。其原因是一些数据包将不可避免地被丢弃,并且您希望对接收器的影响尽可能小。因此,每个数据包有10ms或20ms的音频数据,丢失的数据包可能会导致一个小小的呃逆,但不会像丢失2k个音频数据(〜250ms)那么糟糕。

此外,随着大数据包大小,则必须在发送方在发送之前积累的所有数据。因此,考虑到50ms的典型网络延迟,每个数据包有20ms的音频数据,接收器不会听到发送者说至少70ms的内容。现在想象一下当250ms的音频被发送时会发生什么。在发送者说话和播放该音频的接收器之间将经过270ms。

用户似乎更宽容的数据包丢失在这里和那里,这会导致低于标准杆的音频质量,因为大多数电话的音频质量并没有很大的开始。然而,用户也习惯于在现代电话线路上的非常低的延迟,因此引入甚至250ms的往返延迟可能是非常令人沮丧的。

现在,就实现缓冲而言,我发现了一个很好的策略来使用Queue(哎呀,在这里使用.NET :)),然后将它包装到一个跟踪期望的最小和最大数据包数的类在队列中。使用严格的锁定,因为您很可能会从多个线程访问它。如果队列“落底”并且其中有零包(缓冲区欠载),则设置一个标志并返回空值,直到包数达到您想要的最小值。但是,您的消费者必须检查返回的null,并且不将任何事情排入输出缓冲区。或者,您的消费者可以跟踪最后一个数据包并重复排队,这可能会导致循环音频,但在某些情况下,可能会比“静音”更好。您必须这样做,直到生产者将足够的数据包放入队列以达到最小值。这会给用户带来更长时间的沉默,但这通常比短暂,频繁的沉默时间(短暂性)更好。如果你得到了一连串的数据包,并且生产者填满了队列(达到所需的最大值),你可以开始忽略新的数据包,或者将足够多的数据包从队列的前面丢弃,以返回最小值。

虽然挑选那些最小/最大值是艰难的。您试图在发送者和接收者之间保持最小延迟的情况下平衡流畅的音频(无欠载)。 VoIP很有趣,但肯定会令人沮丧!祝你好运!

+0

感谢您的输入。我喜欢! – Xiphias3 2010-10-23 20:58:03