// SDK 配置
var Config = {
  APPID: "", // 应用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 = $(
      `
        <div class="alert alert-danger" role="alert">
          <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
          <span id="errorConten">${errorText}</span>
        </div>
      `
    );
    $("#warningBox").html("").append(errMsg);
    //警告框自动消失
    setTimeout(function () {
      $('[data-dismiss="alert"]').alert("close");
    }, 2000);
  },
  // 全局警告框
  alertWhole: function (text, classStyle) {
    if (!classStyle) {
      classStyle = "alert-danger";
    }
    var oMsg = $(
      `
      <div class="alert ${classStyle}" role="alert">
        <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <span id="errorConten">${text}</span>
      </div>
    `
    );
    $("#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 = $(
          '<button type="button" class="btn btn-light user-tag" onclick="Utils.deleteButtonUser(this, ' +
            allInputVal +
            ')">' +
            allInputVal +
            '<i class="iconfont icon-delete_close"></i>' +
            '<i class="iconfont icon-delete_open"></i>' +
            "</button>"
        );
        $("#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 = $(
        '<div class="video-preview_small_box" id="' + userid + 'Window"></div>'
      );
      var basicView = $(
        '<div class="d-flex video-preview justify-content-center align-items-center" id="' +
          userid +
          'VideoView">' +
          '<div class="basicView_img" id="' +
          userid +
          'basicView_img"><img draggable="false" class="d-flex img-responsive" src="assets/images/logo_title.png" /></div>' +
          "</div>" +
          "<!-- 左下角小方格 -->" +
          '<div class="prompt_little d-flex" id="' +
          userid +
          "PromptLittle" +
          '">' +
          '<i class="iconfont icon-audio_close_slant icon_color_red" id="' +
          userid +
          'AudioState"></i>' +
          "<div>" +
          userid +
          "</div>" +
          "</div>"
      );
      var statusView = $(
        "<!-- 用户不在线 无人应答 拒绝 -->" +
          '<div id="' +
          userid +
          'StatusView" class="video-preview_state d-flex justify-content-center align-items-center">' +
          '<div class="video-preview_status d-flex flex-column align-items-center">' +
          '<span><i class="iconfont icon-loading video-icon_font"></i></span>' +
          '<span id="' +
          userid +
          'Status">' +
          (status === 1 ? "无人应答" : status === 0 && "等待应答") +
          "</span>" +
          "</div>" +
          "</div>"
      );
      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 = $(
      `
        <i class="${oldbigUid}" id="${bigUid + "BigAudioState"}"></i>
        <div>${bigUid}</div>
      `
    );
    $("#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() < 4) {
        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(4), //自己的用户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");
  },
  // 初始设置 (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();
  },
  // 隐藏被呼叫页面
  hiddenCalledPage: function () {
    !$("#reciveCallPage").hasClass("d-none") &&
      $("#reciveCallPage").addClass("d-none");
    $("#callerIdView").html("");
  },
  // 显示视频页面
  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 = $(
            '<option value="' + camera.deviceId + '">' + label + "</option>"
          );
          $("#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 = $(
            '<option value="' + camera.deviceId + '">' + label + "</option>"
          );
          $("#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) =>
                  `<p class="stats-row">${stat.description}: ${stat.value} ${stat.unit}</p>`
              )
              .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) =>
                  `<p class="stats-row">${stat.description}: ${stat.value} ${stat.unit}</p>`
              )
              .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 === 4) {
        //查询状态
        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 () {
  //查看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;
  });

  // 打开设置
  $("#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);
