use pybind
This commit is contained in:
parent
f688c690aa
commit
ceff0bd694
24
build.sh
24
build.sh
|
@ -1,17 +1,9 @@
|
||||||
g++ -DBOOST_DEBUG_PYTHON -shared -fPIC \
|
g++ -shared -fPIC -std=c++11 \
|
||||||
-I/usr/include/python3.10 -I/usr/include/python3.10/numpy -I./include \
|
$(python3 -m pybind11 --includes) \ # 自动获取 pybind11 和 Python 头文件路径
|
||||||
|
-I./include \ # 保留自定义头文件路径
|
||||||
-L./lib -L/usr/lib/x86_64-linux-gnu \
|
-L./lib -L/usr/lib/x86_64-linux-gnu \
|
||||||
-DRTC_NUMPY_IMPL \
|
-lMRTCEngine \ # 保留其他必要库
|
||||||
rtc_plugins.cpp util/RTCContext.cpp \
|
-lpython3.10 \ # 仍然需要链接 Python
|
||||||
-lMRTCEngine -lboost_python310 -lboost_numpy310 -lpython3.10 \
|
-Wl,-rpath='$ORIGIN/lib' \ # 保留运行时库路径
|
||||||
-Wl,-rpath='$ORIGIN/lib' \
|
-o rtc_plugins$(python3-config --extension-suffix) \ # 标准化输出文件名
|
||||||
-o rtc_plugins.so
|
rtc_plugins.cpp util/RTCContext.cpp
|
||||||
#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
|
|
||||||
|
|
223
rtc_plugins.cpp
223
rtc_plugins.cpp
|
@ -1,7 +1,10 @@
|
||||||
// rtc_plugins.cpp
|
#define IMPLEMENT_NUMPY_API
|
||||||
|
#include "util/RTCContext.h"
|
||||||
|
#include <pybind11/pybind11.h>
|
||||||
|
#include <pybind11/numpy.h> // pybind11 的 NumPy 支持
|
||||||
|
#include <pybind11/detail/common.h>
|
||||||
|
|
||||||
#define IMPLEMENT_NUMPY_API // 标记这是实现文件
|
namespace py = pybind11;
|
||||||
#include "util/numpyStub.h"
|
|
||||||
#include "util/RTCContext.h"
|
#include "util/RTCContext.h"
|
||||||
|
|
||||||
// 提供转换接口
|
// 提供转换接口
|
||||||
|
@ -9,10 +12,15 @@ void** get_numpy_api() {
|
||||||
return (void**)RTC_PLUGINS_ARRAY_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, py::object callback) {
|
||||||
|
|
||||||
int init(const char* selfUserId, const char* selfDisplayName, const char* selfRoomId, boost::python::object callback) {
|
|
||||||
if (!PyArray_API) {
|
if (!PyArray_API) {
|
||||||
std::cout << "PyArray_API is null in outer init" << std::endl;
|
std::cout << "PyArray_API is null in outer init" << std::endl;
|
||||||
} else {
|
} else {
|
||||||
|
@ -47,178 +55,57 @@ int initSend(const char* srcRoomId, const char* destRoomId, const int16_t destCh
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int getSize() {
|
// NumPy 数据交互(关键修改)
|
||||||
return RTCContext::instance().getSize();
|
py::array_t<int16_t> getNumpyData() {
|
||||||
|
return py::array_t<int16_t>(
|
||||||
|
RTCContext::instance().getNumpyData() // 假设返回的是已有 NumPy 数组
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace bp = boost::python;
|
int sendCustomAudioData(int16_t destChannelIndex, py::array_t<int16_t> inputArray,
|
||||||
namespace np = boost::python::numpy;
|
int32_t sampleRate, uint64_t channelNum, uint64_t dataLen) {
|
||||||
np::ndarray getNumpyData() {
|
py::gil_scoped_release release;
|
||||||
return RTCContext::instance().getNumpyData();
|
|
||||||
|
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();
|
return RTCContext::instance().getListData();
|
||||||
}
|
}
|
||||||
int16_t getDataCount() {
|
int getSize() {
|
||||||
return RTCContext::instance().getDataCount();
|
return RTCContext::instance().getSize();
|
||||||
}
|
|
||||||
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<PyArrayObject*>(arr.ptr());
|
|
||||||
if (PyArray_SIZE(npArray) != static_cast<npy_intp>(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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
RetAudioFrame getData() {
|
RetAudioFrame getData() {
|
||||||
return RTCContext::instance().getData();
|
return RTCContext::instance().getData();
|
||||||
}
|
}
|
||||||
|
int16_t getDataCount() {
|
||||||
/*
|
return RTCContext::instance().getDataCount();
|
||||||
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<PyArrayObject*>(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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
PYBIND11_MODULE(rtc_plugins, m) {
|
||||||
|
init_numpy();
|
||||||
|
// 可选:暴露 RetAudioFrame 类(需额外绑定)
|
||||||
|
py::class_<RetAudioFrame>(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");
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -56,242 +56,7 @@ void RTCContext::onSoundLevelUpdate(const char* roomId, const char* peerId, uint
|
||||||
{
|
{
|
||||||
std::cout << "RTCContext::onSoundLevelUpdate()" << std::endl;
|
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<npy_intp>::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<PyArray_SimpleNew_t>(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<npy_intp>::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<npy_intp>(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<uintptr_t>(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<PyArrayObject*>(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<npy_intp>::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<npy_intp>::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<npy_intp>(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<PyArray_SimpleNew_t>(numpyApi_[93]);
|
|
||||||
std::cout << " 函数地址: " << (void*)PyArray_SimpleNew << std::endl;
|
|
||||||
|
|
||||||
std::cout << "[5.1] 验证函数指针..." << std::endl;
|
|
||||||
void* func_ptr = numpyApi_[93];
|
|
||||||
if (reinterpret_cast<uintptr_t>(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<uintptr_t>(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() {
|
void printTimestamp() {
|
||||||
// 获取系统当前时间点
|
// 获取系统当前时间点
|
||||||
auto now = std::chrono::system_clock::now();
|
auto now = std::chrono::system_clock::now();
|
||||||
|
@ -310,173 +75,7 @@ void RTCContext::onAudioProcess(const char* roomId, const char* peerId,
|
||||||
mrtc::MRTCAudioFrame& audioFrame,
|
mrtc::MRTCAudioFrame& audioFrame,
|
||||||
mrtc::MRTCAudioSourceType audioSourceType)
|
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);
|
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<npy_intp>::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<npy_intp>(audioFrame.dataCount) };
|
|
||||||
// std::cout << "step2" << std::endl;
|
|
||||||
// np::dtype dtype = np::dtype::get_builtin<int16_t>();
|
|
||||||
// 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)
|
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)
|
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();
|
mrtc::IMRTCEngineFactory * rtcFactory = mrtc::getMRTCEngineFactory();
|
||||||
if (!rtcFactory)
|
if (!rtcFactory)
|
||||||
{
|
{
|
||||||
|
@ -537,46 +130,16 @@ bool RTCContext::init(const char* selfUserId, const char* selfDisplayName, const
|
||||||
std::cout << "RTCContext::instance().registerListener() failed" << std::endl;
|
std::cout << "RTCContext::instance().registerListener() failed" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
namespace py = boost::python;
|
|
||||||
namespace np = boost::python::numpy;
|
|
||||||
Py_Initialize(); // 初始化 Python
|
|
||||||
np::initialize();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool RTCContext::initRecv(const char* destRoomId, const char* srcUserId, const int16_t destChannelIndex)
|
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_)
|
while (!isOnConsumer_)
|
||||||
{
|
{
|
||||||
std::cout << "wait for OnConsumer" << std::endl;
|
std::cout << "wait for OnConsumer" << std::endl;
|
||||||
sleep(3);
|
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;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -661,15 +224,11 @@ void RTCContext::setpData(void* pData)
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
pData_ = pData;
|
pData_ = pData;
|
||||||
}
|
}
|
||||||
void RTCContext::setPyCallback(boost::python::object callback) {
|
void RTCContext::setPyCallback(py::object callback) {
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
pyCallback_ = callback;
|
pyCallback_ = callback;
|
||||||
}
|
}
|
||||||
void RTCContext::setNumpyApi(void **numpyApi) {
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
numpyApi_ = numpyApi;
|
|
||||||
std::cout << "setNupyApi, numpyApi_:" << numpyApi_[93] << std::endl;
|
|
||||||
}
|
|
||||||
void RTCContext::setData(const mrtc::MRTCAudioFrame& frame) {
|
void RTCContext::setData(const mrtc::MRTCAudioFrame& frame) {
|
||||||
std::lock_guard<std::mutex> lock(dataMutex_);
|
std::lock_guard<std::mutex> lock(dataMutex_);
|
||||||
if (dataSize_ == totalSize_) {
|
if (dataSize_ == totalSize_) {
|
||||||
|
@ -699,8 +258,6 @@ RetAudioFrame RTCContext::getData() {
|
||||||
}
|
}
|
||||||
return {}; // 返回空对象
|
return {}; // 返回空对象
|
||||||
}
|
}
|
||||||
namespace bp = boost::python;
|
|
||||||
namespace np = boost::python::numpy;
|
|
||||||
np::ndarray RTCContext::getNumpyData() {
|
np::ndarray RTCContext::getNumpyData() {
|
||||||
std::cout << "step1" << std::endl;
|
std::cout << "step1" << std::endl;
|
||||||
std::lock_guard<std::mutex> lock(dataMutex_);
|
std::lock_guard<std::mutex> lock(dataMutex_);
|
||||||
|
@ -710,33 +267,25 @@ np::ndarray RTCContext::getNumpyData() {
|
||||||
std::cout << "step3" << std::endl;
|
std::cout << "step3" << std::endl;
|
||||||
size_t length = frame.dataCount; // 数据长度
|
size_t length = frame.dataCount; // 数据长度
|
||||||
std::cout << "step4" << std::endl;
|
std::cout << "step4" << std::endl;
|
||||||
|
if (!dataPtr || length == 0) {
|
||||||
PyGILState_STATE gstate = PyGILState_Ensure();
|
return py::array_t<int16_t>({0}); // 返回空数组
|
||||||
np::ndarray result = np::empty(bp::make_tuple(length), np::dtype::get_builtin<int16_t>());
|
|
||||||
try {
|
|
||||||
if (!dataPtr || length == 0) {
|
|
||||||
result = np::zeros(bp::make_tuple(0), np::dtype::get_builtin<int16_t>());
|
|
||||||
} else {
|
|
||||||
result = np::empty(bp::make_tuple(length), np::dtype::get_builtin<int16_t>());
|
|
||||||
std::memcpy(result.get_data(), dataPtr, length * sizeof(int16_t));
|
|
||||||
}
|
|
||||||
} catch (...) {
|
|
||||||
PyGILState_Release(gstate); // 异常时释放GIL
|
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
PyGILState_Release(gstate);
|
|
||||||
return result;
|
|
||||||
|
|
||||||
|
// 直接构造 pybind11 的 NumPy 数组(自动管理内存)
|
||||||
|
py::array_t<int16_t> result({static_cast<py::ssize_t>(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<std::mutex> lock(dataMutex_);
|
std::lock_guard<std::mutex> lock(dataMutex_);
|
||||||
RetAudioFrame frame = getData();
|
RetAudioFrame frame = getData();
|
||||||
int16_t* dataPtr = frame.data.get(); // 你的数据指针
|
py::list result;
|
||||||
size_t length = frame.dataCount; // 数据长度
|
if (frame.data) {
|
||||||
bp::list result;
|
for (int i = 0; i < frame.dataCount; i++) {
|
||||||
if (dataPtr && length > 0) {
|
result.append(frame.data.get()[i]);
|
||||||
for (size_t i = 0; i < length; ++i) {
|
|
||||||
result.append(dataPtr[i]); // 逐个元素添加(值传递)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
// RTCContext.h
|
// RTCContext.h
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
//#include "numpyConfig.h"
|
|
||||||
#include "numpyStub.h"
|
|
||||||
|
|
||||||
#include "IMRTCEngine.hpp"
|
#include "IMRTCEngine.hpp"
|
||||||
#include "MRTCEngineDefine.hpp"
|
#include "MRTCEngineDefine.hpp"
|
||||||
#include "IMRTCEngineFactory.hpp"
|
#include "IMRTCEngineFactory.hpp"
|
||||||
|
@ -18,27 +15,18 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#include <boost/python.hpp>
|
// pybind11 头文件
|
||||||
#include <boost/python/detail/wrap_python.hpp>
|
#include <pybind11/pybind11.h>
|
||||||
#include <boost/python/numpy.hpp>
|
#include <pybind11/numpy.h>
|
||||||
#include <boost/python/detail/prefix.hpp>
|
#include <pybind11/stl.h>
|
||||||
#include <boost/python/module.hpp>
|
namespace py = pybind11;
|
||||||
#include <boost/python/def.hpp>
|
|
||||||
#include <numpy/ndarrayobject.h>
|
|
||||||
#include <numpy/arrayobject.h>
|
#include <numpy/arrayobject.h>
|
||||||
|
|
||||||
|
|
||||||
// 必须声明外部变量(关键!)
|
|
||||||
//#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 ENV_PRODUCT
|
||||||
//#define SEND_MODE
|
//#define SEND_MODE
|
||||||
|
|
||||||
// 音频数据帧
|
// 音频数据帧
|
||||||
struct RetAudioFrame final
|
struct RetAudioFrame
|
||||||
{
|
{
|
||||||
std::unique_ptr<int16_t[]> data;
|
std::unique_ptr<int16_t[]> data;
|
||||||
int dataCount = 0;
|
int dataCount = 0;
|
||||||
|
@ -100,14 +88,13 @@ public:
|
||||||
int16_t getSize();
|
int16_t getSize();
|
||||||
void setData(const mrtc::MRTCAudioFrame& frame);
|
void setData(const mrtc::MRTCAudioFrame& frame);
|
||||||
RetAudioFrame getData();
|
RetAudioFrame getData();
|
||||||
np::ndarray getNumpyData();
|
py::array_t<int16_t> getNumpyData();
|
||||||
bp::list getListData();
|
py::list getListData();
|
||||||
int16_t getDataCount();
|
int16_t getDataCount();
|
||||||
|
|
||||||
void* getpData() const;
|
void* getpData() const;
|
||||||
void setpData(void* pData);
|
void setpData(void* pData);
|
||||||
void setPyCallback(boost::python::object callback);
|
void setPyCallback(py::object callback);
|
||||||
void setNumpyApi(void** numpyApi);
|
|
||||||
|
|
||||||
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 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,
|
int16_t sendCustomAudioData(const int16_t channelIndex, void* customData, int32_t sampleRate,
|
||||||
|
@ -126,8 +113,7 @@ private:
|
||||||
bool isOnConsumer_ = false;
|
bool isOnConsumer_ = false;
|
||||||
bool isJoinMultiRoom_ = false;
|
bool isJoinMultiRoom_ = false;
|
||||||
bool isMultiRoom_ = false;
|
bool isMultiRoom_ = false;
|
||||||
boost::python::object pyCallback_;
|
py::object pyCallback_;
|
||||||
void ** numpyApi_;
|
|
||||||
std::vector<RetAudioFrame> data_;
|
std::vector<RetAudioFrame> data_;
|
||||||
mutable std::mutex dataMutex_;
|
mutable std::mutex dataMutex_;
|
||||||
const int16_t totalSize_ = 100;
|
const int16_t totalSize_ = 100;
|
||||||
|
|
|
@ -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 <numpy/arrayobject.h>
|
|
||||||
#else
|
|
||||||
// 用户头文件路径
|
|
||||||
extern void* RTC_PLUGINS_ARRAY_API[]; // 严格匹配NumPy类型
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue