<template>
  <div id="app">
    <template v-if="isLogin">
      <video id="v2" autoplay playsinline muted></video>
      <div class="marke">
        <!-- 手柄状态 -->
        <svg
          viewBox="0 -50 1024 1024"
          version="1.1"
          xmlns="http://www.w3.org/2000/svg"
          width="30"
          height="30"
        >
          <path
            d="M817.68 803.17a130.23 130.23 0 0 1-125.6-96.37l-14-52.19a54.08 54.08 0 0 0-52.16-40H398.07a54.08 54.08 0 0 0-52.16 40l-14 52.19c-15.54 58-68.21 96.37-125.6 96.37A130 130 0 0 1 80.78 639.51l66.72-249a181.66 181.66 0 0 1 63.19-97.15A177.79 177.79 0 0 1 322 254.58h380a177.79 177.79 0 0 1 111.31 38.79 181.66 181.66 0 0 1 63.19 97.15l66.72 249a130 130 0 0 1-125.54 163.65zM322 274.58A160 160 0 0 0 166.87 395.5v0.13l-66.73 249a110 110 0 0 0 212.5 56.94l14-52.19a74.11 74.11 0 0 1 71.48-54.85h227.81a74.11 74.11 0 0 1 71.48 54.85l14 52.19a110 110 0 0 0 212.5-56.94L857.13 395.5A160 160 0 0 0 702 274.58z"
            :fill="contrlState ? '#00CED1' : 'rgba(0, 0, 0, 0.3)'"
          ></path>
          <path
            d="M580 213.86a12 12 0 0 1 12 12v28H432v-28a12 12 0 0 1 12-12h136m0-20H444a32 32 0 0 0-32 32v48h200v-48a32 32 0 0 0-32-32z"
            :fill="contrlState ? '#00CED1' : 'rgba(0, 0, 0, 0.3)'"
          ></path>
          <path
            d="M512 213.86a10 10 0 0 1-10-10v-63a60.07 60.07 0 0 1 60-60 10 10 0 0 1 0 20 40 40 0 0 0-40 40v63a10 10 0 0 1-10 10zM330 344.86a90 90 0 1 1-90 90 90.1 90.1 0 0 1 90-90m0-20a110 110 0 1 0 110 110 110 110 0 0 0-110-110z"
            :fill="contrlState ? '#00CED1' : 'rgba(0, 0, 0, 0.3)'"
          ></path>
          <path
            d="M330 384.86a50 50 0 1 1-50 50 50.06 50.06 0 0 1 50-50m0-20a70 70 0 1 0 70 70 70 70 0 0 0-70-70zM697 344.86a14 14 0 1 1-14 14 14 14 0 0 1 14-14m0-20a34 34 0 1 0 34 34 34 34 0 0 0-34-34zM697 496.86a14 14 0 1 1-14 14 14 14 0 0 1 14-14m0-20a34 34 0 1 0 34 34 34 34 0 0 0-34-34zM773 420.86a14 14 0 1 1-14 14 14 14 0 0 1 14-14m0-20a34 34 0 1 0 34 34 34 34 0 0 0-34-34zM621 420.86a14 14 0 1 1-14 14 14 14 0 0 1 14-14m0-20a34 34 0 1 0 34 34 34 34 0 0 0-34-34z"
            :fill="contrlState ? '#00CED1' : 'rgba(0, 0, 0, 0.3)'"
          ></path>
        </svg>
        <!-- 音频 -->
        <Record />
        <!-- 信号 -->
        <Signal :signalValue="4" />
        <!-- 电量 -->
        <Battery :quantity="60" />
      </div>
      <div class="gauge">
        <Gauge :value="50" :gears="speed" />
      </div>
      <Loading v-if="showLoading" />
    </template>
    <Login v-else :err="error" @loginBack="login" />
  </div>
</template>

<script>
const { io } = require("socket.io-client");
import Login from "@/components/login";
import Loading from "@/components/loading";
import Record from "@/components/record";
import Signal from "@/components/signal";
import Battery from "@/components/battery";
import Gauge from "@/components/gauge";
import { Message } from "view-design";

