2012-05-09 34 views
2

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

本質的に、私は音のキューを維持し、それらが列に並ぶにつれて音を次々と再生する必要があります。状況によっては、再生中のサウンドを停止して別のサウンドを再生する必要があります。

  1. 私のコードは、サウンドの再生が終了したときに知っておく必要があります。だから私はSoundPlayer制御と相互に排他的であることが判明する二つの要求を持っています。
  2. 音はこれを実装するには、バックグラウンド

でプレイしている、私はSoundControllerというクラスを作成しました。これはバックグラウンドスレッドを持ち、ThreadDispatcherを使用して、BeginInvokeを使用して、サウンドの再生に使用するメソッドへの呼び出しをキューに入れます。このメソッドは、SoundPlayer.PlaySyncを呼び出してサウンドを再生する前に、SoundControllerイベントのイベントを発生させ、その後、PlaySyncが返された後に別のイベントを発生させます。

私のUIスレッドでは、サウンドを停止する必要がある時点で、私はSoundControllerクラスのStopメソッドを呼び出します。これにより、SoundPlayerStopメソッドが呼び出され、サウンドの再生が停止されます。そしてここで問題が起こるのです。 SoundPlayer.Stopは音を止めませんが、サウンドが終了するのを待ってから戻ってきます。

これは私のGUIを停止させます。私は非同期に呼び出すことができますが、私のGUIは停止しませんが、サウンドは停止しません。

私が言ったように、WPF MediaPlayerは私たちのためには機能しませんでしたが、とにかくそれは残酷でした。イベントを発生させたり、バックグラウンドスレッドでサウンドを再生したり、再生を停止させたりするサウンドを再生する他の方法はありますか?

編集2012年6月26日:

これは、月を超えるためにここに出てきたと私は何の回答を得ませんしました。だから私はSoundPlayerコントロールに他の選択肢がないと思います。

私は別の角度から問題に来る新しい質問を投稿します。

答えて

1

この質問に対する回答はありませんでした。私はこれを超えました。したがって、WPFコントロールとWIN32 API呼び出しを行うことは、不思議に思う人には、MediaElement WPFコントロールです。

どの代替手段を使用しましたか?いずれも

私のために、SoundControllerクラスに2番目のスレッドを追加する必要があることが判明しました。 2番目のスレッドはDispatcherを実行しません。代わりに、私はループで書いたコードを実行します:

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

もう少しですが、問題ではありません。いずれにせよ、これはうまくいくようです。サウンドは別のThreadで再生されているので、SoundPlayer.Stopメソッドを呼び出すことによって、現在再生中のサウンドを別のThreadから打ち切ることができます。

EDIT:

ここでは、私のコードのストリップダウンバージョンです。私は特別な音と関係がある私のプログラムの要求に特有のものをいくつか削除しました。これは、基本的なプロセスの仕組みを示しています。 Sounds Dictionaryにあなたのプログラムが起動

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

、クラスをロードするキー&サウンドファイル。このようにして、ユーザが再生したい音の鍵をPlaySoundメソッドに渡すだけです。

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

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

私はDictionaryを初期化したまま、あなたにスレッドを開始します。

+0

私はこの正確な問題をWPFではなくwinformsアプリで実行しましたが、このケースでは問題は疑問です。なぜ、/ 2番目のワーカースレッドを追加すると、ここで違いが出るのかが不明です( '.stop()'がクロススレッドで動作するかどうかは確かではありません)私はこの明日か月曜日に戻って、その周りに私の頭を包み込むようにするつもりですが、これについて詳述したり、スケルトンコードに入れたいと思う時間や動機があれば、私は非常に感謝しています:-) – DaveRandom

+0

問題は、 'Play'メソッドを呼び出すスレッドがサウンドを再生中であるため、自分自身を中断できないことです。サウンドの再生が終了するまで「停止」の呼び出しを実行することはできませんが、それまでにはそれは遅すぎます。演奏中の音を止める唯一の方法は、別のスレッドから「停止」を呼び出すことです。だからこそ私はサウンドを演奏することに専念した別のスレッドを追加しました。私は私の答えを編集し、いくつかのスケルトンコードを追加します。 –

+0

このアップデートではお世話になりましたが、午前中に遊びに行く予定です – DaveRandom