文档反馈
文档反馈

互动直播 PC Demo 源码导读

概述

互动直播是网易云信的一款针对目前市场比较热门的直播解决方案。在方案中结合了网易云信 IM 能力的聊天室模型和网易云信音视频能力的多人会议模型。.Demo使用Visual Studio 2013 Update5开发(必须使用Update5版本)。

Demo源码中目录结构中的C++封装层文件夹名字尾部携带_vs2010的为vs2010创建的工程项目,对应的不携带_vs2010的为vs2013创建的工程项目,即Demo目前加载的工程,该工程依赖Demo工程。

Demo的主要功能由Demo工程本身以及UI组件工程共同完成,Demo工程和UI组件工程具有相同的目录结构。UI组件位于tool_kits\ui_component\ui_kit目录,UI组件的相关文档详见:云信UI组件

Demo源码版本历史

Demo源码版本历史

界面开发资料

网易云信Duilib使用说明

代码托管地址

网易云信Duilib使用说明

控件属性

控件属性

界面布局介绍

网易云信 DuiLib 布局功能指南

会话多窗口实现介绍

从3.0.0版本开始,Demo对会话窗口的实现进行了升级,方便开发者快速开发类似QQ,微信等多窗口模式。

会话窗口多窗口合并及分开功能及升级说明

CEF开发指南

从3.4.0版本开始,Demo增加了Cef控件,方便开发者开发Web相关的功能模块。

CEF开发指南

Duillib高分屏(高DPI)支持

从3.5.0版本开始,Duilib增加了对高分屏的支持,方便在用户设置了DPI后保持软件界面的清晰效果。

Duillib高分屏(高DPI)支持

目录结构

打包说明

开发者在打包自己的应用时,应确保将以下云信SDK相关文件打包进去。

其他的文件及目录是应用程序相关的,开发者根据自己程序的使用情况选择是否打包。

功能点指引

SDK C++封装层

因为SDK所有接口都是C接口,为了方便使用C++的同学使用,我们提供了nim_cpp_sdknim_chatroom_cpp_sdk静态库。静态库位于libs\nim_sdk_desktop\nim_cpp_sdklibs\nim_sdk_desktop\nim_chatroom_cpp_sdklibs\nim_sdk_desktop\nim_player_cpp_sdk目录,它将C接口SDK封装为C++代码,demo和UI组件都直接使用nim_cpp_sdknim_chatroom_cpp_sdknim_player_cpp_sdk静态库的C++封装层代码。开发者可以直接在解决方案中导入nim_cpp_sdk工程、nim_chatroom_cpp_sdknim_player_cpp_sdk工程。

封装层提供的包装文件如下:

SDK 初始化

SDK的初始化在main.cpp中InitNim方法进行。

示例:

//sdk能力参数(必填)
//string(db key必填,目前只支持最多32个字符的加密密钥!建议使用32个字符)
config.database_encrypt_key_ = "Netease"; 

std::string app_key = GetConfigValueAppKey();
// 载入云信sdk,初始化安装目录和用户目录
bool ret = nim::Client::Init(app_key, "NIM_LIVE", "", config); 
assert(ret);
//聊天室初始化
ret = nim_chatroom::ChatRoom::Init("","");
assert(ret);

nim_ui::InitManager::GetInstance()->InitUiKit();
nim_chatroom::ChatroomCallback::InitChatroomCallback();

界面开发

云信PC demo以及UI组件的界面开发都依赖云信DuiLib库,关于云信DuiLib库的使用方法和注意事项,请参考:云信Duilib

登录

登录相关界面代码在gui/login目录下,登录相关的控制逻辑已经封装到了UI组件的,逻辑代码在callback\login\login_callback.cpp文件中。登录界面可以直接调用UI组件的登录函数,示例如下:

std::string username = "123456789";
std::string password = "123456789";
nim_ui::LoginManager::GetInstance()->DoLogin(username, password);

主窗体功能

Demo登录进去之后有两种模式可供用户选择:观众模式和主播模式。Demo提供网络检测功能,可直观的观测到当前网络状态,示例如下:

void LoginForm::NetDetect()
{
    nim::VChat::NetDetect(nbase::Bind(&LoginForm::NetDetectCb, this, std::placeholders::_1, std::placeholders::_2));
}
void LoginForm::NetDetectCb(int code, nim::NetDetectCbInfo info)
{
    if (code == 200)
    {
        nim_chatroom::BypassLiveFontPage::SetNetDetectInfo(info);
    }
}

观众模式

当以观众模式进行互动时,采用播放器SDK拉流,直接看到主播的直播画面。当与主播成功连麦后,停止拉流,进入音视频房间,和主播互动。互动模式有两种:音频互动和视频互动。当观众向主播申请连麦时,观众将自己加入到连麦队列中,加入成功后发送自定义通知给主播。示例如下:

value_info["nick"] = nbase::UTF16ToUTF8(nick);
value_info["avatar"] = "avatar_default";
string info = fw.write(value_info);
Json::Value value;
value["style"] = kAudio;
value["state"] = NTESLiveMicStateConnecting;
value["info"] = info;
string ext = fw.write(value);
RequestPushMicLink(nbase::Int64ToString(room_id_), uid, ext,kAudio);

