|
@@ -0,0 +1,669 @@
|
|
|
|
+<template>
|
|
|
|
+ <div>
|
|
|
|
+ <el-dialog v-el-drag-dialog :visible.sync="showMobile" title="" :close-on-click-modal="false" :close-on-press-escape="false" :custom-class="mobileStyle" @close="close">
|
|
|
|
+ <div slot="title" class="cfff fs14">
|
|
|
|
+ <span class="ml20">{{ mobileName }}</span>
|
|
|
|
+ <el-dropdown placement="bottom" class="fr mr100 oln" trigger="hover" @command="handleCommand" @visible-change="handleVisble">
|
|
|
|
+ <span class="fs14 cfff">{{ bitRateText }}<i :class="caretIcon" /></span>
|
|
|
|
+ <el-dropdown-menu slot="dropdown" class="mobile-dropdown-menu">
|
|
|
|
+ <el-dropdown-item :class="bitRateStyle('1638400')" command="1638400">自动</el-dropdown-item>
|
|
|
|
+ <el-dropdown-item :class="bitRateStyle('491520')" command="491520">极速</el-dropdown-item>
|
|
|
|
+ <el-dropdown-item :class="bitRateStyle('1392640')" command="1392640">标清</el-dropdown-item>
|
|
|
|
+ <el-dropdown-item :class="bitRateStyle('2785280')" command="2785280">高清</el-dropdown-item>
|
|
|
|
+ </el-dropdown-menu>
|
|
|
|
+ </el-dropdown>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="frns">
|
|
|
|
+ <div class="mobile-audio">
|
|
|
|
+ <video
|
|
|
|
+ ref="player"
|
|
|
|
+ width="372px"
|
|
|
|
+ :controls="false"
|
|
|
|
+ autoplay
|
|
|
|
+ @play="ready"
|
|
|
|
+ @error="error"
|
|
|
|
+ @pause="pause"
|
|
|
|
+ @mousedown="handleMouseDown"
|
|
|
|
+ @mousemove="handleMouseMove"
|
|
|
|
+ @mouseup="handleMouseUp"
|
|
|
|
+ @mouseleave="handleMouseLeave"
|
|
|
|
+ />
|
|
|
|
+ <audio
|
|
|
|
+ ref="audioPlayer"
|
|
|
|
+ width="372px"
|
|
|
|
+ controls
|
|
|
|
+ autoplay
|
|
|
|
+ poster="@/assets/equipment/loader-thumb.jpg"
|
|
|
|
+ />
|
|
|
|
+ <div v-if="isMask" class="mask">
|
|
|
|
+ <i v-if="isLoading" class="el-icon-loading" />
|
|
|
|
+ <img v-if="isError" class="w180h148" src="@/assets/equipment/guzhang_lixian_pic.png" alt="">
|
|
|
|
+ <div class="c999 fs12 mt15">{{ maskText }}</div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="mobile-sidebar">
|
|
|
|
+ <i :class="volumeUpIcon" @click="handleRoutine(24)" />
|
|
|
|
+ <i :class="volumeDownIcon" @click="handleRoutine(25)" />
|
|
|
|
+ <el-popover placement="bottom-start" popper-class="nav-popover" width="109" trigger="hover">
|
|
|
|
+ <div class="tac ptb10 c333 fs14">重启</div>
|
|
|
|
+ <i slot="reference" :class="shutDownIcon" @click="reboot" />
|
|
|
|
+ </el-popover>
|
|
|
|
+ <el-popover placement="bottom-start" popper-class="nav-popover" width="109" trigger="hover">
|
|
|
|
+ <div class="tac ptb10 c333 fs14">恢复出厂设置</div>
|
|
|
|
+ <i slot="reference" :class="restartIcon" @click="recovery" />
|
|
|
|
+ </el-popover>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="mobile-bottombar">
|
|
|
|
+ <i :class="menuIcon" @click="handleRoutine(187)" />
|
|
|
|
+ <i :class="homeIcon" @click="handleRoutine(3)" />
|
|
|
|
+ <i :class="backIcon" @click="handleRoutine(4)" />
|
|
|
|
+ </div>
|
|
|
|
+ </el-dialog>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script>
|
|
|
|
+import elDragDialog from '@/directive/el-drag-dialog'
|
|
|
|
+import JMuxer from 'jmuxer'
|
|
|
|
+import { getcardInfoBySn, rebootBatch, recovery, getcardStatus } from '@/api/mobile'
|
|
|
|
+import { ExexuteMouseDown, ExexuteMouseMove, ExexuteMouseUp, ExexuteKeyDown, ExexutePixel, ExexuteCloseServer, CheckScreenDirection, RequestIFrame, ConfigChannel } from '@/utils/control'
|
|
|
|
+import { keycodeMode } from '@/utils/config'
|
|
|
|
+
|
|
|
|
+const VIDEO_WIDTH = 371
|
|
|
|
+const VIDEO_HEIGHT = 660
|
|
|
|
+
|
|
|
|
+export default {
|
|
|
|
+ name: 'DragDialogDemo',
|
|
|
|
+ directives: { elDragDialog },
|
|
|
|
+ props: {
|
|
|
|
+ sn: {
|
|
|
|
+ type: Array,
|
|
|
|
+ default: () => {
|
|
|
|
+ return []
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ mobileName: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: ''
|
|
|
|
+ },
|
|
|
|
+ mobileId: {
|
|
|
|
+ type: Number,
|
|
|
|
+ default: 0
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ data() {
|
|
|
|
+ return {
|
|
|
|
+ showMobile: true,
|
|
|
|
+ fpsCount: 0,
|
|
|
|
+ timeCount: 0,
|
|
|
|
+ isFeed: true,
|
|
|
|
+ curTime: new Date().getTime(),
|
|
|
|
+ requestTime: new Date().getTime(),
|
|
|
|
+ jmuxer: null,
|
|
|
|
+ audioMuxer: null,
|
|
|
|
+ ip: '', // 设备ip
|
|
|
|
+ port: '', // 设备端口号
|
|
|
|
+ size: '', // 设备分辨率
|
|
|
|
+ bitRate: '', // 设备清晰度
|
|
|
|
+ path: 'ws://192.168.11.66:9101', // websocket地址
|
|
|
|
+ socket: null, // websocket类
|
|
|
|
+ isDrag: false,
|
|
|
|
+ isLoading: true, // 加载中
|
|
|
|
+ isMask: true, // 遮罩层
|
|
|
|
+ maskText: '', // 加载文字
|
|
|
|
+ isError: false, // 是否设备故障或者离线
|
|
|
|
+ visble: false, // 下拉菜单是否展开
|
|
|
|
+ isRotate: false, // 是否横屏
|
|
|
|
+ isFlag: false
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ computed: {
|
|
|
|
+ bitRateStyle() {
|
|
|
|
+ return (num) => {
|
|
|
|
+ return this.bitRate === num ? 'pl20 bgcf3f6ff c515ff0 fs14' : 'pl20 c333 fs14'
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ bitRateText() {
|
|
|
|
+ /**
|
|
|
|
+ * 极速 | 491520,60KB/S
|
|
|
|
+ * 标清 | 1392640 ,170KB/S
|
|
|
|
+ * 自动 | 1638400 ,200KB/S
|
|
|
|
+ * 高清 | 2785280 ,340KB/S
|
|
|
|
+ */
|
|
|
|
+ const option = {
|
|
|
|
+ '1638400': '自动',
|
|
|
|
+ '491520': '极速',
|
|
|
|
+ '1392640': '标清',
|
|
|
|
+ '2785280': '高清'
|
|
|
|
+ }
|
|
|
|
+ return option[this.bitRate]
|
|
|
|
+ },
|
|
|
|
+ volumeUpIcon() {
|
|
|
|
+ return this.isLoading || this.isError ? 'icon-volume-up disabled mt50' : 'icon-volume-up mt50'
|
|
|
|
+ },
|
|
|
|
+ volumeDownIcon() {
|
|
|
|
+ return this.isLoading || this.isError ? 'icon-volume-down disabled mt40' : 'icon-volume-down mt40'
|
|
|
|
+ },
|
|
|
|
+ shutDownIcon() {
|
|
|
|
+ return this.isLoading || this.isError ? 'icon-shutdown disabled mt226ormt90' : 'icon-shutdown mt226ormt90'
|
|
|
|
+ },
|
|
|
|
+ restartIcon() {
|
|
|
|
+ return this.isLoading || this.isError ? 'icon-restart disabled mt40' : 'icon-restart mt40'
|
|
|
|
+ },
|
|
|
|
+ menuIcon() {
|
|
|
|
+ return this.isLoading || this.isError ? 'icon-background disabled' : 'icon-background'
|
|
|
|
+ },
|
|
|
|
+ homeIcon() {
|
|
|
|
+ return this.isLoading || this.isError ? 'icon-index disabled mlr64ormlr160' : 'icon-index mlr64ormlr160'
|
|
|
|
+ },
|
|
|
|
+ backIcon() {
|
|
|
|
+ return this.isLoading || this.isError ? 'icon-back disabled' : 'icon-back'
|
|
|
|
+ },
|
|
|
|
+ caretIcon() {
|
|
|
|
+ return this.visble ? 'el-icon-caret-top ml5' : 'el-icon-caret-bottom ml5'
|
|
|
|
+ },
|
|
|
|
+ mobileStyle() {
|
|
|
|
+ return this.isRotate ? 'mobile-dialog rotate' : 'mobile-dialog'
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ created() {
|
|
|
|
+ this.getcardInfoBySn()
|
|
|
|
+ },
|
|
|
|
+ mounted() {
|
|
|
|
+ document.addEventListener('visibilitychange', this.audioPlay)
|
|
|
|
+ document.addEventListener('keydown', this.handleKeyDown)
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
+ this.jmuxer = new JMuxer({
|
|
|
|
+ node: this.$refs.player,
|
|
|
|
+ flushingTime: 15,
|
|
|
|
+ fps: 30,
|
|
|
|
+ mode: 'video',
|
|
|
|
+ debug: false
|
|
|
|
+ })
|
|
|
|
+ this.audioMuxer = new JMuxer({
|
|
|
|
+ node: this.$refs.audioPlayer,
|
|
|
|
+ flushingTime: 1,
|
|
|
|
+ clearBuffer: true,
|
|
|
|
+ fps: 43, // 可以不选
|
|
|
|
+ mode: 'audio',
|
|
|
|
+ debug: false
|
|
|
|
+ })
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ this.curTime = new Date().getTime()
|
|
|
|
+ },
|
|
|
|
+ destroyed() {
|
|
|
|
+ document.removeEventListener('visibilitychange', this.audioPlay)
|
|
|
|
+ document.removeEventListener('keydown', this.handleKeyDown)
|
|
|
|
+ this.socket.send(ExexuteCloseServer(this.sn.join(','))) // 销毁监听
|
|
|
|
+ this.socket.close()
|
|
|
|
+ },
|
|
|
|
+ methods: {
|
|
|
|
+ handleVisble(flag) {
|
|
|
|
+ this.visble = flag
|
|
|
|
+ },
|
|
|
|
+ // 设备恢复出厂设置
|
|
|
|
+ recovery() {
|
|
|
|
+ if (this.isLoading || this.isError) {
|
|
|
|
+ this._message.warning('操作过于频繁,请稍后再试')
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ this.$confirm('<div class="c666 fs18 mb10">确认要恢复出厂设置吗?</div><div class="c999 fs14">恢复出厂后将恢复到初始设置并清除所有数据,恢复出厂过程/n中设备将不可操作。</div>', '恢复出厂', {
|
|
|
|
+ dangerouslyUseHTMLString: true,
|
|
|
|
+ confirmButtonText: '确认',
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
+ customClass: 'cloud-phone-message-box', // 自定义消息样式类名
|
|
|
|
+ confirmButtonClass: 'cloud-phone-confirm-btn', // 自定义确认按钮样式类名
|
|
|
|
+ cancelButtonClass: 'cloud-phone-cancel-btn' // 自定义取消按钮样式类名
|
|
|
|
+ }).then(() => {
|
|
|
|
+ recovery({ sns: this.sn.join(',') }).then(res => {
|
|
|
|
+ if (res.status === 0) {
|
|
|
|
+ this.$alert('<div class="c666 fs18 mb10">恢复出厂设置指令已发送</div><div class="c999 fs14">若恢复出厂设置失败可重试</div>', '恢复出厂', {
|
|
|
|
+ dangerouslyUseHTMLString: true,
|
|
|
|
+ confirmButtonText: '确认',
|
|
|
|
+ customClass: 'cloud-phone-message-box',
|
|
|
|
+ confirmButtonClass: 'cloud-phone-confirm-btn', // 自定义确认按钮样式类名
|
|
|
|
+ callback: action => {
|
|
|
|
+ this.isMask = true
|
|
|
|
+ this.isLoading = true
|
|
|
|
+ this.maskText = '设备恢复出厂设置中...'
|
|
|
|
+ this._send()
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ } else {
|
|
|
|
+ this._message.error('恢复出厂设置指令发送失败,请稍后再试')
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }).catch(() => {})
|
|
|
|
+ },
|
|
|
|
+ // 设备重启
|
|
|
|
+ reboot() {
|
|
|
|
+ if (this.isLoading || this.isError) {
|
|
|
|
+ this._message.warning('操作过于频繁,请稍后再试')
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ this.$confirm('<div class="c666 fs18 mb10">确认要重启设备吗?</div><div class="c999 fs14">重启后将完全关闭后台进程,重启过程中设备将不可操作。</div>', '重启', {
|
|
|
|
+ dangerouslyUseHTMLString: true,
|
|
|
|
+ confirmButtonText: '确认',
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
+ customClass: 'cloud-phone-message-box', // 自定义消息样式类名
|
|
|
|
+ confirmButtonClass: 'cloud-phone-confirm-btn', // 自定义确认按钮样式类名
|
|
|
|
+ cancelButtonClass: 'cloud-phone-cancel-btn' // 自定义取消按钮样式类名
|
|
|
|
+ }).then(() => {
|
|
|
|
+ rebootBatch({ sns: this.sn.join(',') }).then(res => {
|
|
|
|
+ if (res.status === 0) {
|
|
|
|
+ this.$alert('<div class="c666 fs18 mb10">重启指令已发送</div><div class="c999 fs14">若重启失败可重试</div>', '重启', {
|
|
|
|
+ dangerouslyUseHTMLString: true,
|
|
|
|
+ confirmButtonText: '确认',
|
|
|
|
+ customClass: 'cloud-phone-message-box',
|
|
|
|
+ confirmButtonClass: 'cloud-phone-confirm-btn', // 自定义确认按钮样式类名
|
|
|
|
+ callback: action => {
|
|
|
|
+ this.isMask = true
|
|
|
|
+ this.isLoading = true
|
|
|
|
+ this.maskText = '设备重启中...'
|
|
|
|
+ this._send()
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ } else {
|
|
|
|
+ this._message.error('重启指令发送失败,请稍后再试')
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }).catch(() => {})
|
|
|
|
+ },
|
|
|
|
+ async _send() {
|
|
|
|
+ const state = await this.getcardStatus()
|
|
|
|
+ if (state === '1') {
|
|
|
|
+ this.socket.send(ExexuteCloseServer(this.sn.join(','))) // 销毁监听
|
|
|
|
+ this.socket.close()
|
|
|
|
+ this.init()
|
|
|
|
+ this.isLoading = false
|
|
|
|
+ this.isMask = false
|
|
|
|
+ this.maskText = ''
|
|
|
|
+ } else {
|
|
|
|
+ setTimeout(() => {
|
|
|
|
+ this._send()
|
|
|
|
+ }, 3000)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ async getcardStatus() {
|
|
|
|
+ const res = await getcardStatus({ sns: this.sn.join(',') }).then(res => { return res })
|
|
|
|
+ let state = '0'
|
|
|
|
+ if (res.status === 0) {
|
|
|
|
+ state = res.data[0].state
|
|
|
|
+ }
|
|
|
|
+ return state
|
|
|
|
+ },
|
|
|
|
+ // 设置像素
|
|
|
|
+ handleCommand(command) {
|
|
|
|
+ if (this.isLoading || this.isError) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ this.bitRate = command
|
|
|
|
+ const buffer = ExexutePixel(command, this.sn.join(','))
|
|
|
|
+ this.socket.send(buffer)
|
|
|
|
+ },
|
|
|
|
+ // 音量加减、home键、back事件(keyCode的值分别表示为25减音量,24加音量,4为返回键,3为home键,187为切换菜单)
|
|
|
|
+ handleRoutine(code) {
|
|
|
|
+ if (this.isLoading || this.isError) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ const buffer = ExexuteKeyDown(code, this.sn.join(','))
|
|
|
|
+ this.socket.send(buffer)
|
|
|
|
+ },
|
|
|
|
+ // 鼠标点击事件
|
|
|
|
+ handleMouseDown(event) {
|
|
|
|
+ if (this.isLoading || this.isError) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ if (event.button === 0) {
|
|
|
|
+ var posX = this.isRotate ? event.offsetY / VIDEO_HEIGHT * 1920 * 1.0 : event.offsetX / VIDEO_WIDTH * 1080 * 1.0
|
|
|
|
+ var posY = this.isRotate ? (VIDEO_WIDTH - event.offsetX) / VIDEO_WIDTH * 1080 * 1.0 : event.offsetY / VIDEO_HEIGHT * 1920 * 1.0
|
|
|
|
+ var buffer = ExexuteMouseDown(posX.toString(), posY.toString(), this.sn.join(','))
|
|
|
|
+ this.socket.send(buffer)
|
|
|
|
+ this.isDrag = true
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ // 鼠标移开事件
|
|
|
|
+ handleMouseLeave(event) {
|
|
|
|
+ if (this.isLoading || this.isError) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ this.isDrag = false
|
|
|
|
+ var posX = this.isRotate ? event.offsetY / VIDEO_HEIGHT * 1920 * 1.0 : event.offsetX / VIDEO_WIDTH * 1080 * 1.0
|
|
|
|
+ var posY = this.isRotate ? (VIDEO_WIDTH - event.offsetX) / VIDEO_WIDTH * 1080 * 1.0 : event.offsetY / VIDEO_HEIGHT * 1920 * 1.0
|
|
|
|
+ var buffer = ExexuteMouseUp(posX.toString(), posY.toString(), this.sn.join(','))
|
|
|
|
+ this.socket.send(buffer)
|
|
|
|
+ },
|
|
|
|
+ // 鼠标移动事件
|
|
|
|
+ handleMouseMove(event) {
|
|
|
|
+ if (this.isLoading || this.isError) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ if (this.isDrag && event.button === 0) {
|
|
|
|
+ var posX = this.isRotate ? event.offsetY / VIDEO_HEIGHT * 1920 * 1.0 : event.offsetX / VIDEO_WIDTH * 1080 * 1.0
|
|
|
|
+ var posY = this.isRotate ? (VIDEO_WIDTH - event.offsetX) / VIDEO_WIDTH * 1080 * 1.0 : event.offsetY / VIDEO_HEIGHT * 1920 * 1.0
|
|
|
|
+ var buffer = ExexuteMouseMove(posX.toString(), posY.toString(), this.sn.join(','))
|
|
|
|
+ this.socket.send(buffer)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ // 鼠标离开事件
|
|
|
|
+ handleMouseUp(event) {
|
|
|
|
+ if (this.isLoading || this.isError) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ this.isDrag = false
|
|
|
|
+ var posX = this.isRotate ? event.offsetY / VIDEO_HEIGHT * 1920 * 1.0 : event.offsetX / VIDEO_WIDTH * 1080 * 1.0
|
|
|
|
+ var posY = this.isRotate ? (VIDEO_WIDTH - event.offsetX) / VIDEO_WIDTH * 1080 * 1.0 : event.offsetY / VIDEO_HEIGHT * 1920 * 1.0
|
|
|
|
+ var buffer = ExexuteMouseUp(posX.toString(), posY.toString(), this.sn.join(','))
|
|
|
|
+ this.socket.send(buffer)
|
|
|
|
+ },
|
|
|
|
+ // 键盘输入事件
|
|
|
|
+ handleKeyDown(event) {
|
|
|
|
+ if (this.isLoading || this.isError) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ var buffer = ExexuteKeyDown(keycodeMode[event.keyCode] || event.keyCode, this.sn.join(','))
|
|
|
|
+ this.socket.send(buffer)
|
|
|
|
+ },
|
|
|
|
+ // websocket初始化
|
|
|
|
+ init() {
|
|
|
|
+ this.socket = new WebSocket(this.path) // 实例化socket
|
|
|
|
+ this.socket.binaryType = 'arraybuffer'
|
|
|
|
+ this.socket.onopen = this.open // 监听socket连接
|
|
|
|
+ this.socket.onerror = this.onerror // 监听socket错误信息
|
|
|
|
+ this.socket.onmessage = this.getMessage // 监听socket消息
|
|
|
|
+ },
|
|
|
|
+ // websocket连接成功回调
|
|
|
|
+ open() {
|
|
|
|
+ this.isMask = false
|
|
|
|
+ this.isError = false
|
|
|
|
+ this.socket.send(ConfigChannel(this.sn))
|
|
|
|
+ this.socket.onmessage = this.getMessage
|
|
|
|
+ },
|
|
|
|
+ // websocket连接失败回调
|
|
|
|
+ onerror() {
|
|
|
|
+ console.log('websocket连接失败')
|
|
|
|
+ this.isLoading = false
|
|
|
|
+ this.isError = true
|
|
|
|
+ this.maskText = '设备故障或离线'
|
|
|
|
+ },
|
|
|
|
+ getMessage(event) {
|
|
|
|
+ const data = this.parse(event.data) // 分离音视频数据
|
|
|
|
+ const audioData = {
|
|
|
|
+ audio: data.audio,
|
|
|
|
+ video: null,
|
|
|
|
+ duration: data.duration
|
|
|
|
+ }
|
|
|
|
+ // const videoData = {
|
|
|
|
+ // audio: null,
|
|
|
|
+ // video: data.video,
|
|
|
|
+ // duration: data.duration
|
|
|
|
+ // }
|
|
|
|
+
|
|
|
|
+ if (this.$refs.audioPlayer && this.$refs.audioPlayer.readyState === 2) {
|
|
|
|
+ const playPromise = this.$refs.audioPlayer.play()
|
|
|
|
+ if (playPromise !== undefined) {
|
|
|
|
+ playPromise.then(() => {
|
|
|
|
+ this.$refs.audioPlayer.play()
|
|
|
|
+ }).catch(() => {})
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (data.audio != null) { // 喂音频
|
|
|
|
+ this.audioMuxer.feed(audioData)
|
|
|
|
+ }
|
|
|
|
+ if (data.video != null && this.isFeed) { // 喂视频
|
|
|
|
+ this.jmuxer.feed(data)
|
|
|
|
+ }
|
|
|
|
+ if (data.video) {
|
|
|
|
+ if (new Date().getTime() - this.curTime >= 1000) {
|
|
|
|
+ this.fpsCount = 0
|
|
|
|
+ this.curTime = new Date().getTime()
|
|
|
|
+ } else {
|
|
|
|
+ this.fpsCount++
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ // 弹窗关闭
|
|
|
|
+ close() {
|
|
|
|
+ this.$emit('closeDialog', 'showMobile')
|
|
|
|
+ },
|
|
|
|
+ // 根据sn获取设备获取清晰度、端口号和ip
|
|
|
|
+ getcardInfoBySn() {
|
|
|
|
+ var list = []
|
|
|
|
+ list.push(this.mobileId)
|
|
|
|
+ getcardInfoBySn({ mobileIdList: list }).then(res => {
|
|
|
|
+ if (res.status === 0) {
|
|
|
|
+ this.ip = res.data[0].ip
|
|
|
|
+ this.port = res.data[0].port
|
|
|
|
+ this.size = res.data[0].size
|
|
|
|
+ this.bitRate = res.data[0].bitRate === '0' ? '1638400' : res.data.bitRate
|
|
|
|
+ this.path = `ws://${res.data[0].ip}:${res.data[0].websocketPort.toString()}`
|
|
|
|
+ //console.log(this.path)
|
|
|
|
+ this.init()
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+ pause() {
|
|
|
|
+ this.isFeed = false
|
|
|
|
+ },
|
|
|
|
+ audioPlay() {
|
|
|
|
+ if (document.visibilityState === 'visible') {
|
|
|
|
+ this.isFlag = true
|
|
|
|
+ this.socket.send(RequestIFrame(this.sn.join(',')))
|
|
|
|
+ } else {
|
|
|
|
+ this.isFlag = false
|
|
|
|
+ this.isFeed = false
|
|
|
|
+ this.$refs.player.pause()
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ ready() {
|
|
|
|
+ this.isLoading = false
|
|
|
|
+ },
|
|
|
|
+ error() {
|
|
|
|
+ this.isMask = true
|
|
|
|
+ this.isError = true
|
|
|
|
+ },
|
|
|
|
+ parse(data) {
|
|
|
|
+ // var input = new Uint8Array(data)
|
|
|
|
+ // var dv = new DataView(input.buffer)
|
|
|
|
+ // var duration = dv.getUint16(0, true) // 获取duration
|
|
|
|
+ // var audioLength = dv.getUint16(2, true)
|
|
|
|
+ // var audio
|
|
|
|
+ // var video
|
|
|
|
+
|
|
|
|
+ // if (audioLength === 0) {
|
|
|
|
+ // video = input.subarray(4)
|
|
|
|
+ // } else {
|
|
|
|
+ // audio = input.subarray(4, (audioLength + 4))
|
|
|
|
+ // video = input.subarray(audioLength + 4)
|
|
|
|
+ // }
|
|
|
|
+
|
|
|
|
+ // return {
|
|
|
|
+ // audio: audio,
|
|
|
|
+ // video: video,
|
|
|
|
+ // duration: duration
|
|
|
|
+ // }
|
|
|
|
+ var input = new Uint8Array(data)
|
|
|
|
+ var duration
|
|
|
|
+ var video
|
|
|
|
+ var audio
|
|
|
|
+ if (input[0] === 0 && input[1] === 0 && input[2] === 0 && input[3] === 1) {
|
|
|
|
+ video = input
|
|
|
|
+ duration = 24
|
|
|
|
+ var nalType = input[4] & 0x1f
|
|
|
|
+ if (nalType === 0x05 && this.isFlag) { // 策略, 找到sps、sps、或I帧,才继续渲染
|
|
|
|
+ this.isFeed = true
|
|
|
|
+ }
|
|
|
|
+ } else if (input[0] === 0xff) {
|
|
|
|
+ audio = input
|
|
|
|
+ duration = 24
|
|
|
|
+ } else if (input[23] === 0x0b) {
|
|
|
|
+ this.$alert('<div class="c666 fs18 mb10">设备' + this.mobileName + '已在其它端受控</div>', '提示', {
|
|
|
|
+ dangerouslyUseHTMLString: true,
|
|
|
|
+ confirmButtonText: '确认',
|
|
|
|
+ customClass: 'cloud-phone-message-box',
|
|
|
|
+ confirmButtonClass: 'cloud-phone-confirm-btn', // 自定义确认按钮样式类名
|
|
|
|
+ callback: action => {
|
|
|
|
+ this.showMobile = false
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ } else if (input[0] === 0x68 && input[23] === 0x05) {
|
|
|
|
+ var state = CheckScreenDirection(input.slice(24, 24 + 8))
|
|
|
|
+ if (state === 1) {
|
|
|
|
+ this.isRotate = false
|
|
|
|
+ } else {
|
|
|
|
+ this.isRotate = true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ audio: audio,
|
|
|
|
+ video: video,
|
|
|
|
+ duration: duration
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style lang="scss">
|
|
|
|
+ .ml111 {margin-left: 111px;}.mt50{margin-top: 50px;}.mt40{margin-top: 40px;}
|
|
|
|
+ .w180h148 {width: 180px;height: 148px;}.mr100{margin-right: 100px;}
|
|
|
|
+ .mobile-dialog {
|
|
|
|
+ width: 417px;
|
|
|
|
+ height: 740px;
|
|
|
|
+ background: #141414;
|
|
|
|
+ box-shadow: 0px 0px 30px 0px rgba(0, 0, 0, 0.5);
|
|
|
|
+ border-radius: 0;
|
|
|
|
+ &.rotate {
|
|
|
|
+ width: 705px;
|
|
|
|
+ height: 452px;
|
|
|
|
+ .el-dialog__body {
|
|
|
|
+ padding: 0;
|
|
|
|
+ .mt226ormt90{
|
|
|
|
+ margin-top: 90px;
|
|
|
|
+ }
|
|
|
|
+ .mlr64ormlr160{
|
|
|
|
+ margin-left: 160px;
|
|
|
|
+ margin-right: 160px;
|
|
|
|
+ }
|
|
|
|
+ .mobile-audio {
|
|
|
|
+ width: 660px;
|
|
|
|
+ height: 372px;
|
|
|
|
+ position: relative;
|
|
|
|
+ video {
|
|
|
|
+ transform:rotate(-90deg);
|
|
|
|
+ position: absolute;
|
|
|
|
+ top: -145px;
|
|
|
|
+ left: 145px;
|
|
|
|
+ }
|
|
|
|
+ .mask {
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 100%;
|
|
|
|
+ background-color: #fff;
|
|
|
|
+ position: absolute;
|
|
|
|
+ top: 0;
|
|
|
|
+ left: 0;
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ flex-direction: column;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ .mobile-sidebar {
|
|
|
|
+ width: 45px;
|
|
|
|
+ height: 372px;
|
|
|
|
+ display: flex;
|
|
|
|
+ flex-direction: column;
|
|
|
|
+ align-items: center;
|
|
|
|
+ }
|
|
|
|
+ .mobile-bottombar {
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 40px;
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ .el-dialog__header {
|
|
|
|
+ height: 40px;
|
|
|
|
+ line-height: 40px;
|
|
|
|
+ padding: 0;
|
|
|
|
+ .el-dialog__headerbtn {
|
|
|
|
+ top: 13px;
|
|
|
|
+ right: 15px;
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ .el-dialog__close {
|
|
|
|
+ color: #fff;
|
|
|
|
+ font-weight: 800;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ .el-dialog__body {
|
|
|
|
+ padding: 0;
|
|
|
|
+ .mt226ormt90 {
|
|
|
|
+ margin-top: 226px;
|
|
|
|
+ }
|
|
|
|
+ .mlr64ormlr160{
|
|
|
|
+ margin-left: 64px;
|
|
|
|
+ margin-right: 64px;
|
|
|
|
+ }
|
|
|
|
+ .mobile-audio {
|
|
|
|
+ width: 371px;
|
|
|
|
+ height: 660px;
|
|
|
|
+ position: relative;
|
|
|
|
+ .mask {
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 100%;
|
|
|
|
+ background-color: #fff;
|
|
|
|
+ position: absolute;
|
|
|
|
+ top: 0;
|
|
|
|
+ left: 0;
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ flex-direction: column;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ .mobile-sidebar {
|
|
|
|
+ width: 46px;
|
|
|
|
+ height: 660px;
|
|
|
|
+ display: flex;
|
|
|
|
+ flex-direction: column;
|
|
|
|
+ align-items: center;
|
|
|
|
+ }
|
|
|
|
+ .mobile-bottombar {
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 40px;
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ .mobile-dropdown-menu {
|
|
|
|
+ width: 110px;
|
|
|
|
+ padding: 5px 0;
|
|
|
|
+ border: none;
|
|
|
|
+ box-shadow: 0px 0px 30px 0px rgba(0, 0, 0, 0.3);
|
|
|
|
+ .popper__arrow {
|
|
|
|
+ border-width: 10px;
|
|
|
|
+ border-bottom-color: #fff !important;
|
|
|
|
+ top: -8px !important;
|
|
|
|
+ left: 60px !important;
|
|
|
|
+ }
|
|
|
|
+ .el-dropdown-menu__item {
|
|
|
|
+ height: 40px;
|
|
|
|
+ line-height: 40px;
|
|
|
|
+ &:hover {
|
|
|
|
+ background-color: #F3F6FF;
|
|
|
|
+ color: #333;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ audio {
|
|
|
|
+ display: none;
|
|
|
|
+ }
|
|
|
|
+</style>
|