<template>
  <div
    class="flv-media"
    v-loading="loading"
    element-loading-text="加载中"
    element-loading-background="rgba(0, 0, 0, 0.8)"
  >
    <video ref="VideoMedia" muted @ended="destroyPlayer"></video>
    <div v-if="result.error" class="media-error" @click.stop="() => {}">
      <div class="media-error-content">
        <span>{{ result.message }}，</span>
        <el-button type="text" @click="reloadVideo">点击刷新</el-button>
      </div>
    </div>
    <div v-if="!liveUrl" class="media-error" @click.stop="() => {}">
      <div class="media-error-content">
        <span>无视频源</span>
      </div>
    </div>
    <div
      v-if="liveUrl && !result.error && !loading && !hideAudioIcon"
      class="media-video-muted"
      @click.stop="videoMuted"
    >
      <i :class="['icon', !muted ? 'icon-audio-act' : 'icon-audio']"></i>
    </div>
  </div>
</template>

<script>
import flvjs from "flv.js";
// doc: https://github.com/bilibili/flv.js/blob/42343088f22619cf014a057b3878fe3d320016a6/docs/api.md
import timeMixin from "../../../mixins/timeMixin";

export default {
  name: "flv-media",
  mixins: [timeMixin],
  props: {
    liveUrl: {
      type: String,
    },
    maxRetryCount: {
      type: Number,
      default: 3,
    },
    hideAudioIcon: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      flvPlayer: null,
      muted: true,
      retryCount: 0,
      loading: false,
      result: {
        error: false,
        message: "",
      },
    };
  },
  watch: {
    muted: {
      handler() {
        this.$emit("media-muted-change", this.muted);
      },
      immediate: true,
    },
  },
  mounted() {
    this.initVideo();
    this.retryCount++;
  },
  methods: {
    initVideo() {
      if (!this.liveUrl) return;
      if (!flvjs.isSupported()) return;
      this.loading = true;

      this.flvPlayer = flvjs.createPlayer(
        {
          type: "flv",
          isLive: true,
          hasAudio: true,
          url: this.liveUrl,
        },
        {
          fixAudioTimestampGap: false,
          autoCleanupSourceBuffer: true,
        }
      );
      this.flvPlayer.attachMediaElement(this.$refs.VideoMedia);
      this.flvPlayer.load();
      this.flvPlayer.play();
      this.flvPlayer.on(flvjs.Events.ERROR, this.playError);
      this.flvPlayer.on(flvjs.Events.METADATA_ARRIVED, () => {
        this.loading = false;
        this.retryCount = 0;
      });
    },
    playError(errorType) {
      switch (errorType) {
        case flvjs.ErrorTypes.NETWORK_ERROR:
          console.log("网络问题，准备重试！");
          this.retryPlay();
          break;
        case flvjs.ErrorTypes.MEDIA_ERROR:
          console.log("媒体问题，准备重试！");
          this.retryPlay();
          break;
        default:
          console.log("未知问题，无法播放！");
          this.result = {
            error: true,
            message: "播放失败",
          };
          break;
      }
    },
    retryPlay() {
      if (this.retryCount >= this.maxRetryCount) {
        console.log("已尝试最大次数重新播放！");
        this.result = {
          error: true,
          message: "播放失败",
        };
        this.retryCount = 0;
        this.loading = false;
        return;
      }

      this.addSetTime(() => {
        this.reloadVideo();
        console.log("已重新播放");
      }, 1000);
    },
    playPlayer() {
      this.flvPlayer.play();
    },
    pausePlayer() {
      this.flvPlayer.pause();
    },
    destroyPlayer() {
      if (!this.flvPlayer) return;
      this.flvPlayer.pause();
      this.flvPlayer.unload();
      this.flvPlayer.detachMediaElement();
      this.flvPlayer.destroy();
      this.flvPlayer = null;
      this.clearSetTs();
    },
    mutedPlayer(muted) {
      if (!this.flvPlayer) return;
      this.flvPlayer.muted = muted;
      this.muted = this.flvPlayer.muted;
    },
    videoMuted() {
      if (!this.flvPlayer) return;
      const muted = this.flvPlayer.muted;
      this.$emit("muted-change");
      this.flvPlayer.muted = !muted;
      this.muted = this.flvPlayer.muted;
    },
    reloadVideo() {
      this.result = {
        error: false,
        message: "",
      };
      this.loading = true;
      this.$nextTick(() => {
        this.destroyPlayer();
        this.initVideo();
        this.retryCount++;
      });
    },
  },
  beforeDestroy() {
    this.destroyPlayer();
  },
};
</script>
