如何异步播放声音,但自己在队列中?

时间:2014-03-05 20:16:42

标签: c# .net audio asynchronous

我只想在彼此之后播放4种声音(sound1-> sound2-> sound3),但不会在每次播放期间停止我的代码中的流程或不等待每个声音完成。

我到处搜索过这个问题,但是我读到的每个方向都遇到了其他一些问题。

到目前为止,我最好的选择是:使用我已经使用的System.Media中的SoundPlayer并创建自己的队列功能,但Soundplayer没有完成播放"事件所以我不知道何时开始下一个声音。 (真的,微软?)

其他解决方案和问题: DirectSound似乎很难在.NET(c#)中工作。 赢得Playsound并没有真正帮助,因为它不能排队。

1 个答案:

答案 0 :(得分: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);
            }
        }
    }
}