跳到主要内容

实现音视频会议

本教程是为了让新手快速了解融云音视频微信小程序 RTCLib SDK(@rongcloud/plugin-wechat-rtc)。

提示

融云 RTCLib SDK 在小程序平台仅支持音视频会议,不支持音视频直播

微信音视频小程序开发须知

单个房间内最多 16 人同时进行音频通话(因手机硬件配置通话人数会有上线浮动)。

  • 音视频小程序 SDK 设计特点:融云音视频小程序 SDK 基于微信的小程序框架提供的原生媒体组件封装了两个自定义组件。开发者仅需引入自定义组件、配合发布和订阅接口,即可完成小程序的基础音视频功能。
    • rc-livepusher:融云自定义的音视频推流组件,封装了微信的实时音视频录制原生组件 live-pusher
    • rc-liveplayer:融云自定义的音视频拉流组件,封装了微信的实时音视频播放原生组件 live-player
  • 微信原生组件限制:微信小程序的 live-pusherlive-player 是由客户端创建的原生组件(native-component)。在开始开发前,请确保您了解微信原生组件的功能及限制(详见微信文档原生组件的使用限制)。建议您在使用到原生组件时尽量在真机上进行调试,确保小程序音视频效果稳定可靠。
  • 微信类目审核:请确保您的小程序已通过支持 live-pusherlive-player 两个媒体组件的类目审核,且在微信小程序控制台开通了 live-pusherlive-player 的权限。
  • 设备权限要求:使用小程序录制音视频前,必须授于摄像头和麦克风权限。详见微信小程序用户信息授权文档: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/authorize.html

前置条件

  • 创建融云开发者账号,获取 App Key。注册成功后,融云控制台会默认自动创建您的首个应用,默认生成开发环境下的 App Key,使用国内数据中心。注意:同一个应用的开发环境与生产环境提供不同的 App Key,两个环境之间数据隔离。
  • 已经完成 开通音视频服务,请开通音视频通话服务。开发环境下可免费开通,每个应用均可享有 10000 分钟免费体验时长,免费体验时长用完即止。生产环境下需要先预存费用才可开通。服务开通后最长 30 分钟生效。详见开通音视频服务
  • 已经完成 开通小程序服务

Demo 项目

融云提供了微信小程序 Demo 项目。

https://downloads.rongcloud.cn/Wechat_RTCLib_Demo_v5.1.0.zip

步骤 1:导入 SDK

小程序 RTC SDK 强依赖小程序 IM SDK,使用 RTC SDK 前必须引入 IM SDK。

您可以使用 NPM 安装 RTC SDK 与其依赖的 IMLib SDK。

  1. 安装 5.X 版本 IMLib。

    npm install @rongcloud/engine@latest @rongcloud/imlib-next@latest -S
    @rongcloud/enginenpm version
    @rongcloud/imlib-next@latestnpm version
  2. 安装 RTCLib。

    npm install @rongcloud/plugin-wechat-rtc
    @rongcloud/plugin-wechat-rtcnpm version

    RTCLib(@rongcloud/plugin-wechat-rtc)安装过程中,会将内部的 rcComponents 移动至 node_modules 下。rcComponents 文件夹中存放了推、拉流自定义组件 rc-livepusherrc-liveplayer

    rcComponents 文件夹目录结构如下:

    |- rcComponents/
    |- rc-liveplayer.js
    |- rc-liveplayer.json
    |- rc-liveplayer.wxml
    |- rc-liveplayer.wxss
    |- rc-livepusher.js
    |- rc-livepusher.json
    |- rc-livepusher.wxml
    |- rc-livepusher.wxss
  3. 依赖包安装完毕后,在小程序开发者工具的菜单中,寻找 "工具 -> 构建 npm" 选项,对依赖的 npm 包进行小程序所需的二次编译。

  4. 全部下载安装完成后,即可在代码中导入 IMLib 与 RTCLib 库。

    const RongIMLib = require('@rongcloud/imlib-next');
    const RongRTCLib = require('@rongcloud/plugin-wechat-rtc');

步骤 2:引入推、拉流自定义组件

开发者仅需引入融云基于微信的小程序框架原生媒体组件封装的自定义推拉流组件(rc-livepusherrc-livepusher)、配合发布和订阅接口,即可完成小程序的基础音视频功能。

如需在您的小程序的某页面中使用自定义推、拉流组件,您需要在该页面同名的配置文件中增加以下配置:

{
"usingComponents": {
"rc-livepusher": "../../rcComponents/rc-livepusher",
"rc-liveplayer": "../../rcComponents/rc-liveplayer"
}
}

引入组件示例:假设 pages 目录下包含 main 目录,按照微信的开发框架要求,main 目录下会包含如下文件。

  |- pages/
|- main/
|- main.js
|- main.json // 页面配置文件,请在该页面中增加配置
|- main.wxml
|- main.wxss

