3

I have created a WinForm application which contains an AxWMPLib.AxMediaPlayer in which I play some videos. I also have to play some other custom sounds in a different thread. For this I used System.Media.SoundPlayer.PlaySync(). This thread plays couple of sound files sequentially in a loop. The problem is when I pause/stop the video the button event sounds are played fine. But when the video is running, sometimes some of the sound files are skipped. And it happens randomly. Could anyone give some explanation about the problem and how to over come it. I mean how could I play the both sounds and video in parallel.

The video is playing in the UI thread and the other sounds are playing from different thread.Please check out the code bellow:

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


    }

}

My objective is to play the looped sound files sequentially with the video playing in parallel.

Abdur Rahman
  • 657
  • 16
  • 46
  • The only way your playSound() method could work well is when it runs on a separate thread. In which case btnPlay_Click is missing code, it doesn't ensure that this thread is in sync with the video. If playSound is actually running on the UI thread then you have various amounts of trouble, including the UI freezing and becoming unresponsive which in turn affects the video player. SoundPlayer is otherwise too primitive to properly detect that a sound finished playing. Plenty of audio libraries around that can do a better job. – Hans Passant Apr 08 '13 at 11:50
  • @HansPassant Thanks for the threading idea. I am checking it.. and let you know if it works. You should place an answer of this question. – Abdur Rahman Apr 09 '13 at 08:42
  • @HansPassant Hello I separate the sound play in different thread. But it doesn't solve the problem. I still have missing sound. I edited the question and added the new code please check out that. – Abdur Rahman Apr 09 '13 at 08:51

1 Answers1

2

You should not use SoundPlayer for this purpose; SoundPlayer is a lightweight, convenience class for playing occasional incidental sounds in an application. It will occasionally skip sounds if other things are going on in the audio subsystem (like a video playing). Here is a good sample that shows how to use the low-level waveOutOpen API for playing sounds.

MusiGenesis
  • 74,184
  • 40
  • 190
  • 334
  • Thanks for the answer. I am checking it. If it works.. I let you know. – Abdur Rahman Apr 18 '13 at 06:11
  • I've downloaded the source code from the Code project link you gave.When I run it and try to play a wav file the program crashes. – Abdur Rahman Apr 18 '13 at 07:04
  • After running the program I clicked open button and select a wav file. Then I pressed the play button then it crashes. It crashes at the third line of function WaveOutPlayer.The error is Object reference not set to an instance of an object. – Abdur Rahman Apr 18 '13 at 12:51
  • What is the third line? I'm on a macbook right now so I can't run this myself. There may be something wrong with the WAV file you're selecting. – MusiGenesis Apr 18 '13 at 14:03
  • the third line is WaveOutHelper.Try(WaveNative.waveOutOpen(out m_WaveOut, device, format, m_BufferProc, 0, WaveNative.CALLBACK_FUNCTION)); I have tried several wav files but it causes the same error – Abdur Rahman Apr 18 '13 at 14:20
  • Looks like this is a common problem with this sample running on Windows 7 on a 64-bit processor; PInvoke signatures need to be different. Check out [this link](http://www.codeproject.com/Articles/4889/A-full-duplex-audio-player-in-C-using-the-waveIn-w) - the comments discuss this issue. – MusiGenesis Apr 18 '13 at 15:24
  • I am sorry I was not here... Did you get the bounty ?? – Abdur Rahman Apr 21 '13 at 09:18
  • @AbdurRahman: doesn't look like it. Don't worry about it, happy to help. – MusiGenesis Apr 21 '13 at 13:42