Playing audio

WPF comes with excellent built-in audio and video support, as you'll see in the next couple of chapters of this tutorial. In this particular article, we'll be discussing the ability to play audio, coming from actual audio files, e.g. in the MP3 format, but first, let's have a look at couple of simpler approaches.

System sounds and the SoundPlayer

WPF has a class called SoundPlayer, which will play audio content based on the WAV format for you. WAV is not a very widely used format today, mainly because it's uncompressed and therefore takes up a LOT of space.

So while the SoundPlayer class is simple to use, it's not terribly useful. Instead, we'll be focusing on the MediaPlayer and MediaElement classes, which allows the playback of MP3 files, but first, let's have a look at the simplest way of playing a sound in your WPF application - the SystemSounds class.

The SystemSounds class offers several different sounds, which corresponds to the sound defined for this event by the user in Windows, like Exclamation and Question. You can piggyback on these sounds and settings and play them with a single line of code:

SystemSounds.Beep.Play();

Here's a complete example, where we use all of the currently available sounds:

<Window x:Class="WpfTutorialSamples.Audio_and_Video.SystemSoundsSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="SystemSoundsSample" Height="200" Width="150">
    <StackPanel Margin="10" HorizontalAlignment="Center" VerticalAlignment="Center">
        <Button Name="btnAsterisk" Click="btnAsterisk_Click">Asterisk</Button>
        <Button Name="btnBeep" Margin="0,5" Click="btnBeep_Click">Beep</Button>
        <Button Name="btnExclamation" Click="btnExclamation_Click">Exclamation</Button>
        <Button Name="btnHand" Margin="0,5" Click="btnHand_Click">Hand</Button>
        <Button Name="btnQuestion" Click="btnQuestion_Click">Question</Button>
    </StackPanel>
</Window>
using System;
using System.Media;
using System.Windows;

namespace WpfTutorialSamples.Audio_and_Video
{
	public partial class SystemSoundsSample : Window
	{
		public SystemSoundsSample()
		{
			InitializeComponent();
		}

		private void btnAsterisk_Click(object sender, RoutedEventArgs e)
		{
			SystemSounds.Asterisk.Play();
		}

		private void btnBeep_Click(object sender, RoutedEventArgs e)
		{
			SystemSounds.Beep.Play();
		}

		private void btnExclamation_Click(object sender, RoutedEventArgs e)
		{
			SystemSounds.Exclamation.Play();
		}

		private void btnHand_Click(object sender, RoutedEventArgs e)
		{
			SystemSounds.Hand.Play();
		}

		private void btnQuestion_Click(object sender, RoutedEventArgs e)
		{
			SystemSounds.Question.Play();
		}
	}
}

A simple application for testing the SystemSounds

There are of course several limitations to using this approach. First of all, you only get access to these five sounds, and second of all, the user may have disabled them in Windows, in which case the expected sound will be replaced with silence. On the other hand, if you only want to use these sounds the same way that Windows does, it makes it extremely easy to produce a sound for warnings, questions etc. In that case, it's a good thing that your application will respect the user's choice of silence.

The MediaPlayer class

The MediaPlayer class uses Windows Media Player technology to play both audio and video in several modern formats, e.g. MP3 and MPEG. In this article, we'll be using it for playing just audio, and then focus on video in the next article.

Playing an MP3 file with the MediaPlayer class is very simple, as we'll see in this next example:

<Window x:Class="WpfTutorialSamples.Audio_and_Video.MediaPlayerAudioSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MediaPlayerAudioSample" Height="100" Width="200">
    <Grid VerticalAlignment="Center" HorizontalAlignment="Center">
        <Button Name="btnOpenAudioFile" Click="btnOpenAudioFile_Click">Open Audio file</Button>
    </Grid>
</Window>
using System;
using System.Windows;
using System.Windows.Media;
using Microsoft.Win32;

namespace WpfTutorialSamples.Audio_and_Video
{
	public partial class MediaPlayerAudioSample : Window
	{
		private MediaPlayer mediaPlayer = new MediaPlayer();

		public MediaPlayerAudioSample()
		{
			InitializeComponent();
		}

