从C线程调用Python函数,并传递可变C数组

3 投票
1 回答
592 浏览
提问于 2025-04-17 16:49

我正在为一个用C++写的小型音频库创建一个Python扩展。当打开音频流时,会传递一个回调函数作为参数(当然还有其他参数)。下面是一个稍微简化的使用案例:

AudioThingy *a = new AudioThingy();
a->openStream(..., callbackFunction);
a->startStream();

我的Python扩展把这个功能封装在一个Python类里面。

thingy = AudioThingy()
thingy.openStream(..., pythonCallbackFunction)
thingy.startStream()

现在,这个扩展有一个作为C函数的回调,它会传递给C++库。每当音频流有更新时,这个回调就会接收到一些关于流的信息,还有一个指向音频缓冲区的空指针(void pointer),这个指针会根据流的格式参数被转换成正确的数据类型。我的目的是让这个用C实现的回调函数调用用户指定的Python函数,并传入某种数组作为参数,这个数组会被填充来自于例如用Python打开的wav文件的音频数据。

我想要做的事情,代码大概是这样的:

static int __audiothingy_callback(void *buffer, ...) {
  PyGILState_STATE state = PyGILState_Ensure();
  /*
      cast the void pointer to the correct data type (short, int, long, etc.)
      wrap it for Python somehow
  */
  PyEval_CallObject(the_python_function, arglist);
  PyGILState_Release(state);
  //proceed to fill the buffer with stuff passed back from python
  for (...)
    *casted_buffer++ = ????
  Py_DECREF(arglist);
  return 0;
}

总结一下:我该如何在一个线程中从C传递一个可变数组(类型正确)到一个Python函数,这样就可以用来填充音频缓冲区?也许可以用不同于我上面描述的方法来实现?欢迎任何建议。

1 个回答

2

我觉得你可以尝试几种方法。如果你在用Python 2.7,可以通过新的缓冲协议创建一个内存视图对象:

然后,你需要从这个缓冲区创建一个内存视图对象:

另一种方法是导入数组模块,然后用它来创建你想要的类型的数组。你可以使用:

然后,根据所需的类型构建数组:

PyObject *array = PyObject_CallFunction(array_type, "c", 'd');   

更简单的方法是直接使用字节数组对象:

撰写回答