Play Background Audio In Windows 7.1 Mango Phone

In this article, I provide a walkthrough to "Play Background Audio" in Mango or a Window 7.1 phone. This article is fully based on the Beta version. In this article, I will show how to play local media.

In this article, I will provide a walkthrough to "Play Background Audio" in Mango or a Windows 7.1 phone. This article is fully based on the Beta version and you will see how to play local media.

Step 1: Firstly, let us create a Windows Phone Application. To create it, open Visual Studio and select Windows Phone Application from the installed templates.

AudWinPho1.gif

Since Background Audio playing is a feature of 7.1 version, do not forget to select Windows Phone 7.1 as the Target Version.

AudWinPho2.gif

Step 2:

The next step we need to do is to add a project for Audio Playback Agent. So, right-click the solution and add a new project and from installed templates select Windows Phone Audio Playback Agent project type.

AudWinPho3.gif

After adding this project, you will have two projects in the Solution Explorer. One is an Audio Playback Agent and another is the Phone Application.

AudWinPho4.gif

Step 3:

Since both the projects have been created, now add a few music files to play. To do this right-click on AudioPlaybackAgent project and create a new folder. Give desired name to this folder. In this case, I am naming the newly created folder Music.

Right-click on the Music folder and add existing items. Add music files to this folder.

AudWinPho5.gif

After adding Music files select all the Music files, right-click and open Properties:

AudWinPho6.gif

In the Properies windows you need to change Copy to Output Directory property to Copy if newer:

AudWinPho7.gif

Step 4:

By now, music resources are added. Now you need to create a representation class for the songs track. Right-click on AudioPlaybackAgent project and add a class. Give a desired name.

AudWinPho8.gif

Track.cs

  1. using System;  
  2. namespace AudioPlaybackAgent1  
  3. {  
  4.     public class Track  
  5.     {  
  6.         public Uri Source  
  7.         {  
  8.             get;  
  9.             set;  
  10.         }  
  11.         public string Artist   
  12.         {  
  13.             get;  
  14.             set;  
  15.         }  
  16.         public string Title  
  17.         {  
  18.             get;  
  19.             set;  
  20.         }  
  21.         public string Album   
  22.         {  
  23.             get;  
  24.             set;  
  25.         }  
  26.         public Track(Uri source, string artist, string title, string album)  
  27.         {  
  28.             Source = source;  
  29.             Artist = artist;  
  30.             Title = title;  
  31.             Album = album;  
  32.         }  
  33.     }  
  34. }  

Step 5: Let us add required functionalities or modify default functionalities to perform various operations on an Audio file. 

Returning List of Songs

Firstly, you need to return a list of songs. To return a list of songs use GetSongs() in the AudioPlayer.cs class:

AudWinPho9.gif

The above function is returning a list of Tracks.

To track the record number add a class level global variable. Let us say we have added:

AudWinPho10.gif

Playing Song

Now we need to add a function to play a song. Create a function called Play.

AudWinPho11.gif
  1. As Input parameter pass a BackGroundAudioPlayer object.

  2. Create a Track to play. As a parameter you need to pass the source of the track, title, artist and album name.

  3. After creation of the Track call the Play () method on the BackgroundAudioPlayer object.

Playing Next Song

To play the next song we need to track the current track record and increase it by 1. Once it is equal to the total number of songs in the list reinitialize it to 0.

AudWinPho12.gif

Playing Previous Song

To play the previous song we need to track the current track record and decrease it by 1. Once it is less than 0 then reinitialize it to the maximum number of songs in the list.

AudWinPho13.gif

Handling User actions

We need to handle user actions like Play, Stop, and Pause etc. For that we need to modify the overridden function on UserAction. Add the following switch case in the on UserAction method.

AudWinPho14.gif

Handling Play state changes

To handle Play state changes add the following switch case in the OnPlayStateChanged() overridden method.

AudWinPho15.gif

Finally, after adding all the required functions and making all modifications to the AudioPlayer.cs class it would look like below:

