Хорошо, поэтому я делаю программное обеспечение для голосового чата. Я использую для этого NAudio, отличную библиотеку.Голосовой чат, увеличенная задержка (буфер) - Можно ли это решить?
Но у меня проблема. Буфер может повышаться, когда что-то происходит. Я предполагаю, что это из примера, когда ОС загружает что-то, и приложение Voice Chat помещается на «hold» в течение секунды. За это время он добавляет данные в буфер, заставляя текущие данные задерживаться.
И поскольку приемник играет в одинаковом темпе все время, он всегда будет задерживаться.
Теперь у меня есть «решение» для этого, чтобы очистить буфер, когда он достигает определенной длины. Хотя это совсем не идеально, и это скорее хитрость, чем решение.
Теперь введите код. Сначала я инициализирую то, что я использую.
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 почти то же самое, за исключением петли. waveprovider используется в принимающей части для воспроизведения звука. Waveformat - это хорошо, waveformat, it's importat, чтобы установить его и иметь все то же самое, по крайней мере, в моем приложении.
Ниже представлена принимающая сторона. Как вы можете, он помещает данные в массив байтов, а затем воспроизводит их. ничего странного.
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 (звук Loopback, который воспроизводится).
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;
}
Я не уверен, что это даже можно решить. Но поскольку я не вижу других программ голосового чата, у меня есть предположение, что должно быть что-то, что можно сделать.
К сожалению, у меня уже есть это, и, как правило, я выполняю свои потоки с наивысшим приоритетом. И это ничего не меняет: похоже, это что-то другое, потому что оно складывается независимо от того, что. Довольно сложно и сложно отслеживать. – Zerowalker
Нечетный. Даже система низкого уровня должна справиться с такими проблемами без проблем. Это проблема сети? Профилированы ли вы, чтобы узнать, сколько времени ваш код выполняет для каждой фазы? Вы пытались отделить код записи от другого сетевого кода? – Corey
Да, но я думаю, что это ошибка в фактическом «Waveprovider», как если бы я записывал данные на Клиенте и на сервере (как файл), оба будут одинаковыми, никаких сбоев, которые могут случиться, когда я слушаю в чат Live. Значение Waveprovider должно быть причиной этого как-то, так как оно может быть в 10 мс все время, тогда оно «взломается» и может стать 80 мс, не уверен, что происходит, но сохраненное, что так же жидкое, как всегда, и сохраненное данные и данные в Waveprovider должны быть одинаковыми; S – Zerowalker