Question

I want to play a wav file synchronously on the gui thread, but my call to PlaySync is returning early (and prematurely stopping playback). The wav file is 2-3 minutes.

Here's what my code looks like:

        //in gui code (event handler)
        //play first audio file
        JE_SP.playSound("example1.wav");

        //do a few other statements
        doSomethingUnrelated();

        //play another audio file
        JE_SP.playSound("example2.wav");

    //library method written by me, called in gui code, but located in another assembly
    public static int playSound(string wavFile, bool synchronous = true,
        bool debug = true, string logFile = "", int loadTimeout = FIVE_MINUTES_IN_MS)
    {
        SoundPlayer sp = new SoundPlayer();
        sp.LoadTimeout = loadTimeout;
        sp.SoundLocation = wavFile;
        sp.Load();

        switch (synchronous)
        {
            case true:
                sp.PlaySync();
                break;
            case false:
                sp.Play();
                break;
        }

        if (debug)
        {
            string writeMe = "JE_SP: \r\n\tSoundLocation = " + sp.SoundLocation
                + "\r\n\t" + "Synchronous = " + synchronous.ToString();
            JE_Log.logMessage(writeMe);
        }

        sp.Dispose();
        sp = null;

        return 0;
    }

Some things I've thought of are the load timeout, and playing the audio on another thread and then manually 'freeze' the gui by forcing the gui thread to wait for the duration of the sound file. I tried lengthening the load timeout, but that did nothing.

I'm not quite sure what the best way to get the duration of a wav file is without using code written by somebody who isn't me/Microsoft. I suppose this can be calculated since I know the file size, and all of the encoding properties (bitrate, sample rate, sample size, etc) are consistent across all files I intend to play. Can somebody elaborate on how to calculate the duration of a wav file using this info? That is, if nobody has an idea about why PlaySync is returning early.

Edits:

Of Note: I encountered a similar problem in VB 6 a while ago, but that was caused by a timeout, which I don't suspect to be a problem here. Shorter (< 1min) files seem to play fine, so I might decide to manually edit the longer files down, then play them separately with multiple calls.

Additional Info: I noticed that the same file stops consistently at the same time. The files were created using Audacity. Would it be possible that PlaySync is expecting a certain encoding of the files that differs from what I had Audacity produce?

Was it helpful?

Solution

Just in case anybody else runs into problems with playing a large wav file synchronously, here is a method I wrote which uses WMP as an alternative:

public static int playSoundWMP(string soundFile, bool synchronous = true)
    {
        Stopwatch sw = new Stopwatch();
        sw.Start();

        wmp.URL = soundFile;
        wmp.controls.play();

        Thread.Yield();

        while (wmp.playState == WMPLib.WMPPlayState.wmppsTransitioning)
        {
            Application.DoEvents();
            Thread.Yield();
        }

        int duration = Convert.ToInt32(wmp.currentMedia.duration * 1000);
        double waitTime = wmp.currentMedia.duration;

        if (synchronous)
        {
            Thread.Sleep(duration);
        }

        long elapsed = sw.ElapsedMilliseconds;
        sw.Stop();
        sw = null;

        return (int) wmp.currentMedia.duration * 1000;
    }

This method uses WMP to play an audio file instead of the SoundPlayer class, so it can play larger wav files more reliably...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top