Как отправить указатель на функцию обратного вызова, которая инкапсулирована в классе - PullRequest
2 голосов
/ 29 ноября 2011

На самом деле я пишу программу на C ++, используя библиотеку PortAudio. Эта библиотека использует функцию обратного вызова для управления вводом и выводом звука. В C ++ я реализовал эту функцию обратного вызова в своем классе «Аудио», и я не могу отправить ее в Pa_OpenDefaultStream (). Компилятор говорит «этот аргумент несовместим с параметром типа PaStreamCallback *» с этой строкой:

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

Когда я использую C, отправка моей функции обратного вызова, как это работает хорошо. Как я могу отправить свою функцию обратного вызова в эту функцию OpenDefaultStream?

Ответы [ 3 ]

3 голосов
/ 29 ноября 2011

Вам необходимо реализовать простую глобальную функцию с той же сигнатурой, что и 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); 

Я предполагал, что вы сделаете функцию обратного вызова, чтобы принять все остальные аргументы.

0 голосов
/ 15 августа 2014

Я знаю, что это было давно, но я столкнулся с той же проблемой и нашел решение в стиле 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);
};
0 голосов
/ 17 января 2014

Ответ Эрика Олсона прекрасно работает, когда у вас есть возможность передать «пользовательские данные» или контекст.Если это невозможно, вам, вероятно, понадобится безобразный хак, чтобы получить указатель this из обратного вызова.Я видел, что у класса с обратным вызовом также есть статическая копия этого указателя, которая будет работать, только если у вас есть только один экземпляр класса.Гадко, но это работает.

Это уродство является аргументом для всех API, чтобы иметь элегантный способ решения этой проблемы, в идеале без нарушения безопасности типов с помощью переинтерпретации.

...