var webrtcroom = require('../../../utils/webrtcroom.js') var imHandler = require('./im_handler.js') var webim = require('../../../utils/webim_wx'); const SHOWINTERACT_TYPE = { BOARD: 1, // 白板 COMMENT: 2 // 聊天 } const ROLE_TYPE = { AUDIENCE: 'audience', // 观众, 可以看到白板 PRESENTER: 'presenter' // 主播, 没有白板,暂时不支持小程序端作为老师 } Page({ /** * 页面的初始数据 */ data: { webrtcroomComponent: null, roomID: '', // 房间id roomname: '', // 房间名称 beauty: 5, muted: false, debug: false, frontCamera: true, role: ROLE_TYPE.AUDIENCE, // presenter 代表主播,audience 代表观众 userID: '', userSig: '', sdkAppID: '', roomCreator: '', comment: [], toview: null, showInteractType: SHOWINTERACT_TYPE.COMMENT, // 标识不展示 // 互动类型 SHOWINTERACT_TYPE: SHOWINTERACT_TYPE, ROLE_TYPE: ROLE_TYPE, sketchpad: { width: 0, height: 0 }, isErrorModalShow: false, heartBeatFailCount: 0, //心跳失败次数 autoplay: true, enableCamera: true }, /** * 监听 IM 事件 */ onIMEvent: function (e) { const CONSTANT = this.data.webrtcroomComponent.data.CONSTANT; let code = e.detail.code; let tag = e.detail.tag; let data = e.detail.detail; switch (tag) { // 登录事件 case CONSTANT.IM.LOGIN_EVENT: if (code) { wx.showToast({ icon: 'none', title: `登录IM失败,ErrCode: ${code}` }); console.error(`登录IM失败,ErrCode: ${code}`); } else { wx.showToast({ title: '登录IM成功' }); console.log('登录IM成功'); } break; // 创建群|进群状态 case CONSTANT.IM.JOIN_GROUP_EVENT: if (code) { wx.showToast({ icon: 'none', title: `创建群|进群失败,ErrCode: ${code}` }); console.error(`创建群|进群失败,ErrCode: ${code}`); } else { wx.showToast({ title: '创建群|进群成功' }); console.log('创建群|进群成功'); } break; // 连接状态 case CONSTANT.IM.CONNECTION_EVENT: switch (code) { case webim.CONNECTION_STATUS.ON: console.log('连接状态正常...'); break; case webim.CONNECTION_STATUS.OFF: console.error('连接已断开,无法收到新消息,请检查下你的网络是否正常'); break; default: console.error('未知连接状态,status=' + code); break; } break; case CONSTANT.IM.GROUP_SYSTEM_NOTIFYS: // 监听(多终端同步)群系统消息事件,必填 console.log(`群系统消息事件,code:${code}`); break; case CONSTANT.IM.GROUP_INFO_CHANGE_NOTIFY: // 监听群资料变化事件,选填 console.log("执行 群资料变化 回调: " + JSON.stringify(groupInfo)); var groupId = groupInfo.GroupId; var newFaceUrl = groupInfo.GroupFaceUrl; //新群组图标, 为空,则表示没有变化 var newName = groupInfo.GroupName; //新群名称, 为空,则表示没有变化 var newOwner = groupInfo.OwnerAccount; //新的群主id, 为空,则表示没有变化 var newNotification = groupInfo.GroupNotification; //新的群公告, 为空,则表示没有变化 var newIntroduction = groupInfo.GroupIntroduction; //新的群简介, 为空,则表示没有变化 if (newName) { console.log("群id=" + groupId + "的新名称为:" + newName); } break; case CONSTANT.IM.BIG_GROUP_MSG_NOTIFY: // 接收到IM大群消息 console.log('接收到大群(直播聊天室)消息通知'); var msgs = data; imHandler.handleGroupMessage(msgs, (msg) => { if (!msg.content) { return; } var time = new Date(); var h = time.getHours() + '', m = time.getMinutes() + '', s = time.getSeconds() + ''; h.length == 1 ? (h = '0' + h) : ''; m.length == 1 ? (m = '0' + m) : ''; s.length == 1 ? (s = '0' + s) : ''; time = h + ':' + m + ':' + s; msg.time = time; if (msg.fromAccountNick == '@TIM#SYSTEM') { msg.fromAccountNick = ''; msg.content = msg.content.split(';'); msg.content = msg.content[0]; this.updateComment({ roomID: this.data.roomID, userID: msg.fromAccountNick, userName: msg.userName, userAvatar: msg.userAvatar, message: msg.content, time: msg.time }); } else { var content try { // 自定义消息 content = JSON.parse(msg.content); } catch (error) { // 普通消息 this.updateComment({ roomID: this.data.roomID, userID: msg.fromAccountNick, userName: msg.userName, message: msg.data, time: msg.time }); return; } var data = content.data; var desc = null; try { desc = JSON.parse(content.desc); } catch (error) { desc = {}; } var ext = content.ext; if (ext === 'TXWhiteBoardExt') { // 如果是白板消息 var whiteBoardCom = this.selectComponent('#white_board'); if (whiteBoardCom) { var data = JSON.parse(data); if (data.action === 'currentBoard') { whiteBoardCom.updateCurrentBoard(data.currentBoard); } else { whiteBoardCom.addData(data); } } } else if (ext === 'TEXT') { // 如果是普通消息 this.updateComment({ roomID: this.data.roomID, userID: msg.fromAccountNick, userName: desc.nickName, message: data, time: msg.time }); } } }); break; } }, /** * 监听房间事件 */ onRoomEvent: function (e) { var self = this; switch (e.detail.tag) { case 'error': if (this.data.isErrorModalShow) { return; } if (e.detail.code === -10) { // 进房失败,一般为网络切换的过程中 this.data.isErrorModalShow = true; wx.showModal({ title: '提示', content: e.detail.detail, confirmText: '重试', cancelText: '退出', success: function (res) { self.data.isErrorModalShow = false if (res.confirm) { self.joinRoom(); } else if (res.cancel) { // self.goBack(); } } }); } else { // 在房间内部才显示提示 console.error("error:", e.detail.detail); var pages = getCurrentPages(); console.log(pages, pages.length, pages[pages.length - 1].__route__); if (pages.length > 1 && (pages[pages.length - 1].__route__ == 'pages/webrtcroom/room/room')) { this.data.isErrorModalShow = true; wx.showModal({ title: '提示', content: e.detail.detail, showCancel: false, complete: function () { self.data.isErrorModalShow = false pages = getCurrentPages(); if (pages.length > 1 && (pages[pages.length - 1].__route__ == 'pages/webrtcroom/room/room')) { wx.showToast({ title: `code:${e.detail.code} content:${e.detail.detail}` }); wx.navigateBack({ delta: 1 }); } } }); } } break; } }, /** * 更新聊天内容 * @param {Object} msg 消息内容 */ updateComment(msg) { // 普通消息 this.data.comment.push({ content: msg.message, name: msg.userName, uid: msg.userID, time: msg.time }); this.setData({ comment: this.data.comment, toview: null // 滚动条置底 }); this.setData({ toview: 'scroll-bottom' // 滚动条置底 }); }, /** * 切换摄像头 */ changeCamera: function () { this.data.webrtcroomComponent.switchCamera(); this.setData({ frontCamera: !this.data.frontCamera }) }, /** * 设置美颜 */ setBeauty: function () { this.data.beauty = (this.data.beauty == 0 ? 5 : 0); this.setData({ beauty: this.data.beauty }); }, /** * 切换是否静音 */ changeMute: function () { this.data.muted = !this.data.muted; this.setData({ muted: this.data.muted }); }, /** * 是否显示日志 */ showLog: function () { this.data.debug = !this.data.debug; this.setData({ debug: this.data.debug }); }, /** * 创建房间 * 房间创建成功后,发送心跳包,并启动webrtc-room标签 */ createRoom: function () { var self = this; webrtcroom.createRoom(self.data.userID, this.data.roomname, function (res) { console.log('创建房间成功:', res); self.data.roomID = res.data.roomID; // 成功进房后发送心跳包 self.sendHeartBeat(self.data.userID, self.data.roomID); // 设置webrtc-room标签中所需参数,并启动webrtc-room标签 self.setData({ userID: self.data.userID, userSig: self.data.userSig, sdkAppID: self.data.sdkAppID, roomID: self.data.roomID, privateMapKey: res.data.privateMapKey }, function () { self.data.webrtcroomComponent.start(); }) }, function (res) { console.error('创建房间失败[' + res.errCode + ';' + res.errMsg + ']'); self.onRoomEvent({ detail: { tag: 'error', code: -999, detail: '创建房间失败[' + res.errCode + ';' + res.errMsg + ']' } }) }); }, /** * 进入房间, 包括进入IM和进入推流房间 */ enterRoom: function () { var self = this; webrtcroom.enterRoom(self.data.userID, self.data.roomID, function (res) { // 成功进房后发送心跳包 self.sendHeartBeat(self.data.userID, self.data.roomID); // 设置webrtc-room标签中所需参数,并启动webrtc-room标签 self.setData({ userID: self.data.userID, userSig: self.data.userSig, sdkAppID: self.data.sdkAppID, roomID: self.data.roomID, privateMapKey: res.data.privateMapKey }, function () { self.data.webrtcroomComponent.start(); }) }, function (res) { console.error(self.data.ERROR_CREATE_ROOM, '进入房间失败[' + res.errCode + ';' + res.errMsg + ']') self.onRoomEvent({ detail: { tag: 'error', code: -999, detail: '进入房间失败[' + res.errCode + ';' + res.errMsg + ']' } }) }); }, /** * 发送心跳包 */ sendHeartBeat(userID, roomID) { var self = this; // 发送心跳 webrtcroom.startHeartBeat(userID, roomID, function () { self.data.heartBeatFailCount = 0; }, function () { self.data.heartBeatFailCount++; // wx.navigateTo({ // url: '../roomlist/roomlist' // }); // 2次心跳都超时,则认为真正超时了 if (self.data.heartBeatFailCount > 2) { wx.hideToast(); wx.showToast({ icon: 'none', title: '心跳超时,请重新进入房间', complete: function () { setTimeout(() => { self.goBack(); }, 1000); } }); } else { wx.hideToast(); wx.showToast({ icon: 'none', title: '心跳超时,正在重试...' }); } }); }, /** * 返回上一页 */ goBack() { var pages = getCurrentPages(); if (pages.length > 1 && (pages[pages.length - 1].__route__ == 'pages/webrtcroom/room/room')) { wx.navigateBack({ delta: 1 }); } }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { this.setData({ userID: wx.getStorageSync('webrtc_room_userid') }); this.data.roomID = options.roomID || ''; this.data.roomname = options.roomName; this.data.username = options.userName; this.setData({ roomCreator: options.roomCreator || this.data.userID }); this.joinRoom(); }, /** * 进入房间 */ joinRoom() { console.log('room.js onLoad'); var time = new Date(); time = time.getHours() + ':' + time.getMinutes() + ':' + time.getSeconds(); console.log('*************开始多人音视频:' + time + '**************'); // webrtcComponent this.data.webrtcroomComponent = this.selectComponent('#webrtcroom'); var self = this; wx.showToast({ icon: 'none', title: '获取登录信息中' }); webrtcroom.getLoginInfo( self.data.userID, function (res) { self.data.userID = res.data.userID; wx.setStorageSync('webrtc_room_userid', self.data.userID); self.data.sdkAppID = res.data.sdkAppID; self.data.userSig = res.data.userSig; if (self.data.roomID) { self.enterRoom(); } else { self.createRoom(); } if (self.data.userID === self.data.roomCreator || !self.data.roomCreator) { // 如果创建房间是自己,则是主播 self.setData({ role: ROLE_TYPE.PRESENTER }); } else { self.setData({ role: ROLE_TYPE.AUDIENCE }); } }, function (res) { wx.showToast({ icon: 'none', title: '获取登录信息失败,请重试', complete: function () { setTimeout(() => { self.goBack(); }, 1500); } }); }); }, /** * 生命周期函数--监听页面初次渲染完成 */ onReady: function () { // 设置房间标题 wx.setNavigationBarTitle({ title: this.data.roomname }); // 计算一次白板的宽高 this.resizeSketchpad(); }, /** * 生命周期函数--监听页面显示 */ onShow: function () { var self = this; console.log('room.js onShow'); // 保持屏幕常亮 wx.setKeepScreenOn({ keepScreenOn: true }) }, /** * 生命周期函数--监听页面隐藏 */ onHide: function () { var self = this; console.log('room.js onHide'); }, /** * 生命周期函数--监听页面卸载 */ onUnload: function () { console.log('room.js onUnload'); webrtcroom.quitRoom(this.data.userID, this.data.roomID); }, /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh: function () { }, /** * 页面上拉触底事件的处理函数 */ onReachBottom: function () { }, /** * 用户点击右上角分享 */ onShareAppMessage: function () { return { // title: '', path: '/pages/main/main', imageUrl: 'https://mc.qcloudimg.com/static/img/dacf9205fe088ec2fef6f0b781c92510/share.png' } }, /** * 展示白板 */ showBoard() { this.setData({ showInteractType: this.data.SHOWINTERACT_TYPE.BOARD }, () => { if (this.data.webrtcroomComponent) { var body = { cmd: 'sketchpad', data: { userID: this.data.userID, userName: this.data.userName, userAvatar: '', msg: '{"type":"request", "action":"currentBoard"}' } } var msg = { data: JSON.stringify(body) } // 同步当前白板 this.data.webrtcroomComponent.sendC2CCustomMsg(this.data.roomCreator, msg, (res) => { console.log('C2C消息发送成功'); }, (err) => { wx.showToast({ icon: 'none', title: `消息发送失败,code: ${err.ErrorCode}` }); }); } }); }, /** * 展示聊天面板 */ showComment() { this.setData({ showInteractType: this.data.SHOWINTERACT_TYPE.COMMENT }); }, // IM输入框的信息 bindInputMsg: function (e) { this.data.inputMsg = e.detail.value; }, // 发送IM消息 sendComment: function () { var msg = this.data.inputMsg || ''; if (this.data.webrtcroomComponent) { if (!msg || !msg.trim()) { wx.showToast({ icon: 'none', title: '不能发送空消息' }); console.error('不能发送空消息'); return; } var msgLen = webim.Tool.getStrBytes(msg); var maxLen, errInfo; maxLen = webim.MSG_MAX_LENGTH.GROUP; // 群组最大支持的消息长度 if (msgLen > maxLen) { errInfo = "消息长度超出限制(最多" + Math.round(maxLen / 3) + "汉字)"; wx.showToast({ icon: 'none', title: errInfo }); console.error(errInfo); return; } this.data.webrtcroomComponent.sendGroupCustomMsg({ data: msg, // 要发送的消息内容 ext: 'TEXT', // 自定义消息的类型 desc: JSON.stringify({ // 扩展数据 nickName: '自定义昵称' + new Date().getTime() }) }, (res) => { // 发送成功 this.setData({ inputMsg: '' }); }, (err) => { wx.showToast({ icon: 'none', title: `消息发送失败,code: ${err.ErrorCode}` }); console.error(`消息发送失败,code: ${err.ErrorCode} info:${err.SrcErrorInfo}`); }); } }, /** * 计算宽高 */ pixel: function ({ value, unit }, cb) { wx.getSystemInfo({ success: function (res) { var vw = res.windowWidth; var vh = res.windowHeight; var resultPixelValue = 0; if (unit == 'px') { resultPixelValue = value; } else if (unit == 'vw') { resultPixelValue = value / 100 * vw; } else if (unit == 'vh') { resultPixelValue = value / 100 * vh; } else { console.log('支持单位:vw, vh'); } console.log("{value: %d, unit: %s} ==> %d px", value, unit, resultPixelValue); cb(resultPixelValue); }, fail: function () { console.log('获取系统信息失败'); cb(0); } }) }, /** * 重置画面的宽高 */ resizeSketchpad() { var self = this; self.pixel({ value: 100, unit: 'vh' }, function (res1) { self.pixel({ value: 100, unit: 'vw' }, function (res2) { var fullHeight = res1; var fullWidth = res2; // 100vh - 100vw*9/16 - 100vw/3 - 1vh - 10vh - 5vh + 2vw/3 var rHeight = fullHeight - fullWidth * 9 / 16 - fullWidth / 3 - fullHeight * 0.01 - fullHeight * 0.1 - fullHeight * 0.05 + fullWidth * 0.02 / 3; self.setData({ sketchpad: { height: rHeight, width: fullWidth, } }, () => { console.log("normal screen: h1 = %d, w1 = %d", rHeight, fullWidth); }); }); }); } })