Using MCI to play MP3 files - having some problems

Started by
4 comments, last by Gage64 15 years, 5 months ago
I've written a program that allows you to play an MP3 file, based on this tutorial. Here is the code. The tutorial uses C++ while I'm using C#, but I don't think it matters.

class MP3File : IDisposable
{
    [DllImport("winmm.dll")]
    static extern int mciSendString(string command, StringBuilder buffer,
        int bufferSize, IntPtr hwndCallback);

    [DllImport("winmm.dll")]
    static extern bool mciGetErrorString(int error, StringBuilder desc, uint descLen);

    string fileName;
    bool paused = false;

    void SendCommand(string command)
    {
        int ret = mciSendString(command, null, 0, IntPtr.Zero);
        if (ret != 0)
        {
            StringBuilder errorDesc = new StringBuilder(1024);
            mciGetErrorString(ret, errorDesc, 1024);
            Console.WriteLine("The command: " + command + "\ntriggered the following error: " + errorDesc.ToString());
        }
    }

    public MP3File(string name)
    {
        fileName = name;
        string command = "open \"" + fileName + "\" type mpegvideo alias " + fileName;
        SendCommand(command);
    }
    
    #region IDisposable Members

    public void Dispose()
    {
        Stop();
        SendCommand("close " + fileName);
    }

    #endregion

    public void Play(int start)
    {
        // Note: start is in milliseconds

        if (paused)
        {
            paused = true;
            Play();  // Better use a separate function but whatever
        }

        SendCommand("play " + fileName + " from " + start.ToString());
    }

    public void Play()
    {
        Play(0);
    }

    public void Stop()
    {
        SendCommand("stop " + fileName);
        paused = false;
    }

    public void Pause()
    {
        SendCommand("pause " + fileName);
        paused = true;
    }

    public void Resume()
    {
        SendCommand("resume " + fileName);
        paused = false;
    }
}

class Program
{
    static char ReadKey()
    {
        ConsoleKeyInfo keyInfo = Console.ReadKey(true);
        return keyInfo.KeyChar;
    }

    static void PrintMenu()
    {
        Console.WriteLine("Select an option:");
        Console.WriteLine("1) Play");
        Console.WriteLine("2) Stop");
        Console.WriteLine("3) Pause");
        Console.WriteLine("4) Resume");
        Console.WriteLine("9) Quit");
    }
    
    static void Main(string[] args)
    {
        PrintMenu();

        using (MP3File file = new MP3File(args[0]))
        {
            char ch;
            while ((ch = ReadKey()) != '9')
            {
                switch (ch)
                {
                    case '1':
                        file.Play(10000);
                        break;
                    case '2':
                        file.Stop();
                        break;
                    case '3':
                        file.Pause();
                        break;
                    case '4':
                        file.Resume();
                        break;
                }
            }
        }
    }
}

There are two problems I'm currently trying to solve. First, as soon as the program starts I get a message (printed by SendCommand()) saying that the "open" command caused an unknown problem, but I'm still able to play the file and perform the other operations. Also, if I exit the program immediately or after the file has been stopped, I get a message (caused by the "close" command) saying that "The specified device is not open or is not recognized by MCI". If, however I exit the program while the file is playing or paused, I don't get any errors. Any idea what's causing this? Second, I want Play() to restart playing the file regardless of whether it's stopped, paused or already playing, but it only works after Stop() has been called. If Play() is called while the file is playing, it stops and I need to call Play() again to make it restart. If it's called while the file is paused, then I also need to call it twice (the first call does nothing). Adding the 'paused' variable solved this problem (not the first one), but maybe there's another solution that solves both problems more elegantly. Also, it still doesn't work if I call Pause() after calling Stop() (that is, I still have to call Play() twice). All of these operations don't cause any error messages to be printed. I looked at the documentation for these commands but haven't found anything that explains this. Any help would be greatly appreciated.
Advertisement
Try removing the "type mpegvideo" part of the open string.
Quote:Original post by Headkaze
Try removing the "type mpegvideo" part of the open string.


Just tried it, didn't change anything.

Also, I now always get the second error message, with your suggestion or without it, even though I didn't change anything else. Maybe this isn't a problem with my code but with something else?
I can tell you that every time I used mci open command, I used a short name without spaces as an alias. You are using the full file name as the alias, which could be too long or could contain spaces. This could be what's confusing it.
Quote:Original post by ValMan
I can tell you that every time I used mci open command, I used a short name without spaces as an alias. You are using the full file name as the alias, which could be too long or could contain spaces. This could be what's confusing it.


Thanks for the advice, but the full path I'm using is "d:/file.mp3" - short and has no spaces.
Well it turns out that it does work if I call Play() after Stop() + Pause(), it's just that the file that I'm using has a slight delay at the start and I just didn't give it enough time to start playing...

As for restarting a file that's currently playing, I managed to get that working by just calling Stop() inside of Play(). Don't know why I didn't think of that sooner...

My Play() function now looks like this:

public void Play(int start){    if (paused)    {        paused = false;        Play();    }    else    {        Stop();        SendCommand("play " + fileName + " from " + start.ToString());    }}


And it works exactly as I want.

So, that just leaves those pesky error messages...

This topic is closed to new replies.

Advertisement