Vue3实时检测的录音功能

如果有人声并且大于20db,则开始录制。低于20db超过4秒,停止录制

语音实时检测

<template>
	<div class="auto-recorder">
		<canvas ref="canvas"></canvas>
		<button @click="toggleRecording" :disabled="isRecording">
			{{ isRecording ? '录音中' : '未录音' }}
		</button>

		<audio v-if="audioUrl" controls :src="audioUrl"></audio>
	</div>
</template>

<script>
	export default {
		data() {
			return {
				isRecording: false, //显示当前录音状态
				mediaRecorder: null,
				audioChunks: [], //存储录音数据的数组
				audioContext: null, //用于处理音频
				analyser: null, //用于分析音频频谱
				bufferSize: 2048, //用于设置分析音频的缓冲区大小。
				threshold: 0, //用于设置录音阈值的属性 db
				canvasContext: null, //用于存储 Canvas 上下文的属性。
				canvasWidth: 400,
				canvasHeight: 200,
				silentTime: 0, //记录静音时间
				audioUrl: '',
				silenceInterval: null //计时器ID
			};
		},
		mounted() {
			this.setupAudio();
			this.setupCanvas();
			this.draw();
		},
		methods: {
			async setupAudio() { //异步方法,用于设置音频环境。
				//使用 navigator.mediaDevices.getUserMedia 方法请求用户媒体设备(麦克风)的权限
				//返回一个 MediaStream 对象。
				const stream = await navigator.mediaDevices.getUserMedia({
					audio: true
				});
				//创建一个新的 AudioContext 对象,用于处理音频。
				this.audioContext = new AudioContext();
				//创建 AnalyserNode 对象,用于分析音频频谱。
				this.analyser = this.audioContext.createAnalyser();
				//创建一个 MediaStreamAudioSourceNode 对象,表示从媒体流中读取数据。
				const microphone = this.audioContext.createMediaStreamSource(stream);
				//将媒体流连接到分析器节点。
				microphone.connect(this.analyser);
				//设置 FFT(Fast Fourier Transform)大小,用于控制音频数据的分析精度。
				this.analyser.fftSize = this.bufferSize;
			},
			//设置 Canvas 元素的方法
			setupCanvas() {
				// 获取组件中引用的 Canvas 元素。
				const canvas = this.$refs.canvas;
				// 获取 Canvas 2D 上下文,用于绘制图形。
				this.canvasContext = canvas.getContext('2d');
				// 设置 Canvas 宽度。
				canvas.width = this.canvasWidth;
				// 设置 Canvas 高度。
				canvas.height = this.canvasHeight;
				// 设置画布背景颜色为黑色。
				this.canvasContext.fillStyle = '#000';
				// 绘制一个填充矩形,覆盖整个画布,用黑色填充。
				this.canvasContext.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
			},
			//这是一个负责绘制音频波形图的函数,并且会检查声音的分贝是否超过阈值。
			draw() {
				//请求下一帧动画
				requestAnimationFrame(this.draw);
				if (this.analyser != null) { //当前不在录音的情况
					// 获取音频频域数据的数组长度
					const bufferLength = this.analyser.frequencyBinCount;
					// 创建一个无符号 8 位整数数组,用于存储音频频域数据
					const dataArray = new Uint8Array(bufferLength);
					// 从 AnalyserNode 获取音频频域数据
					this.analyser.getByteTimeDomainData(dataArray);
					// 设置画布的填充颜色为黑色
					this.canvasContext.fillStyle = '#000';
					// 绘制一个黑色的矩形,覆盖整个画布,用于清空画布
					this.canvasContext.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
					// 设置绘制线条的宽度为 2 像素
					this.canvasContext.lineWidth = 2;
					// 设置绘制线条的颜色为绿色
					this.canvasContext.strokeStyle = '#00ff00';
					// 开始绘制新路径
					this.canvasContext.beginPath();
					// 计算每个数据片段在画布上的宽度
					const sliceWidth = this.canvasWidth * 1.0 / bufferLength;
					// 初始化 x 坐标
					let x = 0;
					// 遍历音频频域数据数组,绘制波形图
					for (let i = 0; i < bufferLength; i++) {
						// 将音频数据归一化到 [-1, 1] 的范围
						const v = dataArray[i] / 128.0;
						// 根据归一化的数据计算波形图在画布上的 y 坐标
						const y = v * this.canvasHeight / 2;
						// 如果是第一个数据点,则将画笔移动到该点;否则,从上一个点绘制直线到当前点
						if (i === 0) {
							this.canvasContext.moveTo(x, y);
						} else {
							this.canvasContext.lineTo(x, y);
						}
						// 更新 x 坐标
						x += sliceWidth;
					}
					// 绘制直线到画布的右边中央
					this.canvasContext.lineTo(this.canvasWidth, this.canvasHeight / 2);
					// 绘制路径
					this.canvasContext.stroke();

					// 检测声音分贝是否超过阈值
					const average = this.calculateAverage(dataArray);

					// 如果平均值超过阈值
					if (average > this.threshold) {
						if (!this.isRecording) {
							this.startRecording(); //开始录音
						}
						this.silentTime = 0; //重置静音时间
					} else {
						if (this.isRecording) {
							// 开始计时,如果静音时间超过4秒,停止录音
							if (!this.silenceInterval) {
								this.silenceInterval = setInterval(() => {
									this.silentTime++;
									if (this.silentTime >= 4) {
										this.stopRecording();
										clearInterval(this.silenceInterval);
										this.silenceInterval = null;
										this.silentTime = 0; //重置静音时间
									}
								}, 1000);
							}
						}
					}
				}
			},
			// 定义了一个名为 calculateAverage 的方法,接受一个 dataArray 参数。
			calculateAverage(dataArray) {
				// 初始化一个 sum 变量用于存储音频数据的总和。
				let sum = 0;
				// 获取 dataArray 的长度并存储在 length 变量中。
				const length = dataArray.length;
				// 使用 for 循环遍历 dataArray。
				// 对于每个元素,减去128并加到 sum 上。
				// 这是因为音频数据范围在0到255之间,128表示音量的中值。
				for (let i = 0; i < length; i++) {
					sum += (dataArray[i] - 128);
				}
				// 返回音频数据的平均值。
				return sum / length;
			},
			// 控制音频录制的功能
			async toggleRecording() {
				if (!this.isRecording) {
					try {
						// 请求用户麦克风的音频输入
						const stream = await navigator.mediaDevices.getUserMedia({
							audio: true
						});

						// 创建 MediaRecorder 实例,用于录制音频
						this.mediaRecorder = new MediaRecorder(stream);


						// 添加事件监听器,当有音频数据可用时,将其存储到 audioChunks 中
						// 保存数据(数据有效)
						this.mediaRecorder.addEventListener('dataavailable', event => {
							if (event.data.size > 0) {
								this.audioChunks.push(event.data);
							}
						});
						// 开始录制媒体流
						this.mediaRecorder.start();
						this.isRecording = true;
					} catch (error) {
						console.error('录音失败...', error);
					}
				}
			},
			async stopRecording() {
				// 停止录制媒体流。
				this.mediaRecorder.stop();
				// 等待 MediaRecorder 停止录制完成
				await new Promise(resolve => {
					this.mediaRecorder.addEventListener('stop', resolve);
				});
				// 创建一个 Blob 对象,用于存储录制的音频数据
				const blob = new Blob(this.audioChunks, {
					type: 'audio/pcm'
				});
				console.log('Blob size:', blob.size);
				if (blob.size > 0) {
					console.log('Blob contains audio data');
				} else {
					console.log('Blob is empty');
				}
				this.audioUrl = URL.createObjectURL(blob);
				console.log("this.audioChunks", this.audioChunks);
				console.log("已发送给后端!");
				// 将录音数据发送给后端
				// 这里需要实现发送录音数据给后端的逻辑
				console.log('录音数据', blob);
				// 重置录音状态和录音数据数组
				this.isRecording = false;
				this.audioChunks = [];
			},
			async startRecording() {
				this.toggleRecording();
				console.log('录音中');
			}
		}
	};
