本文介绍如何创建一个微信小程序 RTC 项目,实现音视频通话功能。
由于平台限制,微信小程序 SDK 的媒体能力与其他端存在差异,详见 微信小程序 SDK 媒体能力上限。
开始前,请确保你的开发环境满足如下条件:
调试 RTC 微信小程序 Demo 过程中,需要使用小程序的 live-pusher 和 live-player 功能标签,用于支持音视频上行和下行(播放)能力,目前微信只向特定行业的认证企业账号开放这两个标签的使用。
下载并安装最新版本的微信开发者工具
至少一台安装有微信 App 的移动设备
微信 App iOS 最低版本要求:6.5.21
微信 App Android 最低版本要求:6.5.19
小程序基础库最低版本要求:1.7.0
参考 RTC 接入指南获取 AppId 。
在开发阶段,你可以在控制台生成并使用临时 Token。正式上线后,Token 应由你的应用服务端生成,下发到你的应用客户端。应用客户端在加入 RTC 房间时,必须携带正确的 Token。你可以通过阅读密钥说明了解更多 Token 相关。
进入微信公众平台 -> 【</> 开发】 -> 【接口设置】,打开 实时播放音视频流 和 实时录制音视频流 的开关。
进入微信公众平台 -> 【</> 开发】 -> 【开发设置】,将如下域名配到服务器域名里
https://common.rtc.volcvideo.com; https://common-hl.rtc.volcvideo.com; https://log.snssdk.com;
wss://ws.rtc.volcvideo.com; wss://ws-hl.rtc.volcvideo.com; wss://ws-ag-agsxxa.rtc.volcvideo.com; wss://ws-ag-aghbwh.rtc.volcvideo.com; wss://ws-ag-agsdqd.rtc.volcvideo.com; wss://ws-ag-agjsnj.rtc.volcvideo.com; wss://ws-ag-aggdsz.rtc.volcvideo.com;
../lib
路径下。. ├── components │ ├── v-player │ │ ├── v-player.js │ │ ├── v-player.json │ │ ├── v-player.wxml │ │ └── v-player.wxss │ └── v-pusher │ ├── 1.png │ ├── v-pusher.js │ ├── v-pusher.json │ ├── v-pusher.wxml │ └── v-pusher.wxss ├── lib │ ├── miniapp-rtc.min.js ├── pages │ ├── meeting │ │ ├── meeting.js │ │ ├── meeting.json │ │ ├── meeting.wxml │ │ └── meeting.wxss
require
将小程序 SDK 集成到你的项目中。const VolcMiniappSdk = require('../../lib/miniapp-rtc.min.js');
参考如下流程,完成你的项目。
通过 new Client
创建 client 对象。client 接口中包含的成员函数提供了音视频通话的核心功能,例如进入房间、发布和订阅音视频流等。
将以下示例代码加入到 meeting.js
中。
Page({ onReady() { this.client = new VolcMiniappSdk.Client(); this.client.init(APPID) // APPID 的获取方式详见【步骤1】。 }, });
调用 client.join 方法初始化 client 对象和进入房间。
将以下示例代码加入到 meeting.js
中。
Page({ join() { this.client.join(TOKEN, ROOMID, USERID) // Token 的获取方式详见【步骤1】 } });
ROOMID 和 USERID 在同一 AppID 下唯一,你需要自行维护,参见赋值规范。
成功加入房间成功后,可以调用 client.publish 发布本地音视频流。成功发布后,SDK 会返回该路音视频流的 URL。
meeting.json
中。{ "usingComponents": { "v-pusher": "../../components/v-pusher/v-pusher" } }
meeting.js
中。Page({ publish() { this.client.publish().then(url => { this.setData({ publishUrl: url }) }) } })
meeting.wxml
中。<v-pusher wx:if="{{pushUrl}}" id="volc-pusher" url="{{pushUrl}}" enable-mic="{{true}}" enable-camera="{{true}}" beauty="{{0}}" bind:pusherstatechange="pusherStateChange" bind:pushernetstatuschange="pusherNetStatusChange" />
meeting.js
中。Page({ pusherStateChange(e) { const target = e.detail; this.client.reportPusherStateChange( target.detail.code, target.detail.message, ); }, pusherNetStatusChange(e) { const info = e?.detail?.detail?.info; this.client.reportPusherNetStatusChange(info); }, })
订阅流要在加入房间成功之后
meeting.json
中。{ "usingComponents": { "v-pusher": "../../components/v-pusher/v-pusher", "v-player": "../../components/v-player/v-player" } }
meeting.js
中。Page({ data: { remoteStreams: [], }, subscribe(uid, screen) { this.client.subscribe(uid, { screen }).then(url => { this.setData({ ...this.data.remoteStreams, { uid, screen, url, id: `${uid}-${screen ? 1 : 0}` } }) }) }, _handleClientEvents() { if (this.client) { this.client.removeAllListeners(); } this.client.on(VolcEngineRTCMiniappSDK.EVENTS.STREAM_ADDED, (e) => { const { uid, screen } = e; this.subscribe(uid, screen) }) } })
meeting.wxml
中。<view wx:for="{{remoteStreams}}" wx:key="id" class="player-container"> <view> <v-player url="{{item.url}}" uid="{{item.uid}}" screen="{{item.screen ? 1 : 0}}" bind:playerstatechange="playerStateChange" bind:playernetstatuschange="playerNetStatusChange" /> </view> </view>
meeting.js
中。Page({ pusherNetStatusChange(e) { const info = e?.detail?.detail?.info; this.client.reportPusherNetStatusChange(info); }, playerStateChange(e) { const uid = e?.detail?.uid; this.client.reportPlayerStateChange( uid, e?.detail?.e?.detail?.code, e?.detail?.e?.detail?.message, ); }, })
传入参数如下:
属性 | 含义 | 类型 | 默认值 |
---|---|---|---|
url | 推流地址 | string | 无 |
enableCamera | 是否开启摄像头 | boolean | true |
enbaleMic | 是否开启麦克风 | boolean | true |
beauty | 是否开启美颜和美颜等级 取值范围 0 - 9 0 代表不开启 | number | 0 |
live-pusher 提供了 2 个回调,监控上行媒体流状态
将以下示例代码加入到v-pusher.wxml
中。
<view class="pusher-view"> <!-- mode: RTC 实时通话 background-mute: true 进入后台静音(兼容旧版本) 其他配置请参考小程序文档: https://developers.weixin.qq.com/miniprogram/dev/component/live-pusher.html --> <live-pusher class="pusher" url="{{url}}" mode="RTC" autopush="true" max-bitrate="500" min-bitrate="200" beauty="{{beauty}}" bindstatechange="bindstatechange" bindnetstatus="bindnetstatus" enable-camera="{{enableCamera}}" enable-mic="{{enableMic}}" aspect="3:4" /> <view class="info"> {{state === 'init' ? '相机启动中' : state === 'error' ? '相机启动失败' : ''}} </view> </view>
将以下示例代码加入到v-pusher.js
中。
Component({ properties: { url: { type: String, value: '', }, enableCamera: { type: Boolean, value: true, }, enableMic: { type: Boolean, value: true, }, beauty: { type: Number, value: 0, }, state: { type: String, // init: 启动中 ok: 正常推流 error: 推流失败 value: 'init', }, }, data: {}, lifetimes: { ready: function () { if (!this.livePusherContext) { this.livePusherContext = wx.createLivePusherContext(this); } }, detached: function () { this.stop(); }, }, methods: { stop: function () { if (this.livePusherContext) { this.livePusherContext.stop(); } }, switchCamera: function () { if (this.livePusherContext) { this.livePusherContext.switchCamera(); } }, bindstatechange: function (e) { // emit to page this.triggerEvent('pusherstatechange', e); if (e.detail.code === -1307) { this.setData({ state: 'error', }); } if (e.detail.code === 1008) { if (this.data.state === 'init') { this.setData({ state: 'ok', }); } } }, bindnetstatus: function (e) { // emit to page this.triggerEvent('pushernetstatuschange', e); }, }, });
传入参数如下:
属性 | 含义 | 类型 | 默认值 |
---|---|---|---|
url | 拉流地址 | string | 无 |
uid | 流的发布者 | string | 无 |
screen | 流是否为屏幕共享流 | 0 | 1 | 0 |
live-player 提供了 2 个回调,监控下行媒体流状态
将以下示例代码加入到v-player.wxml
中。
<view class="player-view"> <!-- mode: RTC 实时通话 background-mute: true 进入后台静音(兼容旧版本) 其他配置请参考小程序文档: https://developers.weixin.qq.com/miniprogram/dev/component/live-player.html --> <live-player src="{{url}}" id="v-player-{{uid}}-{{screen}}" data-uid="{{uid}}" class="player" mode="RTC" autoplay="true" object-fit="fillCrop" background-mute="true" bindstatechange="bindstatechange" bindnetstatus="bindnetstatuschange" debug="{{true}}" /> <view class="info"> {{state === 'init' ? '播放器启动中' : state === 'error' ? '播放器启动失败' : ''}} </view> </view>
将以下示例代码加入到v-player.js
中。
Component({ properties: { url: { type: String, value: '', }, uid: { type: String, value: '', }, screen: { type: String, // '0' camera stream '1' screen stream value: '0', }, state: { type: String, // init: 启动中 ok: 正常推流 error: 推流失败 value: 'init', }, }, data: {}, lifetimes: { ready: function () { if (!this.livePlayerContext) { this.livePlayerContext = wx.createLivePlayerContext( `v-player-${this.data.uid}-${this.data.screen}`, this, ); } }, detached: function () { if (this.livePlayerContext) { this.livePlayerContext.stop(); } }, }, methods: { bindstatechange: function (e) { // emit to page this.triggerEvent('playerstatechange', { uid: this.data.uid, e }); if (e.detail.code === 2004) { if (this.data.state === 'init') { this.setData({ state: 'ok', }); } } else if (e.detail.code === -2301) { this.setData({ state: 'error', }); } }, bindnetstatuschange: function (e) { // emit to page this.triggerEvent('playernetstatuschange', { uid: this.data.uid, e }); }, }, });