Question

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 ?

Was it helpful?

Solution

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.

OTHER TIPS

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 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);
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top