如何在封装在类中的回调函数上发送指针

时间:2011-11-28 20:58:56

标签: c++ audio callback portaudio

我实际上是使用库PortAudio在C ++中编写程序。 该库使用回调函数来管理音频输入和输出。 在C ++中,我在我的类“Audio”中实现了这个回调函数,我无法将它发送到Pa_OpenDefaultStream()。编译器用这一行说“这个参数与PaStreamCallback *类型的参数不兼容”:

Pa_OpenDefaultStream(&this->_stream, 1, 2, paFloat32, this->_sampleRate, this->_framesPerBuffer, callbackFunction, NULL);

当我使用C时,像这样发送我的callbackFunction效果很好。 如何将回调函数发送到此OpenDefaultStream函数?

3 个答案:

答案 0 :(得分:3)

您需要实现一个与PaStreamCallback具有相同签名的普通全局函数。

看起来PaStreamCallback接受一个参数,void * userData。这通常被称为上下文参数。如果不了解PortAudio,我猜你可以用它来表示你的类实例。当你调用Pa_OpenDefaultStream时,为userData指针传递“this”,在你的例子中你写了NULL。

以下是您需要的函数包装器的示例实现:

int MyPaStreamCallback (const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
{
     MyClass *myClass = reinterpret_cast<MyClass*>(userData);
     return myClass->callbackFunction(input, output, frameCount, timeInfo, statusFlags);
}

然后用以下代码替换原始代码:

Pa_OpenDefaultStream(&this->_stream, 1, 2, paFloat32, this->_sampleRate, this->_framesPerBuffer, MyPaStreamCallback , this); 

我认为你会让你的callbackFunction采取所有其他的args。

答案 1 :(得分:0)

当你有机会传递“用户数据”或上下文时,Erik Olson的回答很有效。如果这是不可能的,你可能需要一个丑陋的黑客来从回调中获取你的这个指针。我已经看到带回调的类也有一个这个指针的静态副本,只有当你只有一个类的实例时才能工作。 Ugggggly,但它的工作原理。

这种丑陋是所有API的一个参数,它有一种优雅的方式来处理这个问题,理想情况下不会使用重新解释转换破坏类型安全性。

答案 2 :(得分:0)

我知道它已经有一段时间了,但我遇到了同样的问题并找到了C ++ 11风格的解决方案。

所以我们有

 int AudioHandler::CallBackFunction(const void *inputBuffer, void *outputBuffer,
                               unsigned long framesPerBuffer,
                               const PaStreamCallbackTimeInfo* timeInfo,
                               PaStreamCallbackFlags statusFlags,
                               void *userData);

然后,在AudioHander.cpp中执行全局变量:

 AudioHandler* veryDangerousHandler;

最后:

PaStreamCallback* callbackus = [](const void *inputBuffer, void *outputBuffer,
        unsigned long framesPerBuffer,
        const PaStreamCallbackTimeInfo* timeInfo,
        PaStreamCallbackFlags statusFlags,
        void *userData) -> int
{
    return veryDangerousHandler->CallBackFunction(inputBuffer, outputBuffer,
                            framesPerBuffer,
                            timeInfo,
                            statusFlags,
                            userData);
};