实现音视频通话
更新时间: 2024/09/18 16:26:13
网易云信音视频通话产品的基本功能包括高质量的实时音视频通话。当您成功初始化 SDK 之后,您可以简单体验本产品的基本业务流程。本文档为您展示音视频通话提供的基本业务流程。
前提条件
请确认您已完成以下操作:
实现流程
实现音频通话的 API 时序图如下图所示。
sequenceDiagram
participant App
participant NERtcSDK
participant 云信服务端
Note over App, 云信服务端: 初始化NERtcEngine
App->>NERtcSDK: initialize
Note over App, 云信服务端: 加入房间
App->>NERtcSDK: joinChannel
NERtcSDK->>云信服务端: 请求加入房间
NERtcSDK-->>App: onJoinChannel
Note over App, 云信服务端: 离开房间
App->>NERtcSDK: leaveChannel
NERtcSDK->>云信服务端: 请求离开房间
Note over App, 云信服务端: 销毁实例
App->>NERtcSDK: release
实现视频通话的 API 时序图如下图所示。
sequenceDiagram
participant App
participant NERtcSDK
participant 云信服务端
Note over App, 云信服务端: 初始化NERtcEngine
App->>NERtcSDK: initialize
Note over App, 云信服务端: 设置本地视图
App->>NERtcSDK: setupLocalVideoCanvas
App->>NERtcSDK: enableLocallVideo
Note over App, 云信服务端: 加入房间
App->>NERtcSDK: joinChannel
NERtcSDK->>云信服务端: 请求加入房间
NERtcSDK-->>App: onJoinChannel
Note over App, 云信服务端: 设置远端视图
Note right of NERtcSDK: 远端用户加入房间
NERtcSDK-->>App: onUserJoined 远端用户加入房间的回调
NERtcSDK-->>App: onUserVideoStart 远端用户发布视频流的回调
App->>NERtcSDK: setupRemoteVideoCanvas 设置远端视频画布
App->>NERtcSDK: subscribeRemoteVideoStream 订阅远端视频流
云信服务端-->>App: onFirstVideoFrameDecoded 已接收到远端视频首帧并完成解码的回调
Note over App, 云信服务端: 离开房间
App->>NERtcSDK: leaveChannel
NERtcSDK->>云信服务端: 请求离开房间
Note over App, 云信服务端: 销毁实例
App->>NERtcSDK: release
1. 引用头文件和动态库
在您的工程中对应的文件里引入 linux/api
目录下的头文件,并引用 lib 动态库。
步骤三 初始化
在操作 SDK 其他接口前,需要先完成初始化。
- 调用
createNERtcEngine
方法创建一个 NERtcEngine 实例。 - 调用
initialize
方法完成初始化。 - 根据 App 的应用场景,调用setChannelProfile设置房间的场景属性,不同场景的推荐配置请参见音视频参数配置推荐。
- 通过初始化接口中注册
IRtcEngineEventHandlerEx
子类,监听事件,您需要重点关注的事件类型请参见常用的回调。
示例代码如下:
cpp // 创建 RTC 引擎对象并返回指针。
nertc::IRtcEngineEx *rtc_engine_ = (IRtcEngineEx *)createNERtcEngine();
// 设置已开通音视频功能的云信应用的AppKey。
rtc_engine_context_.app_key = app_key_.c_str();
// 设置日志目录的完整路径,采用UTF-8 编码。
rtc_engine_context_.log_dir_path = log_dir_path_.c_str();
// 设置日志级别,默认级别为 kNERtcLogLevelInfo。
rtc_engine_context_.log_level = log_level;
// 指定 SDK 输出日志文件的大小上限,单位为 KB。如果设置为 0,则默认为 20 M。
rtc_engine_context_.log_file_max_size_KBytes = log_file_max_size_KBytes;
// 设置SDK向应用发送回调事件的通知。
rtc_engine_context_.event_handler = event_hander_;
// 初始化 NERTC SDK 服务。
if (kNERtcNoError != rtc_engine_->initialize(rtc_engine_context_))
{
//获取音频设备管理指针
rtc_engine_->queryInterface(nertc::kNERtcIIDAudioDeviceManager, (void **)&_adm);
//获取视频谁管理指针
rtc_engine_->queryInterface(nertc::kNERtcIIDVideoDeviceManager, (void **)&_vdm);
//设置房间场景
rtc_engine_->setChannelProfile(nertc::kNERtcChannelProfileCommunication);
//设置用户角色
rtc_engine_->setClientRole(nertc::kNERtcClientRoleBroadcaster);
}
步骤四 设置本地视图
初始化成功后,可以设置本地视图,来预览本地图像。您可以根据业务需要实现加入房间之前预览或加入房间后预览。
在加入房间前,默认预览分辨率为 640*480,您可以通过 setVideoConfig
接口的 width
和 height
参数调整采集分辨率。
-
实现加入房间前预览。
- 调用
setupLocalVideoCanvas
与startVideoPreview(type)
方法,在加入房间前设置本地视图,预览本地图像。
示例代码如下:
cpp
// 示例 static void onYuvDataIncoming( nertc::uid_t uid, /**< uid */ void *data, /**< 数据指针 */ uint32_t type, /**< NERtcVideoType */ uint32_t width, /**< 宽度 */ uint32_t height, /**< 高度 */ uint32_t count, /**< 数据类型个数,即offset及stride的数目 */ uint32_t offset[4], /**< 每类数据偏移 */ uint32_t stride[4], /**< 每类数据步进 */ uint32_t rotation, /**< NERtcVideoRotation */ void *user_data /**< 用户透传数据 */ ); NERtcVideoCanvas canvas; canvas.cb = onYuvDataIncoming; canvas.user_data = this; // Linux SDK 不支持内置渲染,因此需要用户拿到视频原始数据进行外部渲染,比如使用OpenGL。 canvas.window = nullptr; canvas.scaling_mode = mode; // 设置本地视频画布 rtc_engine_->setupLocalVideoCanvas(&canvas); // 开启本地预览 rtc_engine_->startVideoPreview();
- 若要结束预览,或者准备加入房间时,调用
stopVideoPreview(type)
方法停止预览。
stopVideoPreview(type)
的type
参数请与startVideoPreview(type)
的保持一致,即同为主流或辅流的开启和停止预览。 - 调用
-
实现加入房间后预览。
调用
enableLocalVideo
方法进行视频的采集发送与预览。成功加入房间后,即可预览本地图像。示例代码如下:
cpp
// 示例 NERtcVideoCanvas canvas; canvas.cb = onYuvDataIncoming; canvas.user_data = this; // Linux SDK 不支持内置渲染,因此需要用户拿到视频原始数据进行外部渲染,比如使用OpenGL。 canvas.window = nullptr; canvas.scaling_mode = mode; // 设置本地视频画布 rtc_engine_->setupLocalVideoCanvas(&canvas); bool enabled = true; // 启动视频流 rtc_engine_->enableLocalVideo(enabled);
步骤四 加入房间
加入房间前,请确保已完成初始化相关事项。若您的业务中涉及呼叫邀请等机制,建议通过信令实现,总体实现流程请参见一对一会话操作流程,具体呼叫邀请机制的实现请参见邀请机制。
调用 joinChannel
方法加入房间。
示例代码如下:
cpp rtc_engine_->joinChannel(token, channel_name, uid);
重要参数说明
参数 | 说明 |
---|---|
token | 安全认证签名(NERTC Token)。
|
channel_name | 房间名称,长度为 1 ~ 64 字节。目前支持以下 89 个字符:a-z, A-Z, 0-9, space, !#$%&()+-:;≤.,>? @[]^_{|}~"。 设置相同房间名称的用户会进入同一个通话房间。 |
uid | 用户的唯一标识 id,房间内每个用户的 uid 必须是唯一的。 |
SDK 发起加入房间请求后,服务器会进行响应,您可以通过初始化时设置的 rtc_engine_context_.event_handler
的 onJoinChannel
回调监听加入房间的结果,同时该回调会抛出当前通话房间的 channelId 与加入房间总耗时(毫秒);其中 channelId 即音视频通话的 ID,建议您在业务层保存该数据,以便于后续问题排查。
步骤五 设置远端视图
音视频通话过程中,除了要显示本地的视频画面,通常也要显示参与互动的其他连麦者/主播的远端视频画面。
-
监听远端用户进出频道。
IRtcEngineEventHandler
通过以下回调获取相关信息:-
onUserJoined
:监听远端用户加入通话房间的事件,并抛出对方的 uid。当本端加入房间后,也会通过此回调抛出通话房间内已有的其他用户。 -
onUserVideoStart
:监听远端用户发布视频流的事件,回调中携带对方的 uid 与发布的视频分辨率。
-
-
设置远端视频画布。
在监听到远端用户加入房间或发布视频流后,本端可以调用
setupRemoteVideoCanvas
方法设置远端用户在本地显示时的缩放模式和镜像模式。- 视频缩放模式(NERtcVideoScalingMode):包括适应区域、填充、适应视频。
- 视频镜像模式:默认为关闭视频镜像模式,您也可以根据需要开启镜像模式。
示例代码
cpp
// 示例 static void onYuvDataIncoming( nertc::uid_t uid, /**< uid */ void *data, /**< 数据指针 */ uint32_t type, /**< NERtcVideoType */ uint32_t width, /**< 宽度 */ uint32_t height, /**< 高度 */ uint32_t count, /**< 数据类型个数,即offset及stride的数目 */ uint32_t offset[4], /**< 每类数据偏移 */ uint32_t stride[4], /**< 每类数据步进 */ uint32_t rotation, /**< NERtcVideoRotation */ void *user_data /**< 用户透传数据 */ ); NERtcVideoCanvas canvas; canvas.cb = onYuvDataIncoming; canvas.user_data = this; // Linux SDK 不支持内置渲染,因此需要用户拿到视频原始数据进行外部渲染,比如使用OpenGL。 canvas.window = nullptr; canvas.scaling_mode = mode; rtc_engine_->setupRemoteVideoCanvas(uid, &canvas);
-
监听远端视频流发布。
当房间中的其他用户发布视频流时,本端会触发
onUserVideoStart
回调。 -
订阅远端视频流。
在设置完远端视频画布后,且监听到远端用户发布视频流时,本端可以调用
subscribeRemoteVideoStream
方法对其发起视频流的订阅,来将对方的视频流渲染到视频画布上。示例代码如下:
cpp
//以订阅指定远端用户的视频主流为例 void NRTCEngine::subscribeRemoteUserVideoStream(nertc::uid_t uid) { int ret_temp = rtc_engine_->subscribeRemoteVideoStream(uid, nertc::kNERtcRemoteVideoStreamTypeHigh, true); if (ret_temp) { qDebug("[ERROR] can not subscribe remote video stream! ERROR CODE: %d", ret_temp); } }
-
监听远端用户离开房间或停止发布视频。
-
onLeaveChannel
:远端用户离开房间回调。 -
onUserVideoStop
:远端用户关闭视频功能回调。
-
步骤六 音频流
本地音频的采集发布和远端音频订阅播放默认启动,正常情况下无需开发者主动干预。
步骤七 退出通话房间
调用 leaveChannel
方法退出通话房间。
示例代码如下:
cpp rtc_engine_->leaveChannel();
真正退出房间后,SDK 会走入初始化时设置的 rtc_engine_context_.event_handler 回调事件通知中的 onLeaveChannel
。
步骤八 销毁实例
当确定短期内不再使用音视频通话实例时,可以释放对应的对象资源。
示例代码如下:
cpp // 同步销毁 IRtcEngine 对象
rtc_engine_->release(true);
// 销毁 RTC 引擎对象
destroyNERtcEngine((void*&)rtc_engine_);
rtc_engine_ = nullptr;
// 音频设备管理指针
_adm = nullptr;
// 视频设备管理指针
_vdm = nullptr;
建议您在调用 release
和 destroyNERtcEngine
方法彻底销毁 NERtc 实例后再卸载库,否则可能会导致异常崩溃。
常用的回调
//nertc_event_handler.h
#pragma once
#include "nertc_engine_event_handler_ex.h"
#include "nertc_engine_media_stats_observer.h"
//用户继承nertc::IRtcEngineEventHandlerEx,根据实际业务场景重写相关回调即可
class NertcEventHandler: public nertc::IRtcEngineEventHandlerEx,
public nertc::IRtcMediaStatsObserver
{
public:
NertcEventHandler();
~NertcEventHandler();
public:
virtual void onError(int error_code, const char* msg) override;
virtual void onWarning(int warn_code, const char* msg) override;
virtual void onJoinChannel(nertc::channel_id_t cid, nertc::uid_t uid, nertc::NERtcErrorCode result, uint64_t elapsed) override;
virtual void onConnectionStateChange(nertc::NERtcConnectionStateType state, nertc::NERtcReasonConnectionChangedType reason) override;
virtual void onLeaveChannel(nertc::NERtcErrorCode result) override;
virtual void onUserJoined(nertc::uid_t uid, const char * user_name) override;
virtual void onUserLeft(nertc::uid_t uid, nertc::NERtcSessionLeaveReason reason) override;
virtual void onUserAudioStart(nertc::uid_t uid) override;
virtual void onUserAudioStop(nertc::uid_t uid) override;
virtual void onUserVideoStart(nertc::uid_t uid, nertc::NERtcVideoProfileType max_profile) override;
virtual void onUserVideoStop(nertc::uid_t uid) override;
virtual void onUserSubStreamVideoStart(nertc::uid_t uid, nertc::NERtcVideoProfileType max_profile) override;
virtual void onUserSubStreamVideoStop(nertc::uid_t uid) override;
virtual void onUserAudioMute(nertc::uid_t uid, bool mute) override;
virtual void onUserVideoMute(nertc::uid_t uid, bool mute) override;
virtual void onNetworkQuality(const nertc::NERtcNetworkQualityInfo *infos, unsigned int user_count) override;
};
//nertc_event_handler.cpp
#include "nertc_event_impl.h"
NertcEventHandler::NertcEventHandler()
{
}
NertcEventHandler::~NertcEventHandler()
{
}
void NertcEventHandler::onError(int error_code, const char* msg)
{
//错误信息回调
}
void NertcEventHandler::onWarning(int warn_code, const char* msg)
{
//警告信息回调
}
void NertcEventHandler::onJoinChannel(nertc::channel_id_t cid, nertc::uid_t uid, nertc::NERtcErrorCode code, uint64_t elapsed)
{
//本端用户成功加入房间通知回调,建议在收到此回调后再进行推拉流或订阅的操作
}
void NertcEventHandler::onConnectionStateChange(nertc::NERtcConnectionStateType state, nertc::NERtcReasonConnectionChangedType reason)
{
//房间连接状态改变通知回调
}
void NertcEventHandler::onLeaveChannel(nertc::NERtcErrorCode result)
{
//本端用户成功退出房间通知回调
}
void NertcEventHandler::onUserJoined(nertc::uid_t uid, const char * user_name)
{
//远端用户加入房间通知回调,建议在收到此回调后再进行设置远端视图等的操作
}
void NertcEventHandler::onUserLeft(nertc::uid_t uid, nertc::NERtcSessionLeaveReason reason)
{
//本端用户成功退出房间通知回调
}
void NertcEventHandler::onUserAudioStart(nertc::uid_t uid)
{
//远端用户推音频流通知回调,建议在收到此回调后再进行订阅音频流的操作
}
void NertcEventHandler::onUserAudioStop(nertc::uid_t uid)
{
//远端用户停止推音频流通知回调,建议在收到此回调后再进行取消订阅音频流的操作
}
void NertcEventHandler::onUserVideoStart(nertc::uid_t uid, nertc::NERtcVideoProfileType max_profile)
{
//远端用户推视频流通知回调,建议在收到此回调后再进行订阅视频流的操作
}
void NertcEventHandler::onUserVideoStop(nertc::uid_t uid)
{
//远端用户停止推视频流通知回调,建议在收到此回调后再进行取消订阅视频流的操作
}
void NertcEventHandler::onUserSubStreamVideoStart(nertc::uid_t uid, nertc::NERtcVideoProfileType max_profile)
{
//远端用户开启屏幕共享回调,建议在收到此回调后再进行设置视频辅流画布设置及订阅操作
}
void NertcEventHandler::onUserSubStreamVideoStop(nertc::uid_t uid)
{
//远端用户停止屏幕共享回调,建议在收到此回调后再取消订阅视频辅流及清空画布
}
void NertcEventHandler::onUserAudioMute(nertc::uid_t uid, bool mute)
{
// 远端用户是否静音回调,感知并刷新界面展示远端用户麦克风状态
}
void NertcEventHandler::onUserVideoMute(nertc::uid_t uid, bool mute)
{
//远端用户暂停/恢复发送视频流回调,感知并刷新界面,展示远端用户摄像头状态
}
void NertcEventHandler::onNetworkQuality(const nertc::NERtcNetworkQualityInfo *infos, unsigned int user_count)
{
//用户网络质量回调,感知并提示用户当前网络状态
}