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

发布于 2024-12-18 06:09:26 字数 392 浏览 3 评论 0原文

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

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

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

I'm actually coding a program in C++ using the library PortAudio.
This library is using a callback function tu manage audio input and output.
In C++, I implemented this callback function in my class "Audio" and I can't send it to Pa_OpenDefaultStream(). The compiler says "this argument is incompatible with parameter of type PaStreamCallback*" with this line :

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

When I use C, sending my callbackFunction like this works well.
How can I send my callback function to this OpenDefaultStream function ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

甜柠檬 2024-12-25 06:09:26

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

看起来 PaStreamCallback 接受一个参数 void* userData。这就是通常所说的上下文参数。如果不了解 PortAudio,我想您可以使用它来表示您的类实例。当您调用 Pa_OpenDefaultStream 时,将“this”传递给 userData 指针,在示例中您在此处写入了 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); 

我假设您将使回调函数接受所有其他参数。

You need to implement a plain global function with the same signature as PaStreamCallback.

It looks like PaStreamCallback takes an argument, void* userData. This is what's usually called a context argument. Without knowledge of PortAudio I guess that you can use this to represent your class instance. When you call Pa_OpenDefaultStream, pass "this" for the userData pointer, where you wrote NULL in your example.

Here is a sample implememtation of the function wrapper you need:

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

Then replace your original code with:

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

I assumed you would make your callbackFunction to take all the other args.

挽袖吟 2024-12-25 06:09:26

当您有机会传递“用户数据”或上下文时,埃里克·奥尔森的答案非常有效。如果这是不可能的,您可能需要一个丑陋的黑客来从回调中获取 this 指针。我已经看到带有回调的类也有该指针的静态副本,只有当您只有该类的一个实例时,该副本才有效。丑陋但它有效。

这种丑陋是所有 API 都应该有一种优雅的方式来处理这个问题的理由,最好不要使用重新解释强制转换来破坏类型安全。

Erik Olson's answer works great when you have the opportunity to pass in "user data" or context. If this isn't possible, you'll probably need an ugly hack to get ahold of your this pointer from within the callback. I've seen the class with the callback also have a static copy of this pointer, which would work only if you've got only one instance of the class. Ugggggly but it works.

This ugliness is an argument for all APIs to have an elegant way of dealing with this problem, ideally without breaking type safety using the reinterpret cast.

半边脸i 2024-12-25 06:09:26

我知道已经有一段时间了,但我遇到了同样的问题并找到了 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);
};

I know it's been a while, but I encountered same problem and found solution in C++11 style.

So we have

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

Then, where in AudioHander.cpp do global variable:

 AudioHandler* veryDangerousHandler;

And in the end:

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);
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文