Here's a deceptively simple question:
What is the proper way to asynchronously play an embedded .wav resource file in Windows Forms?
Attempt #1:
var player = new SoundPlayer();
player.Stream = Resources.ResourceManager.GetStream("mySound");
player.Play(); // Note that Play is asynchronous
- Good: doesn't block the UI thread
- Bad: SoundPlayer and the embedded resource stream are not immediately disposed.
Attempt #2:
using (var audioMemory = Resources.ResourceManager.GetStream("mySound"))
{
using (var player = new SoundPlayer(audioMemory))
{
player.Play();
}
}
- Good: UI thread is not blocked, SoundPlayer and audio memory stream are immediately disposed.
- Bad: Race condition! Play() is async, and if audio memory gets disposed before Play is done...boom! Runtime exception is thrown.
Attempt #3:
using (var audioMemory = Resources.ResourceManager.GetStream("mySound"))
{
using (var player = new SoundPlayer(audioMemory))
{
player.PlaySync();
}
}
- Good: Player and audio stream are immediately disposed.
- Bad: PlaySync blocks the UI thread
Attempt #4:
ThreadPool.QueueUserWorkItem(ignoredState =>
{
using (var audioMemory = Resources.ResourceManager.GetStream("mySound"))
{
using (var player = new SoundPlayer(audioMemory))
{
player.PlaySync();
}
}
});
- Good: UI doesn't freeze, player and memory stream are immediately disposed.
- Bad: Because this fires often, we may run out of thread pool threads! See Larry Osterman's what's wrong with this code part 26.
It seems like SoundPlayer should have a PlayAsyncCompleted event. Unfortunately, no such event exists. Am I missing something? What's the proper way to asynchronously play a .wav embedded resource in Windows Forms?