原生JS实现录音、录视频

313 阅读1分钟

一、录音频

模板

<template>
  <div class="audio-box">
    <span style="padding-right: 20px">音频录制:</span>
    <el-button
      :type="recording ? 'danger' : 'primary'"
      @click="handleStartOrStop"
      circle
    >
      <i class="iconfont" :class="recording ? 'icon-stop' : 'icon-start'"></i>
    </el-button>
    <audio controls :src="audioSrc" ref="recordPlayer" class="audio-item">
      <a :href="audioSrc"> Download audio </a>
    </audio>
  </div>
</template>

JS

<script>
export default {
  data() {
    return {
      mediaRecorder: null,
      recording: false, // 正在
      audioSrc: null,
      chunks: [],
    };
  },
  methods: {
    handleStartOrStop() {
      if (!this.recording) {
        this.start();
      } else {
        this.stop();
      }
    },
    start() {
      // 停止之前的录制内容
      this.mediaRecorder && this.mediaRecorder.stop();

      let constraints = { audio: true }; // 请求音频

      let mediaStream = navigator.mediaDevices.getUserMedia(constraints);
      mediaStream.then(
        (stream) => {
          this.$message.success("开始录制");
          this.chunks = [];
          this.recording = true;
          let audioContext = new AudioContext();

          // 创建一个新的音视频对象
          let destination = audioContext.createMediaStreamDestination();
          // 创建音视频源
          let mediaStreamSource = audioContext.createMediaStreamSource(stream);
          // 将音视频源 链接 到新音视频对象 中
          mediaStreamSource.connect(destination);

          // 媒体录制接口
          let mediaRecorder = new MediaRecorder(destination.stream);

          // 有可用数据流时触发,e.data即需要的音视频数据
          mediaRecorder.ondataavailable = (e) => this.chunks.push(e.data);
          // 间视频录制结束时触发
          mediaRecorder.onstop = () => {
            // 通过Blob数据块, 合成完整的Blob块数据
            let blob = new Blob(this.chunks, { type: "audio/mpeg" });
            // 通过Blob合建对象URL本地地址
            let url = URL.createObjectURL(blob);
            this.audioSrc = url;
          };
          // 將 mediaRecorder 对象扔到全局this中, 用于其他方法调用
          this.mediaRecorder = mediaRecorder;
          // 录制开始
          mediaRecorder.start();
        },
        () => {
          console.log("打开失败!");
        }
      );
    },
    stop() {
      this.recording = false;
      this.$message.success("录制完成!");
      // 返回录制的二进制数据, 调用这个方法后会生成一个新的Blob对象
      this.mediaRecorder.requestData();
      // 停止录制
      this.mediaRecorder.stop();
    },
  },
};
</script>

二、录视频

模板

<template>
  <div class="video-box">
    <span class="word-span">视频录制:</span>
    <el-button
      :type="recording ? 'danger' : 'primary'"
      @click="handleStartOrStop"
      circle
    >
      <i class="iconfont" :class="recording ? 'icon-stop' : 'icon-start'"></i>
    </el-button>
    <video id="video" autoplay class="video-item" v-show="recording"></video>
    <video
      class="video-item"
      controls
      :src="audioSrc"
      v-show="!recording && audioSrc"
    ></video>
  </div>
</template>

JS

<script>
export default {
  data() {
    return {
      mediaRecorder: null,
      recording: false, // 正在
      audioSrc: null,
      mediaBlobs: [], // 存储流
      recorder: null,
      medisStream: null,
    };
  },
  methods: {
    handleStartOrStop() {
      if (!this.recording) {
        this.start();
      } else {
        this.stop();
      }
    },
    async start() {
      this.recording = true;
      const self = this;
      this.$message.success("开始录制视频!");
      // 读取输入流
      this.medisStream = await navigator.mediaDevices.getUserMedia({
        audio: true,
        video: true,
      });
      var video = document.getElementById("video");
      video.srcObject = this.medisStream;
      video.play(); //播放视频
      // 生成 MediaRecorder 对象
      this.recorder = new MediaRecorder(this.medisStream);
      // 将 stream 转成 blob 来存放
      this.recorder.ondataavailable = (e) => {
        self.mediaBlobs.push(e.data);
      };
      // 停止时生成预览的 blob url
      this.recorder.onstop = () => {
        let recordedBlob = new Blob(this.mediaBlobs, { type: "video/webm" });
        this.audioSrc = URL.createObjectURL(recordedBlob);
      };
      this.recorder?.start(1000);
    },
    stop() {
      this.recording = false;
      this.$message.success("录制完成!");
      this.recorder?.stop();
      this.medisStream.getTracks().forEach((track) => track.stop());
    },
  },
};
</script>