c++boostboost-threadmcisendstring

mciSendString doesn't pause sound played from a thread


Recently I already asked for a solution similar to this questions:

Is there a way to pause/stop a mp3 file playing with mcisendstring with the "wait" option?

I want to implement a function in my audio player which allows people to have sound playing continuosly, while a slider moves according to the current second the track is running in, and also with the functionality to go to the next track after the current track is over

After (as you can read in the link) trying to do it with

mciSendString("play mp3 wait", NULL, 0, NULL);

which failed due to the problem that the track can't be paused or stopped until it is finished, I am now trying to implement it another way. Currently, when I start to play the track, I also start another thread, which is starting a counter. The counter is getting the length of the track in seconds, and is counting down the time, also offering a mutex for pausing/resuming the counter. In order to stop my MusicCycle from simply looping uncontrolled, I am joining the thread, therefore waiting for its termination.

void Music::MusicCycle(std::wstring trackPath)
{
    while (true)
    {
        OpenMP3(trackPath);
        mciSendString("play mp3", NULL, 0, NULL);

        m_counterThread = boost::thread(boost::bind(&Counter::StartCount, m_counter, <length of track in seconds>));
        m_counterThread.join();

        //... Get new track here
    }
}

Note that this whole method is created in a thread as well:

m_cycleThread = boost::thread(boost::bind(&Music::MusicCycle, this, trackPath));

The thread started by the MusicCycle function is looking like this:

void Counter::StartCount(int seconds)
{
    boost::mutex::scoped_lock lock(m_mutex);

    for (int i = 0; i < seconds; i++)
    {
        while (m_counterLock)
        {
            m_condVar.wait(lock);
        }

        boost::this_thread::sleep(boost::posix_time::seconds(1));
    }
}

Also, I added another functionality to lock/unlock the mutex here with my Pause/Resume methods, which also call the corresponding mciSendString functions

mciSendString("resume mp3", NULL, 0, NULL);

mciSendString("pause mp3", NULL, 0, NULL);

When I would call pause now, mciSendString would pause the track, and also lock the counter so it won't keep on counting down.

However, the problem is that it still doesn't work. The pause simply doesn't affect the playing of music, despite my efforts to think up a solution without using the wait option in the mciSendString

Any advice?

EDIT: Turns out this is actually happening due to threading. I've been doing some C# for a good amount of time and you could use Invokes to work around thread problems. Maybe this is possible here as well?

EDIT2: I read up a bit and it seems like there is an option to Post a method in the message queue of another thread via PostMessage WinAPI call. Is this a possiblity here? If yes, could anyone provide a good example? I read up a bit but I don't really understand alot so far

Is there something like this in C++ as well?


Solution

  • EDIT: Turns out this is actually happening due to threading. I've been doing some C# for a good amount of time and you could use Invokes to work around thread problems.

    Yes. Ifff you need a user-land thread for the asynchronous events then a queued message is your course of action (like C#'s (or Java's etc.) invoke-on-UI-thread). That's hard work.

    EDIT2: I read up a bit and it seems like there is an option to Post a method in the message queue of another thread via PostMessage WinAPI call. Is this a possiblity here? If yes, could anyone provide a good example? I read up a bit but I don't really understand alot so far

    Is there something like this in C++ as well?

    What you're referring to is just the general message-pump/event-loop that underlies almost¹ all UI frameworks. C++ doesn't "have" GUI natively, but certainly libraries exist that have similar facilities.

    Boost Asio was one mentionable. If you already have a GUI framework, it'll have it's own event loop (Qt, MFC etc. have it).

    Regardless of what is used, all Win32 GUI applications end up using the message pump you referred to which does indeed allow messages to be posted. This is almost always the wrong level of abstraction, unless you're actively developing your GUI framework².

    You can always build your own. Just have some kind of (priority) queue to receive messages and have a main loop processing these. Call them events and pronto: event-driven design.


    ¹ there's a wave back at the moment with new-fangled back-to-basics like https://github.com/ocornut/imgui

    ² the fact that this question exists tells me you are not doing that