Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/262.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用System.Media.SoundPlayer异步播放声音文件?_C#_Winforms_Audio - Fatal编程技术网

C# 如何使用System.Media.SoundPlayer异步播放声音文件?

C# 如何使用System.Media.SoundPlayer异步播放声音文件?,c#,winforms,audio,C#,Winforms,Audio,这里有一个看似简单的问题: 在Windows窗体中异步播放嵌入式.wav资源文件的正确方法是什么? 尝试#1: 好:不会阻塞UI线程 坏:SoundPlayer和嵌入式 资源流不会立即恢复 处置 尝试#2: 好:UI线程未被阻塞,SoundPlayer和音频内存流立即被释放 坏:比赛条件!Play()是异步的,如果音频内存在播放完成之前被释放,那么…砰!引发运行时异常 尝试#3: 好:立即处理播放器和音频流 错误:PlaySync阻止UI线程 尝试#4: 好:UI不会冻结,播放器和

这里有一个看似简单的问题:

在Windows窗体中异步播放嵌入式.wav资源文件的正确方法是什么?

尝试#1:

  • 好:不会阻塞UI线程
  • 坏:SoundPlayer和嵌入式 资源流不会立即恢复 处置
尝试#2:

  • 好:UI线程未被阻塞,SoundPlayer和音频内存流立即被释放
  • 坏:比赛条件!Play()是异步的,如果音频内存在播放完成之前被释放,那么…砰!引发运行时异常
尝试#3:

  • 好:立即处理播放器和音频流
  • 错误:PlaySync阻止UI线程
尝试#4:

  • 好:UI不会冻结,播放器和内存流立即被释放
  • 坏:因为这经常触发,我们可能会耗尽线程池线程!看拉里·奥斯特曼的

似乎SoundPlayer应该有一个完整的事件。不幸的是,不存在这样的事件。我错过什么了吗?在Windows窗体中异步播放.wav嵌入式资源的正确方法是什么?

我仍然使用win32 API中的良好ol'waveOut\uuuuuuuuu函数。下面是一个很好的代码示例:


编辑:解决问题的一个更简单的方法是提取嵌入的资源,将其保存为真实文件,然后使用SoundPlayer播放该文件。有点笨重,但很简单,您不会遇到资源处置问题。

我没有足够的声誉发表评论,所以我只回答

如果您对播放声音的要求“看似简单”(您只想在单个winform用户执行某些操作时偶尔播放声音),那么我将使用上面的尝试4

拉里·奥斯特曼(Larry Osterman)的《代码第26部分出了什么问题》(what's Out with this code part 26)在每次击键时都会衍生出一个新的线程池线程(播放声音)。他指出,在大约15秒钟的打字时间内,它就饱和了默认的500个线程池大小,但这也是使用异步RPC的客户机/服务器应用程序的情况,该应用程序也使用了线程池。真的不是一个“看似简单”的应用程序


如果您试图每秒(或更快)对声音字节进行排队,每次10秒或100秒,那么这并不是一个“简单的应用程序”,排队的线程/优先级子系统可能是合适的。

使用waveOut,您能否异步播放声音并在完成后处理音频流?当然。链接中的代码正是这样做的(除非它没有-我可能给了你错误的链接)。waveOut\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。相对过于复杂,但功能强大。感谢您的反馈。我的应用程序是一个带有异步RPC的客户端/服务器应用程序,当远程用户发送一些消息时会播放声音。不幸的是,这正是奥斯特曼所描述的那种问题。我的应用程序并不简单,但是,我确实认为“从嵌入式资源异步播放声音文件”是一个简单的场景。我同意“从嵌入式资源异步播放声音文件”是一个简单的场景,但您需要在远程用户发送消息时播放声音(假设您可以收到大量消息)不是。。。因此,如果声音已经播放,并且新消息到达,您是否希望(a)忽略消息,因为声音已经播放?如果是这样,不要使用线程池,只使用一个命名线程,如果该线程已经在运行,则不要执行任何操作。如果线程未运行,请启动它。(b)将“相同”的声音排队以再次播放?如果是这样,每次收到消息时,增加一个共享变量(如果为零,则启动线程)。在线程池线程中,每次播放消息时,都会减少循环中的变量。(c) 有不同的声音吗?您必须构建一个队列来“保存”要播放的声音。当你收到信息时,把声音放在队列上,播放时把声音去掉。谢谢你的建议。我已经把你的答案记下来了。
var player = new SoundPlayer();
player.Stream = Resources.ResourceManager.GetStream("mySound");
player.Play(); // Note that Play is asynchronous
using (var audioMemory = Resources.ResourceManager.GetStream("mySound"))
{
    using (var player = new SoundPlayer(audioMemory))
    {
        player.Play();
    }
}
using (var audioMemory = Resources.ResourceManager.GetStream("mySound"))
{
    using (var player = new SoundPlayer(audioMemory))
    {
        player.PlaySync();
    }
}
ThreadPool.QueueUserWorkItem(ignoredState =>
  {
    using (var audioMemory = Resources.ResourceManager.GetStream("mySound"))
    {
        using (var player = new SoundPlayer(audioMemory))
        {
            player.PlaySync();
        }
    }
  });