How to: Play Background Audio for Windows Phone
March 22, 2012
This topic demonstrates how to create a Windows Phone application for Windows Phone 7.5 that continues playing audio even when the application is no longer in the foreground. There are two types of background audio applications. One plays local media, and the other plays streaming media. This article describes how to implement a Windows Phone application that plays local media by using an audio playback agent.
Tip: |
|---|
For a description of the architecture of a background audio application, read the Background Audio Overview for Windows Phone. The overview also includes best practices to follow when implementing your app. |
To play background audio, create a Windows Phone Audio Playback Agent using the Silverlight project template for Windows Phone in Visual Studio. Then, reference the background agent from your application.
Tip:
|
|---|
|
For more information about playing background audio in a Windows Phone application, download the Background Audio Player Sample and the Background Audio Streamer Sample from the Code Samples for Windows Phone page. |
Important Note:
|
|---|
|
This article requires the use of the Windows Phone SDK. See Installing the Windows Phone SDK. |
Creating a Windows Phone Background Audio Application
-
Create a new project by selecting the File | New Project… menu command.
-
The New Project dialog is displayed. Expand the Visual C# templates, and then select the Silverlight for Windows Phone templates.
-
Select the Windows Phone Application template. Fill in the Name as desired and click OK.
-
Select Windows Phone 7.1 as the target version and click OK.
-
In Solution Explorer, right-click the Solution node and choose Add | New Project…
-
In the Add New Project dialog, click Windows Phone Audio Playback Agent.
-
Fill in the Name as desired and click OK.
-
Your solution should now have two projects, the application project and the background agent project.
Right-click the References node in the application project and select Add Reference…
-
In the Add Reference dialog, click the Projects tab. Select the background agent we created earlier and click OK.
Adding Audio Files
-
In Solution Explorer, right-click the application project and choose Add | New Folder. Name the folder Audio.
-
Right-click the Audio folder you just created and choose Add | Existing Item… from the context menu.
-
In the Add Existing Item dialog, navigate to “%PUBLIC%\Music\Sample Music” (usually C:\Users\Public\Music\Sample Music) and select several audio files. For information about file formats that the background audio player supports, see Supported Media Codecs for Windows Phone.
-
Click the Add button.
-
In Solution Explorer, select all the audio files you just added in the Audio directory. In the Properties pane, change the Copy to Output Directory field from “Do not copy” to “Copy if newer.”
Creating the User Interface
-
This application has a very simple user interface. In the Solution Explorer, double-click MainPage.xaml to open it in the XAML designer/editor.
-
Replace the StackPanel element named TitlePanel with the following XAML code:
<!--TitlePanel contains the name of the application and page title--> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock x:Name="ApplicationTitle" Text="BACKGROUND AUDIO PLAYER" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBlock x:Name="PageTitle" Text="play a song" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> </StackPanel>
-
Replace the Grid element named ContentPanel with this XAML code:
<!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <StackPanel Orientation="Horizontal" Width="420" Margin="18,40,18,0" VerticalAlignment="Top"> <Button Content="prev" x:Name="prevButton" Height="140" Width="140" Click="prevButton_Click"/> <Button Content="play" x:Name="playButton" Height="140" Width="140" Click="playButton_Click"/> <Button Content="next" x:Name="nextButton" Height="140" Width="140" Click="nextButton_Click"/> </StackPanel> <TextBlock x:Name="txtCurrentTrack" Height="75" HorizontalAlignment="Left" Margin="12,193,0,0" VerticalAlignment="Top" Width="438" TextWrapping="Wrap" /> </Grid>
A StackPanel is a very convenient element for arranging buttons. In this case, we arrange them horizontally by setting the Orientation property appropriately.
-
The user interface in the designer should look like this:
Modifying the Code Behind the User Interface
-
In Solution Explorer, right-click MainPage.xaml and choose View Code from the context menu.
-
Add the following using statements to the top of your MainPage.xaml.cs file:
-
Add the following button click event handler code to your MainPage class in MainPage.xaml.cs:
#region Button Click Event Handlers private void prevButton_Click(object sender, RoutedEventArgs e) { BackgroundAudioPlayer.Instance.SkipPrevious(); } private void playButton_Click(object sender, RoutedEventArgs e) { if (PlayState.Playing == BackgroundAudioPlayer.Instance.PlayerState) { BackgroundAudioPlayer.Instance.Pause(); } else { BackgroundAudioPlayer.Instance.Play(); } } private void nextButton_Click(object sender, RoutedEventArgs e) { BackgroundAudioPlayer.Instance.SkipNext(); } #endregion Button Click Event Handlers
Notice that the playButton_Click handler actually toggles between play and pause depending in the current state of playback.
-
In the constructor for the MainPage class, add an event handler for the PlayStateChanged event.
-
Implement the Instance_PlayStateChanged method as follows:
void Instance_PlayStateChanged(object sender, EventArgs e) { switch (BackgroundAudioPlayer.Instance.PlayerState) { case PlayState.Playing: playButton.Content = "pause"; break; case PlayState.Paused: case PlayState.Stopped: playButton.Content = "play"; break; } if (null != BackgroundAudioPlayer.Instance.Track) { txtCurrentTrack.Text = BackgroundAudioPlayer.Instance.Track.Title + " by " + BackgroundAudioPlayer.Instance.Track.Artist; } }
-
Since this application is designed to play audio in the background, it is likely that the user will return to this application with audio already playing. The user interface should show this by updating appropriately to reflect the current state of playback, as well as the currently playing track. To update the UI when the application is loaded, override the OnNavigatedTo virtual method by adding the following code to the MainPage class in MainPage.xaml.cs:
protected override void OnNavigatedTo(NavigationEventArgs e) { if (PlayState.Playing == BackgroundAudioPlayer.Instance.PlayerState) { playButton.Content = "pause"; txtCurrentTrack.Text = BackgroundAudioPlayer.Instance.Track.Title + " by " + BackgroundAudioPlayer.Instance.Track.Artist; } else { playButton.Content = "play"; txtCurrentTrack.Text = ""; } }
-
In Solution Explorer, right-click App.xaml and choose View Code from the context menu.
-
Add the following using statements to App.xaml.cs:
-
The BackgroundAudioPlayer can play files only from isolated storage or from a remote URI. Add the following method to your App class. Make sure the files array contains the actual names of the audio files you added to your project.
private void CopyToIsolatedStorage() { using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication()) { string[] files = new string[] { "Kalimba.mp3", "Maid with the Flaxen Hair.mp3", "Sleep Away.mp3" }; foreach (var _fileName in files) { if (!storage.FileExists(_fileName)) { string _filePath = "Audio/" + _fileName; StreamResourceInfo resource = Application.GetResourceStream(new Uri(_filePath, UriKind.Relative)); using (IsolatedStorageFileStream file = storage.CreateFile(_fileName)) { int chunkSize = 4096; byte[] bytes = new byte[chunkSize]; int byteCount; while ((byteCount = resource.Stream.Read(bytes, 0, chunkSize)) > 0) { file.Write(bytes, 0, byteCount); } } } } } }
-
Add a call to the CopyToIsolatedStorage method to the constructor for your App class.
The AudioPlayerAgent is the piece of the application that will continue to run in the background when the user switches to another foreground application.
Implementing the Audio Player Agent
-
In Solution Explorer, double-click AudioPlayer.cs in the Agent project to open the file in the code editor.
-
Add the following using statement to the top of AudioPlayer.cs:
-
In the AudioPlayer.cs file, declare a static integer at class scope level in the AudioPlayer class. This variable keeps the current track number.
-
Create a static list of tracks by adding the following code to the AudioPlayer class in AudioPlayer.cs:
// A playlist made up of AudioTrack items. private static List<AudioTrack> _playList = new List<AudioTrack> { new AudioTrack(new Uri("Kalimba.mp3", UriKind.Relative), "Kalimba", "Mr. Scruff", "Ninja Tuna", null), new AudioTrack(new Uri("Maid with the Flaxen Hair.mp3", UriKind.Relative), "Maid with the Flaxen Hair", "Richard Stoltzman", "Fine Music, Vol. 1", null), new AudioTrack(new Uri("Sleep Away.mp3", UriKind.Relative), "Sleep Away", "Bob Acri", "Bob Acri", null), // A remote URI new AudioTrack(new Uri("http://traffic.libsyn.com/wpradio/WPRadio_29.mp3", UriKind.Absolute), "Episode 29", "Windows Phone Radio", "Windows Phone Radio Podcast", null) };
Since it is declared at class scope, it is important that this list is designated as static so that it doesn’t get re-created every time a call is made into our agent.
-
To handle user actions such as clicking the play, next, and previous buttons, add the following three methods to the AudioPlayer class in AudioPlayer.cs:
private void PlayNextTrack(BackgroundAudioPlayer player) { if (++currentTrackNumber >= _playList.Count) { currentTrackNumber = 0; } PlayTrack(player); } private void PlayPreviousTrack(BackgroundAudioPlayer player) { if (--currentTrackNumber < 0) { currentTrackNumber = _playList.Count - 1; } PlayTrack(player); } private void PlayTrack(BackgroundAudioPlayer player) { // Sets the track to play. When the TrackReady state is received, // playback begins from the OnPlayStateChanged handler. player.Track = _playList[currentTrackNumber]; }
-
To handle play state changes, add the following switch statement to the OnPlayStateChanged method, before the call to NotifyComplete:
-
To handle user actions, add the following switch statement to the OnUserAction method, before the call to NotifyComplete:
This is all the code necessary to implement a very basic application that plays audio in the background. This application will run under the lock screen and the universal volume control (UVC) will even control the playback from this application. There is, of course, much more that you can implement such as a much richer user interface, support for playing audio from a remote source using a web URI to an audio file, and so on. We also did not implement support for user actions such as stop, fast-forward, rewind, or seek.
Tip:
Important Note: