当前位置:网站首页>web资源部署后navigator获取不到mediaDevices实例的解决方案(navigator.mediaDevices为undefined)
web资源部署后navigator获取不到mediaDevices实例的解决方案(navigator.mediaDevices为undefined)
2022-07-05 04:05:00 【乐辞】
问题
最近在开发中,有一个功能需要实现录制屏幕的功能,我这边使用了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
边栏推荐
- Behavior perception system
- 25K 入职腾讯的那天,我特么哭了
- 技术教程:如何利用EasyDSS将直播流推到七牛云?
- The scale of computing power in China ranks second in the world: computing is leaping forward in Intelligent Computing
- Basic function learning 02
- [array]566 Reshape the matrix - simple
- 3. Package the bottom navigation tabbar
- Threejs clicks the scene object to obtain object information, and threejs uses raycaster to pick up object information
- ABP vNext microservice architecture detailed tutorial - distributed permission framework (Part 2)
- NEW:Devart dotConnect ADO.NET
猜你喜欢
@The problem of cross database query invalidation caused by transactional annotation
Web components series (VII) -- life cycle of custom components
Behavior perception system
[wp][introduction] brush weak type questions
The scale of computing power in China ranks second in the world: computing is leaping forward in Intelligent Computing
快手、抖音、视频号交战内容付费
Timing manager based on C #
特殊版:SpreadJS v15.1 VS SpreadJS v15.0
25K 入职腾讯的那天,我特么哭了
陇原战“疫“2021网络安全大赛 Web EasyJaba
随机推荐
Summary of scene design
Threejs loads the city obj model, loads the character gltf model, and tweetjs realizes the movement of characters according to the planned route
provide/inject
Use of vscode software
ABP vNext microservice architecture detailed tutorial - distributed permission framework (Part 1)
Containerization Foundation
在线文本行固定长度填充工具
输入的查询SQL语句,是如何执行的?
Uni app change the default component style
[punch in questions] integrated daily 5-question sharing (phase III)
Technical tutorial: how to use easydss to push live streaming to qiniu cloud?
Looking back on 2021, looking forward to 2022 | a year between CSDN and me
C语言课设:影院售票管理系统
Is there a sudden failure on the line? How to make emergency diagnosis, troubleshooting and recovery
Resolved (sqlalchemy+pandas.read_sql) attributeerror: 'engine' object has no attribute 'execution_ options‘
企业级:Spire.Office for .NET:Platinum|7.7.x
Longyuan war "epidemic" 2021 network security competition web easyjaba
北京程序员的真实一天!!!!!
PlasticSCM 企业版Crack
如何实现实时音视频聊天功能