当前位置: 首页 > 工具软件 > mediadevices > 使用案例 >

web资源部署后navigator获取不到mediaDevices实例的解决方案(navigator.mediaDevices为undefined)

夏朗
2023-12-01

问题

最近在开发中,有一个功能需要实现录制屏幕的功能,我这边使用了recordrtc库,在过程中本地开发都没有问题,部署到线上环境时出现 navigator.mediaDevices为undefined,查找了不少文章和官方文章才得以解决

原因和解决方案

由于浏览器的安全策略导致了这个问题,目前经尝试,在以下几种情况中 navigator.mediaDevices 可以正常使用

 1. 地址为localhost:// 访问时
 2. 地址为https:// 时
 3. 为文件访问file:///

// 注:如果有其他方案欢迎指正

另附上 recordrtc 使用源码以供参考 (参考源码使用了element UI)

index.vue
<template>
  <div>
    <button @click="handleScreenRecord">开始录屏</button>
    <el-dialog
      style="max-width: 60%"
      v-model="screenRecorder.dialogVisible"
      :before-close="handleClose"
      top="0"
    >
      <Screenrecording
        :isSubmitting="screenRecorder.isSubmitting"
        @submit="recordedVideoSubmit"
      />
    </el-dialog>
  </div>
</template>
<script>
import { defineComponent, reactive } from "vue";
import Screenrecording from "./ScreenRecorder.vue";
export default defineComponent({
  components: {
    Screenrecording,
  },
  setup() {
    const screenRecorder = reactive({
      fileurl: "",
      dialogVisible: false,
      title: "",
      isSubmitting: false,
    });
    const handleScreenRecord = async () => {
      screenRecorder.dialogVisible = true;
    };
    const recordedVideoSubmit = async (file) => {
      screenRecorder.isSubmitting = true;
      try {
        // 拿到录制后的文件 file,这里是处理 file 的业务逻辑
        console.log("file", file);
      } catch (error) {
        // notify.error(error.message)
      }
      screenRecorder.isSubmitting = false;
    };
    const handleClose = () => {
      screenRecorder.dialogVisible = false;
    };
    return {
      screenRecorder,
      handleScreenRecord,
      recordedVideoSubmit,
      handleClose,
    };
  },
});
</script>
ScreenRecorder.vue
<template>
  <div class="h-recorder-wrapper">
    <el-card class="row">
      <div class="col-12">
        <video
          ref="video"
          style="width: 100%"
          loop
          controls
          autoplay
          playsinline
        />
      </div>
      <div>
        <el-button
          ref="startRecord"
          @click="startRecord"
          :disabled="isSubmitting"
          v-show="!recording && !startedBefore"
          type="primary"
        >
          record
        </el-button>
        <el-button
          ref="recordAgain"
          @click="startRecord"
          v-show="!recording && startedBefore"
          :disabled="isSubmitting"
          type="primary"
        >
          recordAgain
        </el-button>
        <el-button
          ref="stopRecord"
          v-show="recording"
          @click="stopRecord"
          type="primary"
        >
          finish
        </el-button>
        <el-button
          v-show="!recording && startedBefore"
          @click="handleRecordedVideo(video.blob)"
          type="green"
          :loading="isSubmitting"
        >
          submit
        </el-button>
      </div>
    </el-card>
  </div>
</template>
<script>
import RecordRTC from "recordrtc";
export default {
  name: "screen-recorder",
  langPrefix: "components.recorder",
  data() {
    return {
      recorder: null,
      stream: null,
      video: null,
      recording: false,
      startedBefore: false,
    };
  },
  props: {
    isSubmitting: {
      type: Boolean,
      required: true,
    },
  },
  methods: {
    handleRecordedVideo() {
      this.$emit("submit", {
        file: this.video.blob,
      });
    },
    startRecord() {
      this.captureScreen((screen) => {
        this.video.srcObject = screen;
        this.recorder = RecordRTC(screen, {
          type: "video",
        });
        this.recorder.startRecording();
        this.recorder.screen = screen;
        this.startedBefore = this.recording = true;
      });
    },
    stopRecord() {
      this.recorder.stopRecording(this.stopRecordingCallback);
      this.recording = false;
    },
    async stopRecordingCallback() {
      this.video.src = this.video.srcObject = null;
      const blob = this.recorder.getBlob();
      this.video.src = URL.createObjectURL(blob);
      this.video.blob = blob;
      this.recorder.screen.stop();
      this.recorder.destroy();
    },
    getStream() {
      if (navigator.mediaDevices.getDisplayMedia) {
        return navigator.mediaDevices.getDisplayMedia({
          video: {
            displaySurface: "monitor",
            logicalSurface: true,
            cursor: "always",
          },
        });
      }
    },
    invokeGetDisplayMedia(success, error) {
      let displaymediastreamconstraints = {
        video: {
          displaySurface: "monitor",
          logicalSurface: true,
          cursor: "always",
        },
      };
      displaymediastreamconstraints = {
        video: true,
      };

      if (navigator.mediaDevices.getDisplayMedia) {
        navigator.mediaDevices
          .getDisplayMedia(displaymediastreamconstraints)
          .then(success)
          .catch(error);
      } else {
        navigator
          .getDisplayMedia(displaymediastreamconstraints)
          .then(success)
          .catch(error);
      }
    },
    addStreamStopListener(stream, callback) {
      stream.addEventListener(
        "ended",
        () => {
          callback();
          callback = () => {};
        },
        false
      );
      stream.addEventListener(
        "inactive",
        () => {
          callback();
          callback = () => {};
        },
        false
      );
      stream.getTracks().forEach((track) => {
        track.addEventListener(
          "ended",
          () => {
            callback();
            callback = () => {};
          },
          false
        );
        track.addEventListener(
          "inactive",
          () => {
            callback();
            callback = () => {};
          },
          false
        );
      });
    },
    captureScreen(callback) {
      this.invokeGetDisplayMedia(
        (screen) => {
          this.addStreamStopListener(screen, () => {
            this.$refs.stopRecord.click();
          });
          callback(screen);
        },
        (error) => {
          console.error(error);
        }
      );
    },
  },
  mounted() {
    this.video = this.$refs.video;
  },
};
</script>

recordrtc库参考文档:https://github.com/muaz-khan/RecordRTC

 类似资料: