Голосовой чат, увеличенная задержка (буфер) – можно ли это решить?C#

Место общения программистов C#
Ответить
Anonymous
 Голосовой чат, увеличенная задержка (буфер) – можно ли это решить?

Сообщение Anonymous »

Хорошо, я создаю программу для голосового чата.
Я использую для этого NAudio, отличную библиотеку.

Но у меня возникла проблема. Буфер может увеличиться, когда что-то произойдет. Я думаю, это из примера, когда ОС что-то загружает, а приложение «Голосовой чат» ставится на «удержание» на секунду. В течение этого времени он добавляет данные в буфер, вызывая задержку текущих данных.

И поскольку приемник все время воспроизводит один и тот же темп, он будет всегда задерживаться.

Теперь у меня есть «решение» для этой проблемы: очистить буфер, когда он достигнет определенной длины. Хотя это совсем не идеально, и это скорее уловка, чем решение.

Теперь перейдем к частям кода.
Сначала я инициализирую то, что использую. .

Код: Выделить всё

        private NAudio.Wave.WaveInEvent SendStream = new WaveInEvent();
private NAudio.Wave.AsioOut Aut;
private NAudio.Wave.WaveFormat waveformat = new WaveFormat(48000, 16, 2);
private WasapiLoopbackCapture Waloop = new WasapiLoopbackCapture();
private NAudio.Wave.BufferedWaveProvider waveProvider;

waveProvider = new NAudio.Wave.BufferedWaveProvider(waveformat);
waveProvider.DiscardOnBufferOverflow = true;
SendStream.WaveFormat = waveformat;
waveformat используется только для того, чтобы мне не приходилось его постоянно переписывать.
Используется DiscardOnBufferOverflow, поэтому, если я устанавливаю определенную длину в буфере, например 20мс. Он отбросит все вышеперечисленное, иначе вернет исключение. Однако я думаю, что он ничего не сделает, если я не установлю длину, по умолчанию она, вероятно, бесконечна.

И не более того, SendStream - это WaveInEvent это означает, что он будет работать в BackgroundThread, когда я использую DataAvailable. Waloop практически такой же, за исключением того, что это петлевая связь.
В принимающей части для воспроизведения звука используется поставщик волн.
Формат волны — это, ну, формат волны, его важно настроить и все таки по крайней мере в моем приложении.

Вот приемная часть. Как вы можете видеть, он помещает данные в массив байтов, а затем воспроизводит их. ничего странного.

Код: Выделить всё

   byte[] byteData = udpClient.Receive(ref remoteEP);
waveProvider.AddSamples(byteData, 0, byteData.Length);
Вот часть отправки/записи.

Код: Выделить всё

  private void Sendv2()
{
try
{
if (connect == true)
{
if (AudioDevice == "Wasapi Loopback")
{
SendStream.StopRecording();
Waloop.StartRecording();
}
else
{
Waloop.StopRecording();
SendStream.StartRecording();
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}

void Sending(object sender, NAudio.Wave.WaveInEventArgs e)
{
if (connect == true && MuteMic.Checked == false)
{
udpClient.Send(e.Buffer, e.BytesRecorded, otherPartyIP.Address.ToString(), 1500);
}

}
void SendWaloop(object sender, NAudio.Wave.WaveInEventArgs e)
{

byte[] newArray16Bit = new byte[e.BytesRecorded / 2];
short two;
float value;
for (int i = 0, j = 0; i < e.BytesRecorded; i += 4, j += 2)
{
value = (BitConverter.ToSingle(e.Buffer, i));
two = (short)(value * short.MaxValue);

newArray16Bit[j] = (byte)(two & 0xFF);
newArray16Bit[j + 1] = (byte)((two >> 8) & 0xFF);
}
if (connect == true && MuteMic.Checked == false)
{
udpClient.Send(newArray16Bit, newArray16Bit.Length, otherPartyIP.Address.ToString(), 1500);
}

}
Waloop — это Loopback, поэтому он проходит через другой «канал», но здесь это не особо важно.

Очень просто: когда данные доступны (во время записи) и если соединение установлено и т. д., он просто отправляет буфер.

В общем, это очень просто. нравится часть приемника, но наоборот.

Теперь как мне на данный момент решаю вот так:

Код: Выделить всё

 if (waveProvider.BufferedDuration.Milliseconds > 40)
{

waveProvider.ClearBuffer();
TimesBufferClear++;
}
Поэтому я очищаю буфер, если оно превышает 40 мс (это происходит в таймере с интервалом 600 мс).
(TimesBufferClear++; это просто чтобы я мог отслеживать время его очистки)

К сожалению, я понятия не имею, как предотвратить увеличение буфера и установку его в принудительное состояние (20 мс и т. д.) будет просто приводит к тому, что воспроизведение становится все хуже и хуже, чем выше поднимается буфер, поскольку на самом деле оно не останавливается, я думаю, оно просто игнорирует приведенную выше часть.

Вот созданиеg устройств ввода. В моей реализации он немного отличается от ASIO и Wasapi, но работает почти так же, единственная реальная разница заключается в том, что я сообщаю пользовательскому интерфейсу, что ASIO включен или выключен, как вы можете видеть в коде, в конце я добавляю Событие DataAvailable как для SendStream (любой вход, микрофон и т. д.), так и для Waloop (воспроизводимый звук обратной связи).

Код: Выделить всё

  private void CheckAsio()
{

if (NAudio.Wave.AsioOut.isSupported())
{

Aut = new NAudio.Wave.AsioOut();
ASIO.Text += "\nSupported: " + Aut.DriverName;
ASIO.ForeColor = System.Drawing.Color.Green;
Aut.Init(waveProvider);
Aut.Play();
SendStream.NumberOfBuffers = 2;
SendStream.BufferMilliseconds = 10;
}
else
{
AsioSettings.Enabled = false;
ASIO.Text += "\n Not Supported: Wasapi used";
ASIO.ForeColor = System.Drawing.Color.DarkGray;
Wasout = new WasapiOut(AudioClientShareMode.Shared, 0);
Wasout.Init(waveProvider);
Wasout.Play();
SendStream.NumberOfBuffers = 2;
SendStream.BufferMilliseconds = 9;
}
SendStream.DataAvailable += Sending;
Waloop.DataAvailable += SendWaloop;

}
Я не уверен, что это вообще можно решить. Но поскольку я не вижу его в других программах голосового чата, я предполагаю, что должно быть что-то, что можно сделать.

Подробнее здесь: https://stackoverflow.com/questions/182 ... -be-solved
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»