2009-07-21 15 views
11

ここには簡単な質問があります:System.Media.SoundPlayerを使用して非同期にサウンドファイルを再生する方法

Windowsフォームで組み込みの.wavリソースファイルを非同期で再生する適切な方法はありますか?

試み#1:

グッド
var player = new SoundPlayer(); 
player.Stream = Resources.ResourceManager.GetStream("mySound"); 
player.Play(); // Note that Play is asynchronous 
  • :悪いUIスレッド
  • をブロックしません:SoundPlayerのと埋め込まれた 資源の流れはすぐに 配置されていません。

試み#2:

using (var audioMemory = Resources.ResourceManager.GetStream("mySound")) 
{ 
    using (var player = new SoundPlayer(audioMemory)) 
    { 
     player.Play(); 
    } 
} 
  • グッド:UIスレッドがブロックされていない、SoundPlayerのオーディオメモリストリームはすぐに配置されています。
  • 悪い:レース状態! Play()は非同期で、Playが終了する前にオーディオメモリが破棄された場合...ブーム!実行時例外がスローされます。

試み#3:

using (var audioMemory = Resources.ResourceManager.GetStream("mySound")) 
{ 
    using (var player = new SoundPlayer(audioMemory)) 
    { 
     player.PlaySync(); 
    } 
} 
  • グッド:プレーヤーとオーディオストリームがすぐに配置されています。
  • 悪い:PlaySyncはブロックUIスレッド

試行#4:

ThreadPool.QueueUserWorkItem(ignoredState => 
    { 
    using (var audioMemory = Resources.ResourceManager.GetStream("mySound")) 
    { 
     using (var player = new SoundPlayer(audioMemory)) 
     { 
      player.PlaySync(); 
     } 
    } 
    }); 
  • グッド:UIがフリーズしない、プレーヤーやメモリストリームはすぐに配置されています。
  • 悪い:これは頻繁に発生するため、スレッドプールスレッドが不足する可能性があります。 Larry Ostermanのwhat's wrong with this code part 26を参照してください。

SoundPlayerにPlayAsyncCompletedイベントがあるようです。残念ながら、そのようなイベントは存在しません。何か不足していますか? Windowsフォームで.wav埋め込みリソースを非同期に再生する適切な方法は何ですか?

答えて

6

私はコメントするほどの評判がないので、私は答えます。

サウンドを再生するための要件が​​「信じられないほどシンプル」である場合(単一のwinformユーザーが何かをやったときに時折サウンドを再生したい場合)、上記の試行#4を使用します。

Larry Ostermanの "このコードパート26で何が問題なのですか"は、各キーストロークで新しいスレッドプールスレッド(音を鳴らす)を "システム"に送ります。彼はそれを打ち砕くことが、デフォルトの500スレッドプールサイズを約15秒で飽和させたことを示していますが、これもまた、スレッドプールを使用していた非同期RPCを使用するクライアント/サーバーアプリケーションで発生していました。本当に "信じられないほど単純な"アプリケーションではありません。

1秒に10秒または100秒間サウンドバイトを1秒間(またはそれ以上)待ち行列に入れようとしているのであれば、本当に「シンプルなアプリケーション」ではなく、待ち行列に入れられたスレッド/優先度サブシステムがおそらく順番に並ぶでしょう。

+0

フィードバックいただきありがとうございます。私のアプリケーションは、リモートユーザが何らかのメッセージを送信したときにサウンドが再生される非同期RPCを備えたクライアント/サーバアプリケーションです。残念ながら、Ostermanが説明している問題とまったく同じです。私のアプリはシンプルではありませんが、「組み込みリソースから非同期にサウンドファイルを再生する」とは単純なシナリオです。 –

+0

「組み込みリソースから非同期でサウンドファイルを再生する」というのは簡単なシナリオですが、リモートユーザーがメッセージを送信したときにサウンドを再生するという要件はありません。既にサウンドが再生されていて、新しいメッセージが届いていますか? (a)サウンドはすでに再生されているため、メッセージを無視しますか?その場合は、スレッドプールを使用せず、名前付きスレッドを使用し、スレッドがすでに実行中の場合は何もしないでください。スレッドが実行されていない場合は、起動します。 – BlueShepherd

+0

(b) "SAME"の音が再び再生されるようにキューに入れますか?そうであれば、メッセージを受け取るたびに共有変数をインクリメントします(ゼロの場合はスレッドを開始します)。スレッドプールスレッドでは、メッセージを再生するたびに、ループ内の変数を減らします。 (c)別のサウンドをキューに入れますか?再生するサウンドを「ホールド」するためのキューを作成する必要があります。あなたがメッセージを受け取ったときにキューに音を入れて、それらを再生するときにそれらを取り除く – BlueShepherd

2

私はまだwin32 APIのgood ol 'waveOut____関数を使用しています。ここで良いのコードサンプルです:

http://www.codeproject.com/KB/audio-video/cswavplay.aspx

編集:あなたの問題をはるかに簡単な解決策は、埋め込みリソースを抽出し、どこか現実のファイルとして保存し、ファイルを再生するためにSoundPlayerのを使用することです。ちょっと厄介ですがシンプルで、リソースの廃棄に関する問題はありません。

+0

waveOutを使用すると、非同期でサウンドを再生し、終了したらオーディオストリームを破棄できますか? –

+0

リンク内のコードは正確にそうしています(そうでない場合を除いて - 間違ったリンクを与えている可能性があります)。 waveOut____はあなたが好きなことを本当に行うことができる昔のAPIです。相対的に過度に複雑ですが、強力です。 – MusiGenesis