</script>

<style>
	.auto-recorder {
		display: flex;
		flex-direction: column;
		align-items: center;
	}

	canvas {
		margin-top: 20px;
	}
</style>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
要在Vue中实现录音功能,可以考虑使用Web API中的MediaRecorder和getUserMedia方法。这些API允许您访问用户的麦克风并将音频数据录制到文件中。 以下是一个简单的Vue示例,演示如何实现录音功能: 1.首先,您需要在Vue组件中引入MediaRecorder和getUserMedia: ```javascript import { getUserMedia } from 'webrtc-adapter'; import MediaRecorder from 'audio-recorder-polyfill'; ``` 2.在Vue组件的data属性中添加一个名为“recording”的布尔值,用于跟踪录音状态: ```javascript data() { return { recording: false } } ``` 3.在Vue组件的methods属性中添加一个名为“startRecording”的方法,用于开始录音: ```javascript methods: { startRecording() { this.recording = true; const constraints = { audio: true }; navigator.mediaDevices.getUserMedia(constraints) .then(stream => { const options = { mimeType: 'audio/webm' }; const mediaRecorder = new MediaRecorder(stream, options); mediaRecorder.start(); mediaRecorder.ondataavailable = event => { const audioFile = new File([event.data], 'recording.webm'); // Do something with the audio file, e.g. upload it to a server }; this.mediaRecorder = mediaRecorder; }) .catch(error => { console.error('Error accessing user media:', error); }); } } ``` 4.在Vue组件的template中添加一个按钮来启动录音: ```html <template> <div> <button v-if="!recording" @click="startRecording">Start Recording</button> <button v-else @click="stopRecording">Stop Recording</button> </div> </template> ``` 5.添加一个名为“stopRecording”的方法,用于停止录音: ```javascript stopRecording() { this.recording = false; this.mediaRecorder.stop(); } ``` 这就是如何在Vue中实现录音功能的简单示例。请注意,此示例中使用的MediaRecorder和getUserMedia API可能需要polyfill来确保与所有浏览器兼容。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Adellle

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值