DingRTC的基本功能包含初始化SDK、加入频道、本地发布、订阅远端和离开频道等。通过阅读本文,您可以了解DingRTC的基本功能。
前提条件
您已下载并集成最新版本的SDK。具体操作,请参见如何在小程序端集成音视频通信SDK。
您已获取加入频道必需的频道鉴权令牌(Token)。具体操作,请参见使用Token鉴权。
基本概念
您在接入DingRTC 小程序 SDK时,会接触到以下基础概念:
DingRTCClient类,它的实例代表本地客户端,其方法提供加入、离开房间,发布、订阅音视频流等功能;
基本逻辑
调用createClient()方法创建一个客户端实例;
调用join()进入一个RTC频道;
调用publish() 获取推流URL,启动live-pusher完成音视频推流;
订阅远端音视频轨道:
在加入频道前监听"user-published"事件,可获取到所有远端用户的推流事件,其回调参数包含发布人的信息与音视频轨道的类型;
调用subscribe('mcu', 'audio')来获取频道音频的拉流URL,启动live-player实现音频播放;
调用subscribe(userId, 'video',false)来获取用户视频频的拉流URL,启动live-player实现该用户的视频播放;
操作步骤
本文中的实现方法仅供参考,您可以根据实际业务需求进行开发。
创建Client对象。
const DingRTC = require('./path/to/dingrtc_mini_program.umd.0.7.0.js'); const client = DingRTC.createClient();加入频道。
await client.join({ appId: 'your_app_id', // 您在 DingRTC 项目的 AppId token: 'your_token', // 频道鉴权令牌 uid: 'user_001', // 用户 ID,仅支持 [A-Za-z0-9_-],长度不超过 64 个字符 channel: 'channel_001', // 频道 ID,仅支持 [A-Za-z0-9_-],长度不超过 64 个字符 userName: '张三' // 用户名称,长度不超过 UTF-8 编码 64 个字节 });上述代码中的you token需要客户参考使用Token鉴权自行开发。
加入频道所需信息:
属性
类型
描述
appId
string
您在 DingRTC 项目的 AppId,仅支持大小写字母、数字和下划线。
channel
string
频道 Id,字符内容只允许[A-Za-z0-9_-],长度不超过64个字符。
token
string
频道鉴权令牌
uid
string
标识用户的 Id,字符内容只允许[A-Za-z0-9_-],长度不超过64个字符。
说明同一个用户Id在其他端登录,先入会的端会被后入会的端踢出频道。
userName
string
用户名称,长度不超过UTF-8编码64个字节。
发布或取消发布本地音视频。
获取发布音频+视频的推流url
// 调用 publish 方法,SDK 会返回推流配置 const publishResult = await client.publish(); // publishResult 中包含 pusherUrl,需要绑定到 <live-pusher> 组件 this.setData({ pusherUrl: publishResult.pusherUrl, enableMic: true, enableCamera: true });结合微信组件 live-pusher 实现推流
<live-pusher id="pusher" url="{{pusherUrl}}" mode="RTC" autopush="{{pusherUrl ? true : false}}" enable-mic="{{enableMic}}" enable-camera="{{enableCamera}}" device-position="front" bindstatechange="onPusherStateChangeEvent" bindnetstatus="onPusherNetStatusEvent" binderror="onPushError" />传递<live-pusher>组件状态给 SDK
/ 网络状态回调 onPusherNetStatusEvent(event) { client.reportPusherNetStatus(event.detail); }, // 状态变化回调 onPusherStateChangeEvent(event) { client.reportPusherStateChange(event.detail); }, // 错误回调 onPushError(event) { console.error('推流错误:', event.detail); client.reportPusherStateChange(event.detail); }音视频采集设备控制(非SDK提供,通过组建属性控制)
// 静音麦克风 this.setData({ enableMic: false }); // 取消麦克风静音 this.setData({ enableMic: true }); // 关闭摄像头 this.setData({ enableCamera: false }); // 开启摄像头 this.setData({ enableCamera: true });取消发布
await client.unpublish(); // 同时清空页面上的推流 URL this.setData({ pusherUrl: '' });
订阅或取消订阅音视频流。
监听远端用户推流事件
client.on('user-published', async (user, mediaType, auxiliary) => { console.log(`用户 ${user.userId} 发布了 ${mediaType}`); if (mediaType === 'audio') { // 订阅音频合流(全局只需订阅一次) const subscribeResult = await client.subscribe('mcu', 'audio', false); // 更新音频拉流 URL this.setData({ audioRtmpPlayUrl: subscribeResult.rtmpPullUrl }); } else if (mediaType === 'video' && !auxiliary) { // 订阅视频 const subscribeResult = await client.subscribe(user.userId, 'video', false); // 更新用户列表中的视频 URL this.setData({ userList: this.data.userList.map(u => { if (u.userId === user.userId) { return { ...u, hasVideo: true, rtmpPullUrl: subscribeResult.rtmpPullUrl }; } return u; }) }); } });音频订阅:当前不支持指定到个人的音频订阅,必须使用
'mcu'作为 userId 来订阅音频合流视频订阅:每个远端用户需要单独订阅,获取各自的 RTMP 拉流 URL
auxiliary参数表示是否为辅助流(如屏幕共享),通常为false
在 WXML 中使用 live-player 组件实现音频合流播放器(隐藏,全局只需一个):
<live-player wx:if="{{audioRtmpPlayUrl}}" src="{{audioRtmpPlayUrl}}" autoplay="{{audioRtmpPlayUrl ? true : false}}" mode="RTC" style="position: absolute; top:-1rpx; left:-1rpx; width: 1rpx; height: 1rpx;" data-user-id="{{'mcu'}}" min-cache="0.2" max-cache="0.8" bindstatechange="onMcuAudioPlayerStateChange" bindnetstatus="onMcuAudioPlayerNetStatus" binderror="onPlayerError" />在 WXML 中使用 live-player 组件实现视频播放器(每个远端用户一个):
<block wx:for="{{userList}}" wx:key="userId"> <live-player wx:if="{{item.hasVideo && item.rtmpPullUrl}}" id="{{item.userId}}" src="{{item.rtmpPullUrl}}" autoplay="true" muted="false" object-fit="cover" style="width:100%;height:100%" data-user-id="{{item.userId}}" min-cache="0.2" max-cache="0.8" bindstatechange="onVideoPlayerStateChange" bindnetstatus="onVideoPlayerNetStatus" binderror="onPlayerError" /> </block>传递<live-player>组件状态给 SDK
// 音频合流状态回调 onMcuAudioPlayerNetStatus(event) { const subParam = { uid: 'mcu', mediaType: 'audio', auxiliary: false, }; client.reportPlayerNetStatus(subParam, event.detail); }, onMcuAudioPlayerStateChange(event) { const subParam = { uid: 'mcu', mediaType: 'audio', auxiliary: false, }; client.reportPlayerStateChange(subParam, event.detail); }, // 视频状态回调 onVideoPlayerNetStatus(event) { const userId = event.currentTarget.dataset.userId; const subParam = { uid: userId, mediaType: 'video', auxiliary: false, }; client.reportPlayerNetStatus(subParam, event.detail); }, onVideoPlayerStateChange(event) { const userId = event.currentTarget.dataset.userId; const subParam = { uid: userId, mediaType: 'video', auxiliary: false, }; client.reportPlayerStateChange(subParam, event.detail); }, // 错误回调 onPlayerError(event) { const userId = event.currentTarget.dataset.userId; console.error(`播放器错误 [${userId}]:`, event.detail); }取消订阅音频和视频
// 取消订阅视频 await client.unsubscribe(userId, 'video', false); // 更新页面数据,移除视频 URL this.setData({ userList: this.data.userList.map(u => { if (u.userId === userId) { return { ...u, hasVideo: false, rtmpPullUrl: '' }; } return u; }) }); // 取消订阅音频合流(注意:音频仅支持 mcu 合流模式) await client.unsubscribe('mcu', 'audio'); // 更新页面数据,标记音频已取消订阅 this.setData({ hasAudioSubscribed: false });视频: 可以针对特定用户取消订阅,传入该用户的
userId音频: 由于小程序 SDK 仅支持
'mcu'合流模式,取消音频订阅时必须使用userId = 'mcu',无法单独取消某个用户的音频取消订阅后,应及时清理页面上对应的资源(如移除 live-player 组件、清空播放地址等),避免内存泄漏
如果用户完全离开频道,SDK 会自动触发
user-unpublished和participant-left事件,无需手动取消订阅
重连处理。
// 监听推流重连 client.on('pub-media-reconnect-started', () => { wx.showToast({ title: '推流重连中...', icon: 'none' }); }); client.on('pub-media-reconnect-succeeded', (newRtmpUrl) => { wx.showToast({ title: '推流重连成功', icon: 'none' }); // 必须更新 live-pusher 的 url 属性 this.setData({ pusherUrl: newRtmpUrl }); }); client.on('pub-media-reconnect-failed', () => { wx.showModal({ title: '推流重连失败', content: '请检查网络', showCancel: false }); }); // 监听订阅重连 client.on('sub-media-reconnect-started', (subParam) => { console.log(`用户 ${subParam.uid} 视频重连中...`); }); client.on('sub-media-reconnect-succeeded', (subParam, newRtmpUrl) => { console.log(`用户 ${subParam.uid} 视频重连成功`); // 必须更新对应 live-player 的 src 属性 this.updatePlayerUrl(subParam.uid, newRtmpUrl); });错误处理。
try { await client.join({ appId: 'your_app_id', channel: 'channel_001', token: 'your_token', uid: 'user_001', userName: '张三' }); } catch (error) { console.error('加入频道失败:', error); // 获取错误码和错误信息 const errorCode = error.code; const errorMsg = DingRTC.ErrorCodeAndMsgMap[errorCode] || error.message; console.error(`错误码: ${errorCode}, 错误信息: ${errorMsg}`); // 根据错误码进行相应处理 switch (errorCode) { case 'INVALID_TOKEN': case 'TOKEN_EXPIRED': // Token 无效,需要重新获取 console.warn('Token 已失效,请重新获取'); break; case 'UID_ALREADY_IN_USE': // UID 已被使用,需要更换 UID console.warn('该 UID 已被使用,请更换 UID'); break; case 'PERMISSION_DENIED': // 权限被拒绝,引导用户授权 wx.showModal({ title: '权限提示', content: '需要摄像头和麦克风权限才能进行视频通话', success: (res) => { if (res.confirm) { wx.openSetting(); } } }); break; case 'NETWORK_ERROR': // 网络错误,提示用户检查网络 wx.showToast({ title: '网络连接异常', icon: 'none' }); break; default: wx.showToast({ title: '操作失败', icon: 'none' }); } }离开频道。
async leaveChannel() { try { const leaveResult = await client.leave(); console.log('离开频道成功:', leaveResult); // 清空页面数据 this.setData({ pusherUrl: '', audioRtmpPlayUrl: '', userList: [] }); wx.navigateBack(); } catch (error) { console.error('离开频道失败:', error); } }离开频道时务必调用
leave()方法,以释放相关资源页面卸载时应确保正确清理客户端实例
建议在
onUnload()生命周期中调用leave()
后续步骤
您可以下载示例代码,快速运行Demo,实现频道内和其他人进行实时音视频通话,详情请参见运行 小程序 Demo。