当前位置: 首页 > news >正文

vue3实现录音与录像上传功能

录音

<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue';
import useInject from '@/utils/useInject';const props: any = defineProps<{params?: any;
}>();const recObj: any = reactive({blob: null,
});const { $global, $fn } = useInject();const recBtnDom: any = ref(null);
const playerDom: any = ref(null);onMounted(() => {// microphone           麦克风权限// camera                  相机权限// geolocation            地理位置信息// notifications        网站显示桌面通知权限// navigator.mediaDevices.getUserMedia({ audio: true }).then()      麦克风权限// navigator.mediaDevices.getUserMedia({ video: true }).then()      摄像头权限// navigator.geolocation.getCurrentPosition(callback)                     地理位置权限// Notification.requestPermission().then()                                        通知权限navigator.permissions.query({ name: 'microphone' }).then((res) => {if (res.state === 'granted') {// $global.tipsfn({ type: 'ok', con: '已授权录音' });}else{}});if (navigator.mediaDevices?.getUserMedia) {let chunks: any = [];const constraints = { audio: true };navigator.mediaDevices.getUserMedia(constraints).then((stream) => {console.log('授权成功!');const mediaRecorder = new MediaRecorder(stream);$fn.As.stopTouch(recBtnDom.value);recBtnDom.value.onpointerdown = () => {if (mediaRecorder.state === 'recording') {mediaRecorder.stop();recBtnDom.value.textContent = 'record';$global.tipsfn({ type: 'ok', con: '录音结束!' });} else {mediaRecorder.start();$global.tipsfn({ type: 'ok', con: '录音中...' });recBtnDom.value.textContent = 'stop';}console.log('录音器状态:', mediaRecorder.state);};mediaRecorder.ondataavailable = (e: any) => {chunks.push(e.data);};mediaRecorder.onstop = (e: any) => {recObj.blob = new Blob(chunks, {type: 'audio/ogg; codecs=opus',});console.log(666.10001, '录音文件blob', chunks, recObj.blob);chunks = [];var audioURL = window.URL.createObjectURL(recObj.blob);playerDom.value.src = audioURL;};},() => {$global.tipsfn({ type: 'err', con: '授权失败!' });});} else {$global.tipsfn({ type: 'err', con: '浏览器不支持 getUserMedia' });}
});
function uprec() {if (recObj.blob) {var reader = new FileReader();reader.readAsDataURL(recObj.blob);reader.onload = function () {$fn.useApiFiles().request({data: {dir: 'chat/chat',uid: $fn.As.Uuid('CR'),ext: '.ogg',data: reader.result,},}).then((res: any) => {console.log(666.789, res);props?.params?.fn(res);}).catch((err: any) => {$global.tipsfn({ type: 'err', con: err });});};}
}
</script><template><div class="as-ogg-area"><div class="as-ogg-show-area"><audio ref="playerDom" controls></audio></div><div class="as-btn-area"><button ref="recBtnDom">record</button><button @click="uprec">提交</button></div></div>
</template><style scoped>
.as-ogg-area {width: 100%;height: 100%;display: flex;flex-direction: column;
}
.as-ogg-show-area {flex-grow: 1;width: 100%;height: 100%;overflow: hidden;
}
.as-ogg-show-area > audio {width: 100%;height: 100%;
}
.as-btn-area {text-align: center;height: auto;
}
.as-btn-area > button {user-select: none;padding: 5px 12px;margin: 15px 5px 0 5px;
}
</style>

录像

