使用 System.Media.SoundPlayer.PlaySync() 和 AxWindowsMediaPlayer 并行播放声音

Posted

技术标签:

【中文标题】使用 System.Media.SoundPlayer.PlaySync() 和 AxWindowsMediaPlayer 并行播放声音【英文标题】:Playing sound parallelly with System.Media.SoundPlayer.PlaySync() and AxWindowsMediaPlayer 【发布时间】:2013-04-08 10:25:11 【问题描述】:

我创建了一个 WinForm 应用程序,其中包含一个 AxWMPLib.AxMediaPlayer,我可以在其中播放一些视频。我还必须在不同的线程中播放一些其他自定义声音。为此,我使用了 System.Media.SoundPlayer.PlaySync()。该线程循环播放几个声音文件。问题是当我暂停/停止视频时,按钮事件的声音播放得很好。但是当视频运行时,有时会跳过一些声音文件。它是随机发生的。 任何人都可以对这个问题以及如何解决它给出一些解释。我的意思是我怎么能同时播放声音和视频。

视频在 UI 线程中播放,其他声音在不同线程中播放。请查看以下代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using ElectroQ;
using ElectroQServer1.Entities;
using WMPLib;
using System.Media;
using System.Windows.Media;

namespace ElectroQServer1

    public partial class Form1 : Form
    
        Thread dbListenerThread;
        IWMPPlaylist playlist;

        //string[] tokenNumber =  "A001", "B002", "C003", "D004","E005", "F006", "G007","HAMB" ;
        //string[] counterNumber =  "01", "02", "03", "04", "05", "06", "07", "MB" ;
        public Form1()
        
            InitializeComponent();
            //ResizeRedraw = true;
            this.SetStyle(System.Windows.Forms.ControlStyles.DoubleBuffer, true);
            this.WindowState = FormWindowState.Maximized;
            //this.FormBorderStyle = FormBorderStyle.None;
            //this.TopMost = true;


            dbListenerThread = new Thread(RefreshQueueBoard);
            dbListenerThread.Start();

        
        /// <summary>
        /// This method is used to prevent the flickering of the window.
        /// </summary>
        protected override CreateParams CreateParams
        
            get
            
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
                return cp;
            
         
        public void RefreshQueueBoard()
        
            //Thread.Sleep(000);
            while (true)
            
                List<QueueData> lstQData = DA.GetAllQueueData(" where service_status_id = 2 ");
                printToken(lstQData);
                printCounter(lstQData);

                playSound(lstQData);
                Thread.Sleep(1000);
            
        

        public void playSound(List<QueueData> lstQData)
        
            foreach (QueueData qData in lstQData)
            
                if (!qData.SoundPlayed)
                
                    string strSoundFile;
                    PlaySoundFIle(@"Sounds/TN.WAV");
                    foreach (char c in qData.ServiceQueueSerial)
                    
                        strSoundFile = string.Format(@"Sounds/0.WAV", c);
                        PlaySoundFIle(strSoundFile);
                    
                    PlaySoundFIle(@"Sounds/CN.WAV");
                    foreach (char c in qData.ServiceCounterID)
                    
                        strSoundFile = string.Format(@"Sounds/0.WAV", c);
                        PlaySoundFIle(strSoundFile);
                    
                    string strUpdateQuery = string.Format("UPDATE electro_queue SET sound_played = 1 WHERE service_queue_serial = '0'", qData.ServiceQueueSerial);
                    DA.UpdateQueueData(strUpdateQuery);

                
            
        

        public void PlaySoundFIle(string strFile)
        
            //string[] files = new string[4]  @"Sounds/TN.WAV", @"Sounds/CN.WAV", @"Sounds/TN.WAV", @"Sounds/CN.WAV";

            //WaveIO wa = new WaveIO();
            //wa.Merge(files, @"tempfile.wav");
            //MediaPlayer wowSound = new MediaPlayer(); //Initialize a new instance of MediaPlayer of name wowSound
            //wowSound.Open(new Uri(@"tempfile.wav", UriKind.Relative)); //Open the file for a media playback
            //wowSound.Play();
            using (var soundPlayer = new SoundPlayer(strFile))
            
                soundPlayer.PlaySync(); // can also use soundPlayer.Play() but it misses some sound file.
            
        

        private void printToken(List<QueueData> lstQData)
        
            if (InvokeRequired)
            
                this.Invoke(new MethodInvoker(delegate
                
                    pnlQStat.Controls.Clear(); 
                    string dir;
                    //int xpos = 55;
                    //int ypos = 207;
                    int xpos = 10;
                    int ypos = 00;
                    //int k=0;
                    for (int i = 0; i < lstQData.Count; i++)
                    
                       /* if (i == 4 || i == 8)
                        
                            ypos = ypos - 360;
                            xpos = 675;
                        */

                        foreach (char c in lstQData[i].ServiceQueueSerial)
                        
                            if (i == 0)
                            
                                dir = "Resources/_" + c + ".bmp";
                            
                            else
                            
                                dir = "Resources/" + c + ".bmp";
                            
                            createPicBox(dir, "pBox" + i, xpos, ypos);
                            xpos = xpos + 43;

                        

                        ypos = ypos + 50;
                        xpos = 10;


                    
                ));
                return;
            
        

        private void printCounter(List<QueueData> lstQData)
        
            if (InvokeRequired)
            
                this.Invoke(new MethodInvoker(delegate
                

                    //int xpos = 415;
                    //int ypos = 207;
                    //int xpos = 292;
                    int xpos = 220;
                    int ypos = 00;
                    //int k=0;
                    for (int i = 0; i < lstQData.Count; i++)
                    
                        /*if (i == 4 || i == 8)
                        
                            ypos = ypos - 360;
                            xpos = 1035;
                        
                        */
                        foreach (char c in lstQData[i].ServiceCounterID)
                        
                            string dir;
                            if (i == 0)
                            
                                dir = "Resources/_" + c + ".bmp";
                            
                            else
                            
                                dir = "Resources/" + c + ".bmp";
                            
                            //string dir = "Resources/" + c + ".bmp";
                            createPicBox(dir, "pBox" + i, xpos, ypos);
                            xpos = xpos + 63;

                        

                        ypos = ypos + 50;
                        xpos = xpos - 63;


                    
                ));
                return;
            
        
        private void createPicBox(string directory, string name, int xposition, int yposition)
        
            PictureBox picBox = new System.Windows.Forms.PictureBox();
            picBox.Name = name;

            picBox.Location = new System.Drawing.Point(xposition, yposition);
            picBox.Size = new System.Drawing.Size(40, 50);

            picBox.BackgroundImage = Image.FromFile(directory);
            picBox.BackgroundImageLayout = ImageLayout.Stretch;
            pnlQStat.Controls.Add(picBox);
        

        private void Form1_Load(object sender, EventArgs e)
        
            createPlayList();
            //dbListenerThread.Abort(); // this line of code should be placed in onClosing Event.
        

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        
            dbListenerThread.Abort();
            player.playlistCollection.remove(playlist);
        

        private void createPlayList()
        
            playlist = player.playlistCollection.newPlaylist("mpl");
            playlist.appendItem(player.newMedia(@"E:\SONGS\teri-meri-promo-Muskurahat.Com.wmv"));
            playlist.appendItem(player.newMedia(@"E:\MOVZZZ\English\The Kid\THE KID FILM_1_0001.avi"));
            player.currentPlaylist = playlist;
        

        private void btnPlay_Click(object sender, EventArgs e)
        
           // player.URL = @"E:\MOVZZZ\English\The Kid\THE KID FILM_1_0001.avi";
            player.Ctlcontrols.play();
        

        private void btnStop_Click(object sender, EventArgs e)
        
            player.Ctlcontrols.stop();
        


    


