从C线程调用Python函数,并传递可变C数组
我正在为一个用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,可以通过新的缓冲协议创建一个内存视图对象:
然后,你需要从这个缓冲区创建一个内存视图对象:
另一种方法是导入数组模块,然后用它来创建你想要的类型的数组。你可以使用:
- PyImport_ImportModule
- PyModule_GetDict
- PyObject* array_type = PyDict_GetItemString(dict, "array");
然后,根据所需的类型构建数组:
PyObject *array = PyObject_CallFunction(array_type, "c", 'd');
更简单的方法是直接使用字节数组对象:
- PyByteArray_FromStringAndSize来构建字节数组,如果你能把事情安排得当,这样就不需要担心数组元素的大小。