Calling a Python function from a C thread, with a mutable C array

筅森魡賤 提交于 2019-12-23 19:28:35

问题


I'm in the process of creating a Python extension for a small audio library written in C++. When opening an audio stream, a callback function is passed as a parameter (among other parameters of course). A sligthly simplified use case:

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

My Python extension wraps this inside a Python class.

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

Now, the extension has a callback as a C function which it passes to the C++ library. For every stream tick the callback receives some information about the stream along with a void pointer to the audio buffer that the callback casts to the correct data type according to the stream format parameter. My intent is of course for this callback function implemented in C to call the user specified Python function with some sort of array as the argument which would then be filled with audio data from, for example, a wav-file opened with Python.

This is what i want to do, in code:

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;
}

TL;DR: How do I pass a mutable array of the correct type from C, in a thread, to a Python function which can then be used to populate the audio buffer? Maybe it can be done in a different way than I have described above? All input is welcome.


回答1:


I think you could do a couple things. If you're using Python 2.7 you could create a memoryview object using the new buffer protocol:

  • New buffer protocol, Py_buffer

Then, you'd need to create a memoryview object from the buffer:

  • PyMemoryView_FromBuffer

Another strategy would be to import the array module, and use this to create an array of the desired type. You use:

  • PyImport_ImportModule
  • PyModule_GetDict
  • PyObject* array_type = PyDict_GetItemString(dict, "array");

Then, construct the array, according to the type needed:

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

Even easier, you could just use a bytearray object:

  • PyByteArray_FromStringAndSize to construct a byte array if you can structure things such that you don't need to worry about the size of array elements.


来源:https://stackoverflow.com/questions/15033683/calling-a-python-function-from-a-c-thread-with-a-mutable-c-array

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!