前提条件
- 本地化部署公司的媒体服务器,获取到服务器地址、AccessKey和SecretKey。
- 为了避免防火墙安全策略限制正常的 RTC 数据传输,需要对防火墙策略进行设置。
- 为了保证通话体验,建议在正式开始音视频通话前,进行设备检测和浏览器兼容性检测
集成 SDK
SDK 提供了 UMD类型的模块,兼容AMD、CommonJS和全局变量等多种使用场景,满足在不同类型项目中集成。
Require集成
- 在您的 app.js配置中添加如下代码即可:
var avdSDK = require('./lib/rtc-wx-3.2.6.4.min.js');
var pluginStore = new avdSDK.PluginStore();
self.data.getAvdSDK = pluginStore.getAvdSDK();
资源下载
- 单击下载 SDK /并解压
SDK 使用逻辑概览
基本概念
您在使用 RTC WX SDK 时,会接触到以下概念:
- [AVDEngine] 类,其实例代表一个本地客户端。AVDEngine的对象方法提供了获取摄像头列表、麦克风列表、实例化房间类、控制日志等级及日志保存等功能等功能。
实现音视频通话基本逻辑
- 调用
var avdSDK = require('./lib/rtc-wx-3.2.6.4.min.js');
var pluginStore = new avdSDK.PluginStore();
self.data.getAvdSDK= pluginStore.getAvdSDK()方法来实例化创建getAvdSDK对象。
- 调用 //获取应用实例 const app = getApp();
var room = app.data.getAvdSDK.obtainRoom(roomId)方法来实例化房间类。
-
调用 room.join()进入房间。
-
在进入房间后,可以开启摄像头和麦克风并发布到房间。
- 调用 app.data.getAvdSDK.room.selfUser.videos[0].publish()开启摄像头并发布到房间。
- 调用 app.data.getAvdSDK.room.selfUser.audio.publish()开启麦克风并发布到房间。
- 当一个远端用户发布了音视频后,本端会收到远端视频发布通知,本端需要做订阅操作,音频SDK会默认自动订阅。您需要通过如下方式来播放远端音视频:
- 在进房间后监听user.addCallback(app.data.getAvdSDK.Enum.UserCallback.publish_camera_notify, self.onPublishCameraNotify)事件,就能收到该远端用户的发布视频。
- 在进房间后监听 user.addCallback(UserCallback.subscrible_microphone_result, onSubscribleMicrophoneResult)事件,就能收到该远端用户的发布音频。
- 在onSubscribleCameraResult事件回调函数中,调用user.addCallback(app.data.getAvdSDK.Enum.UserCallback.subscrible_camera_result, self.onSubscribleCameraResult);方法播放远端视频。
- 在onSubscribleMicrophoneResult事件回调函数中,调用user.addCallback(app.data.getAvdSDK.Enum.UserCallback.subscrible_microphone_result, self.onSubscribleMicrophoneResult)方法播放远端音频。
创建 AVDEngine 对象
var avdSDK = require('./lib/rtc-wx-3.2.6.4.min.js');
var pluginStore = new avdSDK.PluginStore();
self.data.getAvdSDK= pluginStore.getAvdSDK()
var api = require('../../restApi/api.js');
getAccessToken: function () {
var self = this;
var currTimeStamp = parseInt(new Date().getTime() / 1000)
var promise = new Promise((resolve, reject) => {
api.getCertificate(currTimeStamp).then(res => {
if(res.data) {
//deParams()解密
var certResData = JSON.parse(api.deParams(res.data));
// 比对请求时携带的时间戳和返回的时间戳,用于确认返回的token是此次请求的
if(certResData['timestamp'] != currTimeStamp){
reject('processingError is currTimeStamp');
return;
}
// 通过凭证获取token,certResData()加密
api.getAccessToken(certResData['access_key'],certResData['secret_key']).then((data)=> {
resolve(data.token);
}).catch((error) => {
reject(error);
});
}
}).catch(error => {
reject(error);
})
});
return promise;
}
// 引擎初始化
app.data.getAvdSDK.avdEngine.setDefaultMediaPublishKeepAliveTime(16000);
// serverUrl: MCU服务器地址
// token: 访问令牌
app.data.getAvdSDK.avdEngine.init(config.serverUrl,token).then(self.initSuccess).catch(self.initError)
创建 Room对象
//获取应用实例 const app = getApp();
var room = app.data.getAvdSDK.obtainRoom(roomId)
进入房间
调用room.joinEfficient()进入房间。通常在开始通话
按钮的点击回调里进行调用。 关键参数:
userId
: 用户 ID,由您指定。userName
: 用户名,由您指定。userData
: 用户扩展字段。 可以做为应用层逻辑上的可自定义字段使用,如填入角色。
room.join(userId, userName, '', password).then(function(){
console.log('进房成功');
this.joinSuccess()
}).otherwise(function(error){
console.error('进房失败 ', error);
this.joinError()
});
开启摄像头、麦克风
1.开启摄像头
使用app.data.getAvdSDK.room.selfUser.videos[0].publish()方法开启摄像头,并发布到房间。
//获取应用实例
const app = getApp();
//SDK支持多摄像头的同时开启及发布,这里voides[0]表示取了摄像头设备集里的第一摄像头
var video = app.data.getAvdSDK.room.selfUser.videos[0]
video.publish().then(function(){
var playerUrl = app.data.getAvdSDK.room.selfUser.pusherUrl
console.log(new Date(), "发布视频成功, 推流地址:", playerUrl);
}).otherwise(function(error){
console.log(new Date(), "发布视频出错,error:", error);
});
// 监听推流状态
onPushEvent: function(e) {
var self = this;
// return;
self.createPusherContext();
var code;
if (e.detail) {
code = e.detail.code;
} else {
code = e;
}
var errmessage = '';
switch (code) {
case 1002:
console.log('推流情况:', code);
break;
case -1301:
console.error('打开摄像头失败: ', code);
break;
case -1302:
console.error('打开麦克风失败: ', code);
break;
case -1307:
console.error('推流连接断开: ', code);
self.data.pusher.pusherContext.stop();
console.log('推流连接断开后主动停止推流');
setTimeout(() => {
self.data.pusher.pusherContext.start();
console.log('推流连接断开后主动重新开始推流');
}, 500);
wx.showLoading({
title: '推流连接断开',
})
break;
default:
console.log('推流情况:', code);
}
},
//在wxml中,使用 <live-pusher> 组件播放
<live-pusher url="{{pusher.url}}" bindstatechange="onPushEvent" />
2.开启麦克风
使用app.data.getAvdSDK.room.selfUser.audio.publish()方法开启麦克风,并发布到房间。
var audio = app.data.getAvdSDK.room.selfUser.audio;
audio.publish().then(function(){
console.log('麦克风开启及发布成功');
self.data.pusher.url = app.data.getAvdSDK.room.selfUser.pusherUrl
}).otherwise(function(error){
console.log(new Date(), "发布音频出错,error:", error);
});
//在wxml中,使用 <live-pusher> 组件播放
<live-pusher url="{{pusher.url}}" mode="RTC" autopush bindstatechange="statechange" />
播放远端音视频
a.播放远端音频
默认情况下,SDK 会自动订阅远端音频,您无需调用 API 来订阅操作。
在进房后监听UserCallback.subscrible_microphone_result事件,在收到远端声频订阅反馈事件时,本端可以播放远端声频流。
user.addCallback(app.data.getAvdSDK.Enum.UserCallback.subscrible_microphone_result,self.onSubscribleMicrophoneResult);
/**
* 订阅远端音频流反馈
* @param {Object} stream- 远端音频流
* @param {Object} userId- 所属用户ID
* @param {Object} userName-所属用户名称
*/
onSubscribleMicrophoneResult: function(userId, userName, microphoneId) {
var user = app.data.getAvdSDK.room.getUser(userId);
if(user.userAgent == 'avd_mp4_importer'){
console.log('+++onSubscribleMicrophoneResult avd_mp4_importer user: ', JSON.parse(JSON.stringify(user)))
}else{
self.data.player.playUrlAssist = user.audio.playerUrl;
console.log(new Date(), "+++onSubscribleMicrophoneResult(),user.audio.playerUrl:", user.audio.playerUrl);
self.data.player.audioPlaying = true;
}
}
//在wxml中,使用 <live-player> 组件播放
<live-player src="{{player.playUrlAssist}}" mode="RTC" autoplay bindstatechange="statechange" />
b.播放远端视频
在进房后监听UserCallback.publish_camera_notify事件,在收到远端视频发布通知事件时,通过video.subscrible()进行订阅操作。然后通过监听 UserCallback.subscrible_camera_result事件,在收到远端视频订阅反馈事件时,本端可以播放远端视频流。
user.addCallback(app.data.getAvdSDK.Enum.UserCallback.publish_camera_notify, self.onPublishCameraNotify);
user.addCallback(app.data.getAvdSDK.Enum.UserCallback.subscrible_camera_result, self.onSubscribleCameraResult);
/**
*远端用户发布视频通知,在回调事件里可以做订阅操作
*@param {Object[]} videos - 远端已发布的视频对象集
*/
function onPublishCameraNotify(videos) {
//订阅未订阅的视频
console.log(new Date(), "+++onPublishCameraNotify(),videos:", videos);
videos.forEach(function(video) {
video.subscrible().then(function(){
console.log("订阅视频成功,videoId:",video.id);
}).otherwise(function(error){
console.error('订阅视频失败,videoId:',video.id)
})
});
}
/**
* 订阅远端视频流反馈
* @param {Object} stream - 远端视频流
* @param {Object} userId - 所属用户ID
* @param {Object} userName- 所属用户名称
* @param {Object} cameraId- 摄像头设备ID
*/
function onSubscribleCameraResult(userId, userName, cameraId) {
var videoPuber = app.data.getAvdSDK.room.getUser(userId);
var video = videoPuber.getVideo(cameraId)
if(videoPuber && videoPuber.userAgent == 'avd_mp4_importer'){
console.log(new Date(), '+++onSubscribleCameraResult, tts player, video.playUrl: ', video.playerUrl)
self.data.ttsPlayer.playUrlMain = video.playerUrl;
self.setData({
ttsPlayer: self.data.ttsPlayer
})
}
}
// 监听拉流状态
onTTSPlayEvent: function(error) {
var self = this;
// code == 2006 拉流:视频播放结束
// code == 2105 拉流:当前视频播放出现卡顿
if (error.detail.code < 0) {
console.error('+++onPlayEvent(),拉流失败:', error.detail.code + "," + error.detail.message);
if(error.detail.code == "-2301"){ //网络断连,且经多次重连抢救无效,更多重试请自行重启播放
var playerContext = wx.createLivePlayerContext("ttsPlayer");
playerContext.play();
console.log('+++onPlayEvent(),拉流失败,已经重启播放');
}
} else {
console.log('TTS拉流情况:', error.detail.code + "," + error.detail.message);
}
},
//在wxml中,使用 <live-player> 组件播放
<live-player src="{{ttsPlayer.playUrlAssist}}" mode="RTC" autoplay bindstatechange="onTTSPlayEvent" />
3.退出房间
调用room.leave()方法退出房间,结束音视频通话。
var reason = 1; //退会原因
if (app.data.getAvdSDK.room) {
app.data.getAvdSDK.room.leave(reason).then(function() {
console.log('退会成功!')
});
}
4.处理被踢
除了用户主动退出房间之外,用户也有可能因为如下原因被踢出房间,此时 SDK 会抛出RoomCallback.leave_indication事件,这时不需要调用 room.leave()
退房,SDK 自动进入退房状态。
reason==804
:两个相同 userId 的用户进入相同房间,前一个进房的用户会被踢出。同名用户同时进入同一房间是不允许的行为,可能会导致双方音视频通话异常,应避免出现这种情况。reason == 808
:通过调用服务端踢人Restful接口或时SDK中调踢人接口,将某个用户踢出某个房间,该用户会收到被踢事件。
另一种场景是某个用户把房间关闭了,关闭房间之后,该房间的所有用户都会收到RoomCallback.close_room_notify事件,所有用户都会被踢;
- reason==809:服务没有授权用户入会(最多2个用户),超过15分钟服务器主动关闭房间强制踢人。
reason == 810
:SDK调用接口关闭会议。reason == 811
:服务更新维护时关闭会议。reason == 815
:调用restful接口关闭会议。
app.data.getAvdSDK.room.addCallback(app.data.getAvdSDK.Enum.RoomCallback.leave_indication, this.onLeaveIndication);
/**
* @desc 被踢出会议室
* @param {Object} reason - 被踢原因
* @param {Object} userId - 踢人的操作者
*/
function onLeaveIndication(reason, userId) {
var user = app.data.getAvdSDK.room.getUser(userId);
var userName = '';
if (user != null) {
userName = user.name;
}
if (reason == 804) { //同一个userid加会, 把前一个人踢下线
wx.showModal({
title: '退会提示',
content: '您已在另一终端登陆,被踢出会议室。被踢原因:' + reason,
showCancel: false
});
} else if (reason == 808) { //调用Restful接口把人踢下线或SDK调踢人接口通知会议中的第三方用户
wx.showModal({
title: '退会提示',
content: '您被' + userName + '踢出会议室。被踢原因:' + reason,
showCancel: false
});
} else if (reason == 809) { //无授权 15分钟以后强制踢人
wx.showModal({
title: '退会提示',
content: '无授权,试用时限到期,您被' + userName + '踢出会议室。被踢原因:' + reason,
showCancel: false
});
} else {
wx.showModal({
title: '退会提示',
content: '您已被主持人从会议中踢出',
showCancel: false
});
}
}
app.data.getAvdSDK.room.addCallback(app.data.getAvdSDK.Enum.RoomCallback.close_room_notify, this.onCloseRoomNotify);
/**
* @desc 收到关闭房间通知,退出会议操作
* @param {int} roomId - 房间ID
* @param {int} reason -关闭会议原因
*/
function onCloseRoomNotify(roomId, reason) {
var tips = "";
if(reason == 809) {
tips = "服务没有授权用户入会(最多2个用户),超过15分钟服务器主动关闭房间强制踢人";
}else if(reason == 810) {
tips = "SDK调用接口关闭会议";
}else if(reason == 811){
tips = "服务更新维护时关闭会议";
}else if(reason == 815){
tips = "调用restful接口关闭会议";
}
wx.showModal({
title: '关闭会议提示',
content: '会议已关闭。原因:' + tips,
showCancel: false
});
}
联系我们
如在接入实现过程中遇到问题,欢迎到微信技术对接群里联系沟通,我们会尽快处理。