2

我正在尝试创建此类的两个实例,它们最终将使用 Win32 的 mciSendString 功能播放音乐文件。但是为了测试它,因为这是我第一次尝试使用 std::thread,我编写了一个 test(void) 方法,它输出类 ID,我希望它打印一系列 1 和 2,例如 12122111112212121212 ...

我收到以下错误,test(void) 方法确实存在吗?

错误 1 ​​错误 C2064:术语不计算为采用 0 个参数的函数

#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;
}

更新:我做了一些调整,现在我遇到了参数列表的问题,错误:MusicPlayer::play_sound 函数调用缺少参数列表

#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;
}
4

5 回答 5

5

你不能运行一个对象!您可以运行的是特定对象上的成员函数:std::thread需要告诉线程的入口函数。它使用第一个构造函数参数作为函数对象,将所有其他参数作为参数用于如何调用函数。由于您的类没有函数调用运算符,std::thread因此不知道要调用哪个函数。

有一种方法可以解决问题:

  1. operator()()您为您的类型提供一个函数调用MusicPlayer作为线程的入口函数。
  2. 您将成员函数用作第一个参数,并将实际对象用作传递的参数,例如std::thread t1(&MusicPlayer::test, &A).
  3. 您使用易于绑定的函数对象作为 的参数std::thread,例如std::thread t1(std::bind(&MusicPlayer::test, std::ref(A))
于 2012-12-25T03:38:08.633 回答
2

好的,我已经解决了我的问题,由于 std::thread,std::thread 非常适合在后台播放 mp3 文件。注意: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;
}
于 2012-12-25T19:37:50.610 回答
1

std::thread用作您的类的成员,并通过MusicPlayer将线程函数分配给它来启动后台线程,一旦更改为 state MUSIC_PLAYING

于 2012-12-25T03:34:04.277 回答
1

小问题:

MusicPlayer(void)
bool isPaused(void)
bool isPlaying(void)

具有零参数的函数定义为:

MusicPlayer()
bool isPaused()
bool isPlaying()

主要问题。

线程对象构造函数采用函子。因为您不传递任何参数,所以仿函数也必须采用零参数。这意味着您传递给线程的对象必须可以像这样调用:

MusicPlayer A;
std::thread t1(A);

// This means that the object A is callable like a function.
A();

// For this to work the class MusicPlayer must define the opropriate function operator:

class MusicPlayer
{
    public:
        void operator()() { /* Code run inside thread */ }
};
于 2012-12-25T03:35:23.797 回答
0

你可以尝试类似的东西

std::thread audioThread(([this](){MusicPlayer::play_sound();};
于 2014-03-31T14:59:58.830 回答