如果要在 main 页面(main.wxml)中使用自定义推拉流组件,您需要该页面的配置文件(main.json)中增加上面的配置。

提示

Uniapp 开发者可参考 Uniapp 项目配置 文档。

步骤 3:初始化

RTCLib 强依赖 IMLib。在使用 RTCLib 的能力之前,必须先调用 IMLib 的初始化接口

App Key 是使用 IMLib 进行即时通讯功能开发的必要条件,也是应用的唯一性标识。您必须拥有正确的 App Key,才能进行初始化。您可以登录融云控制台,从服务管理页面,查看您已创建的各个应用的 App Key。

只有在 App Key 相同的情况下,不同用户之间才能互通数据。

初始化 IMLib

调用 IMLib 的 init 方法,初始化 IM 客户端。以下示例使用 Typescript 进行编码,便于开发者更好的理解相关值的类型信息。

初始化时需传入您的融云应用的 App Key。

import * as RongIMLib from '@rongcloud/imlib-next'
// 初始化 IM
RongIMLib.init({
appkey: '<Your-Appkey>',
});

/**
* 监听消息通知
*/
const Events = RongIMLib.Events;
RongIMLib.addEventListener(Events.MESSAGES, (event) => {
console.log('received messages', event.messages);
});

/**
* 监听 IM 连接状态变化
*/
RongIMLib.addEventListener(Events.CONNECTING, () => {
console.log('onConnecting');
});
RongIMLib.addEventListener(Events.CONNECTED, () => {
console.log('onConnected');
});
RongIMLib.addEventListener(Events.DISCONNECT, (status) => {
console.log('连接中断,需要业务层进行重连处理 ->', status)
})

初始化 RTCLib

调用 IMLib 的 installPlugin 方法初始化 RTC 客户端。

// 初始化 RCRTCClient,初始化过程推荐放在建立连接之前
const rtcClient = RongIMLib.installPlugin(RongRTCLib.installer, { /*初始化参数请参考下方参数说明*/ })
  • RTCLib 初始化参数说明

    {
    /**
    * 自定义 MediaServer Url,公有云用户无需关注
    * @description
    * 1. 仅当 `location.hostname` 为 `localhost` 时,`http` 协议地址有效,否则必须使用 `https` 协议地址
    * 2. 当该值有效时,将不再从 IMLib 导航数据中获取 mediaServer 地址
    */
    mediaServer?: string,
    /**
    * 输出日志等级,通过 import { LogLevel } from '@rongcloud/plugin-rtc' 获取枚举值
    * @description
    * * 0 - DEBUG
    * * 1 - INFO
    * * 2 - WARN(default)
    * * 3 - ERROR
    */
    logLevel?: LogLevel
    /**
    * 覆盖默认的日志输出函数,便于业务层保存或上传日志
    */
    logStdout?: (logLevel: LogLevel, content: string) => void
    /**
    * 与 MediaServer 的 http 请求超时时间,单位为毫秒,默认值为 `5000`,有效值 `5000-30000`。
    * 优先级:用户配置 > 导航配置 > 默认时间。
    */
    timeout?: number,
    /**
    * 房间 Ping 间隔时长,默认 `10000` ms,有效值 `3000`-`10000`
    */
    pingGap?: number
    }

步骤 4:建立 IM 连接

提示

必须成功 IM 连接后, 才可执行其他操作。

融云音视频信令传输依赖于融云的即时通信(IM)服务。应用客户端成功连接到融云服务器后,才能使用融云即时通讯 SDK 进行信令传输。

应用客户端建立 IM 连接时必须传入 Token 参数。Token 是与用户 ID 对应的身份验证令牌,是应用客户端用户在融云的唯一身份标识。

在实际业务运行过程中,应用客户端需要通过应用的服务端向融云服务端申请取得 Token,具体方法可参考 Server API 获取 Token

在本教程中,为了快速体验和测试 SDK,我们从控制台「北极星」开发者工具箱 IM Server API 调试 页面获取 Token 用于测试。

  1. 访问控制台「北极星」开发者工具箱的 IM Server API 调试页面。

  2. 用户标签下,找到 用户服务 > 获取 Token 接口。

  3. 根据页面提示,填写 userId,并提交。

    在以下示例中,我们将获取到 userId 为 1 的用户的 Token。

    getToken

    提交后,可在左侧结果中取得 Token 字符串。

  4. 取得临时测试 token 后,调用 connect 方法进行连接融云。以下示例使用 Typescript 进行编码,便于开发者更好的理解相关值的类型信息。

    RongIMLib.connect('<Your-Token>').then((user) => {
    console.log('connect success', user.data.userId);
    })
    .catch((error) => {
    console.log(`连接失败: ${error}`);
    });

步骤 5:加入房间

/**
* 加入普通音视频房间
* @param roomId 房间 Id
* @returns data.room 当前加入的房间实例
* @returns data.userIds 当前房间内的其他用户 id
* @returns data.streams 当前房间内的其他用户发布的资源
*/
const { code, data } = await rtcClient.joinRTCRoom('roomId')

