Задержка голосового чата Java

Я делаю программу голосового чата / мессенджера, и у меня есть голос для работы с одним человеком в чате, но когда я добавляю к нему второго, голоса запаздывают и прерываются. Я думаю, что проблема в классе Client Audio Receive. Если вы так не считаете, я свяжу остальные в 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);
        }
    }
 }

}

Голосовой код на стороне сервера ЗДЕСЬ

Код аудиовхода на стороне клиента ЗДЕСЬ


person Marcus Mardis    schedule 30.04.2016    source источник
comment
Не могли бы вы еще больше сузить проблему?   -  person Matt C    schedule 30.04.2016
comment
нет, я работал над этим за несколько дней до этого.   -  person Marcus Mardis    schedule 30.04.2016


Ответы (1)


Я бы с подозрением отнесся к вашему голосовому коду на стороне сервера: byte[] soundData = new byte[1];. Однобайтовый буфер? Можете ли вы заставить процессор работать больше? О, и вы также делаете это в своем коде аудиовхода на стороне клиента.

Какова скорость передачи данных, с которой вы отправляете голос? Сотовые телефоны используют кадры 20 мс. Они полностью сэмплируются (20 мс), затем передаются на базовую станцию ​​(20 мс) и, возможно, отправляются на другой сотовый телефон (20 мс), а затем, наконец, воспроизводятся через динамик с задержкой не менее 60 мс. Никакой неестественной задержки не слышно. Скорость передачи данных сотового телефона составляет 8 кбит/с, поэтому размер каждого кадра составляет 160 бит или 20 байт. Я бы увеличил размер вашего буфера как минимум до 20 байт (возможно, до 50) и посмотрел бы, получите ли вы какие-либо улучшения.

Параметр «Качество обслуживания» сокета может повлиять на производительность. Для VoIP вам нужно соединение с малой задержкой. Я не уверен, как установить это для сокетов Java; Мне нужно будет немного почитать. TCP_NODELAY — это еще один параметр, который можно установить (если это возможно), чтобы предотвратить замедление последующих пакетов из-за отложенных подтверждений. Это происходит при отправке большого количества небольших пакетов. Отправка больших пакетов смягчит это, что является еще одной причиной для увеличения буфера до более чем 1 байта!


Изменить

Вместо того, чтобы отправлять много крошечных буферов, вы должны накапливать данные в больших кадрах фиксированного размера (например, 20 мс данных) и отправлять только полные кадры. Чтобы накапливать данные в буфере кадра, вы используете метод #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(), если весь буфер не может быть записан в сокет за один вызов.

person AJNeufeld    schedule 30.04.2016
comment
я установил его на 50, но он все еще такой же изменчивый - person Marcus Mardis; 30.04.2016
comment
Вместо того, чтобы читать и отправлять через сокет буферы размером менее 50 байт, попробуйте накапливать до тех пор, пока буфер не заполнится, и отправлять только полные буферы. Затем увеличьте размер буфера еще больше. Возможно, подождите, пока у вас не будет 5 секунд буферизации звука на ресивере, прежде чем начать его воспроизводить; это должно избегать всякой изменчивости. Отладьте это и заработайте, затем уменьшите размер буфера до 3 секунд, 1 секунды, половины секунды и посмотрите, куда вернется отбивная. - person AJNeufeld; 30.04.2016
comment
как сохранить, а потом отправить? - person Marcus Mardis; 01.05.2016
comment
я новичок в этом и я пытался сделать это весь день - person Marcus Mardis; 01.05.2016
comment
См. обновление — я добавил накопление байтов во время операции приема, но вам нужно сделать аналогичный цикл для операции отправки, чтобы обработать случай, когда операционная система не принимает все байты, которые вы пишете, за один вызов. - person AJNeufeld; 02.05.2016