From ceff0bd694c666fd9aa8ce820a4512ae5eb2fc45 Mon Sep 17 00:00:00 2001 From: wangjiyu Date: Sat, 3 May 2025 21:51:02 +0800 Subject: [PATCH] use pybind --- build.sh | 24 +-- rtc_plugins.cpp | 223 +++++--------------- util/RTCContext.cpp | 483 ++------------------------------------------ util/RTCContext.h | 34 +--- util/numpyStub.h | 12 -- 5 files changed, 89 insertions(+), 687 deletions(-) delete mode 100644 util/numpyStub.h diff --git a/build.sh b/build.sh index fa99a88..9d1aa5a 100644 --- a/build.sh +++ b/build.sh @@ -1,17 +1,9 @@ -g++ -DBOOST_DEBUG_PYTHON -shared -fPIC \ - -I/usr/include/python3.10 -I/usr/include/python3.10/numpy -I./include \ +g++ -shared -fPIC -std=c++11 \ + $(python3 -m pybind11 --includes) \ # 自动获取 pybind11 和 Python 头文件路径 + -I./include \ # 保留自定义头文件路径 -L./lib -L/usr/lib/x86_64-linux-gnu \ - -DRTC_NUMPY_IMPL \ - rtc_plugins.cpp util/RTCContext.cpp \ - -lMRTCEngine -lboost_python310 -lboost_numpy310 -lpython3.10 \ - -Wl,-rpath='$ORIGIN/lib' \ - -o rtc_plugins.so -#g++ -shared -fPIC \ -# -I/usr/include/python3.10 -I/usr/include/python3.10/numpy -I./include \ -# -I/usr/include/python3.10 -I/usr/include/numpy \ -# -Wl,-rpath='$ORIGIN/lib' \ -# -lboost_python310 -lpython3.10 \ -# -lMRTCEngine -lboost_python310 -lpython3.10 \ -# -L$(python3 -c "import numpy; print(numpy.get_include())") \ -# rtc_plugins.cpp util/RTCContext.cpp \ -# -o rtc_plugins.so + -lMRTCEngine \ # 保留其他必要库 + -lpython3.10 \ # 仍然需要链接 Python + -Wl,-rpath='$ORIGIN/lib' \ # 保留运行时库路径 + -o rtc_plugins$(python3-config --extension-suffix) \ # 标准化输出文件名 + rtc_plugins.cpp util/RTCContext.cpp diff --git a/rtc_plugins.cpp b/rtc_plugins.cpp index dd37a82..2dce287 100644 --- a/rtc_plugins.cpp +++ b/rtc_plugins.cpp @@ -1,7 +1,10 @@ -// rtc_plugins.cpp +#define IMPLEMENT_NUMPY_API +#include "util/RTCContext.h" +#include +#include // pybind11 的 NumPy 支持 +#include -#define IMPLEMENT_NUMPY_API // 标记这是实现文件 -#include "util/numpyStub.h" +namespace py = pybind11; #include "util/RTCContext.h" // 提供转换接口 @@ -9,10 +12,15 @@ void** get_numpy_api() { return (void**)RTC_PLUGINS_ARRAY_API; } +// 初始化 NumPy(适配 pybind11) +void init_numpy() { + if (import_array() < 0) { + throw py::bind_already_set(); // 自动捕获 NumPy 初始化错误 + } + std::cout << "NumPy API addr: " << PyArray_API << std::endl; +} -namespace py = boost::python; - -int init(const char* selfUserId, const char* selfDisplayName, const char* selfRoomId, boost::python::object callback) { +int init(const char* selfUserId, const char* selfDisplayName, const char* selfRoomId, py::object callback) { if (!PyArray_API) { std::cout << "PyArray_API is null in outer init" << std::endl; } else { @@ -47,178 +55,57 @@ int initSend(const char* srcRoomId, const char* destRoomId, const int16_t destCh return -1; } } -int getSize() { - return RTCContext::instance().getSize(); +// NumPy 数据交互(关键修改) +py::array_t getNumpyData() { + return py::array_t( + RTCContext::instance().getNumpyData() // 假设返回的是已有 NumPy 数组 + ); } -namespace bp = boost::python; -namespace np = boost::python::numpy; -np::ndarray getNumpyData() { - return RTCContext::instance().getNumpyData(); +int sendCustomAudioData(int16_t destChannelIndex, py::array_t inputArray, + int32_t sampleRate, uint64_t channelNum, uint64_t dataLen) { + py::gil_scoped_release release; + + auto buf = inputArray.request(); + if (buf.size != dataLen) { + throw py::value_error("Array length does not match dataLen"); + } + + return RTCContext::instance().sendCustomAudioData( + destChannelIndex, buf.ptr, sampleRate, channelNum, dataLen + ); } -bp::list getListData() { +py::list getListData() { return RTCContext::instance().getListData(); } -int16_t getDataCount() { - return RTCContext::instance().getDataCount(); -} -py::object create_int16_array() { - // 1. 定义数组维度(1维,长度为 4) - npy_intp dims[1] = {4}; - - // 2. 创建原生 C 数组(int16_t 数据) - int16_t data[4] = {1, 2, -3, 4}; // 示例数据 - - // 3. 通过 NumPy C API 创建 PyObject* - PyObject* py_array = PyArray_SimpleNewFromData( - 1, // 维度数 - dims, // 各维度大小 - NPY_INT16, // 数据类型(np.int16) - data // 数据指针 - ); - - if (!py_array) { - throw std::runtime_error("Failed to create NumPy array"); - } - - // 4. 转换为 py::object(自动管理引用计数) - return py::object(py::handle<>(py_array)); -} - -int sendCustomAudioData(int16_t destChannelIndex, py::object pD, - int32_t sampleRate, uint64_t channelNum, uint64_t dataLen) { - try { - // 强制转换为 int16 连续数组 - PyObject* py_array = PyArray_FROM_OTF( - pD.ptr(), - NPY_INT16, - NPY_ARRAY_IN_ARRAY | NPY_ARRAY_FORCECAST - ); - if (!py_array) { - throw std::runtime_error("Failed to convert input to int16 array"); - } - - // 修复点:使用花括号初始化 - py::object arr{py::handle<>(py_array)}; - - // 检查数据长度 - PyArrayObject* npArray = reinterpret_cast(arr.ptr()); - if (PyArray_SIZE(npArray) != static_cast(dataLen)) { - Py_DECREF(py_array); - throw std::runtime_error("Array length does not match dataLen"); - } - - // 处理数据... - void* dataPtr = PyArray_DATA(npArray); - int ret = RTCContext::instance().sendCustomAudioData( - destChannelIndex, dataPtr, sampleRate, channelNum, dataLen - ); - Py_DECREF(py_array); // 释放临时数组 - return ret; - } catch (...) { - PyErr_SetString(PyExc_RuntimeError, "Invalid audio data"); - return -1; - } +int getSize() { + return RTCContext::instance().getSize(); } RetAudioFrame getData() { return RTCContext::instance().getData(); } - -/* -int sendCustomAudioData(const int16_t destChannelIndex, py::object pyData, int32_t sampleRate, uint64_t channelNum, - uint64_t dataLen) { - try { - //py::object pyData = create_int16_array(); - std::cout << "step 1" << std::endl; - // 1. 检查输入有效性 - if (pyData.ptr() == nullptr) { - throw std::runtime_error("Input data is NULL"); - } - - std::cout << "step 2" << std::endl; - std::cout << "pyData ptr is:" << pyData.ptr() << std::endl; - if (!pyData.ptr() || !Py_IsInitialized() || !PyObject_TypeCheck(pyData.ptr(), &PyBaseObject_Type)) { - throw std::runtime_error("Invalid Python object"); - } - std::cout << "step 2" << std::endl; - // 2. 检查是否是 numpy 数组 - if (!PyArray_Check(pyData.ptr())) { - std::cout << "input is notnumpy" << std::endl; - throw std::runtime_error("Input is not a numpy array"); - } - - std::cout << "step 3" << std::endl; - // 3. 转换为 PyArrayObject - PyArrayObject* npArray = reinterpret_cast(pyData.ptr()); - - std::cout << "step 4" << std::endl; - // 4. 检查数据类型是否为 int16 - if (PyArray_TYPE(npArray) != NPY_INT16) { - throw std::runtime_error("Array must be of type int16 (np.int16)"); - } - - std::cout << "step 5" << std::endl; - // 5. 检查数据是否连续 - if (!PyArray_ISCONTIGUOUS(npArray)) { - throw std::runtime_error("Array must be contiguous in memory"); - } - std::cout << "step 6" << std::endl; - - // 6. 获取数据指针 - void* dataPtr = PyArray_DATA(npArray); - if (dataPtr == nullptr) { - throw std::runtime_error("Invalid data pointer"); - } - std::cout << "step 7" << std::endl; - return RTCContext::instance().sendCustomAudioData(destChannelIndex, dataPtr, sampleRate, channelNum, dataLen); - - } catch (const std::exception& e) { - std::cout << "error:" << e.what() << std::endl; - return -1; - } +int16_t getDataCount() { + return RTCContext::instance().getDataCount(); } - */ + +PYBIND11_MODULE(rtc_plugins, m) { + init_numpy(); + // 可选:暴露 RetAudioFrame 类(需额外绑定) + py::class_(m, "RetAudioFrame") + .def_readwrite("data", &RetAudioFrame::data) + .def_readwrite("dataCount", &RetAudioFrame::dataCount) + .def_readwrite("sampleRate", &RetAudioFrame::sampleRate) + .def_readwrite("numChannels", &RetAudioFrame::numChannels) + .def_readwrite("channelIndex", &RetAudioFrame::channelIndex); + m.def("init", &init); + m.def("initRecv", &initRecv); + m.def("initSend", &initSend); + m.def("sendCustomAudioData", &sendCustomAudioData); + m.def("getSize", &getSize); + m.def("getData", &getData); + m.def("getNumpyData", &getNumpyData); + m.def("getListData", &getListData); + m.def("getDataCount", &getDataCount); -void init_numpy() { - // 直接调用底层函数,绕过宏的问题 - if (_import_array() < 0) { - PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); - throw std::runtime_error("NumPy initialization failed"); - } - std::cout << "NumPy API addr: " << PyArray_API << std::endl; -} -BOOST_PYTHON_MODULE(rtc_plugins) { - try { - init_numpy(); - void** numpyApi = (void**)PyArray_API; - if (!numpyApi || !numpyApi[93]) { // 93是PyArray_SimpleNew的偏移量 - std::cout << "NumPy API corrupt! Key functions missing." << std::endl; - PyErr_Print(); - throw std::runtime_error("Invalid NumPy API state"); - } else { - RTCContext::instance().setNumpyApi(numpyApi); - std::cout << "set numpyApi succ:" << numpyApi[93] << std::endl; - } - - /* - if (!PyArray_API) { - std::cout << "PyArray_API is null" << std::endl; - } else { - std::cout << "PyArray_API is not null" << std::endl; - } - */ - - py::def("init", &init); - py::def("initRecv", &initRecv); - py::def("initSend", &initSend); - py::def("sendCustomAudioData", &sendCustomAudioData); - py::def("getSize", &getSize); - py::def("getData", &getData); - py::def("getNumpyData", &getNumpyData); - py::def("getListData", &getListData); - py::def("getDataCount", &getDataCount); - } catch (...) { - PyErr_SetString(PyExc_RuntimeError, "Module initialization failed"); - } } \ No newline at end of file diff --git a/util/RTCContext.cpp b/util/RTCContext.cpp index 6353488..0a4b140 100644 --- a/util/RTCContext.cpp +++ b/util/RTCContext.cpp @@ -56,242 +56,7 @@ void RTCContext::onSoundLevelUpdate(const char* roomId, const char* peerId, uint { std::cout << "RTCContext::onSoundLevelUpdate()" << std::endl; } -/* -void RTCContext::onAudioProcess(const char* roomId, const char* peerId, - mrtc::MRTCAudioFrame& audioFrame, - mrtc::MRTCAudioSourceType audioSourceType) -{ - namespace py = boost::python; - PyGILState_STATE gstate = PyGILState_Ensure(); - - try { - std::cout << "-----------------------------------" << std::endl; - std::cout << "dataCount:" << audioFrame.dataCount << std::endl; - std::cout << "dataCount value: " << audioFrame.dataCount - << " (max: " << std::numeric_limits::max() << ")" << std::endl; - - - std::cout << "onAudioProcess, numpyApi_:" << numpyApi_[93] << std::endl; - if (!numpyApi_ || !numpyApi_[93]) { // 93是PyArray_SimpleNew的偏移量 - std::cout << "numpyApi_ is null in onAudioProcess" << std::endl; - } else { - std::cout << "numpyApi_ is not null in onAudioProcess:" << numpyApi_[93] << std::endl; - } - //auto numpyApi = RTCContext::numpy_api(); - std::cout << "step1" << std::endl; - if (!numpyApi_) { - PyGILState_Release(gstate); - throw std::runtime_error("NumPy C-API not initialized. Call import_array() in module init"); - } - std::cout << "step2" << std::endl; - - using PyArray_SimpleNew_t = PyObject*(*)(int, npy_intp*, int); - - void* func_ptr = numpyApi_[93]; - std::cout << "Raw function pointer: " << func_ptr << std::endl; - - auto ptmp = (PyObject*(*)(int, npy_intp*, int))numpyApi_[93]; - std::cout << "ptmp is:" << ptmp << std::endl; - std::cout << "Pointer sizes:\n" - << "void*: " << sizeof(void*) << "\n" - << "FunctionPtr: " << sizeof(PyObject*(*)(int, npy_intp*, int)) << std::endl; - - // 2. 使用memcpy避免编译器优化问题 - PyArray_SimpleNew_t PyArray_SimpleNew; - static_assert(sizeof(func_ptr) == sizeof(PyArray_SimpleNew), - "Pointer size mismatch"); - std::cout << "step3" << std::endl; - memcpy(&PyArray_SimpleNew, &func_ptr, sizeof(func_ptr)); - - //auto PyArray_SimpleNew = reinterpret_cast(numpyApi_[93]); - std::cout << "step4, PyArray_SimpleNew:" << PyArray_SimpleNew << std::endl; - - // 3. 严格校验输入数据 - if (!audioFrame.data || audioFrame.dataCount <= 0) { - PyGILState_Release(gstate); - throw std::invalid_argument("Invalid audio frame data"); - } - std::cout << "step5" << std::endl; - - // 4. 安全创建维度数组(带边界检查) - if (audioFrame.dataCount > std::numeric_limits::max()) { - PyGILState_Release(gstate); - throw std::overflow_error("Audio frame size exceeds maximum limit"); - } - std::cout << "step6" << std::endl; - npy_intp dims[1] = {static_cast(audioFrame.dataCount)}; - - std::cout << "step7" << std::endl; - // 5. 创建NumPy数组(带内存保护) - PyObject* pyArray = nullptr; - pyArray = PyArray_SimpleNew(1, dims, NPY_INT16); - std::cout << "step8" << std::endl; - if (!pyArray) { - PyGILState_Release(gstate); - throw std::bad_alloc(); - } - std::cout << "step9" << std::endl; - - // 6. 安全拷贝数据(带对齐检查) - if (reinterpret_cast(audioFrame.data) % alignof(int16_t) != 0) { - Py_DECREF(pyArray); - PyGILState_Release(gstate); - throw std::runtime_error("Unaligned audio data pointer"); - } - std::cout << "step10" << std::endl; - std::memcpy(PyArray_DATA(reinterpret_cast(pyArray)), - audioFrame.data, - audioFrame.dataCount * sizeof(int16_t)); - - std::cout << "step11" << std::endl; - // 7. 执行回调(带引用计数保护) - if (!pyCallback_.is_none()) { - try { - pyCallback_( - py::handle<>(pyArray), // 自动管理引用 - audioFrame.dataCount, - audioFrame.sampleRate, - audioFrame.numChannels, - audioFrame.channelIndex - ); - } catch (...) { - Py_DECREF(pyArray); - throw; // 重新抛出异常 - } - } - std::cout << "step12" << std::endl; - - // 8. 释放资源 - Py_DECREF(pyArray); - std::cout << "step13" << std::endl; - PyGILState_Release(gstate); - std::cout << "step14" << std::endl; - - } catch (const std::exception& e) { - std::cerr << "Audio process error: " << e.what() << std::endl; - PyErr_Print(); - } - exit(0); -} - */ -/* -void RTCContext::onAudioProcess(const char* roomId, const char* peerId, - mrtc::MRTCAudioFrame& audioFrame, - mrtc::MRTCAudioSourceType audioSourceType) -{ - namespace py = boost::python; - std::cout << "=== 开始音频处理 ===" << std::endl; - - // 1. 获取GIL - std::cout << "[1] 获取GIL锁..." << std::endl; - PyGILState_STATE gstate = PyGILState_Ensure(); - - try { - // 2. 输入参数校验 - std::cout << "[2] 检查输入参数..." << std::endl; - std::cout << " dataCount: " << audioFrame.dataCount - << " (max: " << std::numeric_limits::max() << ")" << std::endl; - - if (!audioFrame.data || audioFrame.dataCount <= 0) { - std::cout << "[ERROR] 无效音频数据指针或长度" << std::endl; - throw std::invalid_argument("Invalid audio frame data"); - } - - if (audioFrame.dataCount > std::numeric_limits::max()) { - std::cout << "[ERROR] 数据长度超过最大值" << std::endl; - throw std::overflow_error("Audio frame size exceeds maximum limit"); - } - - // 3. 准备数组维度 - std::cout << "[3] 准备数组维度..." << std::endl; - npy_intp dims[1] = {static_cast(audioFrame.dataCount)}; - std::cout << " 维度设置完成: [" << dims[0] << "]" << std::endl; - - // 4. 检查NumPy API状态 - std::cout << "[4] 检查NumPy API状态..." << std::endl; - std::cout << " numpyApi_ 地址: " << numpyApi_ << std::endl; - if (!numpyApi_) { - throw std::runtime_error("NumPy C-API not initialized"); - } - - // 5. 获取PyArray_SimpleNew函数 - std::cout << "[5] 获取PyArray_SimpleNew函数..." << std::endl; - using PyArray_SimpleNew_t = PyObject*(*)(int, npy_intp*, int); - PyArray_SimpleNew_t PyArray_SimpleNew = - reinterpret_cast(numpyApi_[93]); - std::cout << " 函数地址: " << (void*)PyArray_SimpleNew << std::endl; - - std::cout << "[5.1] 验证函数指针..." << std::endl; - void* func_ptr = numpyApi_[93]; - if (reinterpret_cast(func_ptr) < 0x1000) { // 检查是否为合法地址 - std::cerr << "非法函数指针: " << func_ptr << std::endl; - throw std::runtime_error("Invalid PyArray_SimpleNew pointer"); - } - // 6. 创建NumPy数组 - std::cout << "[6] 创建NumPy数组..." << std::endl; - PyObject* pyArray = PyArray_SimpleNew(1, dims, NPY_INT16); - std::cout << " 数组地址: " << pyArray << std::endl; - - if (!pyArray) { - throw std::bad_alloc(); - } - - // 7. 检查内存对齐 - std::cout << "[7] 检查内存对齐..." << std::endl; - std::cout << " 音频数据地址: " << (void*)audioFrame.data - << " 对齐要求: " << alignof(int16_t) << std::endl; - - if (reinterpret_cast(audioFrame.data) % alignof(int16_t) != 0) { - Py_DECREF(pyArray); - throw std::runtime_error("Unaligned audio data pointer"); - } - - // 8. 拷贝数据 - std::cout << "[8] 拷贝音频数据..." << std::endl; - std::cout << " 目标地址: " << PyArray_DATA((PyArrayObject*)pyArray) - << " 字节数: " << audioFrame.dataCount * sizeof(int16_t) << std::endl; - - std::memcpy(PyArray_DATA((PyArrayObject*)pyArray), - audioFrame.data, - audioFrame.dataCount * sizeof(int16_t)); - - // 9. 执行回调 - if (!pyCallback_.is_none()) { - std::cout << "[9] 准备执行Python回调..." << std::endl; - try { - pyCallback_( - py::handle<>(pyArray), - audioFrame.dataCount, - audioFrame.sampleRate, - audioFrame.numChannels, - audioFrame.channelIndex - ); - std::cout << " 回调执行成功" << std::endl; - } catch (...) { - std::cout << "[ERROR] 回调执行失败" << std::endl; - Py_DECREF(pyArray); - throw; - } - } else { - std::cout << "[9] 无回调函数设置" << std::endl; - } - - // 10. 释放资源 - std::cout << "[10] 释放资源..." << std::endl; - Py_DECREF(pyArray); - std::cout << "[11] 释放GIL..." << std::endl; - PyGILState_Release(gstate); - std::cout << "=== 音频处理完成 ===" << std::endl; - - } catch (const std::exception& e) { - std::cout << "[EXCEPTION] 异常捕获: " << e.what() << std::endl; - PyGILState_Release(gstate); - PyErr_Print(); - std::cerr << "Audio process error: " << e.what() << std::endl; - } -} - */ void printTimestamp() { // 获取系统当前时间点 auto now = std::chrono::system_clock::now(); @@ -310,173 +75,7 @@ void RTCContext::onAudioProcess(const char* roomId, const char* peerId, mrtc::MRTCAudioFrame& audioFrame, mrtc::MRTCAudioSourceType audioSourceType) { - //namespace py = boost::python; - //std::cout << "=== 开始音频处理(共享内存版) ===" << std::endl; - //std::cout << "audioFrame:" << audioFrame.dataCount << "," << audioFrame.sampleRate << "," << - // audioFrame.numChannels << "," << audioFrame.channelIndex << std::endl; - - //printTimestamp(); setData(audioFrame); - // 1. 获取GIL - //std::cout << "[1] 获取GIL锁..." << std::endl; - ////PyGILState_STATE gstate = PyGILState_Ensure(); - - //try { - // // 2. 输入参数校验 - // std::cout << "[2] 检查输入参数..." << std::endl; - // std::cout << " dataCount: " << audioFrame.dataCount - // << " (max: " << std::numeric_limits::max() << ")" << std::endl; - - // if (!audioFrame.data || audioFrame.dataCount <= 0) { - // std::cout << "[ERROR] 无效音频数据指针或长度" << std::endl; - // throw std::invalid_argument("Invalid audio frame data"); - // } - - // const size_t data_size = audioFrame.dataCount * sizeof(int16_t); - - // // 3. 创建共享内存 - // std::cout << "[3] 创建共享内存..." << std::endl; - // char shm_name[32]; - // //snprintf(shm_name, sizeof(shm_name), "/audio_shm_%d", getpid()); - // snprintf(shm_name, sizeof(shm_name), "/audio_shm_test"); - - // int fd = shm_open(shm_name, O_CREAT | O_RDWR, 0666); - // if (fd == -1) { - // std::cout << "[ERROR] shm_open失败: " << strerror(errno) << std::endl; - // throw std::runtime_error("Failed to create shared memory"); - // } - // std::cout << " 共享内存fd: " << fd << " 名称: " << shm_name << std::endl; - - // // 4. 设置共享内存大小 - // std::cout << "[4] 设置共享内存大小..." << std::endl; - // if (ftruncate(fd, data_size) == -1) { - // close(fd); - // std::cout << "[ERROR] ftruncate失败: " << strerror(errno) << std::endl; - // throw std::runtime_error("Failed to resize shared memory"); - // } - // std::cout << " 内存大小: " << data_size << " bytes" << std::endl; - - // // 5. 内存映射 - // std::cout << "[5] 内存映射..." << std::endl; - // void* ptr = mmap(NULL, data_size, PROT_WRITE, MAP_SHARED, fd, 0); - // if (ptr == MAP_FAILED) { - // close(fd); - // std::cout << "[ERROR] mmap失败: " << strerror(errno) << std::endl; - // throw std::runtime_error("Failed to map shared memory"); - // } - // std::cout << " 映射地址: " << ptr << std::endl; - - // namespace py = boost::python; - // namespace np = boost::python::numpy; - // // 6. 拷贝数据到共享内存 - // std::cout << "[6] 拷贝音频数据到共享内存..." << std::endl; - // memcpy(ptr, audioFrame.data, data_size); - // std::cout << "step1" << std::endl; - // /* - // npy_intp shape[1] = { static_cast(audioFrame.dataCount) }; - // std::cout << "step2" << std::endl; - // np::dtype dtype = np::dtype::get_builtin(); - // std::cout << "step3" << std::endl; - // np::ndarray audioArray = np::from_data( - // audioFrame.data, // 数据指针 - // dtype, // 数据类型 (int16) - // py::make_tuple(shape[0]), // 形状 (1D) - // py::make_tuple(sizeof(int16_t)), // 步长 - // py::object() // 所有者(Python管理) - // ); - // */ - // std::cout << " 数据拷贝完成" << std::endl; - - // // 7. 执行回调 - // //if (!pyCallback_.is_none()) { - // // std::cout << "[7] 准备执行Python回调..." << std::endl; - // // // 增加引用计数防止提前释放 - // // Py_INCREF(pyCallback_.ptr()); - // // try { - // // std::cout << " pyCallback_ type: " << Py_TYPE(pyCallback_.ptr())->tp_name << std::endl; - // // PyObject* repr = PyObject_Repr(pyCallback_.ptr()); - // // if (repr) { - // // std::cout << " pyCallback_ repr: " << PyUnicode_AsUTF8(repr) << std::endl; - // // Py_DECREF(repr); // 必须手动释放 - // // } - // // // 传递共享内存信息 - // // pyCallback_( - // // py::str(shm_name), // 共享内存名称 - // // data_size, // 数据大小 - // // audioFrame.dataCount, - // // audioFrame.sampleRate, - // // audioFrame.numChannels, - // // audioFrame.channelIndex - // // ); - // // /* - // // pyCallback_( - // // audioArray, // numpy 数组 - // // data_size, // 数据大小 - // // audioFrame.dataCount, - // // audioFrame.sampleRate, - // // audioFrame.numChannels, - // // audioFrame.channelIndex - // // ); - // // */ - // // std::cout << " after callback" << std::endl; - // // if (PyErr_Occurred()) { - // // PyObject *type, *value, *traceback; - // // PyErr_Fetch(&type, &value, &traceback); - // // if (value) { - // // PyObject* str = PyObject_Str(value); - // // if (str) { - // // std::cerr << "Python Error: " << PyUnicode_AsUTF8(str) << std::endl; - // // Py_DECREF(str); - // // } - // // } - // // Py_XDECREF(type); - // // Py_XDECREF(value); - // // Py_XDECREF(traceback); - // // //PyErr_Print(); - // // throw std::runtime_error("Python callback error"); - // // } - // // std::cout << " 回调执行成功" << std::endl; - - // // } catch (const py::error_already_set& e) { - // // std::cerr << "[PYTHON ERROR] "; - // // PyErr_Print(); // 自动打印到stderr - // // // 可选:获取更详细的错误信息 - // // if (PyErr_Occurred()) { - // // PyObject *type, *value, *traceback; - // // PyErr_Fetch(&type, &value, &traceback); - // // std::cerr << "Details: " - // // << PyUnicode_AsUTF8(PyObject_Str(value)) << std::endl; - // // PyErr_Restore(type, value, traceback); - // // } - // // Py_DECREF(pyCallback_.ptr()); - // // } catch (...) { - // // std::cout << "[ERROR] 回调执行失败" << std::endl; - // // munmap(ptr, data_size); - // // close(fd); - // // shm_unlink(shm_name); - // // Py_DECREF(pyCallback_.ptr()); - // // throw; - // // } - // // Py_DECREF(pyCallback_.ptr()); - // //} else { - // // std::cout << "[7] 无回调函数设置" << std::endl; - // //} - - // // 8. 释放资源 - // std::cout << "[8] 释放共享内存资源..." << std::endl; - // munmap(ptr, data_size); - // close(fd); - // shm_unlink(shm_name); - - // std::cout << "[9] 释放GIL..." << std::endl; - // //PyGILState_Release(gstate); - // std::cout << "=== 音频处理完成 ===" << std::endl; - - //} catch (const std::exception& e) { - // std::cout << "[EXCEPTION] 异常捕获: " << e.what() << std::endl; - // //PyGILState_Release(gstate); - // std::cerr << "Audio process error: " << e.what() << std::endl; - //} } void RTCContext::onProducer(uint32_t msgId, mrtc::MRTCProducerInfo& info) @@ -486,12 +85,6 @@ void RTCContext::onProducer(uint32_t msgId, mrtc::MRTCProducerInfo& info) } bool RTCContext::init(const char* selfUserId, const char* selfDisplayName, const char* selfRoomId) { - std::cout << "init, numpyApi_:" << numpyApi_[93] << std::endl; - if (!numpyApi_ || !numpyApi_[93]) { // 93是PyArray_SimpleNew的偏移量 - std::cout << "numpyApi_ is null in init" << std::endl; - } else { - std::cout << "numpyApi_ is not null in init" << std::endl; - } mrtc::IMRTCEngineFactory * rtcFactory = mrtc::getMRTCEngineFactory(); if (!rtcFactory) { @@ -537,46 +130,16 @@ bool RTCContext::init(const char* selfUserId, const char* selfDisplayName, const std::cout << "RTCContext::instance().registerListener() failed" << std::endl; return false; } - namespace py = boost::python; - namespace np = boost::python::numpy; - Py_Initialize(); // 初始化 Python - np::initialize(); return true; } bool RTCContext::initRecv(const char* destRoomId, const char* srcUserId, const int16_t destChannelIndex) { - std::cout << "initRecv, numpyApi_:" << numpyApi_[93] << std::endl; - if (!numpyApi_ || !numpyApi_[93]) { // 93是PyArray_SimpleNew的偏移量 - std::cout << "numpyApi_ is null in initRecv" << std::endl; - } else { - std::cout << "numpyApi_ is not null in initRecv" << std::endl; - } while (!isOnConsumer_) { std::cout << "wait for OnConsumer" << std::endl; sleep(3); } - /* - std::cout << "registerSoundLevelListener" << std::endl; - int16_t ret1 = rtcEngine_->registerSoundLevelListener(mrtc::TYPE_AUDIO_SOURCE_CUSTOM, destRoomId, - srcUserId, destChannelIndex, this); - if (0 != ret1) - { - std::cout << "RTCContext::instance().registerSoundLevelListener() inUser failed, ret:" << ret1; - return false; - } - - std::cout << "muteAudio" << std::endl; - int16_t ret2 = rtcEngine_->muteAudio(destRoomId, srcUserId, mrtc::TYPE_AUDIO_SOURCE_CUSTOM, false, destChannelIndex); - if (0 != ret2) - { - std::cout << "RTCContext::instance().muteAudio() failed, ret:" << ret2; - return false; - } - - std::cout << "init recv succ" << std::endl; - */ return true; } @@ -661,15 +224,11 @@ void RTCContext::setpData(void* pData) std::lock_guard lock(mutex_); pData_ = pData; } -void RTCContext::setPyCallback(boost::python::object callback) { +void RTCContext::setPyCallback(py::object callback) { std::lock_guard lock(mutex_); pyCallback_ = callback; } -void RTCContext::setNumpyApi(void **numpyApi) { - std::lock_guard lock(mutex_); - numpyApi_ = numpyApi; - std::cout << "setNupyApi, numpyApi_:" << numpyApi_[93] << std::endl; -} + void RTCContext::setData(const mrtc::MRTCAudioFrame& frame) { std::lock_guard lock(dataMutex_); if (dataSize_ == totalSize_) { @@ -699,8 +258,6 @@ RetAudioFrame RTCContext::getData() { } return {}; // 返回空对象 } -namespace bp = boost::python; -namespace np = boost::python::numpy; np::ndarray RTCContext::getNumpyData() { std::cout << "step1" << std::endl; std::lock_guard lock(dataMutex_); @@ -710,33 +267,25 @@ np::ndarray RTCContext::getNumpyData() { std::cout << "step3" << std::endl; size_t length = frame.dataCount; // 数据长度 std::cout << "step4" << std::endl; - - PyGILState_STATE gstate = PyGILState_Ensure(); - np::ndarray result = np::empty(bp::make_tuple(length), np::dtype::get_builtin()); - try { - if (!dataPtr || length == 0) { - result = np::zeros(bp::make_tuple(0), np::dtype::get_builtin()); - } else { - result = np::empty(bp::make_tuple(length), np::dtype::get_builtin()); - std::memcpy(result.get_data(), dataPtr, length * sizeof(int16_t)); - } - } catch (...) { - PyGILState_Release(gstate); // 异常时释放GIL - throw; + if (!dataPtr || length == 0) { + return py::array_t({0}); // 返回空数组 } - PyGILState_Release(gstate); - return result; + // 直接构造 pybind11 的 NumPy 数组(自动管理内存) + py::array_t result({static_cast(length)}); + auto buf = result.mutable_unchecked(); + for (size_t i = 0; i < length; i++) { + buf[i] = dataPtr[i]; + } + return result; } -bp::list RTCContext::getListData() { +py::list RTCContext::getListData() { std::lock_guard lock(dataMutex_); RetAudioFrame frame = getData(); - int16_t* dataPtr = frame.data.get(); // 你的数据指针 - size_t length = frame.dataCount; // 数据长度 - bp::list result; - if (dataPtr && length > 0) { - for (size_t i = 0; i < length; ++i) { - result.append(dataPtr[i]); // 逐个元素添加(值传递) + py::list result; + if (frame.data) { + for (int i = 0; i < frame.dataCount; i++) { + result.append(frame.data.get()[i]); } } return result; diff --git a/util/RTCContext.h b/util/RTCContext.h index 490e40e..7ec5855 100644 --- a/util/RTCContext.h +++ b/util/RTCContext.h @@ -1,9 +1,6 @@ // RTCContext.h #pragma once -//#include "numpyConfig.h" -#include "numpyStub.h" - #include "IMRTCEngine.hpp" #include "MRTCEngineDefine.hpp" #include "IMRTCEngineFactory.hpp" @@ -18,27 +15,18 @@ #include #include -#include -#include -#include -#include -#include -#include -#include +// pybind11 头文件 +#include +#include +#include +namespace py = pybind11; #include - -// 必须声明外部变量(关键!) -//#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION - -namespace bp = boost::python; -namespace fs = std::filesystem; -namespace np = boost::python::numpy; #define ENV_PRODUCT //#define SEND_MODE // 音频数据帧 -struct RetAudioFrame final +struct RetAudioFrame { std::unique_ptr data; int dataCount = 0; @@ -100,14 +88,13 @@ public: int16_t getSize(); void setData(const mrtc::MRTCAudioFrame& frame); RetAudioFrame getData(); - np::ndarray getNumpyData(); - bp::list getListData(); + py::array_t getNumpyData(); + py::list getListData(); int16_t getDataCount(); void* getpData() const; void setpData(void* pData); - void setPyCallback(boost::python::object callback); - void setNumpyApi(void** numpyApi); + void setPyCallback(py::object callback); int16_t sendAudioData(uint8_t channelIndex = 0, const void* pData = nullptr, int32_t nSampleRate = 48000, uint64_t nNumberOfChannels = 2, uint64_t dataLength = 0); int16_t sendCustomAudioData(const int16_t channelIndex, void* customData, int32_t sampleRate, @@ -126,8 +113,7 @@ private: bool isOnConsumer_ = false; bool isJoinMultiRoom_ = false; bool isMultiRoom_ = false; - boost::python::object pyCallback_; - void ** numpyApi_; + py::object pyCallback_; std::vector data_; mutable std::mutex dataMutex_; const int16_t totalSize_ = 100; diff --git a/util/numpyStub.h b/util/numpyStub.h deleted file mode 100644 index 4a6a1c9..0000000 --- a/util/numpyStub.h +++ /dev/null @@ -1,12 +0,0 @@ -// numpy_interface.h (新建) -#pragma once - -#ifdef IMPLEMENT_NUMPY_API -// 主模块实现路径 - #define PY_ARRAY_UNIQUE_SYMBOL RTC_PLUGINS_ARRAY_API - #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION - #include -#else -// 用户头文件路径 -extern void* RTC_PLUGINS_ARRAY_API[]; // 严格匹配NumPy类型 -#endif \ No newline at end of file