我正在使用SoundPlayer
类在我的WPF应用程序中播放WAV文件。这些文件很短,是应用程序的一部分,可以响应程序中发生的事件而播放。用户无法控制播放的声音,也无法决定自己播放声音。我也尝试过使用WPF MediaPlayer
控件,但是我遇到了控件问题。 SoundPlayer
工作得很好,但是有问题。
基本上,我需要保持一个声音队列,并在排队时一个接一个地播放声音。在某些情况下,我必须停止正在播放的任何声音,而是播放另一种声音。所以我有两个要求与SoundPlayer
控件相互排斥:
为了实现这一点,我创建了一个名为SoundController
的类。这有一个后台线程,它使用Thread
的{{1}}将调用排队到我用来播放声音的方法,使用Dispatcher
。该方法在调用BeginInvoke
播放声音之前在SoundController
事件中引发事件,然后在SoundPlayer.PlaySync
返回后引发另一个事件。
在我的UI线程中,在我需要停止声音的位置,我调用PlaySync
类的SoundController
方法。这会调用Stop
的{{1}}方法停止播放声音。这就是问题发生的地方。事实证明,SoundPlayer
不会停止声音,但它会在返回之前等待声音完成。
这会阻止我的GUI死机。虽然我可以异步调用它,但我的GUI不会停止,但声音也不会停止。
正如我所说,WPF MediaPlayer不能为我们工作,无论如何它都是矫枉过正的。还有其他替代方法可以播放声音,让我能够提升事件,在后台线程中播放声音,并停止播放吗?
编辑06/26/2012:
这已经在这里待了一个多月了,我没有回复。所以我想Stop
控制没有其他选择。
我将从另一个角度发布一个新问题。
答案 0 :(得分:2)
对这个问题没有回应,我已经超越了这一点。因此,对于任何想知道的人来说,替代方案是MediaElement
WPF控件并进行WIN32 API调用。
我使用哪种替代品?两者都不是。
事实证明,对我来说,我必须在我的SoundController
课程中添加第二个帖子。第二个线程不运行Dispatcher
;相反,它运行我在循环中编写的代码:
AutoResetEvent
。AutoResetEvent
被引发时,它会启动一个while循环,检查是否要播放声音。还有一点但是没关系。无论如何,这似乎工作正常。由于声音是在单独的Thread
播放,因此可以通过调用Thread
方法从其他SoundPlayer.Stop
中止当前播放的声音。
修改强>
这是我的代码的精简版本。我删除了一些特殊于我的程序要求的东西,这些东西与特殊声音有关。这显示了基本过程的工作原理。
private string NextSound { get; set; }
public AutoResetEvent PlayASoundFlag = new AutoResetEvent( false );
private Dictionary<string, SoundPlayer> Sounds { get; set; }
private object soundLocker = new object();
public string SoundPlaying { get; private set; }
public bool Stopping { get; set; }
public void PlaySound( string key, bool stopCurrentSound ) {
if ( !Sounds.ContainsKey( key ) )
throw new ArgumentException( string.Format( "Sound \"{0}\" does not exist", key ), "key" );
lock ( soundLocker ) {
NextSound = key;
if ( SoundPlaying != null && stopCurrentSound )
Sounds[ SoundPlaying ].Stop();
PlayASoundFlag.Set();
}
}
private void SoundController() {
do {
PlayASoundFlag.WaitOne();
while ( !Stopping && NextSound != null ) {
lock ( soundLocker ) {
SoundPlaying = NextSound;
NextSound = null;
}
Sounds[ SoundPlaying ].PlaySync();
lock ( soundLocker )
SoundPlaying = null;
}
} while ( !Stopping );
}
当你的程序启动时,该类加载键和&amp;声音文件进入Sounds Dictionary
。这样,用户所要做的就是将他们想要播放的声音的密钥传递给PlaySound
方法。
如果您愿意,可以将NextSound
属性替换为Queue
。 PlaySound
方法必须将要播放的声音的键排入队列,SoundController
线程必须从while
循环中的线程中取出每个键,当没有任何东西离开时退出在Queue
。
最后,当您的程序停止时,您需要将Stopping
标志设置为true&amp;设置PlayASoundFlag,使代码循环出来。这将导致SoundController
线程停止。
我将初始化Dictionary
并启动线程给你。