Я использую для этого 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;
Используется 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);
}
}
Очень просто: когда данные доступны (во время записи) и если соединение установлено и т. д., он просто отправляет буфер.
В общем, это очень просто. нравится часть приемника, но наоборот.
Теперь как мне на данный момент решаю вот так:
Код: Выделить всё
if (waveProvider.BufferedDuration.Milliseconds > 40)
{
waveProvider.ClearBuffer();
TimesBufferClear++;
}
(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
Мобильная версия