主播模式

当以主播模式进行互动时,主播开启直播后,能正常收到观众的连麦请求,主播可以同意观众的连麦请求。主播同意连麦后,发送自定义通知给用户id,如果此时已有连麦者,应该断开已有的连接,然后再更新连麦者的状态。示例如下:

if ((!bypassingaccout_.empty())&&bypassingaccout_ != bypass_inact_account_)
{
    RequestPopMicLink(nbase::Int64ToString(room_id_), bypassingaccout_);
    SendSysNotifyMsg(kDisConnectingMIC, bypassingaccout_);
}
QLOG_APP(L"BypassAgreeMenuItemClick-bypass_inact_account:{0}") << bypass_inact_account_;
SendSysNotifyMsg(kConnectingMIC, bypass_inact_account_);
bypassingaccout_ = bypass_inact_account_;
string nick = nbase::UTF16ToUTF8(nim_ui::UserManager::GetInstance()->GetUserNameW(bypass_inact_account_));
UpdateBypassMembersState(bypass_inact_account_, NTESLiveMicStateConnecting, bypass_inact_type_, kUpdate, nick);

互动直播的逻辑说明

由于聊天室和多人会议都不是直接针对直播的方案模型,所以需要在应用上层补充一些控制指令来保证直播业务逻辑。 控制指令分为两套:

观众端推拉流切换逻辑说明

       void ChatroomForm::SwitchPullStreamAndInteract(bool pull_stream)
         {
             if (master_)
                  {
                    assert(false);
                    return;
                 }

            if (!pull_stream) //切换为互动
                {
                    if (livestreaming_) //已经在互动
                {
                assert(false);
                return;

            //停止拉流
            pull_stream_stopped_cb_.reset(new nbase::WeakCallback<StdClosure>(ToWeakCallback([this]()
                {
                    //开始互动
                    StartLiveStream();
                    pull_stream_stopped_cb_.reset();
                })));
            nim_comp::PlayerManager* player_manager = nim_comp::PlayerManager::GetInstance();
            if (!player_manager->StopPlay()) //当前没在拉流
                {
                    (*pull_stream_stopped_cb_.get())();
                }
            else //切换为拉流
            {
                interact_stopped_cb_.reset(new nbase::WeakCallback<StdClosure>(ToWeakCallback([this]()
                {
                    //开始拉流
                    nim_comp::PlayerManager* player_manager = nim_comp::PlayerManager::GetInstance();
                    player_manager->StartPlay(nbase::UTF16ToUTF8(rtmp_pull_url_), creater_id_);
                    video_show_ctrl_->SetAccount(creater_id_);
                    interact_stopped_cb_.reset();
                })));
                if (livestreaming_) //如果正在互动,停止互动
                        StopLiveStream();
                else if (nim_comp::PlayerManager::GetInstance()->GetPlayerState() =EN_PLAYER_STATE::EN_PLAYER_STOPPING)
                    {
                        pull_stream_stopped_cb_.reset(new nbase::WeakCallback<StdClosure>(ToWeakCallback([this]()
                            {
                                //开始拉流
                                nim_comp::PlayerManager* player_manager = nim_comp::PlayerManager::GetInstance();
                                player_manager->StartPlay(nbase::UTF16ToUTF8(rtmp_pull_url_), creater_id_);
                                video_show_ctrl_->SetAccount(creater_id_);
                                pull_stream_stopped_cb_.reset();
                            })));
                    }
                else
                    (*interact_stopped_cb_.get())();
                 }
             }
            }

点对点系统通知

*进入麦序队列

参数 说明
type 自定义系统通知类型:加入连麦队列通知 kJoinQueue
roomid 房间ID 聊天室ID
style 网络通话类型 InactionType枚举
info 进入聊天队列用户信息 {"nick" : "","avatar" : ""} 字典

*退出麦序队列

参数 说明
type 自定义系统通知类型:退出连麦队列通知 kExitQueue
roomid 房间ID 聊天室ID

*主播同意连麦

参数 说明
type 自定义系统通知类型:主播同意连麦通知 kConnectingMIC
roomid 房间ID 聊天室ID
style 连麦者连麦方式 InactionType枚举

*连麦者拒绝连麦

当连麦者受到主播同意连麦通知时,会检查自身的连麦状态,如果连麦状态过期则需要发送一条拒绝消息告诉主播

参数 说明
type 自定义系统通知类型:连麦者拒绝连麦通知 kRejectConnecting
roomid 房间ID 聊天室ID

*主播强制连麦者断开

参数 说明
type 自定义系统通知类型:主播强制连麦者断开 kDisConnectingMIC
roomid 房间ID 聊天室ID

聊天室广播消息

*连麦者已连麦

参数 说明
uid 连麦者的 accid
nick 连麦者的昵称
avatar 连麦者的头像
style 连麦者的连麦方式

*连麦者已断开

参数 说明
uid 连麦者的 accid

其他说明

×

反馈成功

非常感谢您的反馈,我们会继续努力做得更好。