一、背景
众所周知,浏览器本身不支持相互之间直接建立信道进行通信,都是通过服务器进行中转。WebRTC应运而生。WebRTC是一个开源项目,旨在使得浏览器能为实时通信(RTC)提供简单的JavaScript接口。说的简单明了一点就是让浏览器提供JS的即时通信接口。但是,使用WebRTC实现一个简易web版的视频通话很繁琐,无法简洁快速的进行开发,那么,如何简洁快速的实现简易web版的视频通话?本文将带大家一起来学习如何简洁快速的实现简易web版的视频通话。
为了简洁快速的实现我们的需求,我们就需要基于WebRTC基础上进行优化、集中的——anyRTC。大家肯定很好奇,anyRTC是什么?anyRTC 为开发者提供实时音视频 API,只需集成 anyRTC SDK,即可快速在应用内构建多种实时互动场景。开发者集成 anyRTC SDK 后,即可以调用不同 API,实现不同场景的实时互动。
二、项目准备
需求:web版的视频通话
用到的技术:anyRTC的RTC实时音视频api、anyRTC的RTM实时消息web api
注册anyRTC: **获取App ID **
需要使用到的RTM - SDK功能
- 创建RTM实时消息引擎:createInstance
- 登录:login
- 退出登录: logout
- 事件监听:on
- 主叫:createLocallnuvitation
- 发送呼叫邀请:send
- 取消呼叫邀请:cancel
- 接受呼叫邀请:accept
- 拒绝呼叫邀请:refuse
**需要使用的RTC - SDK功能 **
- 创建RTC音视频引擎:createClient
- 创建本地音频视频:createMicrophoneAndCameraTracks
- 加入频道:join
- 离开频道:leave
- 开启本地视频发送:publish
- 关闭本地视频发送:unpublish
- 订阅拉流:subscribe
- 取消订阅:unsubscribe
- 静音/取消静音:setEnabled
三、项目开发以及相关js代码
下载或引入 anyRTC
- script导入
使用 <script> 标签引入 SDK 时,产生名为 ArRTM 的全局变量,该变量含有该模块的所有成员。
<script src="https://ardw.anyrtc.io/sdk/web/ArRTM@latest.js"></script>
- npm 导入
npm install --save ar-rtm-sdk;
import ArRTM from "ar-rtm-sdk"; //导入项目
RTM相关
- 创建rtm实例
var rtmClient = ArRTM.createInstance(App ID );
rtmClient.login({uid: 用户id}); //用户id唯一 登录成功后才可以使用RTM
//rtmClient.logout(); //退出登录
- 被邀请用户(接受者)
//收到主叫邀请用户
rtmClient.on("RemoteInvitationReceived", function (remoteInvitation) {
//返回给被叫:接受呼叫邀请成功。
remoteInvitation.on("RemoteInvitationAccepted", async function (response) {
//获取传过来的频道房间
var invitationResponse = JSON.parse(response);
//加入实时通讯频道
await rtcClient.join(App ID, invitationContent.ChanId, null, null) //采集并发布媒体流
}
//返回给被叫:拒绝呼叫邀请成功。
remoteInvitation.on("RemoteInvitationRefused", function () {});
//返回给被叫:主叫已取消呼叫邀请。
remoteInvitation.on("RemoteInvitationCanceled", function (content) {});
//返回给被叫:呼叫邀请进程失败。
remoteInvitation.on("RemoteInvitationFailure", function (reason) {});
//接受邀请
remoteInvitation.accept(); //拒绝邀请
//remoteInvitation.refuse();
}
- 主叫邀请(发起者)
..........
//查询被邀请用户的状态 被邀请用户id calleeId 唯一
var userOnlineResults = await rtmClient.queryPeersOnlineStatus([calleeId]);
if (!userOnlineResults[calleeId] || !userOnlineResults[calleeId]) {
//不允许呼叫,因为对方不在线
return;
}
//创建呼叫邀请
var localInvitation = rtmClient.createLocalInvitation(calleeId);
//这里将呼叫邀请的内容 设置为视频通讯时使用的频道id - 进入同一个频道
localInvitation.content = JSON.stringify({
ChanId: "4562" , //符合命名规则即可
});
//发送呼叫邀请
localInvitation.send();
//返回给主叫:被叫已收到呼叫邀请。
localInvitation.on("LocalInvitationReceivedByPeer", function () {
//对方收到邀请,说明对方已经上线,这个时候应该监听对方的在线状态,如果对方离线 主动取消邀请(防止对方刷新或掉线时无法通知服务端)
rtmClient.subscribePeersOnlineStatus([localInvitation.calleeId]);
rtmClient.on("PeersOnlineStatusChanged", (userOnlineStatus) => {
if (userOnlineStatus[localInvitation.calleeId] === "OFFLINE" && Store.iscalling) {
localInvitation.cancel();
}
});
});
//返回给主叫:被叫已接受呼叫邀请。
localInvitation.on("LocalInvitationAccepted", async function (response) {
//获取传过来的频道房间
var invitationResponse = JSON.parse(response); //加入实时通讯频道
await rtcClient.join(App ID, invitationContent.ChanId, null, null)
//采集并发布媒体流});
//远端用户拒绝了你的呼叫邀请
localInvitation.on("LocalInvitationRefused", function (response) {});
//返回给主叫:呼叫邀请已被成功取消。
localInvitation.on("LocalInvitationCanceled", function () {});
//返回给主叫:呼叫邀请进程失败。
localInvitation.on("LocalInvitationFailure", function (reason) {});
.......
//发起者取消呼叫
//localInvitation.cancel();
.......
RTC相关
- 创建rtc实例
var rtcClient = ArRTC.createClient({
mode: "vp8", //编码格式
codec: rtc //使用场景
});
- 采集视频、音频 并进行预览、发布
......
//采集视频、音频设备
var [cameras, microhones] = await Promise.all([
ArRTC.getCameras(),
ArRTC.getMicrophones(),
]);
if (cameras.length === 0 && microhones.length === 0) {
alert("上麦失败!确实麦克风和摄像头");
return
}
if (cameras.length > 0 && microhones.length > 0) {
//创建音频、视频轨道
[audioTrack, videoTrack] = await ArRTC.createMicrophoneAndCameraTracks(
null, {
encoderConfig: {
bitrateMax: 1130,
// bitrateMin: ,
frameRate: 15,
height: 180,
width: 320,
}
}
);
} else {
if (!videoTrack && !audioTrack) {
alert("没有设备无法发布媒体流");
return
}
}
//预览本地图像 documentId 存放容器的id(html中的属性id)
videoTrack && videoTrack.play(documentId);
//把用户设置为主播角色
rtcClient.setClientRole("host");
//发布
rtcClient.publish([videoTrack, audioTrack])
- 监听相关回调
//通知远端用户发布了新的音频或者视频
rtcClient.on("user-published", async function (user, mediaType) {
//订阅发布的音频或者视频
await rtcClient.subscribe(user, mediaType);
});
//通知远端用户取消发布了音频或视频
rtcClient.on("user-unpublished", async function (user, mediaType) {});
//远端用户加入频道
rtcClient.on("user-joined", function (user) {});
//远端用户离线
rtcClient.on("user-left", function () {
//释放资源
videoTrack && (videoTrack.close(), videoTrack = null);
audioTrack && (audioTrack.close(), audioTrack = null);
rtcClient.leave(); //离开
});
//SDK 与服务器的连接状态发生改变回调
rtcClient.on("connection-state-change", async function (ConnectionState) {});
视频开关、音频开关
//视频开关
videoTrack.isMuted = !videoTrack.isMuted;
videoTrack.setEnabled(!videoTrack.isMuted);
//音频开关
audioTrack.isMuted = !audioTrack.isMuted;
audioTrack.setEnabled(!audioTrack.isMuted);
四、参考
相关demo
https://github.com/anyRTC-UseCase/ARCall