#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 lock(mutex_); isOnRoom_ = true; } void RTCContext::onConsumer(uint32_t msgId, const char* roomId, const char* peerId, RTCENGINE_NAMESPACE::MRTCConsumerInfo& consumerInfo) { //std::cout << "RTCContext::onConsumer()" << std::endl; std::cout << "RTCContext::onConsumer():msgId:" << msgId << ", roomId:" << consumerInfo.roomId << ", displayName:" << consumerInfo.displayName << ", channelIndex" << (int)consumerInfo.channelIndex; std::lock_guard lock(mutex_); isOnConsumer_ = true; std::cout << "registerSoundLevelListener" << std::endl; int16_t ret1 = rtcEngine_->registerSoundLevelListener(mrtc::TYPE_AUDIO_SOURCE_CUSTOM, roomId, peerId, consumerInfo.channelIndex, this); if (0 != ret1) { std::cout << "RTCContext::instance().registerSoundLevelListener() inUser failed, ret:" << ret1; return; } std::cout << "muteAudio" << std::endl; int16_t ret2 = rtcEngine_->muteAudio(roomId, peerId, mrtc::TYPE_AUDIO_SOURCE_CUSTOM, false, consumerInfo.channelIndex); if (0 != ret2) { std::cout << "RTCContext::instance().muteAudio() failed, ret:" << ret2; return; } std::cout << "init recv succ" << 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 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 printTimestamp() { // 获取系统当前时间点 auto now = std::chrono::system_clock::now(); // 转换为时间戳(秒 + 毫秒) auto timestamp = std::chrono::duration_cast( now.time_since_epoch()).count(); auto milliseconds = std::chrono::duration_cast( now.time_since_epoch()).count() % 1000; // 转换为本地时间(可读格式) std::time_t time = std::chrono::system_clock::to_time_t(now); std::cout << "Timestamp: " << timestamp << "." << milliseconds << std::endl; } void RTCContext::onAudioProcess(const char* roomId, const char* peerId, mrtc::MRTCAudioFrame& audioFrame, mrtc::MRTCAudioSourceType audioSourceType) { setData(audioFrame); } 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) { 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) { while (!isOnConsumer_) { std::cout << "wait for OnConsumer" << std::endl; sleep(3); } return true; } bool RTCContext::initSend(const char* srcRoomId, const char* destRoomId, const int16_t destChannelIndex, const uint8_t channelNum) { while (!isOnRoom_) { std::cout << "wait for OnRoom" << std::endl; sleep(3); } if (std::string(srcRoomId) != std::string(destRoomId)) { isMultiRoom_ = true; std::cout << "join multi room" << std::endl; int16_t ret1 = rtcEngine_->joinMultiRoom(destRoomId); if (ret1 != 0) { std::cout << "joinMultiRoom fail, ret:" << ret1; return false; } } else { isMultiRoom_ = false; } mrtc::MRTCAudioOption option; if (std::string(srcRoomId) != std::string(destRoomId)) { strcpy(option.dstRoomId, destRoomId); } option.channelIndex = destChannelIndex; option.channel = channelNum; 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 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_ || (isMultiRoom_ && !isJoinMultiRoom_)) { std::cout << "wait for room and multi room before send" << std::endl; sleep(3); } std::lock_guard 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 lock(mutex_); return rtcEngine_; } void* RTCContext::getpData() const { std::lock_guard lock(mutex_); return pData_; } void RTCContext::setpData(void* pData) { std::lock_guard lock(mutex_); pData_ = pData; } void RTCContext::setPyCallback(py::object callback) { std::lock_guard lock(mutex_); pyCallback_ = callback; } void RTCContext::setData(const mrtc::MRTCAudioFrame& frame) { std::lock_guard lock(dataMutex_); if (dataSize_ == totalSize_) { bottom_ = (bottom_ + 1) % totalSize_; dataSize_--; } RetAudioFrame newFrame; newFrame.dataCount = frame.dataCount; newFrame.sampleRate = frame.sampleRate; newFrame.numChannels = frame.numChannels; newFrame.channelIndex = frame.channelIndex; newFrame.data = std::make_unique(frame.dataCount); std::memcpy(newFrame.data.get(), frame.data, frame.dataCount* sizeof(int16_t)); data_[head_] = std::move(newFrame); head_ = (head_ + 1) % totalSize_; dataSize_++; } RetAudioFrame RTCContext::getData() { //std::lock_guard lock(dataMutex_); if (dataSize_ > 0) { RetAudioFrame frame = std::move(data_[bottom_]); // 移动而非拷贝 bottom_ = (bottom_ + 1) % totalSize_; dataSize_--; return frame; // 返回值优化(RVO)会生效 } return {}; // 返回空对象 } np::ndarray RTCContext::getNumpyData() { std::cout << "step1" << std::endl; std::lock_guard lock(dataMutex_); RetAudioFrame frame = getData(); std::cout << "step2" << std::endl; int16_t* dataPtr = frame.data.get(); // 你的数据指针 std::cout << "step3" << std::endl; size_t length = frame.dataCount; // 数据长度 std::cout << "step4" << std::endl; if (!dataPtr || length == 0) { return py::array_t({0}); // 返回空数组 } // 直接构造 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; } py::list RTCContext::getListData() { std::lock_guard lock(dataMutex_); RetAudioFrame frame = getData(); py::list result; if (frame.data) { for (int i = 0; i < frame.dataCount; i++) { result.append(frame.data.get()[i]); } } return result; } int16_t RTCContext::getDataCount() { std::lock_guard lock(dataMutex_); RetAudioFrame frame = getData(); return frame.dataCount; } int16_t RTCContext::getSize() { std::lock_guard lock(dataMutex_); return dataSize_; }