SoundPlayer的替代品



我正在使用SoundPlayer类在我的WPF应用程序中播放WAV文件。 这些文件很短,是应用程序的一部分,并响应程序中发生的事件而播放。 用户无法控制播放的声音,也无法自行决定播放声音。 我也尝试过使用 WPF MediaPlayer控件,但该控件出现问题。 SoundPlayer运行良好,但存在问题。

从本质上讲,我需要保留一个声音队列,并在它们排队时一个接一个地播放声音。 在某些情况下,我必须停止播放任何声音并播放另一种声音。 因此,我有两个要求,结果证明它们与SoundPlayer控件相互排斥:

  1. 我的代码需要知道声音何时完成播放。
  2. 声音必须在后台播放

为了实现这一点,我创建了一个名为 SoundController 的类。 它有一个后台线程,它使用 ThreadDispatcher将调用排队到我用来播放声音的方法,使用 BeginInvoke 。 该方法在调用SoundPlayer.PlaySync播放声音之前引发SoundController事件中的一个事件,然后在PlaySync返回后引发另一个事件。

在我的 UI 线程中,在我需要停止声音的地方,我调用 SoundController 类的 Stop 方法。 这调用SoundPlayerStop方法来停止播放声音。 这就是问题发生的地方。 事实证明,SoundPlayer.Stop不会停止声音,而是等待声音结束再返回。

这会阻止我的 GUI 死机。虽然我可以异步调用它,但我的 GUI 不会停止,但声音也不会停止。

正如我所说,WPF MediaPlayer对我们不起作用,无论如何,这是矫枉过正。 是否有任何其他播放声音的替代方法,使我能够引发事件、在后台线程中播放声音以及停止播放?

编辑06/26/2012:

这已经在这里一个多月了,我没有得到任何回应。 所以我想除了SoundPlayer控制之外,没有其他选择。

我将发布一个新问题,从不同的角度提出问题。

这个问题

没有回答,我已经超越了这一点。 因此,对于任何想知道的人来说,替代方案是MediaElement WPF 控件和进行 WIN32 API 调用。

那么我使用了哪种替代方案? 也不。

事实证明,对我来说,我必须在SoundController课上添加第二个线程。 第二个线程不运行Dispatcher;相反,它运行我在循环中编写的代码:

  1. 它最初无限期地等待AutoResetEvent
  2. AutoResetEvent被抬起时,它会启动一个 while 循环,检查是否要播放声音。
  3. 如果要播放声音,它会这样做。
  4. 它循环播放,如果在播放最后一个声音时"排队"另一个声音,它会播放该声音。
  5. 重复此操作,直到没有排队等待播放的声音。

还有一点,但没关系。 无论如何,这似乎工作正常。 由于声音在单独的Thread上播放,因此可以通过调用SoundPlayer.Stop方法从不同的Thread中止当前播放的声音。

编辑:

这是我代码的精简版本。 我删除了一些与特殊声音有关的程序要求的特定内容。这显示了基本过程的工作原理。

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 );
}

当程序启动时,该类会将键和声音文件加载到Sounds Dictionary中。这样,用户所要做的就是将他们想要播放的声音的键传递给PlaySound方法。

如果需要,可以将NextSound属性替换为 QueuePlaySound 方法必须将要播放的声音的键排队,并且SoundController线程必须将每个键与while循环中的线程取消排队,当Queue中没有剩余内容时退出。

最后,当程序停止时,您需要将Stopping标志设置为 true 并设置 PlayASoundFlag,以便代码脱离循环。这将导致SoundController线程停止。

我将初始化Dictionary和启动线程留给您。

相关内容

  • 没有找到相关文章

最新更新