index.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. <template>
  2. <div class="room">
  3. <topBar class="room-bar">
  4. <template
  5. v-for="(item, index) in menuList"
  6. :key="index"
  7. >
  8. <component
  9. :is="item.component"
  10. :value="item.value"
  11. @callBack="item.callBack"
  12. />
  13. </template>
  14. </topBar>
  15. <video
  16. ref="remoteVideo"
  17. autoplay
  18. playsinline
  19. />
  20. <div class="room-gauge">
  21. <Gauge
  22. :value="gauge.speed"
  23. :gears="gauge.num % 2 ? '倒档' : '前进'"
  24. />
  25. </div>
  26. </div>
  27. </template>
  28. <script setup lang='ts'>
  29. import {
  30. ref, onMounted, inject, watch,
  31. onUnmounted,
  32. shallowRef,
  33. defineAsyncComponent
  34. } from 'vue'
  35. import WebRtcService from '@/services/webrtc.service'
  36. import topBar from '@/components/topBar.vue'
  37. import Gauge from './component/gauge.vue'
  38. import useStore from '@/store/index'
  39. const RTC = new WebRtcService()
  40. const store = useStore()
  41. const mqtt = inject('MQTT') as Any
  42. const remoteVideo = ref(null as unknown as HTMLVideoElement)
  43. const gauge = ref({ speed: 0, num: 0 })
  44. const menuList = shallowRef([
  45. { name: '信号', value: 0, component: defineAsyncComponent(() => import('./component/signal.vue')) },
  46. { name: '电量', value: 0, component: defineAsyncComponent(() => import('./component/battery.vue')) },
  47. { name: '方向盘', vlaue: 0, component: defineAsyncComponent(() => import('./component/steering.vue')) },
  48. {
  49. name: '静音',
  50. component: defineAsyncComponent(() => import('./component/audio.vue')),
  51. callBack: (mute: boolean) => RTC.muteRemoteAudio(mute)
  52. },
  53. {
  54. name: '录音',
  55. component: defineAsyncComponent(() => import('./component/mic.vue')),
  56. callBack: (blob: Blob) => {
  57. console.log('发送对讲', blob)
  58. }
  59. },
  60. { name: '网速', vlaue: 0, component: defineAsyncComponent(() => import('./component/stats.vue')) }
  61. ])
  62. watch(() => store.mqtt_message, async (value: { type: string, data?: RTCSessionDescriptionInit }) => {
  63. const { type, data } = value
  64. // 接收远程offer
  65. if (type === 'offer') {
  66. await RTC.Peer?.setRemoteDescription(data!)
  67. const answerd = await RTC.Peer?.createAnswer()
  68. await RTC.Peer?.setLocalDescription(answerd)
  69. }
  70. // 发送本地answer
  71. if (type === 'answer') mqtt.send(value)
  72. // 控制数据
  73. if (type === 'control') {
  74. menuList.value[2].vlaue = data ? 1 : 0
  75. const obj = {
  76. type: 'control',
  77. data: {
  78. steering: 0, // 方向 -1-1
  79. throttle: 0, // 油门 0-1
  80. brake: 0, // 刹车 0-1
  81. clutch: 0, // 离合 0-1
  82. leftPaddle: false, // 左拨挡
  83. rightPaddle: false, // 右拨挡
  84. buttonR3: false, // R3
  85. buttonL3: false, // L3
  86. enterKey: false, // 回车键
  87. ...data
  88. }
  89. }
  90. if (obj.data.leftPaddle) gauge.value.num--
  91. if (obj.data.rightPaddle) gauge.value.num++
  92. if (store.rtcConnected) mqtt.send(obj)
  93. }
  94. // 网络状态
  95. if (type === 'WebRtcStats') menuList.value[5].vlaue = data.bitrate || 0
  96. })
  97. onMounted(() => RTC.initRTC(remoteVideo.value))
  98. onUnmounted(() => RTC.distory())
  99. </script>
  100. <style lang="scss" scoped>
  101. .room {
  102. width: 100%;
  103. height: 100%;
  104. position: relative;
  105. video {
  106. width: 100%;
  107. height: 100%;
  108. background: black;
  109. object-fit: fill;
  110. font-size: 0;
  111. z-index: 1;
  112. }
  113. }
  114. </style>