0

I am making a voice chat/messenger program and I got voice to work with one person in the chat but when i add a second to it the voices are laggy and cut up. I think the problem is in the Client Audio Receive class. If you don't think it is I will link the rest in a pastebin.

package client;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;

public class ClientAudioRec implements Runnable {
private ObjectInputStream i2;
private Socket s;
private AudioFormat af;

public ClientAudioRec(Socket s2, AudioFormat audioformat) {
    s = s2;
    af = audioformat;
}
public void run() {
    try {
        i2 = new ObjectInputStream(s.getInputStream());
    } catch (IOException e2) {
        e2.printStackTrace();
    }

    SourceDataLine inSpeaker = null;
    DataLine.Info info = new DataLine.Info(SourceDataLine.class, af);
    try {
        inSpeaker = (SourceDataLine)AudioSystem.getLine(info);
        inSpeaker.open(af);
    } catch (LineUnavailableException e1) {
        e1.printStackTrace();
    }

    int bytesRead = 0;
    byte[] inSound = new byte[100];
    inSpeaker.start();
    while(true)
    {
        try{
            bytesRead = i2.read(inSound, 0, inSound.length);
            } catch (Exception e){
            e.printStackTrace();
        }
        if(bytesRead >= 0)
        {
            inSpeaker.write(inSound, 0, bytesRead);
        }
    }
 }

}

Server Side Voice Code HERE

Client Side Audio Input Code HERE

4

1 回答 1

1

我会怀疑您的服务器端语音代码:byte[] soundData = new byte[1];. 一字节缓冲区?你能让CPU更努力地工作吗?哦,您也在客户端音频输入代码中执行此操作。

您发送语音的数据速率是多少?手机使用 20ms 帧。这些被完全采样(20ms),然后传输到基站(20ms),并可能发送到另一个手机(20ms),最后通过扬声器播放至少60ms的延迟。没有听到不自然的延迟。手机数据速率为 8kbps,因此每帧为 160 位,即 20 字节。我会将您的缓冲区大小增加到至少 20 个字节(可能高达 50 个字节),看看您是否有任何改进。

套接字的“服务质量”设置会影响性能。对于 VoIP,您需要低延迟连接。我不确定如何为 Java Sockets 设置它;我得做一些阅读。 TCP_NODELAY是另一个设置选项(如果可能),以防止延迟确认减慢后续数据包的速度。发送许多小数据包时会发生这种情况。发送更大的数据包可以缓解这种情况,这是将缓冲区增加到 1 字节以上的另一个原因!


编辑

与其发送许多微小的缓冲区,不如将数据累积成更大的固定大小的帧(例如 20ms 的数据),并且只发送完整的帧。要将数据累积到帧缓冲区中,请使用该#read(byte[] buffer, int offset, int length)方法。例如:

byte[] buffer = new byte[100];
int offset = 0;

while(true) {
    // Read as many bytes as possible, up to remaining space in buffer
    int bytes_read = source.read(buffer, offset, buffer.length - offset);

    if (bytes_read >= 0) {
        // Accumulate number of bytes that has been read.
        offset += bytes_read;

        if (offset == buffer.length) {
            // Buffer is full, send it.
            sink.write(buffer, 0, buffer.length);

            // Clear buffer for next frame 
            offset = 0;
        }
    } else {
        break; // End of stream
    }
}

如果读取了 30 个字节,则在 处将它们读入缓冲区offset=0,并offset递增到 30。如果在下一次传递中再读取 60 个字节,则从 开始将它们读入缓冲区offset=30,并offset递增到 90。如果 50 字节变为之后可用,只有 10 个字节将被读取(buffer.length-offset)填充缓冲区。然后发送缓冲区,并将offset其重置为零。剩余的 40 个字节(或者更多,因为数据不断到达)将在下一次调用时读取。

注意:您应该使用类似的循环sink.write(),以防整个缓冲区无法在一次调用中写入套接字。

于 2016-04-30T03:31:40.367 回答