const sleep = (ms) => new Promise((res) => setTimeout(res, ms));
export default {
  components: { Login, Loading, Record, Signal, Battery, Gauge },
  data() {
    return {
      socket: null,
      HOST: "wss://car.caner.top",
      Peer: null,
      isLogin: false,
      error: "",
      remoteVideo: null,
      showLoading: true,
      contrlState: false,
      speed: 1, //1低速档 | 2 高速档
      iceServers: [
        {
          urls: ["stun:caner.top:3478"],
        },
        {
          urls: "turn:caner.top:3478",
          username: "admin",
          credential: "123456",
        },
      ],
    };
  },
  methods: {
    // 网络连接
    intSoketRtc(host) {
      // int socket
      this.socket = io(host, {
        autoConnect: false,
        transports: ["websocket"],
      });

      // socket
      this.socket.on("connect", () => {
        try {
          this.isLogin = true;
          // init webrtc
          this.Peer = new RTCPeerConnection({
            iceServers: this.iceServers,
            bundlePolicy: "max-bundle",
          });

          // listen state
          this.Peer.onicegatheringstatechange = () => {
            console.log("GatheringState: ", this.Peer.iceGatheringState);
            if (this.Peer.iceGatheringState === "complete") {
              const answer = this.Peer.localDescription;
              this.socket.emit("msg", answer);
            }
          };

          // listen track
          this.Peer.ontrack = async (evt) => {
            console.log("track", evt);
            this.remoteVideo = document.getElementById("v2");
            this.remoteVideo.srcObject = evt.streams[0];
          };

          // listen changestate
          this.Peer.oniceconnectionstatechange = async () => {
            const state = this.Peer.iceConnectionState;
            console.log("ICE状态", state);
            if (
              state === "failed" ||
              state === "disconnected" ||
              state === "closed"
            ) {
              this.close("P2P通信失败");
            }

            // ICE连接成功|初始化摇杆
            if (state === "connected") {
              // init Control
              window.addEventListener("gamepadconnected", this.conControl);
              window.addEventListener("gamepaddisconnected", this.disControl);
              await sleep(3000);
              this.showLoading = false;
            }
          };
        } catch (error) {
          this.socket.disconnect();
          this.isLogin = false;
          Message.error({
            content: "webrtc初始化错误" + error,
            duration: 3,
          });
        }
      });

      this.socket.on("msg", async (data) => {
        if (data.type === "offer") {
          console.log(data.sdp);
          await this.Peer.setRemoteDescription(data);
          const answer = await this.Peer.createAnswer();
          await this.Peer.setLocalDescription(answer);
        } else if (data.type === "power") {
          console.log("电量", data);
        } else if (data.type === "signal") {
          console.log("4G信号");
        }
      });

      this.socket.on("joined", async () =>
        this.socket.emit("msg", { type: "startRTC" })
      );

      this.socket.on("leaved", () => this.close("车端断开"));

      this.socket.on("connect_error", (err) => this.close(err));
    },

    // 手柄数据
    ControlData() {
      const data = navigator.getGamepads();
      const db = data[0];
      if (!db) return;
      // 挡位选择AB
      if (db.buttons[1].touched) this.speed = 2;
      if (db.buttons[0].touched) this.speed = 1;
      // 语音按键
      if (db.buttons[7].touched) console.log("R2");
      const params = {
        v0: Math.floor(db.axes[0] * 128 + 128),
        v1: Math.floor(db.axes[1] * 128 + 128),
        v2: Math.floor(db.axes[2] * 128 + 128),
        v3: this.Gear(this.speed, Math.floor(db.axes[3] * 128 + 128)),
      };

      if (this.socket.connected) {
        this.socket.emit("msg", { type: "conctrl", conctrl: params });
      }
      requestAnimationFrame(this.ControlData);
    },

    // 挡位
    Gear(speed, num) {
      // 低速档
      if (speed === 1) {
        if (num < 116) {
          num = 116;
        } else if (num >= 120 && num <= 131) {
          num = 128;
        } else if (num > 140) {
          num = 140;
        }
      }
      // 高速档
      if (speed === 2) {
        if (num < 96) {
          num = 96;
        } else if (num >= 120 && num <= 131) {
          num = 128;
        } else if (num > 160) {
          num = 160;
        }
      }
      return num;
    },

    // 登录
    login(data) {
      if (this.socket) {
        this.socket.auth = {
          roomID: data.roomID,
          name: data.name,
        };
        this.socket.connect();
      } else {
        this.error = "服务器连接失败";
      }
    },

    // 关闭
    close(err) {
      if (this.Peer) this.Peer.close();
      if (this.remoteVideo) this.remoteVideo.srcObject = null;
      this.socket.disconnect();
      this.isLogin = false;
      this.showLoading = false;
      this.error = err || "";
      this.socket = null;
      cancelAnimationFrame(this.ControlData);
      window.removeEventListener("gamepadconnected", this.conControl);
      window.removeEventListener("gamepaddisconnected", this.disControl);
    },

    // 手柄连接
    conControl() {
      this.contrlState = true;
      this.ControlData();
    },

    // 手柄断开连接
    disControl() {
      this.contrlState = false;
      cancelAnimationFrame(this.ControlData);
    },
  },
  mounted() {
    window.addEventListener("gamepadconnected", this.conControl);
    window.addEventListener("gamepaddisconnected", this.disControl);
    this.intSoketRtc(this.HOST);
  },
  destroyed() {
    this.close();
  },
};
</script>

<style>
video,
#app,
html,
body {
  margin: 0;
  padding: 0;
  user-select: none;
  width: 100%;
  height: 100%;
  overflow: hidden;
  min-width: 1000px;
  min-height: 900px;
}

video {
  background: none;
  object-fit: fill;
  font-size: 0;
}
.marke {
  position: fixed;
  top: 0;
  left: 50%;
  width: 555px;
  height: 30px;
  transform: translate(-50%, 0);
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}
.marke::before {
  position: absolute;
  z-index: 0;
  content: "";
  width: 100%;
  height: 0;
  border-top: 30px solid rgba(0, 0, 0, 0.25);
  border-left: 15px solid transparent;
  border-right: 15px solid transparent;
}
.marke > div {
  margin: 0 3px;
}
.gauge {
  position: fixed;
  bottom: 0;
  left: 50%;
  transform: translate(-50%, 0);
  width: 500px;
  height: 185px;
  z-index: 9;
}
/* 隐藏滚动条 */
::-webkit-scrollbar {
  width: 0 !important;
  display: none;
}
</style>