AudioPlayer.cs

  1. using System;  
  2. using Microsoft.Phone.BackgroundAudio;  
  3. using System.Collections.Generic;  
  4. namespace AudioPlaybackAgent1  
  5. {  
  6.     public class AudioPlayer: AudioPlayerAgent  
  7.     {  
  8.         static int CurrentTrackPlaying = 0;  
  9.         /// <summary>  
  10.         /// Called when the playstate changes, except for the Error state (see OnError)  
  11.         /// </summary>  
  12.         /// <param name="player">The BackgroundAudioPlayer</param>  
  13.         /// <param name="track">The track playing at the time the playstate changed</param>  
  14.         /// <param name="playState">The new playstate of the player</param>  
  15.         /// <remarks>  
  16.         /// Play State changes cannot be cancelled. They are raised even if the application  
  17.         /// caused the state change itself, assuming the application has opted-in to the callback  
  18.         /// </remarks>  
  19.         protected override void OnPlayStateChanged(BackgroundAudioPlayer player, AudioTrack track, PlayState playState) {  
  20.                 base.OnPlayStateChanged(player, track, playState);  
  21.                 //TODO: Add code to handle play state changes  
  22.                 switch (playState)  
  23.                 {  
  24.                     case PlayState.TrackEnded:  
  25.                         PlayNext(player);  
  26.                         break;  
  27.                 }  
  28.                 NotifyComplete();  
  29.             }  
  30.             /// <summary>  
  31.             /// Called when the user requests an action using system-provided UI and the application has requesed  
  32.             /// notifications of the action  
  33.             /// </summary>  
  34.             /// <param name="player">The BackgroundAudioPlayer</param>  
  35.             /// <param name="track">The track playing at the time of the user action</param>  
  36.             /// <param name="action">The action the user has requested</param>  
  37.             /// <param name="param">The data associated with the requested action.  
  38.             /// In the current version this parameter is only for use with the Seek action,  
  39.             /// to indicate the requested position of an audio track</param>  
  40.             /// <remarks>  
  41.             /// User actions do not automatically make any changes in system state; the agent is responsible  
  42.             /// for carrying out the user actions if they are supported  
  43.             /// </remarks>  
  44.         protected override void OnUserAction(BackgroundAudioPlayer player, AudioTrack track, UserAction action,  
  45.                 object param)  
  46.         {  
  47.                 base.OnUserAction(player, track, action, param);  
  48.                 switch (action)  
  49.                 {  
  50.                     case UserAction.Play:  
  51.                         Play(player);  
  52.                         break;  
  53.                     case UserAction.Pause:  
  54.                         player.Pause();  
  55.                         break;  
  56.                     case UserAction.Stop:  
  57.                         player.Stop();  
  58.                         break;  
  59.                     case UserAction.FastForward:  
  60.                         player.FastForward();  
  61.                         break;  
  62.                     case UserAction.Rewind:  
  63.                         player.Rewind();  
  64.                         break;  
  65.                     case UserAction.SkipPrevious:  
  66.                         PlayBack(player);  
  67.                         break;  
  68.                     case UserAction.SkipNext:  
  69.                         PlayNext(player);  
  70.                         break;  
  71.                     case UserAction.Seek:  
  72.                         player.Position = (TimeSpan) param;  
  73.                         break;  
  74.                 }  
  75.                 //TODO: Add code to handle user actions through the application and system-provided UI  
  76.                 NotifyComplete();  
  77.             }  
  78.             /// <summary>  
  79.             /// Called whenever there is an error with playback, such as an AudioTrack not downloading correctly  
  80.             /// </summary>  
  81.             /// <param name="player">The BackgroundAudioPlayer</param>  
  82.             /// <param name="track">The track that had the error</param>  
  83.             /// <param name="error">The error that occured</param>  
  84.             /// <param name="isFatal">If true, playback cannot continue and playback of the track will stop</param>  
  85.             /// <remarks>  
  86.             /// This method is not guaranteed to be called in all cases. For example, if the background agent  
  87.             /// itself has an unhandled exception, it won't get called back to handle its own errors.  
  88.             /// </remarks>  
  89.         protected override void OnError(BackgroundAudioPlayer player, AudioTrack track, Exception error, bool isFatal)  
  90.             {  
  91.                 base.OnError(player, track, error, isFatal);  
  92.                 //TODO: Add code to handle error conditions  
  93.                 NotifyComplete();  
  94.             }  
  95.             /// <summary>  
  96.             /// Called when the agent request is getting cancelled  
  97.             /// </summary>  
  98.         protected override void OnCancel()   
  99.         {  
  100.             base.OnCancel();  
  101.             NotifyComplete();  
  102.         }  
  103.         private List < Track > GetSongs()  
  104.         {  
  105.             List < Track > lstSongs = new List < Track > ()   
  106.             {  
  107.                 new Track(new Uri("TujheBhulaDia.mp3", UriKind.Relative),  
  108.                         "Ranveer Kapoor and Priyanka Chopra",  
  109.                         "Tumhe Bhula Dia",  
  110.                         "Anajana Anjani"),  
  111.                     new Track(new Uri("AasPassKhuda.mp3", UriKind.Relative),  
  112.                         "Ranveer Kapoor and Priyanka Chopra",  
  113.                         "Aas Paass Khuda",  
  114.                         "Anajana Anjani"),  
  115.                     new Track(new Uri("AnajanAnajni.mp3", UriKind.Relative),  
  116.                         "Ranveer Kapoor and Priyanka Chopra",  
  117.                         "Anajana Anjani",  
  118.                         "Anajana Anjani")  
  119.             };  
  120.             return lstSongs;  
  121.         }  
  122.         private void Play(BackgroundAudioPlayer player)   
  123.         {  
  124.             var songs = GetSongs();  
  125.             var currentTrack = songs[CurrentTrackPlaying];  
  126.             player.Track = new AudioTrack(currentTrack.Source,  
  127.                 currentTrack.Title,  
  128.                 currentTrack.Artist,  
  129.                 currentTrack.Album,  
  130.                 null);  
  131.             player.Play();  
  132.         }  
  133.         private void PlayNext(BackgroundAudioPlayer player)  
  134.         {  
  135.             var songsCount = GetSongs().Count;  
  136.             if (++CurrentTrackPlaying >= songsCount)  
  137.             {  
  138.                 CurrentTrackPlaying = 0;  
  139.             }  
  140.             Play(player);  
  141.         }  
  142.         private void PlayBack(BackgroundAudioPlayer player)  
  143.         {  
  144.             var songsCount = GetSongs().Count;  
  145.             if (--CurrentTrackPlaying < 0)  
  146.             {  
  147.                 CurrentTrackPlaying = songsCount - 1;  
  148.             }  
  149.             Play(player);  
  150.         }  
  151.     }  
  152. }  
