Skip to content

Playing an Audio File

Jan Wojtecki edited this page Jun 7, 2018 · 3 revisions

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?

Choosing an output device

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.

Selecting a soundcard

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.

Creating the device

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.

Loading the file

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");

Initialising for playback

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.

Starting playback

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();

Repositioning

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);

Stopping playback

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();

Cleaning Up

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();