A taste of development

April 3, 2008

Playing Multiple Simultaneous Sounds in WPF

Filed under: Technology —Tagged , , — simma1990 @ 1:04 pm

Also see: Bloggers in the Mavs Locker Room ?

WPF’s MediaElement makes simple media playback pretty straightforward, but moving beyond the simple scenarios can sometimes raise surprising challenges. For example, I recently saw someone tripped up by the MediaElement when attempting to play several sounds concurrently.

As you’ll see, one solution would have been to use MediaPlayer instead of MediaElement. The difference between these WPF classes is fairly straightforward. MediaPlayer is the class that knows how to play media files – both video and audio. MediaElement is a wrapper around MediaPlayer that provides a simple way to connect it into a visual tree (i.e. a user interface), which in turn lets us hook it into things like the animation system or event triggers.

(Note: do not be misled by the class name. Although WPF and Windows Media Player depend on the same infrastructure for media decoding, the MediaPlayer class is not a wrapper around the Windows Media Player control. While they share codecs, the path by which decoded video gets onto the screen in WPF is significantly different from Windows Media Player.)

How would that get you into trouble when using MediaElement? If it’s a wrapper around MediaPlayer, surely you could use a MediaElement any place a MediaPlayer would work? In fact it’s not always that simple. To see why, we’ll start with a simple example.

One MediaElement

The simplest way to use MediaElement is to add it to a UI and point it at a media file:

Also see: Natural Sorting in C#

Also see: Passing the Community Torch: In Search of a New Chief Executive in Redmond

Also see: Parallels adds “Express Windows Installation”

Also see: When Will Foreign Ownership of US Sports Teams Start ?

Also see: Why Yahoo should say Yes to MicroSoft

Also see: The Internet is Officially Dead & Boring - Its the economy stupid !

Also see: The 2 Technology Magazines You Should Read

<Window x:Class="MediaPlayback.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="Window1" Height="300" Width="300">

 <MediaElement Source="file:///c:/windows/media/tada.wav" />

</Window>

This will play the file soon as the UI loads. If you want a bit more control, you can tell it to wait until you’re ready:

<MediaElement x:Name="audioPlayer"
 Source="file:///c:/windows/media/tada.wav"
 LoadedBehavior="Manual" />
Live Person Server: Live Chat Server for Online Customer Service on Website.

Also see: Silverlight 2 Beta 1 Cross Domain Bug

Also see: Mix 08 Sessions Published

Also see: We Live in an “Open Book” World, the Lie of Information Overload

Also see: Single source code base for Silverlight and WPF solutions

Also see: Important changes to the BASE element for IE 7

Also see: REST2SQL in a Jiffy, with Tagspace for Spice

Also see: The 2 Technology Magazines You Should Read

Also see: A Quick Fix for the Validator SetFocusOnError Bug

Also see: Determining Whether a File Is an Assembly

Also see: On the Perils of Wikipedia

Also see: The PDC and Application Compatibility, but still no Hosting

Also see: A Couple of My Rules for Startups

Also see: DevWeek 2008 Cross Platform Silverlight Demos

Also see: Versioning/Deploying Unmanaged Files

Also see: Java Frameworks State of the (dis)Union.

Also see: Help John Baez and Mike Stay!

Also see: DevWeek 2008 Cross Platform Silverlight Demos

Also see: Is this the best NBA season ever ?

Also see: Hosting

Also see: Sometimes, it’s the small things..

Also see: Finally, the Killer App

Also see: A Couple of My Rules for Startups

Also see: From C# to Java: Part 4

Also see: On the Perils of Wikipedia

Also see: Java perfomance talk

Also see: Startup, Shutdown and related matters

It’ll now hold off until you call audioPlayer.Play().

This approach is also often sufficient for playing multiple different sounds. you can change the Source property and call Play again. However, if you want to play multiple sounds simultaneously, this approach doesn’t work – setting the Source will stop playback if it is in progress. A single MediaElement or MediaPlayer can only play one thing at a time.

That’s OK, because we can always create multiple MediaElements.

Multiple MediaElements

Modifying the example above simply by adding multiple MediaElements to the Window will stop the Xaml from compiling, because Window can have only a single direct descendant. So we need to find something to hold the MediaElements. And this is where the example I saw tripped up: the developer put them into the UI’s Resources section.

On the face of it, this was a perfectly reasonable thing to do – the elements are all playing audio, so it doesn’t seem like they should need to be part of the visual tree, so why not make them resources? After all, WPF’s resource mechanism is designed to hold useful objects, right?

Well this is where the difference between MediaPlayer and MediaElement becomes important. Remember, the distinction is that MediaElement connects media playback into a visual tree. And it turns out that until it makes that connection, MediaElement won’t play the media. That makes sense for video – you don’t want that to start playing before you can see it. But while you might think a connection with the visual tree would be optional for audio, MediaElement sees it differently. (And there are reasons for that. For example, MediaElement can synchronize media playback with timelines of animations in the visual tree.)

Live Help Server: Jerry Messenger is Jabber/XMPP Live Chat Server for a website.

Also see: JSR-294 Superpackages

Also see: REST2SQL in a Jiffy, with Tagspace for Spice

Also see: Big in Japan

Also see: Determining the Referencing Assembly

Also see: Finalization

Also see: Interested in Artificial Intelligence? What about Wiki’s? Well, now you can have both.

Also see: The PDC and Application Compatibility, but still no Hosting

So in this case, the extra functionality provided by the wrapper has worked against us.

One solution is simply to give the MediaElement what it wants. As long as we put it into the visual tree, it’s happy. So we can put the elements into a layout panel such as a Grid or Canvas:

<Canvas>
 <MediaElement x:Name="mediaElem1"
  Source="file:///c:/windows/media/tada.wav"
  LoadedBehavior="Manual" />
 <MediaElement x:Name="mediaElem2"
  Source="file:///c:/windows/media/Windows Logoff Sound.wav"
  LoadedBehavior="Manual" />
</Canvas>
Softwre Development for small and middle size companies. World-class software applications.

Also see: Tagspace: Social Bookmarking for the Whole Web…from Microsoft

Also see: Data Types a la Carte

Also see: Alexbarn Leaves Microsoft…ARGH!

Also see: My Presidential Endorsement:

Also see: Eriskay: a Programming Language Based on Game Semantics

Also see: Apartments and Pumping in the CLR

Also see: Turning bitboards from potential moves into legal moves, pawn moves, and conditional rules.

Also see: My Presidential Endorsement:

Also see: Help John Baez and Mike Stay!

Also see: SIGPLAN Workshop on Undergraduate Programming Language Curriculum

Also see: C# 3.0 Lambdas and Type Inference

Also see: Versioning/Deploying Unmanaged Files

Also see: Why Yahoo should say Yes to MicroSoft

The other approach is to go straight for the MediaPlayer – if we have no need for the visual tree integration features MediaElement offers, we may as well go straight to the underlying player. The only snag is that you can’t initialize MediaPlayer from Xaml – you must use the Open method to point it at the media file, and Xaml doesn’t do method calls. But it’s not a huge amount of effort:

MediaPlayer mp = new MediaPlayer();
mp.Open(new Uri(wavPath));
mp.Play();

That is all the code required; we don’t need anything at all in the Xaml. And to play multiple simultaneous sounds, you can simply create multiple MediaPlayers.

http://www.interact-sw.co.uk/iangblog/2008/01/25/wpf-concurrent-audio

Comments are closed.

Powered by WordPress Hosted by Edublogs.