火山 RTC 引擎11----集成创建房间、加入房间、销毁引擎 到互动项目中
一、相关基本知识
0、测试代码
bytertc::IRTCVideo* m_video = nullptr;bytertc::IRTCRoom* m_room = nullptr;std::unique_ptr<ByteRTCEventHandler> m_handler;std::unique_ptr<ByteRTCRoomHandler> m_roomHandler;
std::string roomid, uid, token;////roomid = "qq";//uid = "qq2";void CreateByterRtcVideo();void StartCapture();void CreateByterRtcRoom();void JoinRoom_ByteRtc();void SetVideoEncoderConfig(int nWidth,int nHeight,int nRate);int PushExternalVideoFrame(bytertc::IVideoFrame* frame);//cbvoid SetByteRtcCBS();//远端用户发流void OnSigUserPublishStream(const std::string roomid, const std::string uid, bytertc::MediaStreamType type);
1、创建引擎
//火山
void NRTCEngine::CreateByterRtcVideo()
{bytertc::LogConfig log;log.log_level = bytertc::LocalLogLevel::kInfo;bytertc::setLogConfig(log);if (m_video == nullptr) {m_handler.reset(new ByteRTCEventHandler());m_video = bytertc::createRTCVideo(g_appid.c_str(), m_handler.get(), nullptr);if (m_video == nullptr) {return;}}else {return;}CreateByterRtcRoom();SetByteRtcCBS(); //放在room之后,否则room为空StartCapture();JoinRoom_ByteRtc();}
2、创建ROOM
void NRTCEngine::CreateByterRtcRoom()
{if (m_video == nullptr) {return;}if (m_room == nullptr) {int ret = 0;QString str_error;roomid = "qq";uid ="qq2";m_roomHandler = std::make_unique<ByteRTCRoomHandler>(roomid, uid);token = Utils::generateToken(roomid, uid);m_room = m_video->createRTCRoom(roomid.c_str());if (m_room == nullptr) {return;}m_room->setRTCRoomEventHandler(m_roomHandler.get());}}
3、设置采集自定义视频
void NRTCEngine::StartCapture() {if (m_video) {m_video->startAudioCapture();int ret1 = m_video->setVideoSourceType(bytertc::kStreamIndexMain, bytertc::kVideoSourceTypeExternal/*kVideoSourceTypeExternal*/);// m_video->startVideoCapture();}
}
4、加入房间
bool NRTCEngine::JoinRoom_ByteRtc(std::string userID) {bytertc::UserInfo uinfo;uinfo.uid = uid.c_str();uinfo.extra_info = nullptr;bytertc::RTCRoomConfig config;config.is_auto_publish = true;config.is_auto_subscribe_audio = true;config.is_auto_subscribe_video = true;config.room_profile_type = bytertc::kRoomProfileTypeCommunication;int ret = m_room->joinRoom(token.c_str(), uinfo, config);if (ret < 0) {return false;}return true;}
5、设置编码
void NRTCEngine::SetVideoEncoderConfig(int nWidth, int nHeight, int nRate)
{static int width = 0;static int height = 0;static int rate = 0;if (width == nWidth && height == nHeight&&rate==nRate)return;bytertc::VideoEncoderConfig encodeConfig;encodeConfig.width = nWidth;encodeConfig.height = nHeight;encodeConfig.frame_rate = 25;encodeConfig.encoder_preference = bytertc::kVideoEncodePreferenceBalance;m_video->setVideoEncoderConfig(encodeConfig);
}
6、发送自定义视频
int NRTCEngine::PushExternalVideoFrame(bytertc::IVideoFrame* pFrame) {int ret = m_video->pushExternalVideoFrame(pFrame);if (ret != 0) {}return ret;
}
7、设置CB
void NRTCEngine::SetByteRtcCBS() {UserPublishStreamCallback callback = [this](const std::string& roomId, const std::string& uid, bytertc::MediaStreamType type) {this->OnSigUserPublishStream(roomId, uid, type);};m_roomHandler->setUserPublishStreamCallback(callback);UserJoinedCallback joinCB = [this](const bytertc::UserInfo& user_info, int elapsed) {if (pChatForm){auto task = [this, user_info, elapsed]() {pChatForm->OnUserJoined_ByterRTC(user_info, elapsed);};Post2UI(task);}};m_roomHandler->setUserJoinedCallback(joinCB);UserLeaveCallback leaveCB = [this](const char* uid, bytertc::UserOfflineReason reason) {if (pChatForm){auto task = [this, uid, reason]() {pChatForm->OnUserLeft_ByterRTC(uid, reason);};Post2UI(task);}};m_roomHandler->setUserLeaveCallback(leaveCB);auto leaveRoomCB = [this](const bytertc::RtcRoomStats& stats) {if (pChatForm){auto task = [this, stats]() {pChatForm->OnLeaveRoom_ByterRTC(stats);};Post2UI(task);}};m_roomHandler->setLeaveRoomCallback(leaveRoomCB);RoomStateChangedCallback RoomStateChangedCB = [this](const std::string& roomid, const std::string& uid, int state, const std::string& extra_info) {if (pChatForm){auto task = [this, roomid,uid,state, extra_info]() {pChatForm->OnJoinChannel_ByterRTC(roomid, uid, state, extra_info);};Post2UI(task);}};m_roomHandler->setRoomStateChangedCallback(RoomStateChangedCB);VideoSinkCB sinkCB = [this](bytertc::IVideoFrame* video_frame) {if (!video_frame)return false;if (pChatForm){auto task = [this, video_frame]() {pChatForm->OnFrameDataCallback_ByterRTC(video_frame);};Post2UI(task);}return true;};m_handler->setVideoSinkCB(sinkCB);
}
二、集合进网易 放在合适的位置
0、网易总体逻辑图
1、加入房间
1)、网易逻辑
1.1)、开始直播按钮
StartLiveStream();
void ChatroomForm::StartLiveStreamBtn(){//点击开始上课按钮QLOG_APP(L"StartLiveStreamBtn");if (livestreaming_){WriteSuccessFuc("StartLiveStreamBtn ... livestreaming_ is true");return;}OnLiveStreamInit(is_Camera_);if (screen_tool_wnd_) screen_tool_wnd_->SetCaptureWnd(cur_handle_id_, false);StartLiveStream();{start_time_stamp_ = 0;InitIntTime();}}
1.2)、切换布局时
void ChatroomForm::Layout_ResumeLive() //切换布局时,继续上课{if (master_){m_bQuicklyResumeAndNotSendStartLiveReq = TRUE;OnLiveStreamInit(is_Camera_);if (screen_tool_wnd_){screen_tool_wnd_->SetCaptureWnd(cur_handle_id_, false);}StartLiveStream();}}
1.3)、继续上课
void ChatroomForm::ResumeLive() //继续上课{//继续上课时,先清空m_BypassCtrlClass.NullAllBypass();m_BypassCtrlClass.ClearAll();m_BypassCtrlClass.AutoAdjustHideShow(); //隐藏旁路控件if (master_){OnLiveStreamInit(is_Camera_);if (screen_tool_wnd_){screen_tool_wnd_->SetCaptureWnd(cur_handle_id_, false);}StartLiveStream();SetPauseRestoreText(L"暂停上课");}}
1.4)、拉流转互动时
//停止拉流pull_stream_stopped_cb_.reset(new nbase::WeakCallback<StdClosure>(ToWeakCallback([this](){bSwitingToInt_ = true;//恢复初始状态, 主控件显示采集video_show_ctrl_->SetVideoFrameMng(&local_video_frame_mng_);video_show_ctrl_->SetAccount(GetLoginAccount());//恢复初始对应状况bypass_show_ctrl1_->SetVideoFrameMng(&nim_comp::VideoManager::GetInstance()->video_frame_mng_);bypass_show_ctrl2_->SetVideoFrameMng(&nim_comp::VideoManager::GetInstance()->video_frame_mng_);bypass_show_ctrl3_->SetVideoFrameMng(&nim_comp::VideoManager::GetInstance()->video_frame_mng_);bypass_show_ctrl4_->SetVideoFrameMng(&nim_comp::VideoManager::GetInstance()->video_frame_mng_);m_BypassCtrlClass.NullAllBypass();m_BypassCtrlClass.ClearAll();//m_BypassCtrlClass.SetMainVideoFrame(creater_id_);//开始互动StartLiveStream();pull_stream_stopped_cb_.reset();})));
2)、火山对比
这里面的核心函数就是开始互动
开始互动的操作,就是加入房间中
2.1)、核心加入房间函数
bool ChatroomForm::StartLiveStream(){JoinChannel_NERTC(GetRoomName());return true;}
void ChatroomForm::JoinChannel_NERTC(std::string roomid){if (BAudioLive())m_engine->SetLiveStreamMode(false);elsem_engine->SetLiveStreamMode(true);JoinChannel_NERTC(roomid, GetLoginAccount_NERTC());}
2.2)、加入房间
2.2.1)、网易
void ChatroomForm::JoinChannel_NERTC(std::string roomid, std::string userID){if (roomid.empty()){//有连麦者无法切换MsgboxCallback cb = [this](MsgBoxRet ret) {if (ret == MB_YES){}};ShowMsgBox(m_hWnd, L"", ToWeakCallback(cb), L"roomid 为空", L"确定", L"", L""/*, g_CefHwnd*/);return;}m_engine->SetChatForm(this); //上一个窗口析构后会置0 此处确保下if (BAudioLive()){//音频模式m_engine->setupLocalVideo(nullptr); //设置本地画布int errorCode = m_engine->joinChannel("", roomid, userID, false, true, 2);if (errorCode == 0) //调用加入房间成功{}int i = 0;i++;}else{void *hWnd = GetHWND();// m_engine->setupLocalVideo(nullptr, onVirtualBkFrameDataCallback); //设置本地画布m_engine->setVideoDevice(kNERtcExternalVideoDeviceID);m_engine->GetRtcEngine()->setExternalVideoSource(true); //设置使用自定义数据源m_engine->enableLocalVideo(true);std::string json=ToHeadModeJson(StudentIntType_== XNWStudentIntType_HeadImg);int errorCode = m_engine->joinChannel("", roomid, userID, true, true, 2,json);if (errorCode == 0) //调用加入房间成功{}}//if (0)//{// void *hWnd = GetHWND();// m_engine->setupLocalVideo(hWnd); //设置本地画布// // int errorCode=m_engine->GetRtcEngine()->startVideoPreview();// m_engine->joinChannel("", roomid, userID, true, true, 2);// m_engine->enableLocalVideo(true);//}}
2.2.2)、火山
void ChatroomForm::JoinChannel_ByterRTC(std::string roomid, std::string userID){if (roomid.empty()){//有连麦者无法切换MsgboxCallback cb = [this](MsgBoxRet ret) {if (ret == MB_YES){}};ShowMsgBox(m_hWnd, L"", ToWeakCallback(cb), L"roomid 为空", L"确定", L"", L""/*, g_CefHwnd*/);return;}m_engine->SetChatForm(this); //上一个窗口析构后会置0 此处确保下m_engine->CreateByterRtcRoom(roomid, userID);m_engine->JoinRoom_ByteRtc(userID);m_engine->StartAudioCapture_ByterRTC();if (BAudioLive()){}else {void* hWnd = GetHWND();m_engine->StartVideoCapture_ByterRTC();std::string json = ToHeadModeJson(StudentIntType_ == XNWStudentIntType_HeadImg);m_engine->SendSEIMessage_ByterRTC(json);}}
3)、兼容改造
使用 g_bUseNeRtcSDK 区分 火山还是网易
JoinChannel_NERTC 改造成 JoinRoom
void ChatroomForm::JoinRoom(std::string roomid){if (BAudioLive())m_engine->SetLiveStreamMode(false);elsem_engine->SetLiveStreamMode(true);if (g_bUseNeRtcSDK)JoinChannel_NERTC(roomid, GetLoginAccount_NERTC());elseJoinChannel_ByterRTC(roomid, GetLoginAccount_NERTC());}
2、离开房间
1)、离开房间
void ChatroomForm::StopIntect(){ LeaveChannel_NERTC();WriteSuccessFuc("ResetStudentUI");}
2)、离开房间时机
2.1)、学生端、老师关闭了学生互动PUSH
case SubExe_SendAnchorPushMsg:case 3://关闭学生互动if (pCurChatForm){pCurChatForm->StopIntect();}break;
2.2)、点击CEF窗口 关闭按钮时
ChatroomForm::CEF_Close(){CloseDevTool();MsgboxCallback cb = [this](MsgBoxRet ret){if (ret == MB_YES){ HideHorverForm();if (BVideoTapeMode()){bool g_bVideoTapeInWeb = true;if (!g_bVideoTapeInWeb){ui::Control* pClassingBox_videoTape = FindControl(L"ClassingBox_videoTape");if (pClassingBox_videoTape&&pClassingBox_videoTape->IsVisible())PauseLive(); //上课中,终止else{//还未上课 }ShowChatWindow(SW_HIDE);//::ShowWindow(GetHWND(), SW_HIDE); }else{//web 播放// m_pCefForm->LoadLocalHtml(); //窗口隐藏后,加载不成功}GetFontPage()->ShowMyClass();}else{if (!BStudentApp()){BOOL bClassing = false;ui::Control* pClassingBox_liveModel = pClassingBox_; //FindControl(L"ClassingBox_liveModel");if (pClassingBox_liveModel&&pClassingBox_liveModel->IsVisible())bClassing = TRUE;if (bClassing)PauseLive(); //上课中,终止else{//还未上课 }AudioHookForm* audioBkForm = GetAudioForm();if (audioBkForm){audioBkForm->LoadBlankWeb();}}else{if (livestreaming_){//下麦//SendStudentIntReq(StuCloseInt);StopIntect();}PausePull();}
2.3)、主动下麦
void ChatroomForm::StudentIntEnd(){//下麦//StopIntect();}
2.4)、点击关闭按钮,返回我的课
void ChatroomForm::CloseInteractWindow()//点击关闭按钮,关闭互动窗口{if (livestreaming_){std::wstring valueStr;ReadSetIni(L"NeedPad", L"BNeed", valueStr);bool bNeed = _ttoi(valueStr.c_str());if (bNeed&&m_studentInRoomSet.size() > 0){//有连麦者无法切换MsgboxCallback cb = [this](MsgBoxRet ret){if (ret == MB_YES){}};ShowMsgBox(m_hWnd, L"有连麦者,无法关闭互动,请结束所有通话后,再试", ToWeakCallback(cb), L"提示", L"确定", L"", L""/*, g_CefHwnd*/);return;}}//关闭,返回我的课MsgboxCallback cb = [this](MsgBoxRet ret){if (ret == MB_YES){if (livestreaming_&&BStudentApp()){//学生互动中 先下麦//SendStudentIntReq(StuCloseInt);StopIntect();}//跳到我的课界面EndWndDirectly(false);}};std::wstring closeInfo;if (BStudentApp())closeInfo = L"确定要暂离直播间吗?";elsecloseInfo = L"关闭后直播将中断,确定关闭吗?";ShowMsgBox(this->GetHWND(), closeInfo, ToWeakCallback(cb), L"确认", L"确定", L"取消",L""/*,g_CefHwnd*/);}
2.5 )、关闭互动
else if (btnText == L"关闭互动"){pBtn->SetText(L"申请互动");StopIntect();GetFontPage()->SendCopyDataMsg(GetFontPage()->m_hParentWnd, "3", SubExe_SendSendStudent); //}
3)、兼容改造
3.1)原来
void ChatroomForm::StopIntect(){ LeaveChannel_NERTC();WriteSuccessFuc("ResetStudentUI");}
3.2)、优化
void ChatroomForm::StopIntect(){ if(g_bUseNeRtcSDK)LeaveChannel_NERTC();elseLeaveChannel_ByterRTC();WriteSuccessFuc("StopIntect");}
void ChatroomForm::LeaveChannel_NERTC(){//m_engine->stopLiveStream(m_currentTaskId.toUtf8());if (livestreaming_){m_engine->stopAudioMixing();m_engine->leaveChannel();m_engine->GetRtcEngine()->enableAudioVolumeIndication(false, 200);}}void ChatroomForm::LeaveChannel_ByterRTC() {if (livestreaming_){m_engine->LeaveRoom_ByterRTC();}}
void NRTCEngine::LeaveRoom_ByterRTC()
{if (m_video == nullptr) {return;}if (m_room) {m_room->leaveRoom();m_room->destroy();m_room = nullptr;}m_video->stopAudioCapture();m_video->stopVideoCapture();
}
3、销毁引擎
3.1)、原销毁引擎
void NRTCEngine::Uninit(){if (rtc_engine_){Sleep(500);//等待底层异步关闭//同步退出rtc_engine_->release(true);destroyNERtcEngine((void *&)rtc_engine_);rtc_engine_ = nullptr;}
}
3.2)、优化
void NRTCEngine::Uninit(){if (rtc_engine_){Sleep(500);//等待底层异步关闭//同步退出rtc_engine_->release(true);destroyNERtcEngine((void *&)rtc_engine_);rtc_engine_ = nullptr;}if (!g_bUseNeRtcSDK){LeaveRoom_ByterRTC();DestroyVideoRTC();}}