Reputation: 71
I am currently writing a Discord bot using D#+, that is supposed to send all audio that's coming through an output sound device to a voice channel.
Using NAudio, I can successfully capture the audio from a device, and my current code looks somewhat like this:
Capture.StartRecording(); // 'Capture' is a WasapiLoopbackCapture object
Capture.DataAvailable += async (s, a) =>
{
await stream.WriteAsync(a.Buffer); // 'stream' is the transmit stream for the Discord connection
};
Unfortunaltey however, D#+ is very specific about requiring 16bit stereo PCM at a sample rate of 48000 Hz, which is not quite the same as the IEEE Floating Point format that the Wasapi Capture Buffer produces, as I found out through some reading. So I know by now that I have to convert the buffer to said PCM format before being able to write it into the Transmit Stream.
After some research, I found some articles like this one and questions on here like this one, that all generally seem to go into the right direction of what I want to achieve, but not quite, or at least I am too unskilled with audio processing to apply it properly and make it work.
So my question is, essentially, how can I constantly convert the data that I get from the WasapiLoopbackCapture buffer into a new buffer with said PCM format? Any help is much appreciated!
Upvotes: 1
Views: 1492
Reputation: 71
Thanks to @GoodNightNerdPride for pointing me to this issue on the NAudio GitHub Page. With the code snippets posted in there, I was able to write this method, which can convert the buffer from an WasapiLoopbackCapture object into 16bit PCM format.
/// <summary>
/// Converts an IEEE Floating Point audio buffer into a 16bit PCM compatible buffer.
/// </summary>
/// <param name="inputBuffer">The buffer in IEEE Floating Point format.</param>
/// <param name="length">The number of bytes in the buffer.</param>
/// <param name="format">The WaveFormat of the buffer.</param>
/// <returns>A byte array that represents the given buffer converted into PCM format.</returns>
public byte[] ToPCM16(byte[] inputBuffer, int length, WaveFormat format)
{
if (length == 0)
return new byte[0]; // No bytes recorded, return empty array.
// Create a WaveStream from the input buffer.
using var memStream = new MemoryStream(inputBuffer, 0, length);
using var inputStream = new RawSourceWaveStream(memStream, format);
// Convert the input stream to a WaveProvider in 16bit PCM format with sample rate of 48000 Hz.
var convertedPCM = new SampleToWaveProvider16(
new WdlResamplingSampleProvider(
new WaveToSampleProvider(inputStream),
48000)
);
byte[] convertedBuffer = new byte[length];
using var stream = new MemoryStream();
int read;
// Read the converted WaveProvider into a buffer and turn it into a Stream.
while ((read = convertedPCM.Read(convertedBuffer, 0, length)) > 0)
stream.Write(convertedBuffer, 0, read);
// Return the converted Stream as a byte array.
return stream.ToArray();
}
With this, streaming the audio captured via WasapiLoopbackCapture
to Discord using D#+ is as simple as this:
var stream = connection.GetTransmitSink();
Capture.StartRecording();
Capture.DataAvailable += async (s, a) =>
{
await stream.WriteAsync(ToPCM16(a.Buffer, a.BytesRecorded, Capture.WaveFormat));
};
Upvotes: 5