SoundPlayer的替代品

时间:2012-05-09 16:49:56

标签: wpf soundplayer

我正在使用SoundPlayer类在我的WPF应用程序中播放WAV文件。这些文件很短,是应用程序的一部分,可以响应程序中发生的事件而播放。用户无法控制播放的声音,也无法决定自己播放声音。我也尝试过使用WPF MediaPlayer控件,但是我遇到了控件问题。 SoundPlayer工作得很好,但是有问题。

基本上,我需要保持一个声音队列,并在排队时一个接一个地播放声音。在某些情况下,我必须停止正在播放的任何声音,而是播放另一种声音。所以我有两个要求与SoundPlayer控件相互排斥:

  1. 我的代码需要知道声音何时播放完毕。
  2. 声音必须在后台播放
  3. 为了实现这一点,我创建了一个名为SoundController的类。这有一个后台线程,它使用Thread的{​​{1}}将调用排队到我用来播放声音的方法,使用Dispatcher。该方法在调用BeginInvoke播放声音之前在SoundController事件中引发事件,然后在SoundPlayer.PlaySync返回后引发另一个事件。

    在我的UI线程中,在我需要停止声音的位置,我调用PlaySync类的SoundController方法。这会调用Stop的{​​{1}}方法停止播放声音。这就是问题发生的地方。事实证明,SoundPlayer不会停止声音,但它会在返回之前等待声音完成。

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

    正如我所说,WPF MediaPlayer不能为我们工作,无论如何它都是矫枉过正的。还有其他替代方法可以播放声音,让我能够提升事件,在后台线程中播放声音,并停止播放吗?

    编辑06/26/2012:

    这已经在这里待了一个多月了,我没有回复。所以我想Stop控制没有其他选择。

    我将从另一个角度发布一个新问题。

1 个答案:

答案 0 :(得分:2)

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

我使用哪种替代品?两者都不是。

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

  1. 它最初无限期地等待AutoResetEvent
  2. AutoResetEvent被引发时,它会启动一个while循环,检查是否要播放声音。
  3. 如果要播放声音,则会这样做。
  4. 它循环播放,如果在播放最后一个声音时另一个声音“排队”,它会播放该声音。
  5. 重复此操作直到没有排队等待播放的声音。
  6. 还有一点但是没关系。无论如何,这似乎工作正常。由于声音是在单独的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属性替换为QueuePlaySound方法必须将要播放的声音的键排入队列,SoundController线程必须从while循环中的线程中取出每个键,当没有任何东西离开时退出在Queue

    最后,当您的程序停止时,您需要将Stopping标志设置为true&amp;设置PlayASoundFlag,使代码循环出来。这将导致SoundController线程停止。

    我将初始化Dictionary并启动线程给你。