// 若加入失败,则 data 值为 undefined
if (code !== RCRTCCode.SUCCESS) {
console.log('join living room failed:', code)
return
}

const { room, userIds, streams: RCRemoteStreams } = data

// 注册房间事件监听器,重复注册时,仅最后一次注册有效
room.registerRoomEventListener({
/**
* 本端被踢出房间时触发
* @description 被踢出房间可能是由于服务端超出一定时间未能收到 rtcPing 消息,所以认为己方离线。
* 另一种可能是己方 rtcPing 失败次数超出上限,故而主动断线
* @param byServer
* 当值为 false 时,说明本端 rtcPing 超时
* 当值为 true 时,说明本端收到被踢出房间通知
* @param state 被踢出房间的原因
*/
onKickOff? (byServer: boolean, state?: RCKickReason): void
// 被踢出房间时,将不能继续发布资源、订阅资源,业务层可去掉远端资源的 UI 展示或重新加入房间
},
/**
* 接收到房间信令时回调,用户可通过房间实例的 `sendMessage(name, content)` 接口发送信令
* @param name 信令名
* @param content 信令内容
* @param senderUserId 发送者 Id
* @param messageUId 消息唯一标识
*/
onMessageReceive (name: string, content: any, senderUserId: string, messageUId: string) {
},
/**
* 监听房间属性变更通知
* @param name
* @param content
*/
onRoomAttributeChange (name: string, content: string) {
},
/**
* 发布者禁用/启用音频
* @param stream RCRemoteStream 类实例
*/
onAudioMuteChange (stream: RCRemoteStream) {
},
/**
* 发布者禁用/启用视频
* @param stream RCRemoteStream 类实例对象
*/
onVideoMuteChange (stream: RCRemoteStream) {
},
/**
* 房间内其他用户新发布资源时触发
* 如需获取加入房间之前房间内某个用户发布的资源列表,可使用 room.getRemoteStreamsByUserId('userId') 获取
* @param streams 新发布的资源列表,一组 RCRemoteStream 实例
*/
onStreamPublish (streams: RCRemoteStream[]) {
// 按业务需求选择需要订阅资源,通过 room.subscribe 接口进行订阅
const { code } = await room.subscribe(streams)
if (code !== RCRTCCode.SUCCESS) {
console.log('资源订阅失败 ->', code)
}
},
/**
* 房间用户取消发布资源
* @param streams 被取消发布的资源列表
* @description 当资源被取消发布时,SDK 内部会取消对相关资源的订阅,业务层仅需处理 UI 展示
*/
onStreamUnpublish (streams: RCRemoteStream[]) {
},
/**
* 人员加入
* @param userIds 加入的人员 id 列表
*/
onUserJoin (userIds: string[]) {
},
/**
* 人员退出
* @param userIds
*/
onUserLeave (userIds: string[]) {
}
})

步骤 6:发布资源

页面如已引入自定义推流组件 rc-livepusher,可发布资源。

发布完资源之后,SDK 内部会把推流地址赋给微信的推流组件 live-pusher,房间内其他人可通过订阅看到发布的资源。

<rc-livepusher></rc-livepusher>

代码示例

// 发布不传任何参数时,默认会发一个 tag 为 RongCloud 的音视频资源
const { code } = await room.publishStream()

步骤 8:订阅资源

页面如已引入自定义拉流组件 rc-liveplayer,可订阅资源。

订阅完资源之后,SDK 内部会把拉流地址赋给微信的拉流组件 live-player,页面中就会展示订阅资源的画面。

<rc-liveplayer id="{{id}}"></rc-liveplayer>

属性 ID 为房间内其他人发布的资源 stream 的唯一标识,可通过 stream.getMsid() 获取。每个 stream 对应一个拉流组件,订阅多个 stream 时,需引入多个 rc-liveplayer 并传入 idrc-liveplayerid 属性为必需绑定项

提示

:订阅一组远端 stream 时,使用 wx:for 渲染 rc-liveplayer 列表,wx:key 需绑定唯一标识符,请使用 stream.getMsid() 的值作为 rc-liveplayer 的唯一标识。

// 一组远端资源
const remoteStreams = [{
stream,
msid: stream.getMsid()
}]
<view wx:for="{{remoteStreams}}" wx:key="msid">
<rc-liveplayer id="{{msid}}"></rc-liveplayer>
</view>

代码示例

// streams 为加入房间时,房间内其他人已发布的资源,或房间事件监听 `onStreamPublish` 收到的房间内其他人新发布的资源
const { code } = await room.subscribe(streams);

步骤 8:离开房间

离开 RTC 房间,退出后将不能再与其他成员进行音视频通话。

// room 为加房间返回的 data.room 实例
await rtcClient.leaveRoom(room);