0

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?

JeffE
  • 794
  • 2
  • 9
  • 15
  • Why do you want to use `PlaySync` instead of `Play`? Wouldn't it be better to _not_ block the UI thread? – AShelly Jan 14 '11 at 21:54
  • If you walk through your code in a debugger, is execution actually stopping at `PlaySync?` – Dave Mateer Jan 14 '11 at 21:57
  • @AShelly blocking the gui thread is actually desirable in my case. (I know, weird.) – JeffE Jan 14 '11 at 22:00
  • @Dave Yes, it is. I have built in and checked plenty of debugging instrumentation in my library code, as well as used the VS debugger – JeffE Jan 14 '11 at 22:01
  • You can try catching the any exception` to see if you are timing out on the load, or finding a corrupted file. – AShelly Jan 14 '11 at 22:12
  • I have some valid wave files that also are not played correctly/at all, the issue might not be in your code – BrokenGlass Jan 14 '11 at 22:19
  • @AShelly If you look at my code, you'll see I do load and play separately. Also I tried your suggestion with no luck. No exception is thrown.. – JeffE Jan 14 '11 at 22:22
  • @BrokenGlass so you also have unresolved problems with the SoundPlayer class? what did you do to work around the issues? – JeffE Jan 14 '11 at 22:23
  • @Hans Passant Fortunately, my library code is tolerant of such calls with omitted OPTIONAL parameters. There is no exception thrown. When logfile is an empty string, it logs to a default file. And even if this was an issue, it would be irrelevant to my problem with PlaySync. – JeffE Jan 15 '11 at 00:25
  • I just created a sample application that is duplicating what you have above (as far as synchronous) and am not having any problems. It would make sense that the *a*synchronous version would cut off early, as your `SoundPlayer` would be disposed / garbage collected before finishing. But no idea on the synchronous version. Sorry. – Dave Mateer Jan 18 '11 at 18:45
  • I just discovered that it is probably the audio files. Each file consistently stops playing at the same time (but still too early ie: stop at 35 seconds when the duration is over 2 min). – JeffE Jan 19 '11 at 19:38

1 Answers1

0

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...

JeffE
  • 794
  • 2
  • 9
  • 15