さて、ボイスチャットソフトを作っています。優れたライブラリである NAudio を使用しています。
しかし、私は問題を抱えています。何かが起こるとバッファが上がることがあります。OSが何かをロードし、ボイスチャットアプリケーションが1秒間「保留」になったときの例からだと思います。その間、バッファにデータが追加され、現在のデータが遅延します。
そしてレシーバーは常に同じペースでプレイしているため、常に遅延が発生します。
これで、特定の長さに達したときにバッファをクリアするという「解決策」があります。これはまったく理想的ではありませんが、解決策というよりはトリックです。
次にコード部分です。まず、使用するものを初期化します。
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 が使用されるため、バッファに特定の長さ (たとえば 20ms) を設定すると、. 上記のものはすべて破棄され、それ以外の場合は例外が返されます。長さを設定しないと何もしないと思いますが、デフォルトではおそらく無限です。
他にはあまりありませんが、SendStream は WaveInEvent です。つまり、DataAvailable を使用すると BackgroundThread で実行されます。Waloop は、ループバックであることを除けばほとんど同じです。waveprovider は、受信部分でオーディオを再生するために使用されます。Waveformat は、まあ、waveformat です。それを設定することが重要であり、少なくとも私のアプリケーションではすべて同じです。
こちらが受け側。ご覧のとおり、データをバイト配列に入れてから再生します。奇妙なことは何もありません。
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 はループバックなので、別の「チャネル」を通過しますが、ここではそれほど重要ではありません。
非常に単純です。データが利用可能な場合 (記録中)、接続が true の場合などは、バッファを送信するだけです。
レシーバー部分とほとんど同じですが、逆です。
現在、これをどのように解決しているかは次のとおりです。
if (waveProvider.BufferedDuration.Milliseconds > 40)
{
waveProvider.ClearBuffer();
TimesBufferClear++;
}
したがって、40ミリ秒を超える場合はバッファをクリアしています(これは600ミリ秒間隔のタイマーにあります)。(TimesBufferClear++; は、クリアされた時間を追跡できるようにするためです)
悲しいことに、バッファーが増加するのを防ぐ方法がわかりません。強制状態 (20ms など) に設定すると、実際には停止しないため、バッファーが上に行くほど再生が悪化します。 、それは私が思う上記の部分を無視するだけです。
これが入力デバイスの作成です。私の実装では ASIO や Wasapi とは少し異なりますが、ほとんど同じように動作します。実際の違いは、コードでわかるように、ASIO がオンまたはオフであることを UI に伝えることです。最後にSendStream (任意の入力、マイクなど) と Waloop (再生中のループバック サウンド) の両方に対する DataAvailable イベント。
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;
}
これさえ解決できるかどうかはわかりません。しかし、私は他のボイスチャットプログラムがそれを持っているのを見ていないので、何かできることがあるに違いないと推測しています.