<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue';
import useInject from '@/utils/useInject';const props: any = defineProps<{params?: any;
}>();const { $global, $fn } = useInject();const webmObj: any = reactive({stat: 0,blob: null,dataChunks: [],newRecorder: null,
});const startBtn: any = ref(null);
const stopBtn: any = ref(null);
const downBtn: any = ref(null);
const preVideo: any = ref(null);
const recVideo: any = ref(null);onMounted(() => {navigator.permissions.query({ name: 'camera' }).then((res) => {if (res.state === 'denied') {// $global.tipsfn({ type: 'err', con: '已拒绝授权录像' });}});// 开始录制function startRecording(stream: any, lengthInMS: any = null) {webmObj.newRecorder = new MediaRecorder(stream);webmObj.newRecorder.ondataavailable = (event: any) => {let data = event.data;webmObj.dataChunks.push(data);};webmObj.newRecorder.start(1000);console.log(webmObj.newRecorder.state + ' start to recording .....');}stopBtn.value.addEventListener('pointerdown', () => {webmObj.stat = 0;// close the recordingrecVideo.value.srcObject.getTracks().forEach((track: any) => track.stop());webmObj.newRecorder.stop();// Play recorded videowebmObj.blob = new Blob(webmObj.dataChunks, { type: 'video/webm' });console.log(666.30003,'视频数据Blob',webmObj.dataChunks,webmObj.blob);preVideo.value.src = URL.createObjectURL(webmObj.blob);// Save download video, click the download button, you can download itdownBtn.value.href = preVideo.value.src;downBtn.value.download = 'RecordedVideo.webm';});startBtn.value.addEventListener('pointerdown', () => {webmObj.stat = 1;// get the streamnavigator.mediaDevices.getUserMedia({audio: true,video: true,}).then((stream) => {// set the stream to left videorecVideo.value.srcObject = stream;// set the stream to <a> for downloaddownBtn.value.href = stream;// captureStream: which is streaming a real-time capture of the content being rendered in the media element.// A MediaStream object  which can be used as a source for audio or video data by other mediarecVideo.value.captureStream =recVideo.value.captureStream ||recVideo.value.mozCaptureStream;startRecording(recVideo.value.captureStream());}).catch((err) => {console.log('recording error: ', err);});});
});
function upvideo() {if (webmObj.blob) {var reader = new FileReader();reader.readAsDataURL(webmObj.blob);reader.onload = function () {$fn.useApiFiles().request({data: {dir: 'chat/chat',uid: $fn.As.Uuid('CV'),ext: '.webm',data: reader.result,},}).then((res: any) => {console.log(666.789, res);props?.params?.fn(res);}).catch((err: any) => {$global.tipsfn({ type: 'err', con: err });});};}
}
</script><template><div class="as-webm-area"><div class="as-webm-show-area"><video v-show="!webmObj.stat" ref="preVideo" controls></video><video v-show="webmObj.stat" ref="recVideo" autoplay muted></video></div><div class="as-btn-area"><button ref="startBtn">开始录制</button><button ref="stopBtn">停止录制</button><button ref="downBtn">下载</button><button @click="upvideo">提交保存</button></div></div>
</template><style scoped>
.as-webm-area {width: 100%;height: 100%;display: flex;flex-direction: column;
}
.as-webm-show-area {flex-grow: 1;width: 100%;height: 100%;overflow: hidden;
}
.as-webm-show-area > video {width: 100%;height: 100%;
}
.as-btn-area {text-align: center;height: auto;
}
.as-btn-area > button {user-select: none;padding: 5px 12px;margin: 15px 5px 0 5px;
}
</style>
http://www.lryc.cn/news/366535.html

相关文章:

  • PHP小方法
  • gulimall-search P125 springboot整合elasticsearch版本冲突
  • 如何在Coze中实现Bot对工作流的精准调用(如何提高Coze工作流调用的准确性和成功率)
  • 毫米波雷达阵列天线设计综合1(MATLAB仿真)
  • Freemarker
  • 基于Zero-shot实现LLM信息抽取
  • 【python】tkinter GUI编程经典用法,Label标签组件应用实战详解
  • 国产操作系统上给麒麟虚拟机安装virtualbox增强工具 _ 统信 _ 麒麟 _ 中科方德
  • (delphi11最新学习资料) Object Pascal 学习笔记---第14章泛型第3节(特定类约束)
  • 【postgresql初级使用】视图上的触发器instead of,替代计划的rewrite,实现不一样的审计日志
  • window.setInterval(func,interval)定时器
  • Einstein Summation 爱因斯坦求和 torch.einsum
  • TCP攻击是怎么实现的,如何防御?
  • Chrome DevTools开发者调试工具
  • 产品创新管理:从模仿到引领,中国企业的创新之路
  • Android 日志实时输出
  • JavaEE初阶---多线程编程(一.线程与进程)
  • react+vite创建
  • 软考 系统架构设计师系列知识点之杂项集萃(29)
  • [Qt开发]当我们在开发兼容高分辨率和高缩放比、高DPI屏幕的软件时,我们在谈论什么。
  • uniapp视频组件层级太高,解决方法使用subNvue原生子体窗口
  • java项目使用jsch下载ftp文件
  • 指针(初阶1)
  • MySQL实体类框架
  • 数据结构之初始泛型
  • 【网络编程开发】7.TCP可靠传输的原理
  • 视觉SLAM十四讲:从理论到实践(Chapter8:视觉里程计2)
  • C语言过度C++语法补充(面向对象之前语法)
  • 类和对象(二)(C++)
  • Chrome DevTools解密:成为前端调试大师的终极攻略