PETZOLD BOOK BLOG

Charles Petzold on writing books, reading books, and exercising the internal UTM


Recent Entries
< PreviousBrowse the ArchivesNext >
Subscribe to the RSS Feed

Playing Music Files on WP7

November 19, 2010
New York, N.Y.

Last month when I gave a talk before the NYC .NET Developer's Group on Windows Phone 7 programming, somebody asked if it were possible for a phone application to play MP3 or WMA files. I said that it was possible to play song files from the user's music library — in fact, I show how in Chapter 18 of Programming Windows Phone 7 — but I didn't see a way to play compressed audio files otherwise. (Playing PCM files is a subject of an article I'm currently working on for the February 2011 issue of MSDN Magazine.)

I was wrong. It is possible for a Windows Phone 7 application to access and play MP3 or WMA files that are stored as either content in the application or referenced over the internet. Such a file becomes an instance of the Song class that you instantiate with the Song.FromUri method. The URI references the file.

Song is an XNA class but you can use it in a Silverlight program. You'll need a reference to the Microsoft.Xna.Framework DLL — ignore the warning message; you are, after all a trained perfessional and you know what you're doing — and you'll want a using directive for the Microsoft.Xna.Framework.Media namespace.

In XNA, you can include an MP3 or WMA file in the program by adding it to the application's Content project, and then access it using the normal ContentManager object available through the Content property of the Game derivative. Call the generic Load method with a type of Song:

Song song = this.Content.Load<Song>("filename-without-extension");

In Silverlight for Windows Phone, just add the file in the application project, perhaps in a directory. By default, the Build Action in the file's properties should be Content, and that's what you should leave it as. You can then access the file using Song.FromUri method with a Uri object that references the filename and directory with a UriKind.Relative argument:

Song song = Song.FromUri("name", new Uri("dir/filename", UriKind.Relative));

The first argument becomes the Name property of the Song object. You can also access a music file over the internet in the same way but without the UriKind.Relative argument.

Song.FromUri returns an object of type Song that you then just pass to the static MediaPlayer.Play method.

MediaPlayer.Play(song);

The downloadable Silverlight PlaySong project (3.6 megs due to a WMA file in the project) demonstrates this technique with an MP3 file of a 1939 recording of the last movement of the Brahms Violin Concerto available on the Internet Archive site and a WMA file stored as content. This WMA file is a short electronic-music composition I originally recorded in 1977. The opening screen of the program looks like this:

You select one or the other, the file is loaded, and it starts playing. The button at the bottom lets you pause and resume.

To compile and run this program, you'll need the Windows Phone 7 development tools installed, of course. You can run the program in the emulator, and the music plays through your PC's speakers. But if you're deploying to an actual phone from Visual Studio, the Zune software can't be running, apparently because it wants total control of media. You'll need to exit Zune and run the WPDTPTConnect32 or 64 program instead so Visual Studio can communicate with the phone.

As with any Silverlight program that plays sounds or music through the XNA framework, your program must include code that calls FrameworkDispatcher.Update at approximately the same rate as the video display refresh, which is about 30 frames per second on the phone. This is commonly done in a separate class (called XnaFrameworkDispatcherService in this project) that is instantiated from the App.xaml file.

Programming Windows Phone 7
Programming Windows Phone 7

Free thousand-page ebook now available!

Comments:

Your screen shot tricked me into believing that you figured out how to extract the composer and conductor metadata out of the Brahms mp3/Song object! I downloaded the app to see how you did it, but I see you had to hard-code the data for the demo.

Mike Hodnick, Fri, 19 Nov 2010 15:06:26 -0500

Sorry for the confusion, Mike. — Charles

No worries...

Have you been able to successfully this app on a real device? I'm getting InvalidOperationExceptions thrown when the Song.FromUri() methods are called.

On a related note, I'm finding that most of my audio apps (MediaStreamSource based) are not working properly on a real WP7 device after getting them to work in the emulator. Your app doesn't use a MediaStreamSource but I'm finding the consistent problems with audio on a real device to be frustrating.

Mike Hodnick, Tue, 23 Nov 2010 16:37:23 -0500

Absolutely on a real device. As I mentioned, if you're running the program on a real device from Visual Studio, you need to use the Connect tool rather than Zune. If you've deployed the program to a real phone, try running the program on the phone with the phone disconnected from the PC. — Charles

The importance of reading strikes again! Pardon my ignorance.

Mike Hodnick, Wed, 24 Nov 2010 08:57:30 -0500

Hi Charles,

I loaded and played an MP3 through the Song.FromUri method in my app. It played once. Then every time after that it played a short blip of the song and the app closes.

Is there any special time/place or actions that are required for loading/playing the song?

Cheers,

Jeff Boggs, Wed, 24 Nov 2010 22:12:13 -0500

I have more extensive song-playing code in Chapter 18 of the book. — Charles

Getting slightly off topic here... but it seems as if the XNA MediaPlayer causes problems with MediaElement when using a custom MediaStreamSource. If I make any call to MediaPlayer (e.g. var state = MediaPlayer.State;), my MediaStreamSource is never asked for any samples. If I remove all calls/references to MediaPlayer, my MediaStreamSource produces samples and I can hear my audio. My FrameworkDispatcher is running in both scenarios, so I don't think the problem is with the FrameworkDispatcher. Any thoughts? I didn't find any references to MediaStreamSource in your book.

Mike Hodnick, Wed, 1 Dec 2010 09:24:10 -0500

I'm not even sure I realized that MediaStreamSource was supported under Silverlight for Windows Phone!

I suspect that you're seeing some kind of conflict on the OS level between the Silverlight interfaces and the XNA interfaces competing for audio resources. — Charles

MediaStreamSource is certainly supported. I've had no problems porting my Silverlight code that used MediaStreamSource to WP7.

The issue I'm running in to is Microsoft's WP7 certification requirement #6.5.1 - which is that you must ask the user if it is ok to stop any currently playing song before you take over the phone's media capabilities (which happens when MediaElement.SetSource() is called).

I've submitted questions on the App Hub forums as well as StackOverflow but I fear (as you mentioned) that there is a low-level OS conflict that cannot be fixed. If that's the case then most of my WP7 app ideas might have to be scrapped.

Mike Hodnick, Wed, 1 Dec 2010 10:20:03 -0500


Recent Entries
< PreviousBrowse the ArchivesNext >
Subscribe to the RSS Feed

(c) Copyright Charles Petzold
www.charlespetzold.com