-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Understanding Output Devices
NAudio offers many different output device classes that can be used to play audio. These include WaveOut
, WaveOutEvent
, DirectSoundOut
, WasapiOut
and AsioOut
. Each one of these implements the IWaveOut
interface, and can be used to play your sounds. But why are there so many options? And how do you know which one to pick?
Well the reason there are so many is that Windows offers many different APIs for playing audio. Let's go through each of the output devices one by one and understand when to use them.
First of all, NAudio offers the WaveOut
and WaveOutEvent
classes, which under the hood call into the waveOut...
Windows APIs. These have been around for ages, and are supported right the way back to Windows XP. Another great benefit of using these classes is that the waveOut...
APIs perform resampling for you if necessary. This makes it really simple to play back a file that has a different sample rate to whatever your system is using.
But what is the difference between WaveOut
and WaveOutEvent
? Well, it all comes down to "callback models". The way these APIs work is that you prepare a short buffer of audio, say 100ms, and give it to the soundcard to play. Then, when the soundcard has finished playing it, it needs to notify you so you can prepare another one. Usually, you operate with at least two buffers, so that one can be filled while the other is playing. That way you won't get any gaps in your playback.
The Windows waveOut...
APIs offer several ways to notify you that a buffer has completed playing. This can be sending a Windows message to the GUI thread of your application. This option is what you'll get by default if you use WaveOut
. It's a great choice if you are building a Windows Forms or WPF application. A nice benefit is that it means the calls to Read
on your IWaveProvider
all happen on the GUI thread, and so you avoid any potential nasty threading issues if you are repositioning on one thread while playing on another.
However, if you are writing a console application, then there is no Windows message loop, and so an alternative callback method must be used. The WaveOut
class does offer a way for you to configure it to use "function" callbacks, but it is generally recommended that you avoid using these, as it is easy to accidentally get yourself into a deadlock with them.
And so the third option is to use Windows events for callbacks, and this is what the WaveOutEvent
class offers. It performs all the reading and queueing of audio on a background thread. This has proved the most stable model over many years, and is generally the recommended one to use. The only thing to bear in mind is that if you manipulate your signal chain while you are playing (say by repositioning or adjusting parameters of real-time effects), then you could get odd results due to working on different threads. Many of the file reader classes in NAudio use lock objects to protect against this automatically.
work in progress