Step 6:

Add a reference for the AudioPlaybackAgent1 project in the Phone Application project. For that right-click on Phone Application project and select Add Reference. In the dialog box choose the Projects tab and choose AudioPlaybackAgent1.

AudWinPho16.gif

Step 7:

To play audio we have done all modification and added codes to AudioPlayBackAgent1 project. Now you need to create a UI in the Phone application project.

Create UI
  1. Add three buttons for Play, Previous and Next

  2. Add a Text block to display Track information

MainPage.xaml

After modifying the above code the user interface would look like:

AudWinPho17.gif

We need to handle click events. Firstly, add the following namespaces:

AudWinPho18.gif

And a click event for three buttons would be fairly straight forward.

AudWinPho19.gif

We need only to call SkipNext and SkipPrevious methods on instance of BackgroundAudioPlayer.

Handling Background player Play State changed event

First you need to register an event in the constructor of MainPage class. This event would check if playing track is not null then would display information in the text block.

AudWinPho20.gif

Handling user Navigation

Since audio would be playing in the background so when user will navigate should be displayed with meaningful information. For that you need to override OnNavigatedTo virtual method.

AudWinPho21.gif

After adding all required events eventually MainPage.xaml.cs will be as below:

MainPage.xaml.cs

  1. using System;  
  2. using System.Windows;  
  3. using Microsoft.Phone.Controls;  
  4. using System.Windows.Navigation;  
  5. using Microsoft.Phone.BackgroundAudio;  
  6. namespace PhoneApp1  
  7. {  
  8.     public partial class MainPage: PhoneApplicationPage  
  9.     {  
  10.         public MainPage()  
  11.         {  
  12.             InitializeComponent();  
  13.             BackgroundAudioPlayer.Instance.PlayStateChanged += new EventHandler(Instance_PlayStateChanged);  
  14.             prevButton.Click += new RoutedEventHandler(prevButton_Click);  
  15.             nextButton.Click += new RoutedEventHandler(nextButton_Click);  
  16.             playButton.Click += new RoutedEventHandler(playButton_Click);  
  17.         }  
  18.         void Instance_PlayStateChanged(object sender, EventArgs e)  
  19.         {  
  20.             AudioTrack tracks = BackgroundAudioPlayer.Instance.Track;  
  21.             if (tracks != null)  
  22.             {  
  23.                 txtCurrentTrack.Text = tracks.Title + " by " + tracks.Artist;  
  24.             }  
  25.         }  
  26.         void playButton_Click(object sender, RoutedEventArgs e)  
  27.         {  
  28.             if (PlayState.Playing == BackgroundAudioPlayer.Instance.PlayerState)   
  29.             {  
  30.                 BackgroundAudioPlayer.Instance.Pause();  
  31.                 playButton.Content = "play";  
  32.             } else {  
  33.                 BackgroundAudioPlayer.Instance.Play();  
  34.                 playButton.Content = "pause";  
  35.             }  
  36.         }  
  37.         void nextButton_Click(object sender, RoutedEventArgs e)  
  38.         {  
  39.             BackgroundAudioPlayer.Instance.SkipNext();  
  40.         }  
  41.         void prevButton_Click(object sender, RoutedEventArgs e)  
  42.         {  
  43.             BackgroundAudioPlayer.Instance.SkipPrevious();  
  44.         }  
  45.         protected override void OnNavigatedTo(NavigationEventArgs e)  
  46.         {  
  47.             if (PlayState.Playing == BackgroundAudioPlayer.Instance.PlayerState)   
  48.             {  
  49.                 playButton.Content = "pause";  
  50.                 txtCurrentTrack.Text = BackgroundAudioPlayer.Instance.Track.Title +  
  51.                     " by " +  
  52.                     BackgroundAudioPlayer.Instance.Track.Artist;  
  53.             } else   
  54.             {  
  55.                 playButton.Content = "play";  
  56.                 txtCurrentTrack.Text = "";  
  57.             }  
  58.         }  
  59.     }  
  60. }  
