2014-03-05 19 views
3

我只是想在彼此之後播放4個聲音(sounds1-> sound2-> sound3),但是在每次播放期間沒有停止我代碼中的流程,或者無需等待每個聲音完成。如何異步播放聲音,但他們自己在隊列中?

我已經在任何地方搜索了這個,但是我讀到的每個方向都陷入了一些其他問題。

到目前爲止,我最好的選擇是:使用System.Media中已有的SoundPlayer並創建自己的隊列函數,但Soundplayer沒有「完成播放」事件,因此我不知道何時開始下一個聲音。 (真的,微軟?)

其他解決方案和問題: DirectSound似乎很難在.NET(c#)中工作。 Win Playsound並沒有真正的幫助,因爲它無法排隊。

+2

你可以在後臺線程中調用'PlaySync()'。 – SLaks

+0

NAudio有一個'PlaybackStopped'事件...它也可能有一個內置隊列;我不太熟悉它。 –

回答

3

您可以嘗試在UI之外的線程上使用PlaySync,例如:後臺線程,因爲有些人已評論。

這裏是一個樣本(未經測試)使用線程安全* BlockingCollection隊列
* 您可以在使用外螺紋

你可能想使自己的類或每當聲音結束時都會引發事件的方法。或者您可以在線程中循環隊列,因爲PlaySync只會自行等待。

using System.Threading; 
using System.Collections.Concurrent; 
namespace PlaySound 
{ 
    public partial class Form1 : Form 
    { 
     private Thread soundPlayThread; 
     private BlockingCollection<string> speakQueue = new BlockingCollection<string>(); 
     private CancellationTokenSource cancelSoundPlay; 
     private int soundPlayCount = 0; 

     public Form1() 
     { 
      InitializeComponent(); 
      cancelSoundPlay = new CancellationTokenSource(); 
     } 

     private void btnStartSoundPlay_Click(object sender, EventArgs e) 
     { 
      StartSoundPlay(); 
     } 

     private void btnStopSoundPlay_Click(object sender, EventArgs e) 
     { 
      cancelSoundPlay.Cancel(); 
      Console.WriteLine("Sound play cancelled."); 
     } 

     private void btnAddToQueue_Click(object sender, EventArgs e) 
     { 
      speakQueue.Add("MyFile.wav"); 
     } 

     private void queueAndPlay(string loc) 
     { 
      if (!File.Exists(loc=loc+".wav")) 
       loc=configPath+"soundnotfound.wav"; 
      speakQueue.Add(loc); 
      StartSoundPlay(); 
     } 


     private void StartSoundPlay() 
     { 
      //Sound Player Loop Thread 
      if (this.soundPlayThread == null || !this.soundPlayThread.IsAlive) 
      { 
       this.soundPlayThread = new Thread(SoundPlayerLoop); 
       this.soundPlayThread.Name = "SoundPlayerLoop"; 
       this.soundPlayThread.IsBackground = true; 
       this.soundPlayThread.Start(); 
       Console.WriteLine("Sound play started"); 
      } 
     } 
     //Method that the outside thread will use outside the thread of this class 
     private void SoundPlayerLoop() 
     { 
      var sound = new SoundPlayer(); 
      foreach (String soundToPlay in this.speakQueue.GetConsumingEnumerable(cancelSoundPlay.Token)) 
      { 
       //http://msdn.microsoft.com/en-us/library/system.media.soundplayer.playsync.aspx 
       speaker.SoundLocation=soundToPlay; 
       //Here the outside thread waits for the following play to end before continuing. 
       sound.PlaySync(); 
       soundPlayCount++; 
       Console.WriteLine("Sound play end. Count: " + soundPlayCount); 
      } 
     } 
    } 
}