|
|
@@ -1,8 +1,5 @@
|
|
|
<script setup lang="ts">
|
|
|
-import { Socket, io } from 'socket.io-client'
|
|
|
-import {
|
|
|
- onMounted, onUnmounted, ref, watch
|
|
|
-} from 'vue'
|
|
|
+import { onUnmounted, ref, watch } from 'vue'
|
|
|
import Login from '@/components/login.vue'
|
|
|
import Gauge from '@/components/gauge.vue'
|
|
|
import Record from '@/components/record.vue'
|
|
|
@@ -10,7 +7,6 @@ import Battery from '@/components/battery.vue'
|
|
|
import Loading from '@/components/loading.vue'
|
|
|
|
|
|
const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms))
|
|
|
-const HOST = 'wss://car.caner.top'
|
|
|
const iceServers = [
|
|
|
{
|
|
|
urls: [ 'stun:caner.top:3478' ]
|
|
|
@@ -21,7 +17,6 @@ const iceServers = [
|
|
|
credential: '123456'
|
|
|
}
|
|
|
]
|
|
|
-const socket = ref(null as null | Socket)
|
|
|
const Peer = ref(null as null | RTCPeerConnection | undefined)
|
|
|
const isLogin = ref(false)
|
|
|
const remoteVideo = ref()
|
|
|
@@ -44,159 +39,166 @@ const SpeedValue = ref(0)
|
|
|
// 方向盘数据
|
|
|
function onContrlData() {
|
|
|
if (showLoading.value) return
|
|
|
- socket.value?.emit('msg', { type: 'conctrl', conctrl: { ...conctrlData.value } })
|
|
|
+ window.$electron.send('sendMqtt', { type: 'conctrl', conctrl: { ...conctrlData.value } })
|
|
|
conctrlAnimation.value = requestAnimationFrame(onContrlData)
|
|
|
}
|
|
|
|
|
|
-// 档位计算
|
|
|
-function countContrlData(v: number) {
|
|
|
- // 转10进制
|
|
|
- const num = parseInt(v.toString(), 10)
|
|
|
- if (conctrlNum.value % 2) {
|
|
|
- // 倒档
|
|
|
- return Math.floor(num / 2)
|
|
|
- }
|
|
|
- // 前进
|
|
|
- return Math.floor(((128 - (num / 2)) + 128))
|
|
|
-}
|
|
|
-
|
|
|
// 关闭
|
|
|
function close(err?: string) {
|
|
|
if (Peer.value) Peer.value?.close()
|
|
|
if (remoteVideo.value) remoteVideo.value.srcObject = null
|
|
|
- if (socket.value) socket.value.disconnect()
|
|
|
isLogin.value = false
|
|
|
showLoading.value = false
|
|
|
error.value = err || ''
|
|
|
- socket.value = null
|
|
|
Peer.value = null
|
|
|
audioStateNum.value = 0
|
|
|
quantity.value = 0
|
|
|
cancelAnimationFrame(conctrlAnimation.value)
|
|
|
+ console.log('退出')
|
|
|
}
|
|
|
|
|
|
-// init socket
|
|
|
-function intSoketRtc(host: string) {
|
|
|
- showLoading.value = true
|
|
|
- // int socket
|
|
|
- socket.value = io(host, {
|
|
|
- autoConnect: false,
|
|
|
- transports: [ 'websocket' ]
|
|
|
- })
|
|
|
+// 初始化rtc
|
|
|
+function initRTC() {
|
|
|
+ try {
|
|
|
+ Peer.value = new RTCPeerConnection({
|
|
|
+ iceServers,
|
|
|
+ bundlePolicy: 'max-bundle'
|
|
|
+ })
|
|
|
|
|
|
- // socket
|
|
|
- socket.value.on('connect', () => {
|
|
|
- try {
|
|
|
- isLogin.value = true
|
|
|
- // init webrtc
|
|
|
- Peer.value = new RTCPeerConnection({
|
|
|
- iceServers,
|
|
|
- bundlePolicy: 'max-bundle'
|
|
|
- })
|
|
|
-
|
|
|
- // listen state
|
|
|
- Peer.value.onicegatheringstatechange = () => {
|
|
|
- console.log('GatheringState: ', Peer.value?.iceGatheringState)
|
|
|
- if (Peer.value?.iceGatheringState === 'complete') {
|
|
|
- const answer = Peer.value.localDescription
|
|
|
- socket.value?.emit('msg', answer)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // listen track
|
|
|
- Peer.value.ontrack = async (evt) => {
|
|
|
- console.log('track', evt)
|
|
|
- remoteVideo.value.srcObject = evt.streams[0]
|
|
|
+ // listen state
|
|
|
+ Peer.value.onicegatheringstatechange = () => {
|
|
|
+ console.log('GatheringState: ', Peer.value?.iceGatheringState)
|
|
|
+ if (Peer.value?.iceGatheringState === 'complete') {
|
|
|
+ const answer = Peer.value.localDescription
|
|
|
+ window.$electron.send('sendMqtt', answer)
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // listen changestate·
|
|
|
- Peer.value.oniceconnectionstatechange = async () => {
|
|
|
- const state = Peer.value?.iceConnectionState
|
|
|
- console.log('ICE状态', state)
|
|
|
- if (
|
|
|
- state === 'failed'
|
|
|
- || state === 'disconnected'
|
|
|
- || state === 'closed'
|
|
|
- ) {
|
|
|
- close('P2P通信失败')
|
|
|
- }
|
|
|
+ // listen track
|
|
|
+ Peer.value.ontrack = async (evt) => {
|
|
|
+ console.log('track', evt)
|
|
|
+ remoteVideo.value.srcObject = evt.streams[0]
|
|
|
+ }
|
|
|
|
|
|
- // ICE连接成功
|
|
|
- if (state === 'connected') {
|
|
|
- await sleep(3000)
|
|
|
- showLoading.value = false
|
|
|
- onContrlData()
|
|
|
- }
|
|
|
+ // listen changestate·
|
|
|
+ Peer.value.oniceconnectionstatechange = async () => {
|
|
|
+ const state = Peer.value?.iceConnectionState
|
|
|
+ console.log('ICE状态', state)
|
|
|
+ if (
|
|
|
+ state === 'failed'
|
|
|
+ || state === 'disconnected'
|
|
|
+ || state === 'closed'
|
|
|
+ ) {
|
|
|
+ close('P2P通信失败')
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
- close('webrtc初始化失败')
|
|
|
- }
|
|
|
- })
|
|
|
|
|
|
- socket.value.on('msg', async (data) => {
|
|
|
- const key = data.type
|
|
|
- if (key === 'offer') {
|
|
|
- await Peer.value?.setRemoteDescription(data)
|
|
|
- const answer = await Peer.value?.createAnswer()
|
|
|
- await Peer.value?.setLocalDescription(answer)
|
|
|
- } else if (key === 'power') {
|
|
|
- quantity.value = data.power
|
|
|
- } else if (key === 'speed') {
|
|
|
- const d = Math.floor(data.data)
|
|
|
- SpeedValue.value = d
|
|
|
+ // ICE连接成功
|
|
|
+ if (state === 'connected') {
|
|
|
+ await sleep(3000)
|
|
|
+ showLoading.value = false
|
|
|
+ onContrlData()
|
|
|
+ }
|
|
|
}
|
|
|
- })
|
|
|
+ console.log('rtc 初始化成功')
|
|
|
+ } catch (error) {
|
|
|
+ close('webrtc初始化失败')
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- socket.value.on('joined', async () => socket.value?.emit('msg', { type: 'startRTC' }))
|
|
|
+// 登录
|
|
|
+async function login(data: { name: string, roomID: string }) {
|
|
|
+ window.$electron.send('loginMqtt', { room: data.roomID, name: data.name })
|
|
|
+}
|
|
|
|
|
|
- socket.value.on('leaved', () => close('车端断开'))
|
|
|
+// 档位计算
|
|
|
+function countContrlData(v: number) {
|
|
|
+ // 转10进制
|
|
|
+ const num = parseInt(v.toString(), 10)
|
|
|
+ if (conctrlNum.value % 2) {
|
|
|
+ // 倒档
|
|
|
+ return Math.floor(num / 2)
|
|
|
+ }
|
|
|
+ // 前进
|
|
|
+ return Math.floor(((128 - (num / 2)) + 128))
|
|
|
+}
|
|
|
|
|
|
- socket.value.on('connect_error', () => close('服务器连接失败'))
|
|
|
+// 发送语音
|
|
|
+function sendAudio(blob: Blob) {
|
|
|
+ window.$electron.send('sendMqtt', { type: 'Meadia', Meadia: blob })
|
|
|
}
|
|
|
|
|
|
-// 遥控数据
|
|
|
-window.$electron?.on('contrlData', (db: Uint8Array) => {
|
|
|
- // 倒档 | 前进 =>右拨片
|
|
|
- conctrlGrears.value = db[6] === 2
|
|
|
- // 鸣笛 =>回车
|
|
|
- warnAudio.value = !!db[54]
|
|
|
- // 录音 =>左拨片
|
|
|
- micState.value = db[6] === 1
|
|
|
- // 静音 =>L3
|
|
|
- audioState.value = db[6] === 64
|
|
|
- // 控制
|
|
|
- conctrlData.value = {
|
|
|
- v0: 128,
|
|
|
- v1: 128,
|
|
|
- v2: parseInt(db[44].toString(), 10), // 方向盘
|
|
|
- v3: countContrlData(db[46]) // 油门
|
|
|
+// mqtt
|
|
|
+window.$electron.on('message', async (msg: any) => {
|
|
|
+ switch (msg.type) {
|
|
|
+ case 'connect':
|
|
|
+ console.log('连接成功')
|
|
|
+ isLogin.value = true
|
|
|
+ showLoading.value = true
|
|
|
+ break
|
|
|
+ case 'disconnect':
|
|
|
+ close('服务器连接失败')
|
|
|
+ break
|
|
|
+ case 'join':
|
|
|
+ window.$electron.send('sendMqtt', { type: 'startRTC' })
|
|
|
+ console.log('开始rtc')
|
|
|
+
|
|
|
+ initRTC()
|
|
|
+ break
|
|
|
+ case 'leave':
|
|
|
+ close('对方断开连接')
|
|
|
+
|
|
|
+ break
|
|
|
+ case 'offer':
|
|
|
+ {
|
|
|
+ await Peer.value?.setRemoteDescription(msg)
|
|
|
+ const answerd = await Peer.value?.createAnswer()
|
|
|
+ await Peer.value?.setLocalDescription(answerd)
|
|
|
+ }
|
|
|
+ break
|
|
|
+ case 'power':
|
|
|
+ quantity.value = msg.power
|
|
|
+ console.log('电量')
|
|
|
+
|
|
|
+ break
|
|
|
+ case 'speed':
|
|
|
+ SpeedValue.value = Math.floor(msg.data)
|
|
|
+ console.log('速度')
|
|
|
+
|
|
|
+ break
|
|
|
+ case 'contrl':
|
|
|
+ {
|
|
|
+ const db = msg.content
|
|
|
+ // 倒档 | 前进 =>右拨片
|
|
|
+ conctrlGrears.value = db[6] === 2
|
|
|
+ // 鸣笛 =>回车
|
|
|
+ warnAudio.value = !!db[54]
|
|
|
+ // 录音 =>左拨片
|
|
|
+ micState.value = db[6] === 1
|
|
|
+ // 静音 =>L3
|
|
|
+ audioState.value = db[6] === 64
|
|
|
+ // 控制
|
|
|
+ conctrlData.value = {
|
|
|
+ v0: 128,
|
|
|
+ v1: 128,
|
|
|
+ v2: parseInt(db[44].toString(), 10), // 方向盘
|
|
|
+ v3: countContrlData(db[46]) // 油门
|
|
|
+ }
|
|
|
+ }
|
|
|
+ console.log('遥控数据', conctrlData.value)
|
|
|
+ break
|
|
|
+ default:
|
|
|
+ break
|
|
|
}
|
|
|
- console.log(6, conctrlData.value)
|
|
|
})
|
|
|
|
|
|
// 窗口事件
|
|
|
function titleEvent(type: string) {
|
|
|
if (type === 'maxWin') winMaxOrMin.value = !winMaxOrMin.value
|
|
|
- if (type === 'loginOut') { close(); return }
|
|
|
- window.$electron?.send(type, winMaxOrMin.value)
|
|
|
-}
|
|
|
-
|
|
|
-// 发送语音
|
|
|
-function sendAudio(blob: Blob) {
|
|
|
- socket.value?.emit('msg', {
|
|
|
- type: 'Meadia',
|
|
|
- Meadia: blob
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-// 登录
|
|
|
-async function login(data: { name: string, roomID: string }) {
|
|
|
- if (!socket.value) intSoketRtc(HOST)
|
|
|
- socket.value!.auth = {
|
|
|
- roomID: data.roomID,
|
|
|
- name: data.name
|
|
|
+ if (type === 'loginOut') {
|
|
|
+ close()
|
|
|
+ } else {
|
|
|
+ window.$electron?.send(type, winMaxOrMin.value)
|
|
|
}
|
|
|
- socket.value?.connect()
|
|
|
}
|
|
|
|
|
|
// 监听按钮状态
|
|
|
@@ -204,21 +206,19 @@ watch([ audioState, warnAudio, conctrlGrears ], () => {
|
|
|
if (showLoading.value) return
|
|
|
if (audioState.value) {
|
|
|
audioStateNum.value++
|
|
|
- socket.value?.emit('msg', { type: 'contrlAudio', contrlAudio: !!(audioStateNum.value % 2) })
|
|
|
+ window.$electron.send('sendMqtt', { type: 'contrlAudio', contrlAudio: !!(audioStateNum.value % 2) })
|
|
|
}
|
|
|
if (conctrlGrears.value) {
|
|
|
conctrlNum.value++
|
|
|
}
|
|
|
- if (warnAudio.value) socket.value?.emit('msg', { type: 'warnAudio' })
|
|
|
+ if (warnAudio.value) window.$electron.send('sendMqtt', { type: 'warnAudio', contrlAudio: !!(audioStateNum.value % 2) })
|
|
|
})
|
|
|
|
|
|
-// 初始化
|
|
|
-onMounted(() => intSoketRtc(HOST))
|
|
|
onUnmounted(() => close())
|
|
|
|
|
|
// 关闭loadingwin
|
|
|
window.$electron.send('close-loading')
|
|
|
-</script>·
|
|
|
+</script>
|
|
|
<template>
|
|
|
<template v-if="isLogin">
|
|
|
<video
|