Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::thread for class instances

I'm attempting to create two instances of this class which will eventually play music files using Win32's mciSendString features. However to test it since this is the first time I've attempted to use std::thread, I wrote a test(void) method which outputs the class ID which I'd expect to print me a series of 1's and 2's like 12122111112212121212...

I'm getting the following error, the test(void) method indeed exists?

Error 1 error C2064: term does not evaluate to a function taking 0 arguments

#include <iostream>
#include <thread>

typedef enum MusicStatus {
    MUSIC_PLAYING = 0, 
    MUSIC_PAUSED, 
    MUSIC_STOPPED, 
    MUSIC_IDLE
} MusicStatus, *pMusicStatus;

class MusicPlayer
{
public:

    MusicPlayer(void) {
        m_bIsPlaying = false;
        m_bIsPaused = false;
    }

    bool isPaused(void) {
        return m_bIsPaused;
    }

    bool isPlaying(void) {
        return m_bIsPlaying;
    }

    MusicStatus getState(void) {
        if ( !m_bIsPlaying && !m_bIsPaused && !m_bIsStopped )
            return MUSIC_IDLE;
        if ( m_bIsPlaying )
            return MUSIC_PLAYING;
        if ( m_bIsPaused ) 
            return MUSIC_PAUSED;
        if ( m_bIsStopped )
            return MUSIC_STOPPED;
        return MUSIC_STOPPED;
    }

    void test(void) {
        for ( int m = 0; m < 100; m++ ) {
            std::cout << this->n;
        }
    }

    int n;

private:

    bool m_bIsPlaying, m_bIsPaused, m_bIsStopped;

};


int main(int argc, char* argv[])
{
    MusicPlayer A;
    MusicPlayer B;
    A.n = 1;
    B.n = 2;

    std::thread t1(A);
    std::thread t2(B);

    t1.join();
    t2.join();

    A.test();
    B.test();

    system("PAUSE");
    return 0;
}

Update: I've made some adjustment, now I'm having an issue with argument list, error: MusicPlayer::play_sound function call missing argument list

#include <iostream>

#pragma comment(lib, "Strmiids.lib") 

#include <thread>
#include <dshow.h>
#include "Lib/NSL.h"

typedef enum MusicStatus {
    MUSIC_PLAYING = 0, 
    MUSIC_PAUSED, 
    MUSIC_STOPPED, 
    MUSIC_IDLE
} MusicStatus, *pMusicStatus;

class MusicPlayer
{
public:

    MusicPlayer() {
        m_bIsPlaying = false;
        m_bIsPaused = false;
        m_bIsStopped = false;
    }

    bool isPaused() {
        return m_bIsPaused;
    }

    bool isPlaying() {
        return m_bIsPlaying;
    }

    MusicStatus getState() {
        if ( !m_bIsPlaying && !m_bIsPaused && !m_bIsStopped )
            return MUSIC_IDLE;
        if ( m_bIsPlaying )
            return MUSIC_PLAYING;
        if ( m_bIsPaused ) 
            return MUSIC_PAUSED;
        if ( m_bIsStopped )
            return MUSIC_STOPPED;
        return MUSIC_STOPPED;
    }

    void playAudio(std::string strFilePath) {
        m_strFilePath = strFilePath;
        std::thread audioThread(play_sound);
        audioThread.join();
    }

private:

    bool m_bIsPlaying, m_bIsPaused, m_bIsStopped;
    std::string m_strFilePath;

    void play_sound() {
        IGraphBuilder *pGraph = NULL;
        IMediaControl *pControl = NULL;
        IMediaEvent   *pEvent = NULL;

        // Initialize the COM library.
        HRESULT hr = CoInitialize(NULL);
        if (FAILED(hr))
        {
            printf("ERROR - Could not initialize COM library");
            return;
        }

        // Create the filter graph manager and query for interfaces.
        hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, 
                            IID_IGraphBuilder, (void **)&pGraph);
        if (FAILED(hr))
        {
            printf("ERROR - Could not create the Filter Graph Manager.");
            return;
        }

        hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
        hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

