rtc_plugins/util/RTCContext.cpp

306 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "RTCContext.h"
void RTCContext::onRoom(uint32_t typeId, RTCENGINE_NAMESPACE::MRTCRoomInfo& roomInfo) {
//std::cout << "RTCContext::onRoom():" << roomInfo.roomId << "," << roomInfo.displayName << "," << roomInfo.userId << "," << roomInfo.message;
std::cout << "RTCContext::onRoom()" << std::endl;
std::lock_guard<std::mutex> lock(mutex_);
isOnRoom_ = true;
}
void RTCContext::onConsumer(uint32_t msgId, const char* roomId, const char* peerId, RTCENGINE_NAMESPACE::MRTCConsumerInfo& consumerInfo) {
std::cout << "RTCContext::onConsumer():" << consumerInfo.roomId << "," << consumerInfo.displayName << "," << consumerInfo.channelIndex;
std::lock_guard<std::mutex> lock(mutex_);
isOnConsumer_ = true;
//std::cout << "RTCContext::onConsumer()" << std::endl;
}
void RTCContext::onRender(const char* roomId, const char* peerId,
RTCENGINE_NAMESPACE::MRTCVideoSourceType sourceType, const RTCENGINE_NAMESPACE::MRTCVideoFrame& videoFrame) {
std::cout << "RTCContext::onRender()" << std::endl;
}
void RTCContext::onCallBackMessage(uint32_t msgId, const char* msg) {
std::lock_guard<std::mutex> lock(mutex_);
if (msgId == (uint32_t)mrtc::JOIN_MULTI_ROOM_SUCCESS) {
std::cout << "receive join multi room callback" << msgId;
isJoinMultiRoom_ = true;
}
std::cout << "RTCContext::onCallBackMessage(), msgId:" << msgId << ", msg:" << msg;
//std::cout << "RTCContext::onCallBackMessage()" << std::endl;
}
void RTCContext::onCallBackCustomData(RTCENGINE_NAMESPACE::MRTCCustomDataObject object) {
//std::cout << "RTCContext::onCallBackCustomData(), obj:" << object.peerId << "," << object.data << "," << object.data_length;
std::cout << "RTCContext::onCallBackCustomData()" << std::endl;
}
void RTCContext::onSoundLevelUpdate(const char* roomId, const char* peerId, uint16_t audioSourceType,
uint8_t channelIndex, uint16_t volume, int32_t vad)
{
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;
std::cout << "-----------------------------------" << std::endl;
std::cout << "dataCount:" << audioFrame.dataCount << audioSourceType << std::endl;
if (audioFrame.data == nullptr) {
std::cout << "sudioFrame data is null" << std::endl;
} else if (!py_callback_.is_none()) {
std::cout << "python callback" << std::endl;
npy_intp dims[1] = {audioFrame.dataCount};
std::cout << "step1" << std::endl;
PyObject* pyArray = PyArray_SimpleNewFromData(1, dims, NPY_INT16, audioFrame.data);
std::cout << "step2" << std::endl;
py_callback_(py::handle<>(pyArray), audioFrame.dataCount, audioFrame.sampleRate, audioFrame.numChannels,
audioFrame.channelIndex);
std::cout << "step3" << 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;
auto numpyApi = RTCContext::numpy_api();
if (!numpyApi) {
PyGILState_Release(gstate);
throw std::runtime_error("NumPy C-API not initialized. Call import_array() in module init");
}
using PyArray_SimpleNew_t = PyObject*(*)(int, npy_intp*, int);
auto PyArray_SimpleNew = reinterpret_cast<PyArray_SimpleNew_t>(numpy_api[93]);
// 3. 严格校验输入数据
if (!audioFrame.data || audioFrame.dataCount <= 0) {
PyGILState_Release(gstate);
throw std::invalid_argument("Invalid audio frame data");
}
// 4. 安全创建维度数组(带边界检查)
if (audioFrame.dataCount > std::numeric_limits<npy_intp>::max()) {
PyGILState_Release(gstate);
throw std::overflow_error("Audio frame size exceeds maximum limit");
}
npy_intp dims[1] = {static_cast<npy_intp>(audioFrame.dataCount)};
// 5. 创建NumPy数组带内存保护
PyObject* pyArray = nullptr;
pyArray = PyArray_SimpleNew(1, dims, NPY_INT16);
if (!pyArray) {
PyGILState_Release(gstate);
throw std::bad_alloc();
}
// 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::memcpy(PyArray_DATA(reinterpret_cast<PyArrayObject*>(pyArray)),
audioFrame.data,
audioFrame.dataCount * sizeof(int16_t));
// 7. 执行回调(带引用计数保护)
if (!py_callback_.is_none()) {
try {
py_callback_(
py::handle<>(pyArray), // 自动管理引用
audioFrame.dataCount,
audioFrame.sampleRate,
audioFrame.numChannels,
audioFrame.channelIndex
);
} catch (...) {
Py_DECREF(pyArray);
throw; // 重新抛出异常
}
}
// 8. 释放资源
Py_DECREF(pyArray);
PyGILState_Release(gstate);
} catch (const std::exception& e) {
std::cerr << "Audio process error: " << e.what() << std::endl;
PyErr_Print();
}
}
void RTCContext::onProducer(uint32_t msgId, mrtc::MRTCProducerInfo& info)
{
std::cout << "-----------------------------------" << std::endl;
std::cout << "RTCContext::onProducer()" << std::endl;
}
bool RTCContext::init(const char* selfUserId, const char* selfDisplayName, const char* selfRoomId)
{
if (!PyArray_API) {
std::cout << "PyArray_API is null in init" << std::endl;
} else {
std::cout << "PyArray_API is not null in init" << std::endl;
}
mrtc::IMRTCEngineFactory * rtcFactory = mrtc::getMRTCEngineFactory();
if (!rtcFactory)
{
return false;
}
rtcEngine_ = rtcFactory->produceMRTCEngine();
if (!rtcEngine_)
{
return false;
}
mrtc::MRTCEngineConfig engineConfig;
strcpy(engineConfig.domain, domain);
strcpy(engineConfig.applicationId, appid);
strcpy(engineConfig.appSecrectKey, appSecrectKey);
engineConfig.port = port;
if (0 != rtcEngine_->init(engineConfig, this))
{
std::cout << "RTCContext::instance().init() failed" << std::endl;
return false;
}
if (0 != rtcEngine_->setUserInfo(selfUserId, selfDisplayName, selfRoomId))
{
std::cout << "RTCContext::instance().setUserInfo() failed" << std::endl;
return false;
}
mrtc::MRTCJoinAuthority authority;
strcpy(authority.applicationId, appid);
strcpy(authority.appSecretKey, appSecrectKey);
mrtc::MRTCJoinConfig loginConfig;
if (0!= rtcEngine_->joinRoom(authority, loginConfig))
{
std::cout << "RTCContext::instance().joinRoom() failed" << std::endl;
return false;
}
if (0 != rtcEngine_->registerListener(mrtc::MRTCListenerType::TYPE_LISTENER_ROOM, this))
{
std::cout << "RTCContext::instance().registerListener() failed" << std::endl;
return false;
}
if (0 != rtcEngine_->registerListener(mrtc::MRTCListenerType::TYPE_LISTENER_CONSUMER, this))
{
std::cout << "RTCContext::instance().registerListener() failed" << std::endl;
return false;
}
return true;
}
bool RTCContext::initRecv(const char* destRoomId, const char* srcUserId, const int16_t destChannelIndex)
{
if (!PyArray_API) {
std::cout << "PyArray_API is null in init" << std::endl;
} else {
std::cout << "PyArray_API is not null in init" << 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;
}
bool RTCContext::initSend(const char* destRoomId, const int16_t destChannelIndex)
{
while (!isOnRoom_)
{
std::cout << "wait for OnRoom" << std::endl;
sleep(3);
}
std::cout << "join multi room" << std::endl;
int16_t ret1 = rtcEngine_->joinMultiRoom(destRoomId);
if (ret1 != 0)
{
std::cout << "joinMultiRoom fail, ret:" << ret1;
return false;
}
mrtc::MRTCAudioOption option;
strcpy(option.dstRoomId, destRoomId);
option.channelIndex = destChannelIndex;
std::cout << "startCustomAudio" << std::endl;
int16_t ret2 = rtcEngine_->startCustomAudio(option);
if (ret2 != 0)
{
std::cout << "startCustomAudio fail, ret:" << ret2;
return false;
}
std::cout << "init send succ" << std::endl;
return true;
}
void RTCContext::destorySend(const int16_t selfChannelIndex)
{
rtcEngine_->stopCustomAudio(selfChannelIndex);
}
int16_t RTCContext::sendAudioData(uint8_t channelIndex, const void* pData, int32_t nSampleRate, uint64_t nNumberOfChannels, uint64_t dataLength)
{
std::lock_guard<std::mutex> lock(mutex_);
if (pData_)
{
return rtcEngine_->sendCustomAudioData(channelIndex, pData, nSampleRate, nNumberOfChannels, dataLength);
}
return 0;
}
int16_t RTCContext::sendCustomAudioData(const int16_t channelIndex, void* customData, int32_t sampleRate,
uint64_t channelNum, uint64_t dataLen)
{
while(!isOnRoom_ || !isJoinMultiRoom_) {
std::cout << "wait for room and multi room before send" << std::endl;
sleep(3);
}
std::lock_guard<std::mutex> lock(mutex_);
if (customData == nullptr) {
std::cout << "customData is null" << std::endl;
return -1;
}
std::cout << "customData addr is:" << customData << std::endl;
return rtcEngine_->sendCustomAudioData(channelIndex, customData, sampleRate, channelNum, dataLen);
}
mrtc::IMRTCEngine* RTCContext::getRtcEngine() const
{
std::lock_guard<std::mutex> lock(mutex_);
return rtcEngine_;
}
void* RTCContext::getpData() const
{
std::lock_guard<std::mutex> lock(mutex_);
return pData_;
}
void RTCContext::setpData(void* pData)
{
std::lock_guard<std::mutex> lock(mutex_);
pData_ = pData;
}
void RTCContext::setPyCallback(boost::python::object callback) {
std::lock_guard<std::mutex> lock(mutex_);
py_callback_ = callback;
}