简介
anyrtc Web SDK 4.0 能实现基于 anyrtc SD-RTN™ 的实时音视频通信功能,支持语音通话、视频通话、音频互动直播、视频互动直播等场景。anyrtc Web SDK 是一个全量重构的版本,主要针对 API 的易用性和内部架构做了较大的调整。
如果你之前没有接触过 anyrtc Web SDK 相关的产品,anyrtc Web SDK 将会成为一个很好的起点。如果你之前接触过 anyrtc Web SDK,请注意 anyrtc Web SDK 在使用和开发步骤上和原先的 SDK 有较大的不同。最明显的不同之处在于,anyrtc Web SDK 删除了原来的 Stream 对象,通过 LocalTrack 和 RemoteTrack 对象来控制媒体流。
浏览器兼容性
anyrtc Web SDK 兼容大部分主流浏览器,如下表所示
准备工作
APPID获取地址:
anyRTC;
SDK获取地址:
webSDK;
定义变量
// 本地客户端
var client = null;
// 计时器
var timer = null;
// 跨房间配置对象
var configuration = null;
// 显示配置信息开关
var offon = false;
// 本地是否发布
var publised = false;
// 是否播放远端视频
var remotePlay = false;
// 本地音视频轨道
var track = {
videoTrack: null,
audioTrack: null,
};
初始化页面
ArRTM 是引入sdk后自动抛出的。
var init = async function () {
client = ArRTC.createClient({ mode: "rtc", codec: "h264" }); // 创建sdk全局实例
};
加入频道
登录 anyrtc RTM 系统的用户 ID。该字符串不可超过 64 字节。以下为支持的字符集范围:
26 个小写英文字母 a-z
26 个大写英文字母 A-Z
10 个数字 0-9
空格
"!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ","
请不要将 uid 设为空、null,或字符串 "null"。
uid 不支持 number 类型。建议调用 toString() 方法转化非 string 型 uid。
var join = async function () {
const appid = element.configBox.appid.value;
const channel = element.configBox.channel.value;
const token = element.configBox.token.value;
if (!appid) {
api.addMessage({ type: 'error', message: 'Please enter the appid' });
return;
};
if (!channel) {
api.addMessage({ type: 'error', message: 'Please enter the channel' });
return;
};
// 获取摄像头
const cameras = await api.cameras(); // 核心代码
// 获取麦克风
const microphones = await api.microphones(); // 核心代码
if (!cameras || !microphones) return;
client.join(appid, channel, token || null).then(() => {
// 如果有音频对象就播放
track.audioTrack && track.audioTrack.play(); // 核心代码
// 如果有视频对象就播放
track.videoTrack && track.videoTrack.play(element.videoBox.localVideo, { fit: 'contain' }); // 核心代码
api.addMessage({ type: 'success', message: 'Join Success' });
// 开始监听回调函数
api.callBack(); // 核心代码
}, () => {
api.addMessage({ type: 'error', message: 'Join Failed' });
})
};
监听回调
var callBack = async function () {
// 监听远端用户发布 (对方跨房间发布以后,可以在这里拿到对方发布的媒体流)
client.on("user-published", async (user, mediaType) => {
await client.subscribe(user, mediaType);
if (mediaType === "video") {
remotePlay = true;
// 播放远端视频
user.videoTrack.play(element.videoBox.remoteVideo, { fit: 'contain' }); // 核心代码
};
if (mediaType === "audio") {
// 播放远端音频
user.audioTrack.play(); // 核心代码
};
});
// 监听远端用户取消发布
client.on("user-unpublished", (user, mediaType) => {
if (mediaType === "video") {
remotePlay = false;
};
});
};
获取摄像头
var cameras = async function () {
const Cameras = await ArRTC.getCameras(); // 核心代码
if (Cameras.length) {
const ICameraVideoTrack = await ArRTC.createCameraVideoTrack();
track.videoTrack = ICameraVideoTrack;
return true;
} else {
api.addMessage({ type: 'error', message: 'No cameras are available' });
return false;
};
};
获取麦克风
var microphones = async function () {
const Microphones = await ArRTC.getMicrophones(); // 核心代码
if (Microphones.length) {
const IMicrophoneAudioTrack = await ArRTC.createMicrophoneAudioTrack();
track.audioTrack = IMicrophoneAudioTrack;
return true;
} else {
api.addMessage({ type: 'error', message: 'No microphones are available' });
return false;
};
};
发布本地音视频
var publish = function () {
// 发布本地音视频 (核心代码)
client.publish([track.videoTrack, track.audioTrack]).then(() => {
api.addMessage({ type: 'success', message: 'Publish Success' });
publised = true;
}, () => {
api.addMessage({ type: 'error', message: 'Publish Failed' });
});
};
开始跨房间
跨房间之前一定要先发布本地视频, 否则跨房间以后对方只能看到黑屏
var start = function () {
const forChannel = element.configBox.forChannel.value;
const channel = element.configBox.channel.value;
if (forChannel === "") {
api.addMessage({ type: 'error', message: 'Please enter the forChannel number' });
return;
};
if (forChannel === channel) {
api.addMessage({ type: 'error', message: 'forChannel and channel repeat' });
return;
};
// 生成跨房间配置对象
configuration = ArRTC.createChannelMediaRelayConfiguration(); // 核心代码
// 设置本地房间信息 channel 是本地房间号
configuration.setSrcChannelInfo({ channelName: channel }); // 核心代码
// 设置目标房间信息 forChannel 是对方房间号
configuration.addDestChannelInfo({ channelName: forChannel }); // 核心代码
var timer = setTimeout(() => {
api.addMessage({ type: 'error', message: 'Leave Failed' });
}, 3000);
// 开始跨房间
client.startChannelMediaRelay(configuration); // 核心代码
clearTimeout(timer);
api.addMessage({ type: 'success', message: 'start rtmp success' });
};
获取音视频状态
var state = function (type) {
// 获取本地或远端的音频状态(核心代码)
var audioState = client[type === 'localVideo'? 'getLocalAudioStats' : 'getRemoteAudioStats']();
// 获取本地或远端的视频状态(核心代码)
var videoState = client[type === 'localVideo'? 'getLocalVideoStats' : 'getRemoteVideoStats']();
var ele = document.getElementsByClassName(type)[0];
ele && element.videoBox[type].removeChild(ele);
var stateBox = document.createElement('div');
stateBox.className = `state ${type}`;
var videost = document.createElement('div');
var audiost = document.createElement('div');
[audioState, videoState].forEach((li, index) => {
for (var key in li) {
if (type === 'localVideo') {
var div = document.createElement('div');
div.innerHTML = `${key}: ${li[key]}`;
(index === 0? audiost : videost).appendChild(div);
} else {
for (var item in li[key]) {
var div = document.createElement('div');
div.innerHTML = `${item}: ${li[key][item]}`;
(index === 0? audiost : videost).appendChild(div);
};
};
};
})
stateBox.appendChild(videost);
stateBox.appendChild(audiost);
element.videoBox[type].appendChild(stateBox);
};
停止跨房间
var stop = function () {
// 停止跨房间
client.stopChannelMediaRelay(); // 核心代码
element.configBox.forChannel.value = '';
};
取消发布本地音视频
var unPublish = function () {
// 取消发布本地音视频(核心代码)
client.unpublish([track.videoTrack, track.audioTrack]).then(() => {
api.addMessage({ type: 'success', message: 'UnPublish Success' });
}, () => {
api.addMessage({ type: 'error', message: 'UnPublish Failed' });
});
};
退出频道
var leave = async function () {
// 离开频道 (核心代码)
client.leave().then(() => {
api.addMessage({ type: 'success', message: 'Leave Success' });
element.operationBox.join.disabled = false;
element.operationBox.join.classList.remove('disabled');
for (var key in element.operationBox) {
if (key !== 'join') {
element.operationBox[key].disabled = true;
element.operationBox[key].classList.add('disabled');
};
};
for (var key in element.configBox) {
element.configBox[key].value = '';
};
track.videoTrack.stop();
track.audioTrack.stop();
configuration = null;
offon = false;
publised = false;
remotePlay = false;
track = {
videoTrack: null,
audioTrack: null,
}
}, () => {
api.addMessage({ type: 'error', message: 'Leave Failed' });
});
};