我的目标是顺序播放循环播放的声音文件,同时并行播放视频。

【问题讨论】:

您的 playSound() 方法可以正常工作的唯一方法是在单独的线程上运行。在这种情况下 btnPlay_Click 缺少代码,它不能确保该线程与视频同步。如果 playSound 实际上是在 UI 线程上运行,那么您会遇到各种麻烦,包括 UI 冻结和无响应,进而影响视频播放器。 SoundPlayer 过于原始,无法正确检测到声音是否播放完毕。周围的大量音频库可以做得更好。 @HansPassant 感谢线程的想法。我正在检查它.. 并让你知道它是否有效。你应该回答这个问题。 @HansPassant 您好,我将声音播放分开在不同的线程中。但这并不能解决问题。我仍然缺少声音。我编辑了问题并添加了新代码,请查看。 【参考方案1】:

您不应为此使用SoundPlayerSoundPlayer 是一个轻量级、方便的类,用于在应用程序中播放偶尔的附带声音。如果音频子系统中发生其他事情(如视频播放),它偶尔会跳过声音。这里是a good sample that shows how to use the low-level waveOutOpen API for playing sounds。

【讨论】:

感谢您的回答。我正在检查它。如果它有效.. 我让你知道。 我已经从您提供的代码项目链接中下载了源代码。当我运行它并尝试播放 wav 文件时,程序崩溃了。 运行程序后,我单击打开按钮并选择一个 wav 文件。然后我按下播放按钮然后它崩溃了。它在函数 WaveOutPlayer 的第三行崩溃。错误是对象引用未设置为对象的实例。 第三行是什么?我现在在 macbook 上,所以我不能自己运行它。您选择的 WAV 文件可能有问题。 第三行是 WaveOutHelper.Try(WaveNative.waveOutOpen(out m_WaveOut, device, format, m_BufferProc, 0, WaveNative.CALLBACK_FUNCTION));我尝试了几个 wav 文件,但它导致相同的错误

以上是关于使用 System.Media.SoundPlayer.PlaySync() 和 AxWindowsMediaPlayer 并行播放声音的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)