-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Playing an Audio File
Suppose you simply want to play an audio file that you've already got on your system - a WAV, or MP3 file for example. How do you do that with NAudio?
Well because NAudio gives you access to several different Windows audio APIs, there are a few decisions that need to be made. First of all we need to create an output device. In NAudio, an output device is an implementation of IWaveOut
. The one we will choose for this first example is WaveOutEvent
. WaveOutEvent
uses the legacy waveOut... APIs, which have the advantage of being supported right back to Windows XP. They also have the advantage of taking care of resampling for you, so you don't need to worry about what the sample rate of the file you are playing is. Finally, this particular class uses "event" callbacks to play audio on a background thread. This has the advantage that you can use it to play audio whether your application is a WPF, WinForms, Console app or even Windows Service.
Creating our instance of WaveOutEvent
is simple. By default it will use "device 0" which means use the default soundcard on your computer. However, you can pass in a device number to the constructor to select a different soundcard if you have more than one.
The first step is to create our output device:
waveOut = new WaveOutEvent();
Now normally you would save waveOut
to a field in a class rather than a local variable, and that's because you could be playing for a long time, and probably don't want to block in your code until playback has finished. It's Disposable, so you'll need a reference to call Dispose
once playback is finished.
Now we need to create a "Wave Provider" which we will pass to the wave out device for playback. You can play anything that implements IWaveProvider
(and ISampleProvider
too thanks to an extension method that performs the conversion). For WAV files, you can use WavFileReader
and for MP3 files you can use Mp3FileReader
. There are other reader files available including AiffFileReader
and WmaFileReader
(in a separate assembly).
Note: If you are using Windows Vista and above, you should consider using MediaFoundationReader
which uses the power of the Windows Media Foundation to be able to read all kinds of audio file formats, including WAV, WMA, AAC, MP3 and it can even read the audio out of various video files. This is however dependent on what Media Foundation codecs are installed on your system.
Let's keep things simple for this example and just load an MP3 file with Mp3FileReader
. As with our output device, we'll save the reader to a private field in the class, as we will want to dispose it when we're done (it can also be used for repositioning during playback).
mp3Reader = new Mp3FileReader("example.mp3");
Now we've created our output device and wave provider, the next thing we need to do is initialize it for playback and this is done by passing the wave provider into the Init
function on the output device. Like this:
waveOut.Init(mp3Reader);
This will actually open the soundcard device ready for playback, but won't start playing. Note that at this point it will check whether your soundcard can actually play the audio format that has been passed in. An IWaveProvider
has a WaveFormat
property, and not all output devices can play all wave formats. However, in this case, it is very likely to succeed, as Mp3FileReader
will have already converted the MP3 audio into PCM for us.
Now we're ready to begin playback, and we can do so by simply calling Play
on our output device. It's important to note that this is not a blocking call. It just begins playback. If you want to be notified when playback ends, we'll discuss how to do that shortly.
waveOut.Play();
You can reposition during playback by setting the Position
property of the mp3Reader
you passed into waveOut.Init
. The position is in terms of bytes, but is the number of bytes of the PCM decompressed audio. You may find it easier to use the CurrentTime
property, which is a TimeSpan
.
// reposition to five seconds in
mp3Reader.CurrentTime = TimeSpan.FromSeconds(5.0);
By default, the output device (WaveOutEvent
in our case) will keep playing until we reach the end of the input stream we passed into Init
. This is indicated when the IWaveProvider.Read
method returns 0. Assuming you passed in an Mp3FileReader
or another file reader, then your file will eventually reach the end.
You can get notification that playback has finished by subscribing to the PlaybackStopped
event. This event will also be able to tell you if playback has stopped due to an error with the soundcard. For example, if your device is a USB headset and you unplug it midway through playing, then you will see one of these errors.
waveOut.PlaybackStopped += OnPlaybackStopped;
You can of course request that playback stops at any time by calling Stop
. Note that playback may not actually have stopped when this method exits. You've simply requested that playback stops, and it normally happens very quickly. But only when you get the PlaybackStopped
event can you be sure it has completely stopped.
waveOut.Stop();
You are quite free to start playback again by calling Play
. Playback will resume by reading the next audio from the file where you left off. Pause can be used when you don't want the listener to miss even a few milliseconds of audio when they restart. But beware of repositioning while paused. If you want to restart after pause from a different place in the file, it's best to call Stop
first, before starting up again.
waveOut.Stop();
mp3Reader.Position = 0; // go back to the beginning
// ... some time later:
waveOut.Play();
If you've completely finished playback, remember to clean up properly by calling Dispose
on the waveOut
device, and on the mp3FileReader
.
mp3Reader.Dispose();
waveOut.Dispose();