315 lines
12 KiB
C++
315 lines
12 KiB
C++
#include "RTCContext.h"
|
||
#include <fstream>
|
||
|
||
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()" << std::endl;
|
||
std::cout << "RTCContext::onConsumer():msgId:" << msgId << ", roomId:" << consumerInfo.roomId << ", displayName:"
|
||
<< consumerInfo.displayName << ", type:" << consumerInfo.audioSourceType << ", channelIndex:" << (int)consumerInfo.channelIndex
|
||
<< std::endl;
|
||
if (msgId == RTCENGINE_NAMESPACE::MRTCConsumerStatusType::TYPE_STATUS_CONSUMER_START && std::string(consumerInfo.kind) == "audio") {
|
||
std::lock_guard <std::mutex> lock(mutex_);
|
||
isOnConsumer_ = true;
|
||
std::cout << "registerSoundLevelListener" << std::endl;
|
||
int16_t ret1 = rtcEngine_->registerSoundLevelListener(consumerInfo.audioSourceType, 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, consumerInfo.audioSourceType,
|
||
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<std::mutex> lock(mutex_);
|
||
if (msgId == (uint32_t)mrtc::JOIN_MULTI_ROOM_SUCCESS) {
|
||
std::cout << "receive join multi room callback" << msgId << std::endl;
|
||
isJoinMultiRoom_ = true;
|
||
}
|
||
|
||
std::cout << "RTCContext::onCallBackMessage(), msgId:" << msgId << ", msg:" << msg << std::endl;
|
||
//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<std::chrono::seconds>(
|
||
now.time_since_epoch()).count();
|
||
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||
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)
|
||
{
|
||
//std::cout << "onAudioProcess, roomId:" << roomId << ", peerId:" << peerId << ", type:" << audioSourceType
|
||
// << ", datacount:" << audioFrame.dataCount << std::endl;
|
||
if (audioFrame.data == nullptr || audioFrame.dataCount <= 0) {
|
||
return;
|
||
}
|
||
// 以二进制追加模式打开文件
|
||
//std::ofstream outFile("audio_data.pcm", std::ios::binary | std::ios::app);
|
||
//if (!outFile.is_open()) {
|
||
// std::cerr << "Failed to open file for writing!" << std::endl;
|
||
// return;
|
||
//}
|
||
|
||
//// 写入数据(int16_t格式)
|
||
//outFile.write(reinterpret_cast<const char*>(audioFrame.data),
|
||
// audioFrame.dataCount);
|
||
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<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_ || (isMultiRoom_ && !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::setData(const mrtc::MRTCAudioFrame& frame) {
|
||
std::lock_guard<std::mutex> 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<int16_t[]>(frame.dataCount);
|
||
//std::memcpy(newFrame.data.get(), frame.data, frame.dataCount* sizeof(int16_t));
|
||
std::memcpy(newFrame.data.get(), frame.data, frame.dataCount);
|
||
data_[head_] = std::move(newFrame);
|
||
head_ = (head_ + 1) % totalSize_;
|
||
dataSize_++;
|
||
|
||
}
|
||
|
||
RetAudioFrame RTCContext::getData() {
|
||
//std::lock_guard<std::mutex> lock(dataMutex_);
|
||
if (dataSize_ > 0) {
|
||
RetAudioFrame frame = std::move(data_[bottom_]); // 移动而非拷贝
|
||
bottom_ = (bottom_ + 1) % totalSize_;
|
||
dataSize_--;
|
||
return frame; // 返回值优化(RVO)会生效
|
||
}
|
||
return {}; // 返回空对象
|
||
}
|
||
py::array_t<int16_t> RTCContext::getNumpyData() {
|
||
std::cout << "step1" << std::endl;
|
||
std::lock_guard<std::mutex> 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<int16_t>({0}); // 返回空数组
|
||
}
|
||
|
||
// 直接构造 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;
|
||
}
|
||
py::list RTCContext::getListData() {
|
||
std::lock_guard<std::mutex> lock(dataMutex_);
|
||
RetAudioFrame frame = getData();
|
||
py::list result;
|
||
if (frame.data) {
|
||
for (int i = 0; i < frame.dataCount/sizeof(int16_t); i++) {
|
||
result.append(frame.data.get()[i]);
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
int16_t RTCContext::getDataCount() {
|
||
std::lock_guard<std::mutex> lock(dataMutex_);
|
||
RetAudioFrame frame = getData();
|
||
return frame.dataCount;
|
||
}
|
||
int16_t RTCContext::getSize() {
|
||
std::lock_guard<std::mutex> lock(dataMutex_);
|
||
return dataSize_;
|
||
} |