Step 8: BackGroundAudioPlayer can only play a song from a remote URL or file in Isolated Storage. For that you need to add a function in App.Xaml.cs.

Adding music File to Isolated Storage

AudWinPho22.gif

In the above function the points to be noted are:
  1. Files name are exactly the same as you added in previous steps.

  2. The folder name is exactly the same.

  3. The sequence of File names in string array files is exactly the same as you are returning from GetSongs() method.

  4. Call this function in constructor of App class.

App.xaml.cs

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Net;  
  5. using System.Windows;  
  6. using System.Windows.Controls;  
  7. using System.Windows.Documents;  
  8. using System.Windows.Input;  
  9. using System.Windows.Media;  
  10. using System.Windows.Media.Animation;  
  11. using System.Windows.Navigation;  
  12. using System.Windows.Shapes;  
  13. using Microsoft.Phone.Controls;  
  14. using Microsoft.Phone.Shell;  
  15. using System.IO.IsolatedStorage;  
  16. using System.Windows.Resources;  
  17.    
  18.    
  19. namespace PhoneApp1  
  20. {  
  21.     public partial class App : Application  
  22.     {  
  23.         /// <summary>  
  24.         /// Provides easy access to the root frame of the Phone Application.  
  25.         /// </summary>  
  26.         /// <returns>The root frame of the Phone Application.</returns>  
  27.         public PhoneApplicationFrame RootFrame { getprivate set; }  
  28.         /// <summary>  
  29.         /// Constructor for the Application object.  
  30.         /// </summary>  
  31.         public App()  
  32.         {  
  33.             // Global handler for uncaught exceptions.   
  34.             UnhandledException += Application_UnhandledException;  
  35.    
  36.             // Standard Silverlight initialization  
  37.             InitializeComponent();  
  38.    
  39.             // Phone-specific initialization  
  40.             InitializePhoneApplication();  
  41.    
  42.             // Show graphics profiling information while debugging.  
  43.             if (System.Diagnostics.Debugger.IsAttached)  
  44.             {  
  45.                 // Display the current frame rate counters.  
  46.                 Application.Current.Host.Settings.EnableFrameRateCounter = true;  
  47.    
  48.                 // Show the areas of the app that are being redrawn in each frame.  
  49.                 //Application.Current.Host.Settings.EnableRedrawRegions = true;  
  50.    
  51.                 // Enable non-production analysis visualization mode,   
  52.                 // which shows areas of a page that are handed off to GPU with a colored overlay.  
  53.                 //Application.Current.Host.Settings.EnableCacheVisualization = true;  
  54.    
  55.                 // Disable the application idle detection by setting the UserIdleDetectionMode property of the  
  56.                 // application's PhoneApplicationService object to Disabled.  
  57.                 // Caution:- Use this under debug mode only. Application that disable user idle detection will continue to run  
  58.                 // and consume battery power when the user is not using the phone.  
  59.                 PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;  
  60.             }  
  61.             CopyToIsolatedStorage();  
  62.    
  63.         }  
  64.    
  65.         // Code to execute when the application is launching (eg, from Start)  
  66.         // This code will not execute when the application is reactivated  
  67.         private void Application_Launching(object sender, LaunchingEventArgs e)  
  68.         {  
  69.         }  
  70.    
  71.         // Code to execute when the application is activated (brought to foreground)  
  72.         // This code will not execute when the application is first launched  
  73.         private void Application_Activated(object sender, ActivatedEventArgs e)  
  74.         {  
  75.         }  
  76.    
  77.         // Code to execute when the application is deactivated (sent to background)  
  78.         // This code will not execute when the application is closing  
  79.         private void Application_Deactivated(object sender, DeactivatedEventArgs e)  
  80.         {  
  81.         }  
  82.         // Code to execute when the application is closing (eg, user hit Back)  
  83.         // This code will not execute when the application is deactivated  
  84.         private void Application_Closing(object sender, ClosingEventArgs e)  
  85.         {  
  86.         }  
  87.   
  88.         // Code to execute if a navigation fails  
  89.         private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)  
  90.         {  
  91.             if (System.Diagnostics.Debugger.IsAttached)  
  92.             {  
  93.                 // A navigation has failed; break into the debugger  
  94.                 System.Diagnostics.Debugger.Break();  
  95.             }  
  96.         }  
  97.    
  98.         // Code to execute on Unhandled Exceptions  
  99.         private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)  
  100.         {  
  101.             if (System.Diagnostics.Debugger.IsAttached)  
  102.             {  
  103.                 // An unhandled exception has occurred; break into the debugger  
  104.                 System.Diagnostics.Debugger.Break();  
  105.             }  
  106.         }  
  107.    
  108.         private void CopyToIsolatedStorage()  
  109.         {  
  110.             using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())  
  111.             {  
  112.                 string[] files = new string[] { "TujheBhulaDia.mp3""AasPassKhuda.mp3""AnajanAnajni.mp3" };  
  113.    
  114.                 foreach (var _fileName in files)  
  115.                 {  
  116.                     if (!storage.FileExists(_fileName))  
  117.                     {  
  118.                         string _filePath = "Music/" + _fileName;  
  119.                         StreamResourceInfo resource = Application.GetResourceStream(new Uri(_filePath, UriKind.Relative));  
  120.    
  121.                         using (IsolatedStorageFileStream file = storage.CreateFile(_fileName))  
  122.                         {  
  123.                             int chunkSize = 4096;  
  124.                             byte[] bytes = new byte[chunkSize];  
  125.                             int byteCount;  
  126.                             while ((byteCount = resource.Stream.Read(bytes, 0, chunkSize)) > 0)  
  127.                             {  
  128.                                 file.Write(bytes, 0, byteCount);  
  129.                             }  
  130.                         }  
  131.                     }  
  132.                 }  
  133.             }  
  134.         }  
  135.  
  136.         #region Phone application initialization  
  137.    
  138.         // Avoid double-initialization  
  139.         private bool phoneApplicationInitialized = false;  
  140.    
  141.         // Do not add any additional code to this method  
  142.         private void InitializePhoneApplication()  
  143.         {  
  144.             if (phoneApplicationInitialized)  
  145.                 return;  
  146.    
  147.             // Create the frame but don't set it as RootVisual yet; this allows the splash  
  148.             // screen to remain active until the application is ready to render.  
  149.             RootFrame = new PhoneApplicationFrame();  
  150.             RootFrame.Navigated += CompleteInitializePhoneApplication;  
  151.    
  152.             // Handle navigation failures  
  153.             RootFrame.NavigationFailed += RootFrame_NavigationFailed;  
  154.    
  155.             // Ensure we don't initialize again  
  156.             phoneApplicationInitialized = true;  
  157.         }  
  158.         // Do not add any additional code to this method  
  159.         private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)  
  160.         {  
  161.             // Set the root visual to allow the application to render  
  162.             if (RootVisual != RootFrame)  
  163.                 RootVisual = RootFrame;  
  164.    
  165.             // Remove this handler since it is no longer needed  
  166.             RootFrame.Navigated -= CompleteInitializePhoneApplication;  
  167.         }  
  168.   
  169.         #endregion  
  170.     }  
  171. }  
Step 9:

Now you have created a background music player. Press F5 to run the application. 
AudWinPho23.gif

Read more articles on Microsoft Phone Development: