实时视频通话能够拉近人与人之间的距离,为用户提供沉浸式的交流体验,帮助你的 app 提高用户黏性。
本文介绍如何通过少量代码集成声网视频 SDK ,在你的 app 里实现高质量、低延迟的视频通话功能。
下图展示在 app 中实现声网视频通话的基本工作流程:
实现视频通话的步骤如下:
1. 设置角色
将用户角色均设置为主播。
2. 加入频道
调用 JoinChannel
创建并加入频道。在 App ID 一致的前提下,传入相同频道名的用户会进入同一个频道。
3、4. 在频道内发布和订阅音视频
加入频道后,两位主播可以发布音视频并互相订阅。
参考以下操作,在你的 app 中实现视频通话功能:
使用 Visual Studio 中的 NuGet 包管理器,将 SDK 集成到项目中。详见快速入门:在 Visual Studio 中安装和使用包。
本节介绍如何使用视频 SDK 在你的项目中实现视频通话功能。
为直观地体验视频通话,你需要根据应用场景创建用户界面 (UI)。若你的项目中已有用户界面,可略过此步骤。
如果你想实现视频通话,推荐在 UI 上添加以下控件:
参考以下步骤创建 UI。
创建 Join 和 Leave 按钮
a. 在你的项目中,打开 Solution Explore 窗口,双击 Form1.cs,打开 Toolbox 窗口,选择 Button 控件,依次添加两个按钮,并将两个按钮拖放至合适位置。
b. 将鼠标移至其中一个按钮上,点击鼠标右键,选中 Properties,在打开的 Properties 窗口中修改 Text 属性为 Join,修改 Name 属性为 btnJoin。
c. 重复上一个步骤来修改另一个按钮的属性:修改 Text 为 Leave;修改 Name 为 btnLeave。
创建本地及远端视图窗口
a. 打开 Toolbox 窗口,选中 PictureBox 控件,依次为本地视图和远端视图在合适的位置添加控件。
b. 将鼠标移至本地视图窗口控件上,点击鼠标右键,选中 Properties,在打开的 Properties 窗口中修改 Name 属性为 videoboxLocal;修改 BorderStyle 为 FixedSingle。
c. 重复上一个步骤修改远端视图窗口控件的属性:修改 Name 为 videoboxRemote;修改 BorderStyle 为 FixedSingle。
创建频道名输入框
a. 打开 Toolbox 窗口,选中 TextBox 控件,然后将其拖拽至合适位置。
b. 将鼠标移至添加好的输入框控件上,点击鼠标右键,选中 Properties ,修改其属性 Name 为 txChannelName。
保存上述步骤的更改。
分别双击 Join 和 Leave 按钮,IDE 会自动关联点击事件处理函数。
此时你的 UI 界面如下图所示:
参考以下步骤来实现视频通话逻辑:
在项目中,鼠标右键点击 Solution Explorer 中的 Form1.cs,单击 View Code。
在弹出的 Form1.cs
界面中,将下列代码添加至 using System.Windows.Forms;
之后:
using Agora.Rtc;
创建加入频道相关变量
在 Form1.cs
中,将下列代码添加至 public Form1()
之前:
// 填写项目的 App ID,可在声网控制台中生成。
private readonly string APP_ID = "";
// 填写声网控制台中生成的临时 Token。
private readonly string APP_TOKEN = "";
// 声明 IRtcEngine 实例
private IRtcEngine engine_ = null;
// 声明 RtcEventHandler
private RtcEventHandler handler_ = null;
声明一个 RtcEventHandler
类,用以处理事件
在 Form1.cs
中,将以下代码添加至类 Form1
的定义之后:
internal class RtcEventHandler : IRtcEngineEventHandler
{
// 声明一个代理,用于处理 OnUserJoined 事件。
public delegate void OnUserJoinedHandler(RtcConnection connection, uint remoteUid, int elapsed);
// 声明 OnUserJoined 回调。
public event OnUserJoinedHandler EventOnUserJoined;
public RtcEventHandler()
{
}
public override void OnError(int error, string msg)
{
Console.WriteLine("=====>OnError {0} {1}", error, msg);
}
public override void OnJoinChannelSuccess(RtcConnection connection, int elapsed)
{
Console.WriteLine("----->OnJoinChannelSuccess channel={0} uid={1}", connection.channelId, connection.localUid);
}
public override void OnLeaveChannel(RtcConnection connection, RtcStats stats)
{
Console.WriteLine("----->OnLeaveChannel duration={0}", stats.duration);
}
public override void OnUserJoined(RtcConnection connection, uint remoteUid, int elapsed)
{
Console.WriteLine("----->OnUserJoined uid={0}", remoteUid);
if (EventOnUserJoined != null)
EventOnUserJoined.Invoke(connection, remoteUid, elapsed);
}
public override void OnUserOffline(RtcConnection connection, uint remoteUid, USER_OFFLINE_REASON_TYPE reason)
{
Console.WriteLine("----->OnUserOffline, channel={0}, remoteUid={1}, reason={2}", connection.channelId, remoteUid, reason);
}
public override void OnRemoteVideoStateChanged(RtcConnection connection, uint remoteUid, REMOTE_VIDEO_STATE state, REMOTE_VIDEO_STATE_REASON reason, int elapsed)
{
Console.WriteLine("----->OnRemoteVideoStateChanged, channel={0}, remoteUid={1}, state={2}, reason={3}", connection.channelId, remoteUid, state, reason);
}
}
创建并初始化 IRtcEngine
a. 调用 CreateAgoraRtcEngine
来创建 IRtcEngine
实例。将以下代码添加到 InitializeComponent();
的后面:
// 创建 IRtcEngine。
engine_ = RtcEngine.CreateAgoraRtcEngine();
RtcEngineContext ctx = new RtcEngineContext()
{
appId = APP_ID,
areaCode = AREA_CODE.AREA_CODE_GLOB,
logConfig =
{
filePath = "rtc.log"
}
};
// 初始化 IRtcEngine。
var ret = engine_.Initialize(ctx);
if(ret != 0)
{
Console.WriteLine("=====>Initialize failed {0}", ret);
return;
}
b. 创建并注册事件监听器。将以下代码添加至上一段代码之后:
// 注册事件监听器。
handler_ = new RtcEventHandler();
handler_.EventOnUserJoined += OnUserJoined;
engine_.InitEventHandler(handler_);
c. 开启视频模块。将以下代码添加至上一段代码之后:
// 启用视频模块。
ret = engine_.EnableVideo();
if (ret != 0)
{
Console.WriteLine("=====>EnableVideo failed {0}", ret);
}
d. 开启本地摄像头采集。将以下代码添加至上一段代码之后:
// 启用本地视频采集。
ret = engine_.EnableLocalVideo(true);
if (ret != 0)
{
Console.WriteLine("=====>EnableLocalVideo failed {0}", ret);
}
e. 开启本地摄像头画面预览。将以下代码添加至上一段代码之后:
// 开启本地视频预览。
ret = engine_.StartPreview(VIDEO_SOURCE_TYPE.VIDEO_SOURCE_CAMERA_PRIMARY);
if (ret != 0)
{
Console.WriteLine("=====>StartPreview failed {0}", ret);
}
f. 设置本地摄像头画面预览窗口。将以下代码添加至上一段代码之后:
// 设置本地视频渲染属性。
VideoCanvas canvas = new VideoCanvas();
canvas.view = (long)videoboxLocal.Handle;
canvas.renderMode = RENDER_MODE_TYPE.RENDER_MODE_FIT;
ret = engine_.SetupLocalVideo(canvas);
if (ret != 0)
{
Console.WriteLine("=====>SetupLocalVideo failed {0}", ret);
}
实现加入频道逻辑。用以下代码替换 btnJoin_Click
函数:
private void btnJoin_Click(object sender, EventArgs e)
{
if (null != engine_)
{
ChannelMediaOptions options = new ChannelMediaOptions();
// 将频道场景设置为直播。
options.channelProfile.SetValue(CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING);
// 将用户角色设置为主播。
options.clientRoleType.SetValue(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
// 使用临时 Token 加入频道。
var ret = engine_.JoinChannel(APP_TOKEN, txChannelName.Text, 0, options);
Console.WriteLine("=====>JoinChannel result {0}", ret);
}
}
实现离开频道逻辑。用以下代码替换 btnLeave_Click
函数:
private void btnLeave_Click(object sender, EventArgs e)
{
if (null != engine_)
{
var ret = engine_.LeaveChannel();
Console.WriteLine("=====>LeaveChannel result {0}", ret);
}
}
添加 OnUserJoined
函数用以处理远端用户加入事件,并为远端用户设置视频预览窗口。在 btnLeave_Click
函数的后面添加以下代码:
private void OnUserJoined(RtcConnection connection, uint remoteUid, int elapsed)
{
VideoCanvas canvas = new VideoCanvas();
canvas.view = (long)videoboxRemote.Handle;
canvas.renderMode = RENDER_MODE_TYPE.RENDER_MODE_FIT;
canvas.uid = remoteUid;
int ret = engine_.SetupRemoteVideo(canvas);
Console.WriteLine("----->SetupRemoteVideo, ret={0}", ret);
}
按照以下步骤来测试你的视频通话项目:
Form1.cs
文件的 APP_ID
和 APP_TOKEN
中。声网在 GitHub 上提供了一个开源的示例项目 Agora-C_Sharp-RTC-SDK-API_Example 供你参考,可实现更多的应用场景。