2

このクラスを使用してSoundPlayer、WPFアプリケーションでWAVファイルを再生しています。ファイルは短く、アプリケーションの一部であり、プログラムで発生するイベントに応答して再生されます。ユーザーはどのサウンドを再生するかを制御できず、自分でサウンドを再生することを決定することはできません。WPFMediaPlayerコントロールも使用してみましたが、そのコントロールに問題がありました。はSoundPlayerうまく機能していますが、問題があります。

基本的に、私は音のキューを維持し、それらがキューに入れられるときに次々に音を再生する必要があります。状況によっては、再生中のサウンドを停止して、代わりに別のサウンドを再生する必要があります。SoundPlayerしたがって、コントロールと相互に排他的であることが判明した2つの要件があります。

  1. 私のコードは、サウンドの再生がいつ終了したかを知る必要があります。
  2. サウンドはバックグラウンドで再生する必要があります

これを実装するために、というクラスを作成しましたSoundController。これにはバックグラウンドスレッドがあり、Thread's Dispatcherを使用して、を使用してサウンドを再生するために使用するメソッドへの呼び出しをキューに入れますBeginInvoke。このメソッドは、サウンドを再生するSoundControllerために呼び出す前にイベントでイベントを発生させ、リターン後に別のイベントを発生させます。SoundPlayer.PlaySyncPlaySync

UIスレッドで、サウンドを停止する必要がある時点で、SoundControllerクラスのStopメソッドを呼び出します。SoundPlayerStopメソッドを呼び出して、サウンドの再生を停止します。そして、ここで問題が発生します。SoundPlayer.Stop音が止まらないことがわかりますが、音が終わるのを待ってから戻ります。

これでGUIが機能しなくなります。非同期で呼び出すこともできますが、GUIは停止しませんが、サウンドも停止しません。

私が言ったように、WPF MediaPlayerは私たちのために機能せず、とにかくそれはやり過ぎでした。イベントを発生させ、バックグラウンドスレッドでサウンドを再生し、再生を停止する機能を提供するサウンドを再生するための他の代替手段はありますか?

2012年6月26日編集:

これは1か月以上ここにあり、応答がありません。SoundPlayerですから、コントロール に代わるものは他にないと思います。

問題に別の角度からやってくる新しい質問を投稿します。

4

1 に答える 1

2

この質問に対する回答はありませんでした。私はこれを超えました。したがって、疑問に思っている人にとっては、代替手段はMediaElementWPFコントロールとWIN32API呼び出しの作成です。

では、どの代替手段を使用しましたか?ない。

私にとっては、SoundControllerクラスに2番目のスレッドを追加する必要があることがわかりました。Dispatcher2番目のスレッドは;を実行しません。代わりに、ループで記述したコードを実行します。

  1. 最初は。で無期限に待機しAutoResetEventます。
  2. AutoResetEvent上げると、サウンドが再生されるかどうかを確認するwhileループが開始されます。
  3. サウンドを再生する場合は、再生します。
  4. ループし、最後のサウンドの再生中に別のサウンドが「キューに入れられた」場合は、そのサウンドを再生します。
  5. これは、再生するキューにあるサウンドがなくなるまで繰り返されます。

もう少しありますが、それは問題ではありません。いずれにせよ、これは問題なく機能するようです。サウンドは別のサウンドで再生されているため、メソッドを呼び出すThreadことで、現在再生中のサウンドを別のサウンドから中止できます。ThreadSoundPlayer.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 );
}

プログラムが起動すると、クラスはキーとサウンドファイルをにロードしますSounds Dictionary。そうすれば、ユーザーがしなければならないのは、再生したいサウンドのキーをPlaySoundメソッドに渡すことだけです。

NextSound必要に応じて、プロパティをに置き換えることができますQueue。このPlaySoundメソッドは、再生されるサウンドのキーをエンキューする必要があり、SoundControllerスレッドはwhileループ内のスレッドから各キーをデキューする必要があり、に何も残っていないときに終了しQueueます。

最後に、プログラムが停止したら、Stoppingフラグをtrueに設定し、PlayASoundFlagを設定して、コードがループから抜け出すようにする必要があります。これにより、SoundControllerスレッドが停止します。

Dictionaryスレッドの初期化と開始はあなたに任せます。

于 2012-07-20T13:55:27.920 に答える