C# 如何使用 System.Media.SoundPlayer 异步播放声音文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1161229/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use System.Media.SoundPlayer to asynchronously play a sound file?
提问by Judah Gabriel Himango
Here's a deceptively simple question:
这是一个看似简单的问题:
What is the proper way to asynchronously play an embedded .wav resource file in Windows Forms?
在 Windows 窗体中异步播放嵌入式 .wav 资源文件的正确方法是什么?
Attempt #1:
尝试#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.
- 好:不会阻塞 UI 线程
- 坏: SoundPlayer 和嵌入的资源流没有立即处理。
Attempt #2:
尝试#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.
- 好:UI 线程没有被阻塞,SoundPlayer 和音频内存流被立即处理。
- 坏:比赛条件!Play() 是异步的,如果在 Play 完成之前处理了音频内存...... 抛出运行时异常。
Attempt #3:
尝试#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
- 好:立即处理播放器和音频流。
- 错误:PlaySync 阻塞 UI 线程
Attempt #4:
尝试#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.
- 好:UI 不会冻结,播放器和内存流会立即处理。
- 坏处:因为这经常触发,我们可能会用完线程池线程!请参阅 Larry Osterman 的代码第 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?
SoundPlayer 似乎应该有一个 PlayAsyncCompleted 事件。不幸的是,不存在这样的事件。我错过了什么吗?在 Windows 窗体中异步播放 .wav 嵌入资源的正确方法是什么?
采纳答案by BlueShepherd
I don't have enough reputation to comment so I'll just answer.
我没有足够的声誉来发表评论,所以我只会回答。
If your requirements to play sound are "deceptively simple" (you just want to play the occasional sound when a single winform user does something) then I would use Attempt #4 above.
如果您对播放声音的要求“看似简单”(您只想在单个 winform 用户执行某些操作时偶尔播放声音),那么我将使用上面的尝试 #4。
Larry Osterman's "what's wrong with this code part 26" has his "system" spin off a new threadpool thread (to play sound) with each keystroke. He indicates than hammering away on it saturated the default 500 thread pool size in about 15 seconds of typing but this was also with a client/server app using async RPC that were also using the threadpool. Really not a "deceptively simple" application.
拉里·奥斯特曼 (Larry Osterman) 的“这段代码第 26 部分有什么问题”让他的“系统”在每次击键时分离出一个新的线程池线程(播放声音)。他表示,在大约 15 秒的打字时间内,它会饱和默认的 500 个线程池大小,但这也是使用异步 RPC 的客户端/服务器应用程序也使用线程池。真的不是一个“看似简单”的应用程序。
If you are trying to queue sound bytes every second (or faster) for 10s or 100s of seconds at a time then its really not a "simple application" and a queued threading/priority subsystem would probably be in order.
如果您试图将声音字节每秒(或更快)排队 10 秒或 100 秒,那么它实际上不是一个“简单的应用程序”,并且排队的线程/优先级子系统可能是有序的。
回答by MusiGenesis
I still use the good ol' waveOut____ functions from the win32 API. Here's a good code sample:
我仍然使用 win32 API 中的好 ol'waveOut____ 函数。这是一个很好的代码示例:
http://www.codeproject.com/KB/audio-video/cswavplay.aspx
http://www.codeproject.com/KB/audio-video/cswavplay.aspx
Edit: a much simpler solution to your problem is to extract the embedded resource, save it as a real file somewhere, and then use SoundPlayer to play the file. A little clunky, but simple and you won't have the resource disposal problem.
编辑:解决您的问题的一个更简单的解决方案是提取嵌入的资源,将其作为真实文件保存在某处,然后使用 SoundPlayer 播放该文件。有点笨重,但很简单,你不会有资源处理问题。