1

我正在尝试在 Jack 中设置回调函数。这通常很简单,使用函数“jack_set_process_callback”(在设置“process”回调的情况下)。

API 中的定义是这样的:

int jack_set_process_callback(jack_client_t* client, JackProcessCallback process_callback, void* arg).

在示例代码(具有 C 组件)中,声明了以下全局函数。

int process(jack_nframes_t nframes, void *arg){

  // do something in the callback
  return 0;
}

然后通过以下行将其设置为 Jack 进程回调:

jack_set_process_callback(client, process, 0)

..这可以完美地编译和工作。

我现在正在做的是尝试构建一个基于类的音频程序。我将所有 Jack 的东西都放在一个名为“Sound_Module”的类中。

我想设置为回调的函数的定义现在是这个类的成员函数:

int Sound_Module::process(jack_nframes_t nframes, void *arg){

  // do something in the callback
  return 0;
}

我正在尝试将此方法设置为类构造函数中的回调函数:

(83) jack_set_process_callback(client, process, 0)

但是在编译时这会导致以下错误:

sound_module.cpp:83: error: argument of type ‘int (Sound_Module::)(jack_nframes_t, void*)’ does not match ‘int (*)(jack_nframes_t, void*)’

我从这个错误消息中得到的印象是我需要将回调函数转换为其他东西。我已经尝试了一些事情,例如强制转换为专为回调设计的 Jack 类型,但没有运气 - 下面是从 API 中为“JackProcessCallback”挖出的行。

typedef int(* JackProcessCallback)(jack_nframes_t nframes, void *arg)

谁能阐明这个编译器错误可能暗示什么,或者我可能做错了什么?

谢谢!

4

5 回答 5

3

成员函数与非成员函数不同,因为您只能在函数所属的类类型的对象上调用它们。

您需要编写一个委托给成员函数的非成员函数。当您调用 时jack_set_process_callback,您告诉库将什么传递给void*回调的参数,因此您可以告诉它传回Sound_Module您要为其调用成员函数回调的对象的地址。

非成员回调非常简单:

int Sound_Module_Process_Callback(jack_nframes_t x, void* p)
{
    return static_cast<Sound_Module*>(p)->process(x);
}

注册为:

jack_set_process_callback(client, Sound_Module_Process_Callback, this);
于 2011-08-06T22:41:42.203 回答
2

这是因为类的每个成员函数都有一个隐藏参数this。而是将回调方法声明为static

error: argument of type ‘int (Sound_Module::)(jack_nframes_t, void*)’  
                            // ^^^^^^^^^^^^^

这部分错误消息说它是一个暗示隐藏参数this的成员函数。

does not match ‘int (*)(jack_nframes_t, void*)’

这部分说它是常规的 C 类型回调函数声明。

而是试试这个 -

 class Sound_Module {
    public:
    static int process(jack_nframes_t nframes, void *arg) ; 
   // This is just declaration. Provide the definition in the source file.
 };
于 2011-08-06T22:38:23.343 回答
1

你不能那样做。

tl; dr:成员函数不是自由函数。您的回调必须是免费功能。

更长的答案: set-callback 函数需要一个函数指针作为其回调参数。只有自由函数才能变成函数指针。非静态成员函数不是自由函数,不能变成函数指针!该表达式&Foo::f是一个指向成员函数(PTFM) 的指针,它是一种完全不同的、不兼容的、通常更大的类型。

如果您的客户端功能由 C API 修复,那么您有两种可能的解决方案:

  1. 做一个静态成员函数。静态成员函数本质上只是自由函数,因此它们确实会产生函数指针。在这种情况下,您并没有真正使用类结构并且没有状态(这就是您可以这样做的原因)。

  2. 编写一个全局包装函数。

Sound_Module g_sm1; // global!
Sound_Module g_sm2;

int process1(jack_nframes_t nframes, void *arg)
{
  return g_sm1.process_firsttype(nframes, arg);
}
int process2(jack_nframes_t nframes, void *arg)
{
  return g_sm1.process_secondtype(nframes, arg);
}
int process3(jack_nframes_t nframes, void *arg)
{
  return g_sm2.process_firsttype(nframes, arg);
}
int process4(jack_nframes_t nframes, void *arg)
{
  static Sound_Module s_sm;
  return s_sm.process_firsttype(nframes, arg);
}
于 2011-08-06T22:40:09.783 回答
1

非静态成员函数不能被回调,因为它们只能被类的实例调用。

我认为你应该这样做:

int callback(jack_nframes_t nframes, void* arg)
{
    return static_cast<Sound_Module*>(arg)->process(nframes);
}

并将成员函数定义process

int Sound_Module::process(jack_nframes_t nframes){

  // do something in the callback
  return 0;
}

也就是说,它应该只接受一个参数。不需要第二个参数。

此外,您应该调用jack_set_process_callback

 jack_set_process_callback(client, callback, &soundModule);
                                           //^^^^^^^^^^^^

也就是说,第三个参数应该是 的实例的地址Sound_Modulethis如果您从 as 的成员函数调用它,它也可以是指针Sound_Module

void Sound_Module::SomeNonStaticMemberFunction()
{
     jack_set_process_callback(client, callback, this);
}
于 2011-08-06T22:44:15.337 回答
-1

一种更面向 C++ 的方法,关键是使用 Jack 的 JackProcessCallback 预定义类型:

#include <jack/jack.h>

BaseSoundModule
{
    public:

    jack_client_t * client;

    //Use a constructor to assign a client to the class.
    BaseSoundModule( jack_client_t * external_client ){ client = external_client; }

    //Use Jack's JackProcessCallback predefined type.
    void setProcessCallback( JackProcessCallback, void * pointerArgument )
    {
        jack_set_process_callback( client, JackProcessCallback, pointerArgument );
    }

};

Metronome : public BaseSoundModule
{
    static int process_audio( jack_nframes_t nframes, void * arg )
    {
        //Note #1 at the end of this example
        Metronome * MetroPointer = ( Metronome * ) arg;

        //Call other functions inside your metronome class;
        Metronome->someotherfunc();
    }

    int someotherfunc(){ //return something. }
};

然后你会这样称呼它:

jack_client_t * client;

int main()
{
    Metronome Metro;

    Metronome * MetroPointer = &Metro;

    BaseSoundModule * PolyMetro = &Metro;

    PolyMetro->setProcessCallback( MetroPointer->process_audio, MetroPointer );

}
  • 注意 1:请注意,在 process_audio 中,您还传递了 MetroPointer 作为参数。这意味着您可以在回调中使用子类的其他方法。
于 2012-12-26T00:25:17.157 回答