		private void btnOpenAudioFile_Click(object sender, RoutedEventArgs e)
		{
			OpenFileDialog openFileDialog = new OpenFileDialog();
			openFileDialog.Filter = "MP3 files (*.mp3)|*.mp3|All files (*.*)|*.*";
			if(openFileDialog.ShowDialog() == true)
			{
				mediaPlayer.Open(new Uri(openFileDialog.FileName));
				mediaPlayer.Play();
			}
		}
	}
}

A simple application using the MediaPlayer class

In this example, we just have a single button, which will show an OpenFileDialog and let you select an MP3 file. Once that is done, it will use the already created MediaPlayer instance to open and play this file. Notice that the MediaPlayer object is created outside of the event handler. This makes sure that the object is not prematurely garbage collected because it goes out of scope once the event handler is done, which would result in the playback stopping.

Please also notice that no exception handling is done for this example, as usual to keep the example as compact as possible, but in this case also because the Open() and Play() methods actually doesn't throw any exceptions. Instead, you can use the MediaOpened and MediaFailed events to act when things go right or wrong.

Controlling the MediaPlayer

In our first MediaPlayer example, we just opened and automatically started playing a file, without giving the user a chance to control the playback process, but obviously, the MediaPlayer control offers you full control of playback. Here's an example showing you the most important functions:

<Window x:Class="WpfTutorialSamples.Audio_and_Video.MediaPlayerAudioControlSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MediaPlayerAudioControlSample" Height="120" Width="300">
    <StackPanel Margin="10">
        <Label Name="lblStatus" Content="Not playing..." HorizontalContentAlignment="Center" Margin="5" />
        <WrapPanel HorizontalAlignment="Center">
            <Button Name="btnPlay" Click="btnPlay_Click">Play</Button>
            <Button Name="btnPause" Margin="5,0" Click="btnPause_Click">Pause</Button>
            <Button Name="btnStop" Click="btnStop_Click">Stop</Button>
        </WrapPanel>
    </StackPanel>
</Window>
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
using Microsoft.Win32;

namespace WpfTutorialSamples.Audio_and_Video
{
	public partial class MediaPlayerAudioControlSample : Window
	{
		private MediaPlayer mediaPlayer = new MediaPlayer();

		public MediaPlayerAudioControlSample()
		{
			InitializeComponent();

			OpenFileDialog openFileDialog = new OpenFileDialog();
			openFileDialog.Filter = "MP3 files (*.mp3)|*.mp3|All files (*.*)|*.*";
			if(openFileDialog.ShowDialog() == true)
				mediaPlayer.Open(new Uri(openFileDialog.FileName));

			DispatcherTimer timer = new DispatcherTimer();
			timer.Interval = TimeSpan.FromSeconds(1);
			timer.Tick += timer_Tick;
			timer.Start();
		}

		void timer_Tick(object sender, EventArgs e)
		{
			if(mediaPlayer.Source != null)
				lblStatus.Content = String.Format("{0} / {1}", mediaPlayer.Position.ToString(@"mm\:ss"), mediaPlayer.NaturalDuration.TimeSpan.ToString(@"mm\:ss"));
			else
				lblStatus.Content = "No file selected...";
		}

		private void btnPlay_Click(object sender, RoutedEventArgs e)
		{
			mediaPlayer.Play();
		}

		private void btnPause_Click(object sender, RoutedEventArgs e)
		{
			mediaPlayer.Pause();
		}

		private void btnStop_Click(object sender, RoutedEventArgs e)
		{
			mediaPlayer.Stop();
		}
	}
}

An extended example of the MediaPlayer class

In this example, we have expanded our player a bit, so that it now contains a Play, Pause and Stop button, as well as a label for showing the current playback status. The MP3 file to be played is loaded the same way, but we do it as soon as the application starts, to keep the example simple.

Right after the MP3 is loaded, we start a timer, which ticks every second. We use this event to update the status label, which will show the current progress as well as the entire length of the loaded file.

The three buttons each simply call a corresponding method on the MediaPlayer object - Play, Pause and Stop.

Summary

There are several more options that you can let your user control, but I want to save that for when we have talked about the video aspects of the MediaPlayer class - at that point, I'll do a more complete example of a media player capable of playing both audio and video files, with more options.

<PreviousNext>
^ Back to Top