NAudio
NAudio copied to clipboard
WasapiOut cuts sounds off prematurely
Thanks for a great library! I read the latest blogpost on https://markheath.net/ about Wasapi so I switched over to that.
I think there is an issue though. My apologies if this is known, I couldn't find anything about it.
The problem is that the latency value in WasapiOut affects how much of the sound is played. For example the default value of 200 latency there is a slight cutoff. If you increase it to 1000 the cutoff is longer and a latency of 0 there is practically no cut off (there still might be a millisecond or two though, see comment in code below).
string file = "C:\\temp\\test.wav"; // Test file from https://github.com/jonjonsson/SoundMonster/raw/main/test.wav
Console.WriteLine("The test sound is 4 tones of equal length. Depending on latency the last tone is cut out.");
Console.WriteLine("First test with all default value. The last tone is cut prematurely.");
using (var audioFile = new AudioFileReader(file))
using (var outputDevice = new WasapiOut()) // 200 ms latency default
{
outputDevice.Init(audioFile);
outputDevice.Play();
while (outputDevice.PlaybackState == PlaybackState.Playing)
{
Thread.Sleep(2000);
}
}
Console.WriteLine("Next test with increased latency to 1000 ms. The last tone is completely cut out in this case");
using (var audioFile = new AudioFileReader(file))
using (var outputDevice = new WasapiOut(new MMDeviceEnumerator().GetDefaultAudioEndpoint(DataFlow.Render, Role.Console), AudioClientShareMode.Shared, useEventSync: true, 1000))
{
outputDevice.Init(audioFile);
outputDevice.Play();
while (outputDevice.PlaybackState == PlaybackState.Playing)
{
Thread.Sleep(4000);
}
}
Console.WriteLine("Next test with latency set to 0. All of the sound plays now. That being said the sound ends with a little glitch like it is not cut on a zero crossing (it is perfectly cut).");
using (var audioFile = new AudioFileReader(file))
using (var outputDevice = new WasapiOut(new MMDeviceEnumerator().GetDefaultAudioEndpoint(DataFlow.Render, Role.Console), AudioClientShareMode.Shared, useEventSync: true, 0))
{
outputDevice.Init(audioFile);
outputDevice.Play();
while (outputDevice.PlaybackState == PlaybackState.Playing)
{
Thread.Sleep(5000);
}
}
Console.WriteLine("Final test using WaveOutEvent instead of WasapiOut, works normally, no glitch at the end of sound");
using (var audioFile = new AudioFileReader(file))
using (var outputDevice = new WaveOutEvent())
{
outputDevice.Init(audioFile);
outputDevice.Play();
while (outputDevice.PlaybackState == PlaybackState.Playing)
{
Thread.Sleep(2000);
}
}
thanks, sounds like a bug. The WasapiOut code is loosely based on this sample which includes a sleep to ensure the final bit of audio gets played, but maybe the duration calculation isn't quite right. Having said that, could you also try putting a short sleep in your test before outputDevice
gets Disposed. It might be because PlaybackState
is getting set to Stopped
before the playback thread ends.
Also, I recommend not using 1 second as latency - 200ms is more than long enough. And 0 is also not a good idea - probably should be disallowed, as it will result in the playback thread using more CPU than needed
Thanks Mark!
When I was troubleshooting I tried delaying the dispose but that did not change anything.
I am just using the default 200ms and noticed the problem when trying to loop sounds properly.
What version of NAudio are you using? I've struggled to reproduce this issue with the NAudio demo app - I can hear all four tones (except on DirectSoundOut which does cut them off).
By the way, you mentioned looping - if you want to loop with NAudio, avoid closing and reopening an output device. Instead play an IWaveProvider
that implements looping itself (there's various articles showing how to do this with a LoopStream
)
Actually I have reproduced it now (needed to be using Event sync), and think I have a fix for it
Great, thanks again!
Yep, I'm using LoopsSream. Come to think of it the problem was not during the looping. I just noticed it when I was editing sounds for looping and playing them without looping.
the change I've just pushed should resolve the issue and I also improved a few other issues with WASAPI playback. Feel free to test with the latest code. Not sure when I'll get round to pushing another version
Sounds good! I've only ever used the NuGet package, I'll see how I get a long with the source.