// SDK 配置
var Config = {
APPID: "0677ce568f8c4cebde8457399d89ee98", // 应用ID
RTC_MODE: "live", //RTC 通信模式
RTC_CODEC: "h264", //RTC 视频编码格式
SELECT_CAMERA_DEVICE:
sessionStorage.getItem("defaultCameraDeviceId") || undefined,
// RTC 私有云配置
RTC_setParameters: {
// 是否开启私有云配置
switch: false,
// setParameters: {
// //配置私有云网关
// ConfPriCloudAddr: {
// ServerAdd: "",
// Port: ,
// Wss: false,
// },
// },
},
// RTM 私有云配置
RTM_setParameters: {
// 是否开启私有云配置
switch: false,
// setParameters: {
// //配置内网网关
// confPriCloudAddr: {
// ServerAdd: "",
// Port: ,
// Wss: false,
// },
// },
},
};
// 页面工具类
var Utils = {
// 生成uid
generateNumber(len) {
var numLen = len || 8;
var generateNum = Math.ceil(Math.random() * Math.pow(10, numLen));
return generateNum < Math.pow(10, numLen - 1) ? Utils.generateNumber(numLen) : generateNum;
},
// 断网处理
updateOnlineStatus(e) {
// 仅p2p
if (!Store.Conference && Store.network.status != 0) {
const { type } = e;
Store.localwork = type === "online";
if (navigator.onLine) {
Store.networkSet && clearTimeout(Store.networkSet);
console.log("重连后查询对方状态信息", Store);
// 重连后查询对方状态信息
OperationPackge.p2p.networkSendInfo();
// 连网
} else {
Store.networkSet && clearTimeout(Store.networkSet);
Utils.alertWhole("网络异常");
// 断网 30s 无网络连接自动挂断
Store.networkSet = setTimeout(() => {
console.log("断网 30s 无网络连接自动挂断", Store);
Store.lineworkRTC = false;
OperationPackge.p2p.cancelCall(3);
}, 22000);
let oTimr = 0;
let onTimr = setInterval(() => {
oTimr++;
if (navigator.onLine || oTimr >= 22) {
clearInterval(onTimr);
Store.networkSet && clearTimeout(Store.networkSet);
}
}, 1000);
}
}
},
// 事件打印
printLog() {
console.log.apply(this, arguments);
},
// 局部警告框
alertError: function (errorText) {
var errMsg = $(
`
${errorText}
`
);
$("#warningBox").html("").append(errMsg);
//警告框自动消失
setTimeout(function () {
$('[data-dismiss="alert"]').alert("close");
}, 2000);
},
// 全局警告框
alertWhole: function (text, classStyle) {
if (!classStyle) {
classStyle = "alert-danger";
}
var oMsg = $(
`
${text}
`
);
$("#warningWholeBox").html("").append(oMsg);
//警告框自动消失
setTimeout(function () {
$('[data-dismiss="alert"]').alert("close");
}, 2000);
},
//修改标题名称
setPageTitle: function (title) {
$("title").html(title);
},
// 生成用户标签
createButtonUser: function (allInputVal) {
if (Store.invitationUserIds.length <= 5) {
if (
!~Store.invitationUserIds.indexOf(allInputVal) &&
allInputVal != Store.ownUserId
) {
// 并创建新的div存放
Store.invitationUserIds.push(allInputVal);
var opt = $(
'"
);
$("#multiUserBtn").append(opt);
} else {
Utils.alertError("该用户重复输入或不能输入自己");
}
} else {
Utils.alertWhole("不能一次邀请超过6个");
}
},
// 删除邀请用户标签
deleteButtonUser: function (item, userid) {
if (!!~Store.invitationUserIds.indexOf("" + userid)) {
item.remove();
Store.invitationUserIds.splice(
Store.invitationUserIds.indexOf("" + userid),
1
);
if (Store.invitationUserIds.length == 0) {
!$("#MultipleCalls").hasClass("disabled") &&
$("#MultipleCalls").addClass("disabled");
} else {
$("#MultipleCalls").hasClass("disabled") &&
$("#MultipleCalls").removeClass("disabled");
}
}
},
// 创建用户视图窗口 - 自定义用户状态: 0/1 等待应答/无人应答
createUserView: async function (userid, status) {
if ($(`#${userid}Window`).length == 0) {
// console.log("创建窗口", userid);
// 创建窗口
var box = $(
''
);
var basicView = $(
'" +
"" +
'' +
'
' +
"
" +
userid +
"
" +
"
"
);
var statusView = $(
"" +
'' +
'
' +
'' +
'' +
(status === 1 ? "无人应答" : status === 0 && "等待应答") +
"" +
"
" +
"
"
);
box.append(basicView);
if (status === 0 || status === 3) {
box.append(statusView);
// 创建计时
Store.invitationClearTimeouts["Timeouts" + userid] = setTimeout(
function () {
Utils.alertWhole("用户" + userid + "60s无人接听");
},
Store.invitationTimeout
);
}
$("#mineMutiTitleVideoPreview").append(box);
} else {
// console.log("已经创建视图");
Utils.updateUserViewStatus(userid, 1);
}
},
// 大小屏幕切换
switchover: function (user) {
$(`#${user.uid}Window`).bind("click", function () {
Utils.switchoverFnBind(user);
});
},
// 大小屏幕切换方法绑定
switchoverFnBind: async function (user) {
if (user.uid != Store.bigMutiUser.uid) {
// 切换对应左下角
Utils.switchoverLeftBottom(user.uid);
// 切换后大屏对应的小屏隐藏
Utils.switchoverHidden(user.uid, false);
// 原大屏对应的小屏展示
Utils.switchoverHidden(Store.bigMutiUser.uid, true);
// 设置为大流
if (user.videoTrack) {
user.videoTrack.stop();
Store.rtcClient
.setRemoteVideoStreamType(user.uid, 0)
.then(() => {
console.log("切换大流成功", user.uid);
})
.catch((err) => {
console.log("切换大流失败", user.uid, err);
});
await user.videoTrack.play("peerMutiVideoPreview", {
fit: "contain",
});
}
// 设置为小流
if (Store.bigMutiUser.videoTrack) {
Store.bigMutiUser.videoTrack.stop();
Store.rtcClient
.setRemoteVideoStreamType(Store.bigMutiUser.uid, 1)
.then(() => {
console.log("切换小流成功", Store.bigMutiUser.uid);
})
.catch((err) => {
console.log("切换小流失败", Store.bigMutiUser.uid, err);
});
await Store.bigMutiUser.videoTrack.play(
Store.bigMutiUser.uid + "VideoView",
{
fit: "contain",
}
);
}
// 本地视频窗口(大屏)
if (user.uid == Store.ownUserId) {
Utils.localVideoSwitch(user.uid, Store.setting.enableVideo);
} else {
$("#peerMutiVideoPreviewbasicView_img").hasClass(
"basicView_img_index"
) &&
$("#peerMutiVideoPreviewbasicView_img").removeClass(
"basicView_img_index"
);
// console.log("远端视频为大屏");
// Utils.localVideoSwitch(user.uid,true);
}
Store.bigMutiUser = user;
}
},
// 大小屏幕切换后,大小对应左下角切换
switchoverLeftBottom: function (bigUid) {
// 获取对应的音频类别
var oldbigUid = $("#" + bigUid + "AudioState")?.attr("class");
// 大屏对应左下角展示
var boxBig = $(
`
${bigUid}
`
);
$("#peerMutiVideoPreviewLeftBottom").html("");
$("#peerMutiVideoPreviewLeftBottom").append(boxBig);
},
// 大屏对应的小屏展示隐藏
switchoverHidden: function (bigUid, state) {
if (state) {
// 对应小屏展示
$("#" + bigUid + "Window").removeClass("d-none");
} else {
// 对应小屏隐藏
$("#" + bigUid + "Window").addClass("d-none");
}
},
// 本地视频开关触发样式
localVideoSwitch: function (uid, state) {
if (state) {
$("#peerMutiVideoPreviewbasicView_img").hasClass("basicView_img_index") &&
$("#peerMutiVideoPreviewbasicView_img").removeClass(
"basicView_img_index"
);
// 小屏
$("#" + uid + "basicView_img").hasClass("basicView_img_index") &&
$("#" + uid + "basicView_img").removeClass("basicView_img_index");
} else {
if (Store.bigMutiUser.uid == uid) {
!$("#peerMutiVideoPreviewbasicView_img").hasClass(
"basicView_img_index"
) &&
$("#peerMutiVideoPreviewbasicView_img").addClass(
"basicView_img_index"
);
}
!$("#" + uid + "basicView_img").hasClass("basicView_img_index") &&
$("#" + uid + "basicView_img").addClass("basicView_img_index");
}
},
// 更新用户在线状态
updateUserViewStatus: function (userid, status) {
// console.log("更新用户在线状态");
Store.invitationUserIds.map(function (item) {
if (item === userid) {
if (status === 1 || status === 2) {
// 自定义用户状态: 0/1/2/3 无人应答/对方同意/对方拒绝/对方不在线
$("#" + userid + "StatusView").remove();
// 停止计时
Store.invitationClearTimeouts["Timeouts" + userid] &&
clearTimeout(Store.invitationClearTimeouts["Timeouts" + userid]);
} else {
$("#" + userid + "Status").html(
status === 0 ? "等待应答" : status === 2 && "对方拒绝"
);
}
}
});
},
// 删除用户视图窗口
deleteUserView: async function (userid) {
// console.log("删除用户视图", userid);
// 停止计时
Store.invitationClearTimeouts["Timeouts" + userid] &&
clearTimeout(Store.invitationClearTimeouts["Timeouts" + userid]);
Store.invitationUserIds.map(function (item, index) {
if (item === userid) {
Store.invitationUserIds.splice(index, 1);
}
});
// 如果删除的视图有大视图,清空大视图存储数据
if (Store.bigMutiUser && Store.bigMutiUser.uid === userid) {
Store.bigMutiUser = {};
}
$("#" + userid + "Window") && (await $("#" + userid + "Window").remove());
// 频道内剩余两人时
var oUserData = await Store.rtmChannel.getMembers();
if (oUserData.length < 2) {
// 释放资源
await SdkPackge.RTC.LocalTracksClose();
// 恢复默认
await OperationPackge.public.restoreDefault();
await PageShow.initSetingMulti(); // 恢复初始
// 显示首页
await PageShow.showIndex();
}
},
// 更新用户音频状态
updateUserAudioState: function (userid, haveAudio) {
if (haveAudio) {
$("#" + userid + "AudioState").hasClass("icon-audio_close_slant") &&
$("#" + userid + "AudioState").removeClass("icon-audio_close_slant");
// 对应大屏
$("#" + userid + "BigAudioState")?.hasClass("icon-audio_close_slant") &&
$("#" + userid + "BigAudioState")?.removeClass(
"icon-audio_close_slant"
);
} else {
!$("#" + userid + "AudioState").hasClass("icon-audio_close_slant") &&
$("#" + userid + "AudioState").addClass("icon-audio_close_slant");
// 对应大屏
!$("#" + userid + "BigAudioState")?.hasClass("icon-audio_close_slant") &&
$("#" + userid + "BigAudioState")?.addClass("icon-audio_close_slant");
}
},
// 用户ID输入 用户删除id (仅能输入一位用户)
inputChangId: function (oid) {
//监听用户ID输入
$(oid).bind("input propertychange", function (event) {
var inputVal = $(this).val();
var reg = /^[0-9]+$/;
if (!reg.test(inputVal)) {
$(this).val("");
} else {
$(this).next("input").select();
$(this).next("input").focus();
}
var oItem = "";
for (var i = 0; i < $(oid).length; i++) {
oItem = oItem + $(oid)[i].value;
}
if (oItem.length == 4) {
$("#p2pAudioMakeCall").hasClass("disabled") &&
$("#p2pAudioMakeCall").removeClass("disabled");
$("#p2pVideoMakeCall").hasClass("disabled") &&
$("#p2pVideoMakeCall").removeClass("disabled");
oItem = "";
} else {
!$("#p2pAudioMakeCall").hasClass("disabled") &&
$("#p2pAudioMakeCall").addClass("disabled");
!$("#p2pVideoMakeCall").hasClass("disabled") &&
$("#p2pVideoMakeCall").addClass("disabled");
}
});
//监听用户删除id
$(oid).keydown(function (event) {
//删除往前 添加往后
if ($(this).index() < 4) {
if (event.keyCode == 46 || event.keyCode == 8) {
if (this.value === "") {
$(this).prev("input").val("");
$(this).prev("input").focus();
} else {
this.value = "";
}
// 按钮变暗
!$("#p2pAudioMakeCall").hasClass("disabled") &&
$("#p2pAudioMakeCall").addClass("disabled");
!$("#p2pVideoMakeCall").hasClass("disabled") &&
$("#p2pVideoMakeCall").addClass("disabled");
}
}
});
},
// 用户ID输入 用户删除id (输入多位用户并输出)
inputChangIds: function () {
// 监听用户ID输入 - 创建用户用户标签
$("#multiUserInputs > input").bind(
"input propertychange",
function (event) {
var inputVal = $(this).val();
var reg = /^[0-9]+$/;
if (!reg.test(inputVal)) {
$(this).val("");
} else {
$(this).next("input").select();
$(this).next("input").focus();
var allInputVal = "";
$("#multiUserInputs > input").each(function () {
allInputVal += this.value;
});
// 筛选并创建用户标签
if (allInputVal.length === 4) {
// 生成用户标签
Utils.createButtonUser(allInputVal);
// 清空所有输入框
$("#multiUserInputs > input").each(function () {
this.value = "";
});
$("#multiUserInputs > input")[0].focus();
}
}
if (Store.invitationUserIds.length == 0) {
!$("#MultipleCalls").hasClass("disabled") &&
$("#MultipleCalls").addClass("disabled");
} else {
$("#MultipleCalls").hasClass("disabled") &&
$("#MultipleCalls").removeClass("disabled");
}
}
);
// 监听用户删除id
$("#multiUserInputs > input").keydown(function (event) {
// 删除往前 添加往后
if ($(this).index() < 11) {
if (event.keyCode == 46 || event.keyCode == 8) {
if (this.value === "") {
$(this).prev("input").val("");
$(this).prev("input").focus();
} else {
this.value = "";
}
}
}
});
},
};
// 本地数据存储
var Store = {
// 麦克风设备记录
microhonesList: [],
// 摄像头设备记录
camerasList: [],
repetitionClick: false, // 按钮重复点击标记
Conference: false, // 选择的呼叫模式 false: p2p呼叫 true: 多人呼叫
Calling: false, // 正在通话中(标识)
JoinRTCChannel: false, // 加入 RTC 频道(标识)
rtcClient: null, // 存放 RTC 客户端
rtmClient: null, // 存放 RTM 客户端
rtmChannel: null, // 存放 RTM 频道实例
localInvitation: null, // 存放主叫邀请实例
invitationClearTimeouts: {}, // 存放多个有效期计时(定时器仅多人呼叫使用)
bigMutiUser: {}, // 大屏展示(仅多人呼叫使用)
recordUser: [], // 记录页面展示的音视频轨道(仅多人呼叫使用)
// 大屏展示(仅多人呼叫使用)
bigMutiUser: {
uid: "",
videoTrack: null,
},
remoteInvitation: null, // 存放被叫邀请实例
invitationTimeout: 58 * 1000, // 邀请有效期限
invitationClearTimeout: null, // 邀请有效期计时(定时器)
callDurationInterval: 0, // 通话时长
callDurationClearInterval: null, // 通话时长计时(定时器)
ownUserId: "" + Utils.generateNumber(11), //自己的用户ID - 这里需要转字符串
peerUserId: "", // 远端的用户的ID
// peerUserIdRTM: "", // 远端用户RTM的id
channelId: "" + Utils.generateNumber(9), // 频道房间
// RTC 本地采集的音视频轨道
localTracks: {
videoTrack: null,
audioTrack: null,
},
// RTC 远端视频轨道
remoteVideoTracks: null,
// 设置
setting: {
// p2p设置
// 是否显示视频相关数据
videoDataShow: false,
// 数据显示定时器
videoStatsInterval: null,
videoSize: [1920, 1080], //设置视频采集的分辨率大小
audioDevice: "default", // 设置音频设备ID
videoDevice: "default", // 设置视频设备ID
// 多人设置
enableAudio: true, // 声音开关
enableVideo: true, // 视频开关
},
invitationUserIds: [], // 存放多人通话的用户id
// 接听后频道无人
callChannelPro: null,
callChannelProTime: 15000,
localwork: true, // 本地网络
lineworkRTM: true, // RTM网络连接状态
lineworkRTC: true, // RTC网络连接状态
// 断网相关(p2p)
network: {
// type: "rtm", // 断网时所在页面 rtm rtc
calltype: 0, // 呼叫类型 0:主叫 1:被叫
status: 0, // 当前状态 呼叫中:1 已接受:2 挂断:0
Mode: 0, // 通话类型 语音、视频
},
networkSet: null, // 断网定时挂断
networkTime: 30000, // 断网定时挂断时间
remodVideoEnd: null, // 远端断网定时器
remodVideoEndTime: 10000,
networkReconnection: null, // 断网重连后发送信息无响应
networkReconnectionTime: 10000,
};
// 页面隐藏显示操作类
var PageShow = {
// 显示首页
showIndex: function () {
!$("#meetPage").hasClass("d-none") && $("#meetPage").addClass("d-none");
$("#homePage").hasClass("d-none") && $("#homePage").removeClass("d-none");
!$("#loginForm").hasClass("d-none") && $("#loginForm").addClass("d-none");
!$("#loginMutiFprm").hasClass("d-none") &&
$("#loginMutiFprm").addClass("d-none");
$("#loginHome").hasClass("d-none") && $("#loginHome").removeClass("d-none");
!$("#makeCallPage").hasClass("d-none") &&
$("#makeCallPage").addClass("d-none");
!$("#reciveCallPage").hasClass("d-none") &&
$("#reciveCallPage").addClass("d-none");
!$("#audioPage").hasClass("d-none") && $("#audioPage").addClass("d-none");
!$("#meetMutiPage").hasClass("d-none") &&
$("#meetMutiPage").addClass("d-none");
$("#openP2PInvite").click();
},
// 初始设置 (P2P)
initSetingP2P: function () {
// 清空所有输入框 (p2p)
$("#userInputs > input").each(function () {
this.value = "";
});
// 音频通话计时
$("#audioDuration").html("00:00");
// 视频通话计时
$("#videoDuration").html("00:00");
$("#userInputs > input")[0].focus();
$("#mineVideoPreview_bg").css("zIndex", "0");
$("#audioSwitchBtn > i")
.removeClass("icon-_yinpinguanbizhong")
.addClass("icon-_yinpinkaiqizhong icon_color_blue");
$("#mineVideoPreview").html($("#mineVideoPreview_bg"));
$("#peerVideoPreview").html($("#peerVideoPreview_bg"));
!$("#p2pAudioMakeCall").hasClass("disabled") &&
$("#p2pAudioMakeCall").addClass("disabled");
!$("#p2pVideoMakeCall").hasClass("disabled") &&
$("#p2pVideoMakeCall").addClass("disabled");
!$("#MultipleCalls").hasClass("disabled") &&
$("#MultipleCalls").addClass("disabled");
$("#loginMutiSetting").hasClass("show") &&
$("#loginMutiSetting").removeClass("show");
},
// 断网重连(p2p)
networkP2P: function () {
$("#peerVideoPreview").html($("#peerVideoPreview_bg"));
},
// 断网远端显示/隐藏(p2p)
networkRemoShow: function (fase = true) {
$("#peerVideoPreview").html("");
fase
? $("#peerVideoPreview").addClass("video-preview_big_network")
: $("#peerVideoPreview").removeClass("video-preview_big_network");
},
// 初始设置 (多人)
initSetingMulti: function () {
$("#mineMutiTitleVideoPreview").html(""); // 清空小窗口
$("#peerMutiVideoPreview").html(
$("#peerMutiVideoPreview #peerMutiVideoPreviewbasicView_img")
); // 清空大窗口
$("#callerIdView").html("");
$("#multiUserBtn").html(""); // 清空生成的标签
$("#loginMutiSetting").hasClass("show") &&
$("#loginMutiSetting").removeClass("show");
},
// 登录 RTM
loginRTM: function () {
$(".own-user-id-view").html(Store.ownUserId);
$("#openP2PInvite").attr("disabled", false);
$("#openMultiInvite").attr("disabled", false);
},
// 语音呼叫邀请页面
makeVoiceCall: function () {
$("#calleeIdView").html(Store.localInvitation.calleeId);
!$("#homePage").hasClass("d-none") && $("#homePage").addClass("d-none");
!$("#makeCallPage").hasClass("d-none") &&
$("#makeCallPage").addClass("d-none");
$("#audioPage").hasClass("d-none") && $("#audioPage").removeClass("d-none");
},
// 视频呼叫邀请页面
makeVideoCall: function () {
$("#calleeIdView").html(Store.localInvitation.calleeId);
!$("#homePage").hasClass("d-none") && $("#homePage").addClass("d-none");
!$("#audioPage").hasClass("d-none") && $("#audioPage").addClass("d-none");
$("#makeCallPage").hasClass("d-none") &&
$("#makeCallPage").removeClass("d-none");
},
// 被呼叫页面 是否转语音
toSpeech: function (params) {
params === 1
? $("#changAudioBtn").addClass("d-none")
: ($(".switch-audio-call_item").fadeIn(),
$("#changAudioBtn").removeClass("d-none"));
},
// 显示被呼叫页面
showCalledPage: function () {
$("#callerIdView").html(Store.remoteInvitation.callerId);
!$("#homePage").hasClass("d-none") && $("#homePage").addClass("d-none");
$("#reciveCallPage").hasClass("d-none") &&
$("#reciveCallPage").removeClass("d-none");
},
// 隐藏呼叫邀请页面
hiddenCallPage: function () {
!$("#makeCallPage").hasClass("d-none") && $("#makeCallPage").addClass("d-none");
$("#homePage").hasClass("d-none") && $("#homePage").removeClass("d-none");
!$("#loginForm").hasClass("d-none") && $("#loginForm").addClass("d-none");
!$("#loginMutiFprm").hasClass("d-none") &&
$("#loginMutiFprm").addClass("d-none");
$("#loginHome").hasClass("d-none") && $("#loginHome").removeClass("d-none");
$("#calleeIdView").html("");
// 如果在设置页面 退出设置页面
$("#closeSettingBtn").click();
$("#openP2PInvite").click();
},
// 隐藏被呼叫页面
hiddenCalledPage: function () {
!$("#reciveCallPage").hasClass("d-none") &&
$("#reciveCallPage").addClass("d-none");
$("#callerIdView").html("");
$("#openP2PInvite").click();
},
// 显示视频页面
showVideoPage: function () {
!$("#homePage").hasClass("d-none") && $("#homePage").addClass("d-none");
!$("#audioPage").hasClass("d-none") && $("#audioPage").addClass("d-none");
$("#meetPage").hasClass("d-none") && $("#meetPage").removeClass("d-none");
},
// 显示语音页面
showVoicePage: function () {
!$("#homePage").hasClass("d-none") && $("#homePage").addClass("d-none");
!$("#meetPage").hasClass("d-none") && $("#meetPage").addClass("d-none");
$("#audioPage").hasClass("d-none") && $("#audioPage").removeClass("d-none");
},
// 音频开关(p2p)
audioSwitch: function () {
if (Store.localTracks.audioTrack) {
Store.localTracks.audioTrack.isMuted
? $("#audioSwitchBtn > i")
.removeClass("icon-audio_open icon_color_blue")
.addClass("icon-audio_close")
: $("#audioSwitchBtn > i")
.removeClass("icon-audio_close")
.addClass("icon-audio_open icon_color_blue");
}
},
// 显示会议页面 (多人)
showMeetPage: function () {
!$("#homePage").hasClass("d-none") && $("#homePage").addClass("d-none");
!$("#audioPage").hasClass("d-none") && $("#audioPage").addClass("d-none");
!$("#meetPage").hasClass("d-none") && $("#meetPage").addClass("d-none");
!$("#reciveCallPage").hasClass("d-none") &&
$("#reciveCallPage").addClass("d-none");
$("#meetMutiPage").hasClass("d-none") &&
$("#meetMutiPage").removeClass("d-none");
},
// 本地麦克风状态
setEnableAudio: function (enable) {
if (enable) {
!$("#localAudioEnableIcon").hasClass("icon-audio_open") &&
$("#localAudioEnableIcon").addClass("icon-audio_open");
$("#localAudioEnableIcon").hasClass("icon-audio_close") &&
$("#localAudioEnableIcon").removeClass("icon-audio_close");
} else {
$("#localAudioEnableIcon").hasClass("icon-audio_open") &&
$("#localAudioEnableIcon").removeClass("icon-audio_open");
!$("#localAudioEnableIcon").hasClass("icon-audio_close") &&
$("#localAudioEnableIcon").addClass("icon-audio_close");
}
},
// 本地摄像头开关
setEnableVideo: function (enable) {
if (enable) {
!$("#localVideoEnableIcon").hasClass("icon-video_open") &&
$("#localVideoEnableIcon").addClass("icon-video_open");
$("#localVideoEnableIcon").hasClass("icon-video_close") &&
$("#localVideoEnableIcon").removeClass("icon-video_close");
} else {
$("#localVideoEnableIcon").hasClass("icon-video_open") &&
$("#localVideoEnableIcon").removeClass("icon-video_open");
!$("#localVideoEnableIcon").hasClass("icon-video_close") &&
$("#localVideoEnableIcon").addClass("icon-video_close");
}
Utils.localVideoSwitch(Store.ownUserId, enable);
},
};
// SDK 相关封装
var SdkPackge = {
// SDK 相关环境匹配
Support: {
// 硬件设备支持
hardwareSupport: async function () {
const mediaDevices = await ArRTC.getDevices();
const cameras = [];
const microhones = [];
mediaDevices.forEach((deviceInfo) => {
if (deviceInfo.kind === "audioinput") {
microhones.push(deviceInfo);
} else if (deviceInfo.kind === "videoinput") {
cameras.push(deviceInfo);
}
});
if (cameras.length === 0 && microhones.length === 0) {
Utils.alertWhole("缺少麦克风和摄像头设备", "alert-danger");
$("#MultipleCalls").prop("disabled", true);
return false;
} else {
if (cameras.length === 0) {
Store.setting.enableVideo = false;
$("#userVideoCameraSetting").prop("disabled", true);
}
if (microhones.length === 0) {
Store.setting.enableAudio = false;
$("#userMicrophoneSetting").prop("disabled", true);
}
}
// 记录麦克风设备
Store.microhonesList = microhones;
// 记录摄像头设备
Store.camerasList = cameras;
// 视频设备列表
SdkPackge.Support.camerasList(cameras);
// 音频设备列表
SdkPackge.Support.microhonesList(microhones);
return true;
},
// 视频设备状态变化
cameraChanged: async function (info) {
Utils.alertWhole("您的视频设备发生变化");
await SdkPackge.Support.hardwareSupport();
},
// 音频设备状态变化
microphoneChanged: async function (info) {
Utils.alertWhole("您的音频设备发生变化");
await SdkPackge.Support.hardwareSupport();
},
// 视频设备列表(可选择)
camerasList: function (cameras) {
$("#videoInputSelect").html("");
if (cameras.length > 0) {
cameras.map(function (camera, index) {
var label = camera.label !== "" ? camera.label : "Camera " + index;
var opt = $(
'"
);
$("#videoInputSelect").append(opt);
});
Store.setting.videoDevice = cameras[0].deviceId;
}
},
// 音频设备列表(可选择)
microhonesList: function (microhones) {
$("#audioInputSelect").html("");
if (microhones.length > 0) {
microhones.map(function (camera, index) {
var label =
camera.label !== "" ? camera.label : "Microphone " + index;
var opt = $(
'"
);
$("#audioInputSelect").append(opt);
});
Store.setting.audioDevice = microhones[0].deviceId;
}
},
},
// RTC 相关
RTC: {
// RTC 初始化
init: function () {
// console.log("初始化RTC");
// 创建RTC客户端
Store.rtcClient = ArRTC.createClient({
mode: Config.RTC_MODE,
codec: Config.RTC_CODEC,
});
// 配置私有云
Config.RTC_setParameters.switch
? Store.rtcClient.setParameters(Config.RTC_setParameters.setParameters)
: "";
// RTC SDK 监听用户发布
Store.rtcClient.on("user-published", SdkPackge.RTC.userPublished);
// RTC SDK 监听用户取消发布
Store.rtcClient.on("user-unpublished", SdkPackge.RTC.userUnpublished);
// RTC SDK 监听用户加入频道成功
Store.rtcClient.on("user-joined", SdkPackge.RTC.userJoined);
// RTC SDK 监听用户离开频道
Store.rtcClient.on("user-left", SdkPackge.RTC.userLeft);
// RTC SDK 连接状态
Store.rtcClient.on(
"connection-state-change",
SdkPackge.RTC.connectionStateChange
);
},
// 用户发布
userPublished: async function (user, mediaType) {
// 订阅用户发布的音视频
await Store.rtcClient.subscribe(user, mediaType);
// console.log("用户" + user.uid + "发布" + mediaType);
Utils.printLog("[info] subscribe success");
// 模式判断 多人/p2p
Store.Conference
? OperationPackge.multi.userPublished(user, mediaType)
: OperationPackge.p2p.userPublished(user, mediaType);
},
// 用户取消发布
userUnpublished: async function (user, mediaType) {
Utils.printLog("[info] user-unpublished success");
// 模式判断 多人/p2p
Store.Conference
? OperationPackge.multi.userUnpublished(user, mediaType)
: OperationPackge.p2p.userUnpublished(user, mediaType);
},
// 用户加入频道
userJoined: async function (user) {
// console.log("用户加入频道" + user.uid);
// 多人操作
if (Store.Conference) {
// 更新视图
Utils.updateUserViewStatus(user.uid, 1);
} else {
OperationPackge.p2p.userJoined(user);
}
},
// 用户离开频道
userLeft: async function (user, reason) {
// console.log("用户离开频道", user);
// 模式判断 多人/p2p
Store.Conference
? OperationPackge.multi.userLeft(user, reason)
: OperationPackge.p2p.userLeft(user, reason);
},
// SDK 与服务器的连接状态发生改变
connectionStateChange: async function (curState, revState, reason) {
Store.lineworkRTC =
curState == "CONNECTED" || curState == "DISCONNECTED" ? true : false;
if (curState != "DISCONNECTED") {
Utils.alertWhole(
Store.lineworkRTC ? "RTC 连接成功" : "RTC 连接中",
Store.lineworkRTC ? "alert-success" : "alert-info"
);
}
},
// 本地采集用户音视频
getUserMedia: async function () {
if (Store.camerasList.length === 0 && Store.microhonesList.length === 0) {
await SdkPackge.Support.hardwareSupport();
}
if (Store.Conference) {
// 多人模式
if (Store.camerasList.length > 0 && Store.setting.enableVideo) {
// 开启双流
Store.rtcClient
.enableDualStream()
.then(() => {
console.log("开启双流 Enable Dual stream success!");
})
.catch((err) => {
console.log("开启双流失败", err);
});
Store.localTracks.videoTrack = await ArRTC.createCameraVideoTrack({
cameraId: Store.setting.videoDevice,
encoderConfig: {
bitrateMax: 1130,
// bitrateMin: ,
frameRate: 15,
height: Store.setting.videoSize[1],
width: Store.setting.videoSize[0],
},
}).catch(function (err) {
console.log("err => ", err);
});
}
if (Store.microhonesList.length > 0 && Store.setting.enableAudio) {
Store.localTracks.audioTrack = await ArRTC.createMicrophoneAudioTrack(
{
microphoneId: Store.setting.audioDevice,
}
).catch(function (err) {
console.log("err => ", err);
});
}
} else {
// p2p 模式
if (Store.camerasList.length > 0) {
Store.localTracks.videoTrack = await ArRTC.createCameraVideoTrack({
cameraId: Store.setting.videoDevice,
encoderConfig: {
bitrateMax: 1130,
// bitrateMin: ,
frameRate: 15,
height: Store.setting.videoSize[1],
width: Store.setting.videoSize[0],
},
}).catch(function (err) {
console.log("err => ", err);
});
}
if (Store.microhonesList.length > 0) {
Store.localTracks.audioTrack = await ArRTC.createMicrophoneAudioTrack(
{
microphoneId: Store.setting.audioDevice,
}
).catch(function (err) {
console.log("err => ", err);
});
}
}
// 音频展示(p2p)
PageShow.audioSwitch();
},
// 本地采集用户音频并发布(多人默认关闭音频再打开音频时调用)
getUserMicrophonesPublish: async function () {
var microhones = await ArRTC.getMicrophones();
if (microhones.length > 0) {
Store.localTracks.audioTrack = await ArRTC.createMicrophoneAudioTrack({
microphoneId: Store.setting.audioDevice,
}).catch(function (err) {
console.log("err => ", err);
});
// 发布音频
Store.rtcClient.publish(Store.localTracks.audioTrack);
}
},
// 发布本地采集的音视频track
publishLocalTracks: async function () {
// console.log("发布本地采集的音视频track");
if (Store.localTracks.videoTrack || Store.localTracks.audioTrack) {
// 设置主播身份
await Store.rtcClient.setClientRole("host");
if (Store.localTracks.videoTrack || Store.localTracks.audioTrack) {
Store.rtcClient.publish(Object.values(Store.localTracks));
}
// Store.localTracks.videoTrack &&
// Store.rtcClient.publish(Store.localTracks.videoTrack);
// Store.localTracks.audioTrack &&
// Store.rtcClient.publish(Store.localTracks.audioTrack);
}
},
// 取消本地发布
unpublishLocalTracks: async function () {
// 取消本地音频发布
Store.localTracks.audioTrack &&
Store.localTracks.audioTrack.on("track-ended", () => {
Store.rtcClient.unpublish(Store.localTracks.audioTrack);
});
// 取消本地视频发布
Store.localTracks.videoTrack &&
Store.localTracks.videoTrack.on("track-ended", () => {
Store.rtcClient.unpublish(Store.localTracks.videoTrack);
$("#" + Store.ownUserId + "VideoView").html(
$("#" + Store.ownUserId + "VideoView" + " " + "img")
);
});
},
// 释放采集设备
LocalTracksClose: function () {
Store.localTracks.videoTrack &&
(Store.localTracks.videoTrack.close(),
(Store.localTracks.videoTrack = null));
Store.localTracks.audioTrack &&
(Store.localTracks.audioTrack.close(),
(Store.localTracks.audioTrack = null));
},
},
// RTM 相关
RTM: {
// RTM 初始化
init: function () {
// 创建 RTM 客户端
// console.log("初始化RTM")
Store.rtmClient = ArRTM.createInstance(Config.APPID);
// 配置私有云
Config.RTM_setParameters.switch
? Store.rtmClient.setParameters(Config.RTM_setParameters.setParameters)
: "";
// 配置私有云
// 登录 RTM
Store.rtmClient
.login({
uid: Store.ownUserId,
})
.then(function () {
Store.rtcLogin = true;
// 页面操作
PageShow.loginRTM();
})
.catch(function (err) {
Store.rtcLogin = false;
Utils.alertWhole("RTM 登录失败", "alert-danger");
});
// 监听收到来自主叫的呼叫邀请
Store.rtmClient.on(
"RemoteInvitationReceived",
SdkPackge.RTM.RemoteInvitationReceived
);
// 监听收到来自对端的点对点消息
Store.rtmClient.on("MessageFromPeer", SdkPackge.RTM.MessageFromPeer);
// 通知 SDK 与 RTM 系统的连接状态发生了改变
Store.rtmClient.on(
"ConnectionStateChanged",
SdkPackge.RTM.ConnectionStateChanged
);
},
// 收到来自主叫的呼叫邀请
RemoteInvitationReceived: async function (remoteInvitation) {
Utils.printLog(
"[info]",
"You recive an invitation from " + remoteInvitation.callerId
);
// 是否正在通话
if (Store.Calling) {
// 正在通话中
await OperationPackge.public.callIng(remoteInvitation);
} else {
// 存放被叫实例
Store.remoteInvitation = remoteInvitation;
// 解析主叫呼叫信息
var invitationContent = JSON.parse(remoteInvitation.content);
// 关闭设置
await OperationPackge.p2p.closeSeting();
// 标识为正在通话中
Store.Calling = true;
if (
!invitationContent.VidCodec ||
!invitationContent.AudCodec ||
(invitationContent.VidCodec &&
invitationContent.VidCodec.indexOf("H264") !== -1) ||
(invitationContent.AudCodec &&
invitationContent.AudCodec.indexOf("Opus") !== -1)
) {
Store.Conference = invitationContent.Conference;
// 远端
Store.peerUserId = remoteInvitation.callerId;
Store.Conference // 多人逻辑操作
? OperationPackge.multi.RemoteInvitationReceived(invitationContent) // p2p逻辑操作
: OperationPackge.p2p.RemoteInvitationReceived(invitationContent);
} else {
// 手表不支持 web 端
await OperationPackge.public.watches(remoteInvitation);
}
}
},
// 收到来自对端的点对点消息
MessageFromPeer: function (message, peerId, messageProps) {
message.text = JSON.parse(message.text);
// console.log("收到来自对端的点对点消息", message);
switch (message.text.Cmd) {
case "SwitchAudio":
// 视频转语音
var oTime = setInterval(async function () {
if (Store.localTracks.videoTrack) {
clearInterval(oTime);
// 语音通话
await PageShow.showVoicePage();
// 关闭视频并释放
(await Store.localTracks.videoTrack) &&
(Store.localTracks.videoTrack.close(),
(Store.localTracks.videoTrack = null));
Store.setting.videoStatsInterval &&
clearInterval(Store.setting.videoStatsInterval);
// console.log("关闭视频并释放", Store.localTracks.videoTrack);
// 显示音频通话时长
OperationPackge.public.communicationDuration("audioDuration");
Utils.alertWhole("视频通话转为音频通话", "alert-success");
}
}, 500);
break;
case "EndCall":
if (Store.localTracks.audioTrack || Store.localTracks.videoTrack) {
OperationPackge.p2p.hangupInfo();
}
break;
case "CallState":
// 收到此信令返回给对方状态
if (peerId === Store.peerUserId) {
Store.networkReconnection &&
clearTimeout(Store.networkReconnection);
}
// 回复
OperationPackge.p2p.replySendInfo(peerId);
break;
case "CallStateResult":
Store.networkReconnection && clearTimeout(Store.networkReconnection);
console.log("本地断网重连后对方状态", message, peerId);
break;
default:
break;
}
},
// SDK 与 RTM 系统的连接状态
ConnectionStateChanged: async function (newState, reason) {
Store.lineworkRTM = newState == "CONNECTED" ? true : false;
Utils.alertWhole(
Store.lineworkRTM ? "RTM 连接成功" : "RTM 连接中",
Store.lineworkRTM ? "alert-success" : "alert-info"
);
console.log("SDK 与 RTM 系统的连接状态", newState, reason);
if (newState === "RECONNECTING" && Store.network.status != 0) {
Utils.alertWhole("网络异常");
}
},
},
// RTM 频道相关(多人通话使用)
RTMChannel: {
init: function () {
Store.rtmChannel = Store.rtmClient.createChannel(Store.channelId);
// 监听频道消息
Store.rtmChannel.on(
"ChannelMessage",
OperationPackge.multi.ChannelMessage
);
// 监听频道人员加入, 如果人数超过512,该回调失效
Store.rtmChannel.on("MemberJoined", OperationPackge.multi.MemberJoined);
// 监听频道人员离开
Store.rtmChannel.on("MemberLeft", OperationPackge.multi.MemberLeft);
},
},
};
// 此应用使用的相关逻辑操作封装
var OperationPackge = {
// 公共的操作
public: {
// 回退到首页
backToHome: async function () {
!$("#loginForm").hasClass("d-none") && $("#loginForm").addClass("d-none");
!$("#loginMutiFprm").hasClass("d-none") &&
$("#loginMutiFprm").addClass("d-none");
$("#loginHome").hasClass("d-none") &&
$("#loginHome").removeClass("d-none");
Utils.setPageTitle("anyrtc 呼叫邀请DEMO - anyRTC");
},
// 通讯时长 id 传入要显示的元素id (现仅提供p2p操作)
communicationDuration: function (id) {
// 清除视频通话时长
Store.callDurationClearInterval &&
clearInterval(Store.callDurationClearInterval);
Store.callDurationClearInterval = setInterval(function () {
Store.callDurationInterval++;
var oMin = Math.floor(Store.callDurationInterval / 60);
var oSec = Math.floor(Store.callDurationInterval % 60);
oMin >= 10 ? oMin : (oMin = "0" + oMin);
oSec >= 10 ? oSec : (oSec = "0" + oSec);
$("#" + id).text(oMin + ":" + oSec);
}, 1000);
},
// 本地存储恢复
restoreDefault: function () {
// console.log("加入RTC频道", Store.JoinRTCChannel);
Store.rtcClient && Store.JoinRTCChannel && Store.rtcClient.leave();
Store.rtmChannel && Store.Conference && Store.rtmChannel.leave();
// 邀请有效期计时(定时器)
Store.invitationClearTimeout &&
clearTimeout(Store.invitationClearTimeout);
// 清除通话计时
Store.callDurationClearInterval &&
(clearInterval(Store.callDurationClearInterval),
(Store.callDurationClearInterval = null));
// 清除视频数据展示
Store.setting.videoStatsInterval &&
clearInterval(Store.setting.videoStatsInterval);
Store.networkSet && clearTimeout(Store.networkSet);
Store.remodVideoEnd && clearTimeout(Store.remodVideoEnd);
// 恢复
Object.assign(Store, {
Conference: false, // 选择的呼叫模式 false: p2p呼叫 true: 多人呼叫
invitationTimeout: 58 * 1000, // 邀请有效期限
invitationClearTimeout: null, // 邀请有效期计时(定时器)
callDurationInterval: 0, // 通话时长
callDurationClearInterval: null, // 通话时长计时(定时器)
localInvitation: null, // 存放主叫邀请实例
remoteInvitation: null, // 存放被叫邀请实例
rtmChannel: null, // 存放 RTM 频道实例
Calling: false, // 正在通话中(标识)
JoinRTCChannel: false, // 加入 RTC 频道(标识)
// hangupMuti: false, // 主叫挂断(仅多人使用)
peerUserId: "", // 远端的用户的ID
channelId: "" + Utils.generateNumber(9), // 频道房间
invitationUserIds: [],
// RTC 本地采集的音视频轨道
localTracks: {
videoTrack: null,
audioTrack: null,
},
// 断网相关(p2p)
network: {
// type: "rtm", // 断网时所在页面 rtm rtc
calltype: 0, // 呼叫类型 0:主叫 1:被叫
status: 0, // 当前状态 呼叫中:1 已接受:2 挂断:0
Mode: 0, // 通话类型 语音、视频
},
networkSet: null,
remodVideoEnd: null,
recordUser: [], // 记录页面展示的音视频轨道(仅多人呼叫使用)
// 大屏展示(仅多人呼叫使用)
bigMutiUser: {
uid: "",
videoTrack: null,
},
invitationClearTimeouts: {}, // 存放多个有效期计时(定时器仅多人呼叫使用)
});
},
// 正在通话中
callIng: async function (remoteInvitation) {
// 是否正在通话中
// console.log("正在通话中", Store.ownUserId);
remoteInvitation.response = await JSON.stringify({
// Reason: "Calling",
refuseId: Store.ownUserId,
Reason: "calling",
Cmd: "Calling",
});
await remoteInvitation.refuse();
},
// 手表不支持 web 通话
watches: async function (remoteInvitation) {
remoteInvitation.response = await JSON.stringify({
// Reason: "Calling",
refuseId: Store.ownUserId,
Reason: "calling",
Cmd: "platfrom",
});
await remoteInvitation.refuse();
},
},
p2p: {
// 语音呼叫
makeVoiceCall: async function () {
// 关闭设置
await OperationPackge.p2p.closeSeting();
// 获取输入的用户
var oPeerId = await OperationPackge.p2p.getPeerUserId();
// 查询输入用户合法性
Store.peerUserId = await OperationPackge.p2p.peerUserVaplidity(oPeerId);
if (Store.peerUserId) {
Store.repetitionClick = true;
Store.network = Object.assign(Store.network, {
// type: "rtm",
calltype: 0, // 主叫
status: 1, // 呼叫中
Mode: 1,
});
await OperationPackge.p2p.createLocalInvitationAndSend(1);
// 恢复初始设置
await PageShow.initSetingP2P();
// 显示呼叫邀请页面
await PageShow.makeVideoCall();
Store.repetitionClick = false;
}
},
// 视频呼叫
makeVideoCall: async function () {
// 关闭设置
await OperationPackge.p2p.closeSeting();
var oPeerId = await OperationPackge.p2p.getPeerUserId();
Store.peerUserId = await OperationPackge.p2p.peerUserVaplidity(oPeerId);
if (Store.peerUserId) {
Store.repetitionClick = true;
Store.network = Object.assign(Store.network, {
// type: "rtm",
calltype: 0, // 主叫
status: 1, // 呼叫中
Mode: 1,
});
await OperationPackge.p2p.createLocalInvitationAndSend(0);
// 恢复初始设置
await PageShow.initSetingP2P();
// 显示呼叫邀请页面
await PageShow.makeVideoCall();
Store.repetitionClick = false;
OperationPackge.p2p.videoStats();
}
},
// 接受呼叫
acceptCall: async function (type) {
// console.log("接受呼叫");
var invitationContent = await JSON.parse(Store.remoteInvitation.content);
Store.network = await Object.assign(Store.network, {
// type: "rtm",
calltype: 1, // 被叫
status: 2, // 呼叫中
Mode: invitationContent.Mode,
});
if (invitationContent.Mode === 1 || type === "语音呼叫") {
// 设置响应模式
Store.remoteInvitation.response = await JSON.stringify({
Mode: 1,
Conference: false,
UserData: "",
SipData: "",
});
// 显示语音页面
PageShow.showVoicePage();
} else if (invitationContent.Mode === 0 && type === "视频呼叫") {
Store.remoteInvitation.response = JSON.stringify({
Mode: 0,
Conference: false,
UserData: "",
SipData: "",
});
OperationPackge.p2p.videoStats();
// 显示视频页面
PageShow.showVideoPage();
}
// 接受呼叫
await Store.remoteInvitation.accept();
await PageShow.hiddenCalledPage();
},
// 取消当前通话
cancelCall: async function (type = 0) {
Store.invitationClearTimeout &&
clearTimeout(Store.invitationClearTimeout);
// 隐藏被呼叫页面
await PageShow.hiddenCallPage();
// 页面恢复初始
await PageShow.initSetingP2P();
// 回到首页
await PageShow.showIndex();
switch (type) {
case 0:
Utils.alertWhole("通话已结束", "alert-success");
break;
case 1:
Utils.alertWhole("网络异常,结束通话", "alert-warning");
break;
case 2:
// Utils.alertWhole("已拒绝邀请", "alert-info");
break;
case 3:
Utils.alertWhole("网络连接断开", "alert-warning");
break;
default:
break;
}
Store.network = await Object.assign(Store.network, {
status: 0,
});
// 网络正常后
let oNormal = setInterval(() => {
if (navigator.onLine) {
if (Store.lineworkRTC && Store.lineworkRTM) {
clearInterval(oNormal);
if (Store.JoinRTCChannel) {
// 加入 RTC 频道后挂断 发送挂断信息
Store.rtmClient &&
Store.rtmClient
.sendMessageToPeer(
{
text: JSON.stringify({
Cmd: "EndCall",
}),
},
Store.peerUserId // 对端用户的 uid。
)
.catch((err) => {
// 你的代码:点对点消息发送失败。
// console.log(err);
});
/** 设备采集后释放/无设备后4s后自动释放 */
let time = 0;
const timer = setInterval(async () => {
time++;
if (
time >= 20 ||
Store.localTracks.audioTrack ||
Store.localTracks.videoTrack
) {
clearInterval(timer);
// 释放采集设备
await SdkPackge.RTC.LocalTracksClose();
await OperationPackge.public.restoreDefault();
// 隐藏被呼叫页面
await PageShow.hiddenCallPage();
// 页面恢复初始
await PageShow.initSetingP2P();
// 回到首页
await PageShow.showIndex();
}
}, 200);
} else if (type != 2) {
if (Store.network.calltype == 0) {
// 挂断
Store.localInvitation && Store.localInvitation.cancel();
} else {
// 拒绝接听
Store.remoteInvitation && Store.remoteInvitation.refuse();
}
} else {
OperationPackge.public.restoreDefault();
}
}
}
}, 200);
},
// 音视频设置
setOperation: async function (data) {
switch (data) {
case "分辨率":
Store.localTracks.videoTrack.setEncoderConfiguration({
height: Store.setting.videoSize[1],
width: Store.setting.videoSize[0],
});
break;
case "设置音频设备":
Store.localTracks.audioTrack.setDevice(Store.setting.audioDevice);
break;
case "设置视频设备":
Store.localTracks.videoTrack.setDevice(Store.setting.videoDevice);
break;
default:
break;
}
},
// 视频相关数据
videoStats: function () {
Store.setting.videoStatsInterval &&
clearInterval(Store.setting.videoStatsInterval);
if (Store.setting.videoDataShow) {
// var oa = null;
Store.setting.videoStatsInterval = setInterval(async function () {
// 通话总数据
const oCallAll = await Store.rtcClient.getRTCStats();
// 本地音频数据
const oLocalAudio = await Store.rtcClient.getLocalAudioStats();
// console.log("本地音频数据", oLocalAudio);
// 本地视频数据
const oLocalVideo = await Store.rtcClient.getLocalVideoStats();
// console.log("本地视频数据", oLocalVideo);
if (oLocalVideo) {
$("#userLocalVideoData").removeClass("d-none");
const oLocalVideoList = [
{
description: "视频采集分辨率(高*宽)",
value:
(oLocalVideo.captureResolutionHeight || 0) +
" * " +
(oLocalVideo.captureResolutionWidth || 0),
unit: "",
},
{
description: "实际发送分辨率(高*宽)",
value:
(oLocalVideo.sendResolutionHeight || 0) +
" * " +
(oLocalVideo.sendResolutionWidth || 0),
unit: "",
},
{
description: "视频采集帧率",
value: oLocalVideo.captureFrameRate || 0,
unit: "fps",
},
{
description: "网络延迟RTT",
value: oCallAll.RTT || 0,
unit: "ms",
},
{
description: "发送带宽",
value: (
(Number(oLocalAudio.sendBitrate || 0) +
Number(oLocalVideo.sendBitrate || 0)) /
1024 /
8
).toFixed(3),
unit: "kB/s",
},
{
description: "接收带宽",
value: ((Number(oCallAll.RecvBitrate) || 0) / 1024 / 8).toFixed(
3
),
unit: "kB/s",
},
{
description: "音频发送丢包率",
value: Number(oLocalAudio.packetLossRate || 0).toFixed(3),
unit: "%",
},
{
description: "视频发送丢包率",
value: Number(oLocalVideo.packetLossRate || 0).toFixed(3),
unit: "%",
},
// {
// description: "视频编码格式",
// value: oLocalVideo.codecType || "",
// unit: "",
// },
// {
// description: "视频编码延迟",
// value: oLocalVideo.encodeDelay || 0,
// unit: "ms",
// },
// {
// description: "视频发送码率",
// value: oLocalVideo.sendBitrate || 0,
// unit: "bps",
// },
// {
// description: "发送的视频总字节数",
// value: oLocalVideo.sendBytes || 0,
// unit: "bytes",
// },
// {
// description: "发送的视频总包数",
// value: oLocalVideo.sendPackets || 0,
// unit: "",
// },
// {
// description: "发送的视频总丢包数",
// value: oLocalVideo.sendPacketsLost || 0,
// unit: "",
// },
// {
// description: "视频目标发送码率",
// value: oLocalVideo.targetSendBitrate || 0,
// unit: "bps",
// },
// {
// description: "视频总时长",
// value: oLocalVideo.totalDuration || 0,
// unit: "s",
// },
// {
// description: "视频总卡顿时长",
// value: oLocalVideo.totalFreezeTime || 0,
// unit: "s",
// },
];
$("#userLocalVideoData").html(`
${oLocalVideoList
.map(
(stat) =>
`${stat.description}: ${stat.value} ${stat.unit}
`
)
.join("")}`);
} else {
$("#userLocalVideoData").addClass("d-none");
}
// 远端视频数据
const oRemoVideoData = await Store.rtcClient.getRemoteVideoStats();
const oRemoVideo = oRemoVideoData[Store.peerUserId];
// console.log("远端视频数据", oRemoVideo);
// 远端音频数据
const oRemoAudioData = await Store.rtcClient.getRemoteAudioStats();
const oRemoAudio = oRemoAudioData[Store.peerUserId];
// console.log("远端音频数据", oRemoAudio);
if (oRemoVideo && oRemoAudio) {
$("#userRemodeVideoData").removeClass("d-none");
const oRemoVideoList = [
{
description: "视频接收分辨率(高*宽)",
value:
(oRemoVideo.receiveResolutionHeight || 0) +
" * " +
(oRemoVideo.receiveResolutionWidth || 0),
unit: "",
},
{
description: "视频接收帧率",
value: oRemoVideo.receiveFrameRate || 0,
unit: "fps",
},
{
description: "接收带宽",
value: (
((Number(oRemoVideo.receiveBitrate) || 0) +
(Number(oRemoAudio.receiveBitrate) || 0)) /
1024 /
8
).toFixed(3),
unit: "kB/s",
},
{
description: "视频接收丢包率",
value: Number(oRemoVideo.packetLossRate || 0).toFixed(3),
unit: "%",
},
{
description: "音频接收丢包率",
value: Number(oRemoAudio.packetLossRate || 0).toFixed(3),
unit: "%",
},
// {
// description: "视频解码帧率",
// value: oRemoVideo.decodeFrameRate || 0,
// unit: "fps",
// },
// {
// description: "视频渲染帧率",
// value: oRemoVideo.renderFrameRate || 0,
// unit: "fps",
// },
// {
// description: "远端视频编码格式",
// value: oRemoVideo.codecType || "",
// unit: "",
// },
// {
// description: "传输延迟",
// value: oRemoVideo.transportDelay || 0,
// unit: "ms",
// },
// {
// description: "视频端到端延迟",
// value: oRemoVideo.end2EndDelay || 0,
// unit: "ms",
// },
// {
// description: "接收视频延迟",
// value: oRemoVideo.receiveDelay || 0,
// unit: "ms",
// },
// {
// description: "接收的视频卡顿率",
// value: oRemoVideo.freezeRate || 0,
// unit: "",
// },
// {
// description: "接收的视频总字节数",
// value: oRemoVideo.receiveBytes || 0,
// unit: "bytes",
// },
// {
// description: "接收的视频总包数",
// value: oRemoVideo.receivePackets || 0,
// unit: "",
// },
// {
// description: "接收的视频总丢包数",
// value: oRemoVideo.receivePacketsLost || 0,
// unit: "",
// },
// {
// description: "接收的视频总时长",
// value: oRemoVideo.totalDuration || 0,
// unit: "s",
// },
// {
// description: "接收的视频总卡顿时长",
// value: oRemoVideo.totalFreezeTime || 0,
// unit: "s",
// },
];
$("#userRemodeVideoData").html(`
${oRemoVideoList
.map(
(stat) =>
`${stat.description}: ${stat.value} ${stat.unit}
`
)
.join("")}`);
} else {
$("#userRemodeVideoData").addClass("d-none");
}
}, 1000);
} else {
$("#userLocalVideoData").addClass("d-none");
$("#userRemodeVideoData").addClass("d-none");
}
},
// 关闭设置
closeSeting: function () {
var oTimeTemporary = setInterval(async function () {
if (Store.localTracks.videoTrack || Store.localTracks.audioTrack) {
clearInterval(oTimeTemporary);
$("#loginSetting").hasClass("show") &&
($("#loginSetting").removeClass("show"),
$("#loginMutiSetting").hasClass("show") &&
$("#loginMutiSetting").removeClass("show"),
SdkPackge.RTC.LocalTracksClose());
} else {
clearInterval(oTimeTemporary);
$("#loginSetting").hasClass("show") &&
($("#loginSetting").removeClass("show"),
$("#loginMutiSetting").hasClass("show") &&
$("#loginMutiSetting").removeClass("show"));
}
}, 50);
},
// 获取输入的用户
getPeerUserId: function () {
var calleeId = "";
$("#userInputs > input").each(function (index, el) {
var inputVal = el.value;
if (inputVal === "") {
el.focus();
Utils.alertError("请输入完整的用户ID");
return false;
}
calleeId += inputVal;
});
return calleeId;
},
// 查询输入用户合法性
peerUserVaplidity: async function (calleeId) {
if (calleeId.length === 11) {
//查询状态
var userOnlineResults = await Store.rtmClient.queryPeersOnlineStatus([
calleeId,
]);
if (!userOnlineResults[calleeId] || !userOnlineResults[calleeId]) {
Utils.alertError("不允许呼叫,因为对方不在线");
return;
}
if (calleeId == Store.ownUserId) {
//清空表单
$("#userInputs > input").each(function (index, el) {
el.value = "";
});
Utils.alertError("不能呼叫自己");
return;
}
return calleeId;
}
},
// RTM 主叫: 创建呼叫邀请并发送 (callMode: 视频通话 0 语音通话 1)
createLocalInvitationAndSend: async function (callMode) {
Store.JoinRTCChannel = true;
// 加入实时通讯频道
Store.ownUserId = await Store.rtcClient.join(
Config.APPID,
Store.channelId,
null,
Store.ownUserId
);
// 创建呼叫邀请
Store.localInvitation = Store.rtmClient.createLocalInvitation(
Store.peerUserId
);
// 这里将呼叫邀请的内容 设置为视频通讯时使用的频道id - 进入同一个频道
Store.localInvitation.content = JSON.stringify({
Mode: callMode, // 呼叫类型 视频通话 0 语音通话 1
Conference: false, // 是否是多人会议
ChanId: Store.channelId, // 频道房间
UserData: "",
SipData: "",
VidCodec: ["H264"],
AudCodec: ["Opus"],
});
// 发送呼叫邀请
Store.localInvitation.send();
Utils.printLog("[info]", "you sent an invitation to " + Store.peerUserId);
// 监听被叫已收到呼叫邀请
Store.localInvitation.on(
"LocalInvitationReceivedByPeer",
OperationPackge.p2p.localInvitationReceivedByPeer
);
// 监听被叫已接受呼叫邀请
Store.localInvitation.on(
"LocalInvitationAccepted",
OperationPackge.p2p.localInvitationAccepted
);
// 监听被叫拒绝了你的呼叫邀请
Store.localInvitation.on(
"LocalInvitationRefused",
OperationPackge.p2p.localInvitationRefused
);
// 监听呼叫邀请进程失败
Store.localInvitation.on(
"LocalInvitationFailure",
OperationPackge.p2p.localInvitationFailure
);
// 监听呼叫邀请已被成功取消
Store.localInvitation.on(
"LocalInvitationCanceled",
OperationPackge.p2p.localInvitationCanceled
);
},
// p2p 本地视频视图渲染
createVideoAdd: function () {
// console.log("p2p 本地视频视图渲染");
$("#UserIdChanel").text(Store.ownUserId);
//预览本地图像
var videoBox = document.createElement("div");
videoBox.id = Store.ownUserId;
videoBox.className = "video-preview_box";
document.getElementById("mineVideoPreview").appendChild(videoBox);
Store.localTracks.videoTrack &&
Store.localTracks.videoTrack.play(videoBox.id, {
fit: "contain",
});
},
// p2p 远端音视频渲染
createPeerVideoAdd: function (peer) {
// 清除容器内其他内容
$("#peerVideoPreview").html($("#peerVideoPreview_bg"));
// console.log("p2p 远端音视频渲染");
var videoBox = document.createElement("div");
videoBox.id = peer.uid;
videoBox.className = "video-preview_box";
document.getElementById("peerVideoPreview").appendChild(videoBox);
peer.videoTrack &&
peer.videoTrack.play(videoBox.id, {
fit: "contain",
});
},
// RTM 主叫: 呼叫邀请有效期
localInvitationValidity: function () {
// 呼叫邀请有效期
Store.invitationClearTimeout = setTimeout(function () {
Utils.alertWhole("60s无人接听,取消呼叫");
}, Store.invitationTimeout);
},
// RTM 主叫: 被叫已收到呼叫邀请
localInvitationReceivedByPeer: async function () {
Utils.printLog(
"[info]",
"Your invitation has been received by " + Store.localInvitation.calleeId
);
// 标识为正在通话中
Store.Calling = true;
// 呼叫邀请有效期开始计时
OperationPackge.p2p.localInvitationValidity();
Store.network = Object.assign(Store.network, {
Mode: 0,
status: 1,
calltype: 0,
});
},
// RTM 主叫: 被叫已接受呼叫邀请
localInvitationAccepted: async function (response) {
Utils.printLog(
"[info]",
Store.localInvitation.calleeId + " accepted your invitation"
);
// console.log("p2p 被叫已接受呼叫邀请");
// 呼叫邀请有效期清除计时
Store.invitationClearTimeout &&
clearTimeout(Store.invitationClearTimeout);
Utils.alertWhole("呼叫邀请成功", "alert-success");
var invitationResponse = JSON.parse(response);
// 采集音视频
await SdkPackge.RTC.getUserMedia();
// 隐藏邀请页面
PageShow.hiddenCallPage();
Store.network = Object.assign(Store.network, {
Mode: invitationResponse.Mode,
status: 2,
calltype: 0,
});
if (invitationResponse.Mode == 1) {
// 语音通话
PageShow.showVoicePage();
// 关闭视频并释放
Store.localTracks.videoTrack &&
(await Store.localTracks.videoTrack.close(),
(Store.localTracks.videoTrack = null));
// 发布媒体流
await SdkPackge.RTC.publishLocalTracks();
// 显示通话时长
OperationPackge.public.communicationDuration("audioDuration");
} else {
// 本地预览
await OperationPackge.p2p.createVideoAdd();
// 视频通话
PageShow.showVideoPage();
// 发布媒体流
await SdkPackge.RTC.publishLocalTracks();
// 显示通话时长
OperationPackge.public.communicationDuration("videoDuration");
}
},
// RTM 主叫: 被叫拒绝了你的呼叫邀请
localInvitationRefused: async function (response) {
if (Store.localInvitation) {
Utils.printLog(
"danger",
"Your invitation has been refused by " +
Store.localInvitation.calleeId
);
// console.log("p2p 被叫拒绝了你的呼叫邀请", response);
// 呼叫邀请有效期清除计时
Store.invitationClearTimeout &&
clearTimeout(Store.invitationClearTimeout);
// 字符串转换
response ? (response = JSON.parse(response)) : "";
response.Cmd == "Calling"
? Utils.alertWhole("呼叫的用户正在通话中", "alert-info")
: Utils.alertWhole("用户拒绝了你的呼叫邀请", "alert-info");
// 本地存储恢复
OperationPackge.public.restoreDefault();
// 隐藏呼叫邀请页面
PageShow.hiddenCallPage();
}
},
// RTM 主叫: 呼叫邀请进程失败
localInvitationFailure: async function (response) {
// 呼叫邀请有效期清除计时
Store.invitationClearTimeout &&
clearTimeout(Store.invitationClearTimeout);
},
// RTM 主叫: 呼叫邀请已被成功取消 (主动挂断)
localInvitationCanceled: async function () {
// console.log("p2p 呼叫邀请已被成功取消 主叫主动挂断");
// 呼叫邀请有效期清除计时
Store.invitationClearTimeout &&
clearTimeout(Store.invitationClearTimeout);
// 本地存储恢复
await OperationPackge.public.restoreDefault();
// 隐藏呼叫邀请页面
PageShow.hiddenCallPage();
},
// RTM 被叫: p2p 收到来自主叫的呼叫邀请
RemoteInvitationReceived: async function (invitationContent) {
Store.channelId = invitationContent.ChanId;
Store.network = await Object.assign(Store.network, {
// type: "rtm",
calltype: 1, // 被叫
status: 1, // 呼叫中
Mode: invitationContent.Mode,
});
// console.log("p2p 收到来自主叫的呼叫邀请", Store);
// 被呼叫页面 转换语音按钮是否显示
PageShow.toSpeech(invitationContent.Mode);
// 被呼叫页面展示
PageShow.showCalledPage();
// 监听接受呼叫邀请
Store.remoteInvitation.on(
"RemoteInvitationAccepted",
OperationPackge.p2p.RemoteInvitationAccepted
);
// 监听拒绝呼叫邀请
Store.remoteInvitation.on(
"RemoteInvitationRefused",
OperationPackge.p2p.RemoteInvitationRefused
);
// 监听主叫取消呼叫邀请
Store.remoteInvitation.on(
"RemoteInvitationCanceled",
OperationPackge.p2p.RemoteInvitationCanceled
);
// 监听呼叫邀请进程失败
Store.remoteInvitation.on(
"RemoteInvitationFailure",
OperationPackge.p2p.RemoteInvitationFailure
);
},
// RTM 被叫: 接受呼叫邀请成功
RemoteInvitationAccepted: async function () {
Store.JoinRTCChannel = true;
var invitationContent = JSON.parse(Store.remoteInvitation.response);
// 接受邀请进入计时,如果频道一定时间内无人加入取消
Store.callChannelPro = setTimeout(() => {
console.log("接受邀请进入计时,如果频道一定时间内无人加入取消");
OperationPackge.p2p.cancelCall(1);
}, Store.callChannelProTime);
// RTC 加入房间
Store.ownUserId = await Store.rtcClient.join(
Config.APPID,
Store.channelId + "",
null,
Store.ownUserId
);
// 采集音视频
await SdkPackge.RTC.getUserMedia();
// 隐藏被呼叫页面
await PageShow.hiddenCalledPage();
Store.network = Object.assign(Store.network, {
Mode: invitationContent.Mode,
status: 2,
calltype: 1,
});
if (invitationContent.Mode == 1) {
// 语音通话
await PageShow.showVoicePage();
// 关闭视频并释放
Store.localTracks.videoTrack &&
(await Store.localTracks.videoTrack.close(),
(Store.localTracks.videoTrack = null));
// 发布媒体流
await SdkPackge.RTC.publishLocalTracks();
// 显示通话时长
await OperationPackge.public.communicationDuration("audioDuration");
} else {
// 本地预览
await OperationPackge.p2p.createVideoAdd();
// 视频通话
await PageShow.showVideoPage();
// 发布媒体流
await SdkPackge.RTC.publishLocalTracks();
// 显示通话时长
await OperationPackge.public.communicationDuration("videoDuration");
}
},
// RTM 被叫: 拒绝呼叫邀请成功
RemoteInvitationRefused: async function () {
// console.log("RTM 被叫: 拒绝呼叫邀请成功", Store);
Utils.printLog("[info]", "RemoteInvitationRefused");
OperationPackge.p2p.cancelCall(2);
},
// RTM 被叫: 主叫取消呼叫邀请
RemoteInvitationCanceled: async function () {
// console.log("RTM 被叫: 主叫取消呼叫邀请", Store.network);
if (Store.network.status == 1) {
Utils.printLog("[info]", "RemoteInvitationCanceled");
// 恢复默认
await OperationPackge.public.restoreDefault();
// 隐藏被呼叫页面
await PageShow.hiddenCallPage();
// 页面提示
Utils.alertWhole("主叫取消呼叫邀请");
// 显示首页
PageShow.showIndex();
}
},
// RTM 被叫: 呼叫邀请进程失败
RemoteInvitationFailure: async function () {
if (Store.network.status == 1) {
Utils.printLog("[info]", "RemoteInvitationFailure");
// 恢复默认
await OperationPackge.public.restoreDefault();
// 隐藏被呼叫页面
await PageShow.hiddenCallPage();
// 页面提示
Utils.alertWhole("呼叫邀请进程失败");
// 显示首页
PageShow.showIndex();
}
},
// RTM 收到挂断信息
hangupInfo: async function () {
await Utils.alertWhole("通话已结束", "alert-success");
// 释放采集设备
await SdkPackge.RTC.LocalTracksClose();
// 本地存储恢复
await OperationPackge.public.restoreDefault();
// 通话页面恢复初始
await PageShow.initSetingP2P();
// 回到首页
await PageShow.showIndex();
},
// RTC 用户发布
userPublished: async function (user, mediaType) {
// console.log("p2p 用户" + user.uid + "发布" + mediaType);
Store.peerUserId = user.uid; // 存储远端用户uid
if (mediaType === "video") {
PageShow.networkRemoShow(false);
// 远端用户发布的视频渲染
OperationPackge.p2p.createPeerVideoAdd(user);
} else {
user.audioTrack && user.audioTrack.play();
}
},
// RTC 用户取消发布
userUnpublished: async function (user, mediaType) {
if (mediaType === "video") {
PageShow.networkRemoShow(true);
}
// console.log("用户" + user.uid + "取消发布" + mediaType);
},
// RTC 用户加入频道
userJoined: function (user) {
// console.log("RTC 用户加入频道", user, Store.peerUserId);
if (user.uid == Store.peerUserId) {
Store.callChannelPro && clearTimeout(Store.callChannelPro);
Store.remodVideoEnd && clearTimeout(Store.remodVideoEnd);
}
},
// RTC 用户离开频道
userLeft: async function (user, reason) {
// console.log("RTC 用户离开频道", user, reason);
//因网络断线离开
if (reason == "ServerTimeOut") {
Utils.alertWhole("对方网络异常", "alert-warning");
// await PageShow.networkP2P();
// 10s 远端不在加入离开
Store.remodVideoEnd = setTimeout(async () => {
Utils.alertWhole("通话异常", "alert-warning");
// 释放采集设备
await SdkPackge.RTC.LocalTracksClose();
// 本地存储恢复
await OperationPackge.public.restoreDefault();
// 页面恢复初始
await PageShow.initSetingP2P();
// 回到首页
await PageShow.showIndex();
}, Store.remodVideoEndTime);
// 保留页面
} else {
Utils.alertWhole("通话已结束", "alert-success");
// 释放采集设备
await SdkPackge.RTC.LocalTracksClose();
// 本地存储恢复
await OperationPackge.public.restoreDefault();
// 页面恢复初始
await PageShow.initSetingP2P();
// 回到首页
await PageShow.showIndex();
}
},
// p2p 断网重连后发送查询信息
networkSendInfo: function () {
let oSend = setInterval(() => {
if (Store.lineworkRTC && Store.lineworkRTM) {
clearInterval(oSend);
// 发送查询信息
Store.rtmClient &&
Store.rtmClient
.sendMessageToPeer(
{
text: JSON.stringify({
Cmd: "CallState",
}),
},
Store.peerUserId // 对端用户的 uid。
)
.catch((err) => {
// 你的代码:点对点消息发送失败。
// console.log(err);
});
// 一定时间无响应取消
Store.networkReconnection = setTimeout(() => {
console.log("发送查询信息,一定时间无响应取消");
OperationPackge.p2p.cancelCall(1);
}, Store.networkReconnectionTime);
}
}, 500);
},
// p2p 回复远端断网重连所需信息
replySendInfo: function (peerId) {
let oSend = setInterval(() => {
if (Store.lineworkRTC && Store.lineworkRTM) {
clearInterval(oSend);
// 发送查询信息
Store.rtmClient &&
Store.rtmClient
.sendMessageToPeer(
{
text: JSON.stringify({
Cmd: "CallStateResult",
state:
Store.peerUserId !== peerId ? 0 : Store.network.status,
Mode: Store.network.Mode,
}),
},
peerId // 对端用户的 uid。
)
.catch((err) => {
// 你的代码:点对点消息发送失败。
// console.log(err);
});
}
}, 500);
},
},
multi: {
// 频道消息
ChannelMessage: function (message) {
// console.log("频道消息", message);
},
// 频道人员加入
MemberJoined: function (memberId) {
// console.log("频道人员加入", memberId);
},
// 频道人员离开
MemberLeft: async function (memberId) {
// console.log("频道人员离开", memberId);
await Utils.deleteUserView(memberId);
},
// 音视频设置
setVideoOrAudio: async function () {
PageShow.setEnableAudio(Store.setting.enableAudio);
PageShow.setEnableVideo(Store.setting.enableVideo);
},
// 发起呼叫
makeCall: async function (userOnlineStatus) {
// 在线人员
Store.invitationUserIds = userOnlineStatus.oOline;
// 标识为正在通话中
Store.Calling = true;
Store.JoinRTCChannel = true;
// 本地用户加入 RTM 频道
await OperationPackge.multi.JoinRTMChannel();
// 本地用户加入 RTC 实时通讯频道
Store.ownUserId = await Store.rtcClient.join(
Config.APPID,
Store.channelId,
null,
Store.ownUserId
);
// 提示用户不在线
userOnlineStatus.oNotOline.length > 0 &&
Utils.alertWhole("用户" + userOnlineStatus.oNotOline + "不在线");
// 创建窗口
await Utils.createUserView(Store.ownUserId);
// 隐藏本地窗口
await Utils.switchoverHidden(Store.ownUserId, false);
// 发送呼叫邀请 并创建用户视图
await OperationPackge.multi.SendLocalInvitation(userOnlineStatus.oOline);
// 本地音视频渲染
await OperationPackge.multi.LocalAudioVideoRender();
// 显示会议页面
await PageShow.showMeetPage();
},
// 查询呼叫的用户是否在线
QueryPeersOnlineStatus: async function () {
var userOnlineStatus = await Store.rtmClient.queryPeersOnlineStatus(
Store.invitationUserIds
);
// 分离在线用户和不在线用户
var oOline = [];
var oNotOline = [];
Store.invitationUserIds.map(function (userid, index) {
//不在线
if (userOnlineStatus[userid]) {
oOline.push(userid);
} else {
oNotOline.push(userid);
}
});
return {
oOline, // 在线用户
oNotOline, // 不在线用户
};
},
// 加入 RTM 频道
JoinRTMChannel: async function () {
// 正在通话中
Store.Calling = true;
// RTM 频道初始化
await SdkPackge.RTMChannel.init();
// 加入 RTM 频道
await Store.rtmChannel.join();
},
// 发送呼叫邀请
SendLocalInvitation: function (Online) {
Online.forEach(function (userid) {
// 创建呼叫用户视图
Utils.createUserView(userid, 0);
// 创建呼叫邀请并发送
OperationPackge.multi.createLocalInvitationAndSend(userid);
});
},
// 接受呼叫
acceptCall: async function () {
// 查询频道内在线用户
var oUserData = await Store.rtmChannel.getMembers();
Store.invitationUserIds = oUserData;
Store.remoteInvitation.response = await JSON.stringify({
Mode: 0,
Conference: true,
refuseId: Store.ownUserId,
UserData: "",
SipData: "",
});
await Store.remoteInvitation.accept();
// 在线的用户创建视图窗口
await Store.invitationUserIds.forEach(async function (userid) {
// 创建用户视图窗口
await Utils.createUserView(userid, 0);
if (userid == Store.ownUserId) {
Utils.switchoverHidden(userid, false);
}
});
// 隐藏被呼叫页面
await PageShow.hiddenCalledPage();
// 显示会议页面
await PageShow.showMeetPage();
},
// 本地音视频渲染
LocalAudioVideoRender: async function () {
// 释放采集设备
await SdkPackge.RTC.LocalTracksClose();
// 采集本地图像
await SdkPackge.RTC.getUserMedia();
// 发布音视频
await SdkPackge.RTC.publishLocalTracks();
// 设置音视频
await OperationPackge.multi.setVideoOrAudio();
if (!Store.bigMutiUser.uid || Store.bigMutiUser.uid == Store.ownUserId) {
// 本地预览(默认渲染大屏)
Utils.switchoverLeftBottom(Store.ownUserId);
Store.localTracks.videoTrack &&
(await Store.localTracks.videoTrack.play("peerMutiVideoPreview", {
fit: "contain",
}));
// 记录大屏数据
Store.bigMutiUser = {
uid: Store.ownUserId,
videoTrack: Store.localTracks.videoTrack,
};
} else {
// 本地预览(渲染小屏)
Store.localTracks.videoTrack &&
(await Store.localTracks.videoTrack.play(
Store.ownUserId + "VideoView",
{
fit: "contain",
}
));
}
await Utils.updateUserViewStatus(Store.ownUserId, 1);
// 更新音频状态
await Utils.updateUserAudioState(
Store.ownUserId,
Store.setting.enableAudio
);
// 绑定大小屏切换
await Utils.switchover({
uid: Store.ownUserId,
videoTrack: Store.localTracks.videoTrack,
});
},
// 会议邀请 邀请用户
MeetingUser: async function () {
var userid = "";
$("#userMutiModalInputs > input").each(function () {
userid += this.value;
});
// 清空所有输入框
$("#userMutiModalInputs > input").each(function () {
this.value = "";
});
// 筛选用户
if (userid.length !== 4) {
Utils.alertWhole("用户ID不合法", "alert-danger");
return;
}
// 查看用户已存在
if (
~Store.invitationUserIds.indexOf(userid) ||
userid == Store.ownUserId
) {
Utils.alertWhole("邀请的用户已存在", "alert-danger");
return;
}
// 用户是否在线
var userOnlineStatus = await Store.rtmClient.queryPeersOnlineStatus([
userid,
]);
if (!userOnlineStatus[userid]) {
Utils.alertWhole("用户不在线,无法邀请", "alert-danger");
return;
}
return userid;
},
// RTM 主叫: 创建呼叫邀请并发送
createLocalInvitationAndSend: async function (userid) {
var localInvitation = await Store.rtmClient.createLocalInvitation(userid);
var oUserData = await Store.rtmChannel.getMembers();
if (
[Store.ownUserId].concat(Store.invitationUserIds).length >
oUserData.length
) {
oUserData = [Store.ownUserId].concat(Store.invitationUserIds);
}
oUserData = [...new Set(oUserData)];
// 设置邀请内容
localInvitation.content = await JSON.stringify({
Mode: 0, // 呼叫的类型0:视频 1:语音
Conference: true,
ChanId: Store.channelId,
UserData: oUserData, // 邀请的人员添加到UserData [Store.ownUserId].concat(Store.invitationUserIds)
SipData: "",
VidCodec: ["H264"],
AudCodec: ["Opus"],
});
// 发送
await localInvitation.send();
Utils.printLog("[info]", "you sent an invitation to " + userid);
// 主叫:被叫已收到呼叫邀请。
localInvitation.on("LocalInvitationReceivedByPeer", async function () {
Utils.printLog(
"[info]",
"Your invitation has been received by " + localInvitation.calleeId
);
});
// 主叫:被叫已接受呼叫邀请。
localInvitation.on(
"LocalInvitationAccepted",
OperationPackge.multi.LocalInvitationAccepted
);
// 主叫: 被叫拒绝呼叫邀请
localInvitation.on(
"LocalInvitationRefused",
OperationPackge.multi.LocalInvitationRefused
);
// 主叫: 呼叫邀请已被成功取消。
localInvitation.on("LocalInvitationCanceled", function () {
Utils.printLog("[info]", "Local invitation canceled");
});
// 主叫:呼叫邀请进程失败。
localInvitation.on(
"LocalInvitationFailure",
OperationPackge.multi.LocalInvitationFailure
);
},
// RTM 主叫: 被叫已接受呼叫邀请。
LocalInvitationAccepted: async function (response) {
// console.log("被叫已接受呼叫邀请。", response);
if (response) {
response = JSON.parse(response);
Utils.printLog(
"[info]",
response.refuseId + " accepted your invitation"
);
// 更新用户状态及窗口显示 - 对方已接收
Utils.updateUserViewStatus(response.refuseId, 1);
}
},
// RTM 主叫: 被叫拒绝呼叫邀请
LocalInvitationRefused: async function (response) {
// console.log("被叫拒绝呼叫邀请", response);
const responseInfo = response ? JSON.parse(response) : "";
if (responseInfo) {
// 更新用户状态及窗口显示 - 对方已拒绝
await Utils.updateUserViewStatus(responseInfo.refuseId, 2);
if (responseInfo.Cmd == "Calling") {
await Utils.alertWhole("呼叫的用户正在通话中", "alert-info");
} else {
await Utils.alertWhole(
"用户" + (responseInfo.refuseId || "") + "拒绝呼叫邀请",
"alert-info"
);
}
// 移除用户窗口
await Utils.deleteUserView(responseInfo.refuseId);
}
},
// RTM 主叫: 呼叫邀请进程失败
LocalInvitationFailure: function (reason) {
// console.log("呼叫邀请进程失败", reason);
},
// RTM 被叫: 多人 收到来自主叫的呼叫邀请
RemoteInvitationReceived: async function (invitationContent) {
Utils.printLog(
"[info]",
"You recive an invitation from " + Store.remoteInvitation.callerId
);
// console.log("多人 收到来自主叫的呼叫邀请");
// 加入的频道
Store.channelId = invitationContent.ChanId;
// 加入 RTM 频道
await OperationPackge.multi.JoinRTMChannel();
// 显示被呼叫页面
await PageShow.showCalledPage();
// 显示邀请人
$("#callerIdView").html(invitationContent.UserData.join(","));
// 隐藏转换语音通话按钮
PageShow.toSpeech(1);
// 被叫: 接受呼叫邀请
Store.remoteInvitation.on(
"RemoteInvitationAccepted",
OperationPackge.multi.RemoteInvitationAccepted
);
// 被叫: 拒绝呼叫邀请
Store.remoteInvitation.on(
"RemoteInvitationRefused",
OperationPackge.multi.RemoteInvitationRefused
);
// 被叫: 主叫已取消呼叫邀请
Store.remoteInvitation.on(
"RemoteInvitationCanceled",
OperationPackge.multi.RemoteInvitationCanceled
);
// 被叫: 呼叫邀请进程失败
Store.remoteInvitation.on(
"RemoteInvitationFailure",
OperationPackge.multi.RemoteInvitationFailure
);
},
// RTM 被叫: 接受呼叫邀请
RemoteInvitationAccepted: async function () {
// console.log("被叫: 接受呼叫邀请");
Store.JoinRTCChannel = true;
// 加入 RTC 实时通讯频道
Store.ownUserId = await Store.rtcClient.join(
Config.APPID,
Store.channelId,
null,
Store.ownUserId
);
// 更新用户状态及窗口显示 - 对方已接收
await Utils.updateUserViewStatus(Store.remoteInvitation.callerId, 1);
await OperationPackge.multi.LocalAudioVideoRender();
},
// RTM 被叫: 拒绝呼叫邀请
RemoteInvitationRefused: async function () {
Utils.alertWhole("已拒绝呼叫邀请", "alert-info");
PageShow.initSetingMulti(); // 恢复初始
// 恢复默认
await OperationPackge.public.restoreDefault();
// 显示首页
PageShow.showIndex();
},
// RTM 被叫: 主叫已取消呼叫邀请
RemoteInvitationCanceled: async function () {
// console.log("主叫已取消呼叫邀请");
// 恢复默认
await OperationPackge.public.restoreDefault();
// 隐藏被呼叫页面
await PageShow.hiddenCallPage();
// 页面提示
Utils.alertWhole("主叫取消呼叫邀请");
// 显示首页
PageShow.showIndex();
},
// RTM 被叫: 呼叫邀请进程失败
RemoteInvitationFailure: function () {
// console.log("呼叫邀请进程失败");
},
// RTC 用户发布
userPublished: async function (user, mediaType) {
console.log("用户" + user.uid + "发布" + mediaType);
var oArray = await Store.invitationUserIds.concat([user.uid]);
Store.invitationUserIds = Array.from(await new Set(oArray));
if ($("#" + user.uid + "Window").length > 0) {
// 更新视图
Utils.updateUserViewStatus(user.uid, 1);
} else {
// 创建视图
await Utils.createUserView(user.uid);
}
if (mediaType === "video") {
// 默认接收小流
await Store.rtcClient
.setRemoteVideoStreamType(
user.uid,
Store.bigMutiUser.uid == user.uid ? 0 : 1
)
.then(() => {})
.catch((err) => {
console.log(
Store.bigMutiUser.uid == user.uid
? "默认接收大流失败"
: "默认接收小流失败",
err
);
});
// 绑定大小屏切换
await Utils.switchover(user);
// 存放用户发布的视频
user.videoTrack &&
(await user.videoTrack.play(
Store.bigMutiUser.uid == user.uid
? "peerMutiVideoPreview"
: user.uid + "VideoView",
{
fit: "contain",
}
));
} else {
user.audioTrack && (await user.audioTrack.play());
// 更改用户的音频状态
await Utils.updateUserAudioState(user.uid, user.hasAudio);
}
},
// RTC 用户取消发布
userUnpublished: async function (user, mediaType) {
// console.log("用户" + user.uid + "取消发布" + mediaType);
if (mediaType === "audio") {
Utils.updateUserAudioState(user.uid, false);
}
},
// RTC 用户离开频道
userLeft: async function (user, reason) {
// console.log("RTC 用户离开频道", reason);
//因网络断线离开
if (reason == "ServerTimeOut") {
Utils.alertWhole("用户" + user.uid + "网络断线离开");
} else {
await Utils.alertWhole("用户" + user.uid + "离开", "alert-danger");
}
},
},
};
// SDK 自检
(async function () {
// 利用正则表达式
let url = window.location.toString();
// // 返回参数对象
function queryURLParams(url) {
let pattern = /(\w+)=(\w+)/ig; //定义正则表达式
let parames = {}; // 定义参数对象
url.replace(pattern, ($, $1, $2) => {
parames[$1] = $2;
});
return parames;
}
let userInfo = queryURLParams(url)
Store.ownUserId = userInfo.userID;
let callUserPhone = userInfo.callUserID.toString();
$("#userInputs > input").each(function (index, el) {
$(this).val(callUserPhone[index])
});
// 主动呼叫
setTimeout(function(){
$("#p2pVideoMakeCall").click();
},2000);
console.log("parammmmmmmmm",queryURLParams(url))
//查看sdk版本
console.log("RTC SDK 版本<<<<<<<>>>>>>>>", ArRTC.VERSION);
console.log("RTM SDK 版本<<<<<<<>>>>>>>>", ArRTM.VERSION);
// 视频设备状态变化
ArRTC.onCameraChanged = function (info) {
SdkPackge.Support.cameraChanged(info);
};
// 音频设备状态变化
ArRTC.onMicrophoneChanged = function (info) {
SdkPackge.Support.microphoneChanged(info);
};
// // SDK 设备支持检测
// var fase = await SdkPackge.Support.hardwareSupport();
// fase &&
// // 初始化RTC
// (SdkPackge.RTC.init(),
// // 初始化RTM
// SdkPackge.RTM.init());
// 初始化RTC
SdkPackge.RTC.init();
// 初始化RTM
SdkPackge.RTM.init();
})();
// p2p点击相关操作4
{
// 选择p2p呼叫
$("#openP2PInvite").click(function () {
!$("#loginHome").hasClass("d-none") && $("#loginHome").addClass("d-none");
$("#loginForm").hasClass("d-none") && $("#loginForm").removeClass("d-none");
Utils.setPageTitle("anyrtc P2P呼叫邀请DEMO - anyRTC");
Store.Conference = false;
});
$("#openP2PInvite").click();
// 打开设置
$("#openSettingBtn").click(async function () {
if (!$("#loginSetting").hasClass("show")) {
try {
$("#loginSetting").addClass("show");
// 清空容器
await $("#settingVideoPreview").html("");
// 释放采集设备
await SdkPackge.RTC.LocalTracksClose();
// 重新采集视频
await SdkPackge.RTC.getUserMedia();
// 本地预览
Store.localTracks.videoTrack &&
Store.localTracks.videoTrack.play("settingVideoPreview");
Store.localTracks.audioTrack && Store.localTracks.audioTrack.play();
} catch (error) {
console.log("==> 设置相关错误", error);
if (error.code === "PERMISSION_DENIED") {
Utils.alertWhole("设备被禁用");
}
}
}
});
// 关闭设置
$("#closeSettingBtn").click(async function () {
await OperationPackge.p2p.closeSeting();
});
// 监听用户是否开启视频相关数据展示
$("#videoDataSwitch").change(function () {
var videoEnable = $(this).prop("checked");
Store.setting.videoDataShow = videoEnable;
});
// 监听用户设置视频大小
$("#settingVideoResolution").change(async function () {
Store.setting.videoSize = await $("#settingVideoResolution")
.val()
.split("*")
.map(Number);
await OperationPackge.p2p.setOperation("分辨率");
});
// 监听用户设置音频设备
$("#audioInputSelect").change(async function () {
Store.setting.audioDevice = $("#audioInputSelect").val();
await OperationPackge.p2p.setOperation("设置音频设备");
});
// 监听用户设置视频设备
$("#videoInputSelect").change(async function () {
Store.setting.videoDevice = $("#videoInputSelect").val();
await OperationPackge.p2p.setOperation("设置视频设备");
});
// 监听用户ID输入 监听用户删除id
Utils.inputChangId("#userInputs > input");
// 语音呼叫
$("#p2pAudioMakeCall").click(function () {
if (navigator.onLine && Store.lineworkRTC && Store.lineworkRTM) {
if (!Store.repetitionClick) {
OperationPackge.p2p.makeVoiceCall();
}
} else {
// 页面提示
Utils.alertWhole("当前网络不可用");
}
});
// 视频呼叫
$("#p2pVideoMakeCall").click(function () {
if (navigator.onLine && Store.lineworkRTC && Store.lineworkRTM) {
if (!Store.repetitionClick) {
OperationPackge.p2p.makeVideoCall();
}
} else {
// 页面提示
Utils.alertWhole("当前网络不可用");
}
});
// 主叫-呼叫页面 挂断
$("#cancelCallBtn").click(function () {
// 挂断
Store.localInvitation && Store.localInvitation.cancel();
// 隐藏呼叫邀请页面
PageShow.hiddenCallPage();
// 本地存储恢复
OperationPackge.public.restoreDefault();
});
// 被叫-呼叫页面 转语音通话
$("#changAudioBtn").on("click", function () {
OperationPackge.p2p.acceptCall("语音呼叫");
});
// 音视频展示-语音通话页面 音频开关
$("#audioSwitchBtn").click(async function () {
Store.localTracks.audioTrack.isMuted =
!Store.localTracks.audioTrack.isMuted;
// Store.localTracks.audioTrack.setEnabled(
// !Store.localTracks.audioTrack.isMuted
// );
Store.localTracks.audioTrack &&
(await Store.localTracks.audioTrack.setMuted(
Store.localTracks.audioTrack.isMuted
));
PageShow.audioSwitch();
});
// 音视频展示-语音通话页面 音频挂断
$("#hangupAudioBtn").click(function () {
// 取消当前通话
OperationPackge.p2p.cancelCall();
});
// 音视频展示-视频通话页面 视频挂断
$("#hangupBtn").click(function () {
// 取消当前通话
OperationPackge.p2p.cancelCall();
});
// 音视频展示-视频通话页面 切换语音通话
$("#switchToAudioCall").click(async function () {
// console.log("切换语音通话", Store.peerUserId);
if (Store.localTracks.videoTrack) {
await Store.rtmClient.sendMessageToPeer(
{
text: JSON.stringify({
Cmd: "SwitchAudio",
}),
},
Store.peerUserId // 对端用户的 uid。
);
// 语音通话
await PageShow.showVoicePage();
// 关闭视频并释放
(await Store.localTracks.videoTrack) &&
(Store.localTracks.videoTrack.close(),
(Store.localTracks.videoTrack = null));
Store.setting.videoStatsInterval &&
clearInterval(Store.setting.videoStatsInterval);
// 显示音频通话时长
await OperationPackge.public.communicationDuration("audioDuration");
}
});
}
// 多人点击相关操作
{
// 选择多人呼叫
$("#openMultiInvite").click(function () {
!$("#loginHome").hasClass("d-none") && $("#loginHome").addClass("d-none");
$("#loginMutiFprm").hasClass("d-none") &&
$("#loginMutiFprm").removeClass("d-none");
Utils.setPageTitle("anyrtc 多人呼叫邀请DEMO - anyRTC");
Store.Conference = true;
});
// 用户输入
Utils.inputChangIds("#multiUserInputs > input");
// 监听打开设置按钮点击
$("#multiOpenSettingBtn").click(function () {
if (!$("#loginMutiSetting").hasClass("show")) {
$("#loginMutiSetting").addClass("show");
$("#userVideoCameraSetting").prop("checked", Store.setting.enableVideo);
$("#userMicrophoneSetting").prop("checked", Store.setting.enableAudio);
}
});
// 监听用户摄像头设置开关
$("#userVideoCameraSetting").change(function () {
var videoEnable = $(this).prop("checked");
Store.setting.enableVideo = videoEnable;
});
// 监听用户麦克风设置开关
$("#userMicrophoneSetting").change(function () {
var audioEnable = $(this).prop("checked");
Store.setting.enableAudio = audioEnable;
});
// 监听关闭设置按钮点击
$("#closeMutiSettingBtn").click(function () {
$("#loginMutiSetting").hasClass("show") &&
$("#loginMutiSetting").removeClass("show");
});
// 发起多人音视频通话
$("#MultipleCalls").click(async function () {
if (Store.invitationUserIds.length > 0) {
// 查询呼叫的用户是否在线
var userOnlineStatus =
await OperationPackge.multi.QueryPeersOnlineStatus();
// 输入的用户中有在线的
if (userOnlineStatus.oOline.length > 0) {
// 主叫处理
await OperationPackge.multi.makeCall(userOnlineStatus);
} else {
Utils.alertWhole("您输入的用户全都不在线");
Store.invitationUserIds = [];
$("#multiUserBtn").html("");
}
} else {
Utils.alertWhole("请输入邀请的用户");
}
});
// 音频开关
$("#setAudioEnableBtn").click(async function () {
Store.setting.enableAudio = !Store.setting.enableAudio;
if (Store.setting.enableAudio && !Store.localTracks.audioTrack) {
// 默认关闭音频时打开音频
await SdkPackge.RTC.getUserMicrophonesPublish();
} else {
Store.localTracks.audioTrack &&
(await Store.localTracks.audioTrack.setMuted(
!Store.setting.enableAudio
));
}
// 更改用户的音频状态
Utils.updateUserAudioState(Store.ownUserId, Store.setting.enableAudio);
PageShow.setEnableAudio(Store.setting.enableAudio);
});
// 视频开关
$("#setVideoEnableBtn").click(async function () {
Store.setting.enableVideo = !Store.setting.enableVideo;
if (!Store.localTracks.videoTrack && Store.setting.enableVideo) {
// 默认关闭视频时打开视频
await OperationPackge.multi.LocalAudioVideoRender();
} else {
Store.localTracks.videoTrack &&
(await Store.localTracks.videoTrack.setMuted(
!Store.setting.enableVideo
));
}
PageShow.setEnableVideo(Store.setting.enableVideo);
});
// 挂断
$("#hangupMutiBtn").click(async function () {
Object.keys(Store.invitationClearTimeouts).forEach(function (key) {
Store.invitationClearTimeouts[key] &&
clearTimeout(Store.invitationClearTimeouts[key]);
});
// 释放采集设备
SdkPackge.RTC.LocalTracksClose();
// // 通话页面恢复初始
PageShow.initSetingMulti();
// // 回到首页
PageShow.showIndex();
// // 本地存储恢复
OperationPackge.public.restoreDefault();
});
// 输入框 (会议中邀请)
Utils.inputChangId("#userMutiModalInputs > input");
// 会议中邀请
$("#mutiModalBtn").click(async function () {
// 获取邀请用户
var userid = await OperationPackge.multi.MeetingUser();
if (userid) {
// 发送邀请
await OperationPackge.multi.createLocalInvitationAndSend(userid);
// 创建用户视图窗口
Utils.createUserView(userid, 0);
// 隐藏邀请窗口
$("#invitationModal").modal("hide");
}
});
}
// 被叫页面P2P与多人公共操作
{
// 被叫-呼叫页面 接受邀请
$("#acceptCallBtn").on("click", function () {
Store.Conference
? OperationPackge.multi.acceptCall()
: OperationPackge.p2p.acceptCall("视频呼叫");
});
// 被叫-呼叫页面 拒绝接听
$("#refuseCallBtn").on("click", function () {
Store.remoteInvitation.response = JSON.stringify({
refuseId: Store.ownUserId,
});
// 拒绝接听
Store.remoteInvitation && Store.remoteInvitation.refuse();
});
}
// 断网
window.addEventListener("online", Utils.updateOnlineStatus);
window.addEventListener("offline", Utils.updateOnlineStatus);