        // Build the graph. IMPORTANT: Change this string to a file on your system.
        hr = pGraph->RenderFile(s2ws(m_strFilePath).c_str(), NULL);
        if (SUCCEEDED(hr))
        {
            // Run the graph.
            hr = pControl->Run();
            if (SUCCEEDED(hr))
            {
                // Wait for completion.
                long evCode;
                pEvent->WaitForCompletion(INFINITE, &evCode);

                // Note: Do not use INFINITE in a real application, because it
                // can block indefinitely.
            }
        }
        pControl->Release();
        pEvent->Release();
        pGraph->Release();
        CoUninitialize();
    }

};

int main(void)
{
    MusicPlayer A;
    A.playAudio("music.mp3");
    system("pause");
    return 0;
}
like image 510
johnsonwi Avatar asked Sep 23 '26 16:09

johnsonwi


2 Answers

You cannot run an object! What you can run is a member function on a specific object: std::thread needs to be told the entry function for the thread. It uses the first constructor argument as a function object and all other arguments as parameters for how to call the function. Since your class doesn't have a function call operator, std::thread doesn't know which function to call.

There are a ways you can fix the problem:

  1. You provide a function call operator()() for your MusicPlayer type as the entry function for the threads.
  2. You use a member function as the first argument together with the actual object as a parameter being passed, e.g., std::thread t1(&MusicPlayer::test, &A).
  3. You use a readily bound function object as the parameter to std::thread, e.g., std::thread t1(std::bind(&MusicPlayer::test, std::ref(A)).
like image 86
Dietmar Kühl Avatar answered Sep 25 '26 06:09

Dietmar Kühl


Okay I've solved my issues, its appears std::thread is ideal to playback mp3 files in the background thanks to std::thread. Note: audioThread(&MusicPlayer::play_sound, this);

#include <iostream>

#pragma comment(lib, "Strmiids.lib") 

#include <thread>
#include <dshow.h>
#include "Lib/NSL.h"

typedef enum MusicStatus {
    MUSIC_PLAYING = 0, 
    MUSIC_PAUSED, 
    MUSIC_STOPPED, 
    MUSIC_IDLE
} MusicStatus, *pMusicStatus;

class MusicPlayer
{
public:

    MusicPlayer() {

        m_bIsPlaying = false;
        m_bIsPaused = false;
        m_bIsStopped = false;
        m_pControl = NULL;
        m_pEvent = NULL;
        m_pGraph = NULL;
        m_pEventEx = NULL;
        m_pBasicAudio = NULL;
        m_pMediaSeeking = NULL;

        // Initialize the COM library
        m_hr = CoInitialize(NULL);
        if (FAILED(m_hr)) { // Could not initialize COM library");
            return;
        }

        // Create the filter graph manager and query for interfaces.
        m_hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGraph);

        if (FAILED(m_hr)) { // Could not create the Filter Graph Manager
            return;
        }

        m_hr = m_pGraph->QueryInterface(IID_IMediaControl, (void **)&m_pControl);
        m_hr = m_pGraph->QueryInterface(IID_IMediaEvent, (void **)&m_pEvent);
        m_hr = m_pGraph->QueryInterface(IID_IMediaEventEx, (void **)&m_pEventEx);
        m_hr = m_pGraph->QueryInterface(IID_IBasicAudio, (void**)&m_pBasicAudio);
        m_hr = m_pGraph->QueryInterface(IID_IMediaSeeking, (void**)&m_pMediaSeeking);
    }

    ~MusicPlayer() {
        m_pControl->Release();
        m_pEvent->Release();
        m_pEventEx->Release();
        m_pGraph->Release();
        m_pBasicAudio->Release();
        m_pMediaSeeking->Release();
        CoUninitialize();
    }

    bool isPaused() {
        return m_bIsPaused;
    }

    bool isPlaying() {
        return m_bIsPlaying;
    }

    MusicStatus getState() {
        if ( !m_bIsPlaying && !m_bIsPaused && !m_bIsStopped )
            return MUSIC_IDLE;
        if ( m_bIsPlaying )
            return MUSIC_PLAYING;
        if ( m_bIsPaused ) 
            return MUSIC_PAUSED;
        if ( m_bIsStopped )
            return MUSIC_STOPPED;
        return MUSIC_STOPPED;
    }

    void playAudio(std::string strFilePath) {
        m_strFilePath = strFilePath;
        set_state(MUSIC_PLAYING);
        std::thread audioThread(&MusicPlayer::play_sound, this);
        audioThread.join();
    }

    bool stopAudio() {
        if ( getState() == MUSIC_PLAYING && m_pControl ) {
            m_hr = m_pControl->Stop();
            if ( SUCCEEDED(m_hr) ) {
                set_state(MUSIC_STOPPED);
                return true;
            }
        }
        return false;
    }

    bool pauseAudio() {
        if ( getState() == MUSIC_PLAYING && m_pControl ) {
            return SUCCEEDED(m_pControl->Pause());
        }
        return false;
    }

    long volume() {
        if ( m_bIsPlaying && m_pBasicAudio ) {
            long lVolume = -1;
            m_hr = m_pBasicAudio->get_Volume(&lVolume);
            if ( SUCCEEDED(m_hr) )
                return lVolume;
        }
        return -1;
    }

    bool setVolume(long lVolume) {
        if ( m_bIsPlaying && m_pBasicAudio ) {
            m_hr = m_pBasicAudio->put_Volume(lVolume);
            return SUCCEEDED(m_hr);
        }
        return false;
    }

    long durationInSeconds() {
        return m_ulTrackDuration / 10000000;
    }

    __int64 currentPosition() {
        if ( getState() == MUSIC_PLAYING && m_pMediaSeeking ) {
            __int64 curPosition = -1;
            m_hr = m_pMediaSeeking->GetCurrentPosition(&curPosition);
            if ( SUCCEEDED(m_hr) )
                return curPosition;
        }
        return -1;
    }

    bool setPosition(__int64* pCurrentPos, __int64* pStop, bool bAbsolutePositioning) {
        if ( getState() == MUSIC_PLAYING && m_pMediaSeeking ) {
            DWORD flags = 0;
            if ( bAbsolutePositioning )
                flags = AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame;
            else
                flags = AM_SEEKING_RelativePositioning | AM_SEEKING_SeekToKeyFrame;
            m_hr = m_pMediaSeeking->SetPositions(pCurrentPos, flags, pStop, flags);
            if ( SUCCEEDED(m_hr) )
                return true;
        }
        return false;
    }

private:

    bool m_bIsPlaying, m_bIsPaused, m_bIsStopped;
    std::string m_strFilePath;

    HRESULT m_hr;
    IGraphBuilder *m_pGraph;
    IMediaControl *m_pControl;
    IMediaEvent   *m_pEvent;
    IMediaEventEx *m_pEventEx;
    IBasicAudio   *m_pBasicAudio;
    IMediaSeeking *m_pMediaSeeking;

    // 10,000,000 per second
    __int64 m_ulTrackDuration;

    void set_state(MusicStatus m) {
        switch(m) {
        case MUSIC_STOPPED:
            m_bIsStopped = true;
            m_bIsPlaying = m_bIsPaused = false;
            break;
        case MUSIC_PAUSED:
            m_bIsPaused = true;
            m_bIsPlaying = m_bIsStopped = false;
            break;
        case MUSIC_PLAYING:
            m_bIsPlaying = true;
            m_bIsPaused = m_bIsStopped = false;
            break;
        case MUSIC_IDLE:
            m_bIsPaused = m_bIsPlaying = m_bIsStopped = false;
            break;
        }
    }

    void play_sound() {
        m_hr = m_pGraph->RenderFile(s2ws(m_strFilePath).c_str(), NULL);
        if (SUCCEEDED(m_hr))
        {
            m_hr = m_pControl->Run();
            if (SUCCEEDED(m_hr)) {
                if ( m_pMediaSeeking ) {
                    m_pMediaSeeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
                    m_pMediaSeeking->GetDuration(&m_ulTrackDuration);
                }
            }
        }

    }

};

int main(void)
{
    MusicPlayer A;
    A.playAudio("music.mp3");
    std::cout << A.durationInSeconds();
    system("pause");
    return 0;
}
like image 30
johnsonwi Avatar answered Sep 25 '26 06:09

johnsonwi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!