uniapp 封装uni.getRecorderManager(),支持h5

开发过程中遇到一套代码要编译到几个平台,到h5的时候发现 uni.getRecorderManager() 不支持H5 ,就封装一下,方便管理,不会导致非常乱

h5用到了 lamejs npm lamejs  用于转 MP3 

注意事项:h5需要在 https 环境中使用

 使用:  新建 recorder.js 复制进去

//页面引入
import { startRecording, stopRecording, playAudio } from "../../utils/recorder.js"



	const bindrecorder = () => {
		startRecording({ duration: 30000 })
	}
	const stoprecorder = () => {
		stopRecording((filePath) => {
			console.log("录音文件路径:", filePath);
			filePaths.value = filePath
			// 在这里你可以做其他操作,比如播放录音文件
		});
	}
let recorderManager = null; // 录音管理器实例(用于非H5平台)
let innerAudioContext = null; // 音频播放管理器实例
let recordedFilePath = ""; // 录音文件路径
let mediaRecorder = null; // H5平台的录音器实例
let recordedChunks = []; // 存储H5录音片段
let audioBlob = null; // H5录音文件的 Blob 对象

// 需要引入 MP3 转换库,例如 `lamejs`
import Lame from 'lamejs'; // 在实际应用中需要引入 Lame.js 库

/**
 * 初始化录音管理器
 */
function initRecorderManager() {
	if (process.env.UNI_PLATFORM === 'h5') {
		if (window.location.origin.indexOf("https") === -1) {
			console.error("H5录音功能:请在 https 环境中使用插件recorder.js。");
			return;
		}

		if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
			console.error("当前浏览器不支持 getUserMedia API");
			return;
		}

		if (typeof MediaRecorder === "undefined") {
			console.error("当前浏览器不支持 MediaRecorder API");
			return;
		}

		if (!mediaRecorder) {
			navigator.mediaDevices.getUserMedia({ audio: true })
				.then(stream => {
					try {
						mediaRecorder = new MediaRecorder(stream);

						mediaRecorder.ondataavailable = (event) => {
							if (event.data.size > 0) {
								recordedChunks.push(event.data);
							}
						};
						console.log("H5 录音管理器已初始化");
					} catch (e) {
						console.error("MediaRecorder 初始化错误:", e.message);
					}
				})
				.catch(err => {
					console.error("H5 录音初始化错误:", err.message);
				});
		}
	} else {
		if (!recorderManager) {
			recorderManager = uni.getRecorderManager();
			console.log("非 H5 录音管理器已初始化");
		}
	}
}

/**
 * 初始化音频管理器
 */
function initAudioContext() {
	if (!innerAudioContext) {
		innerAudioContext = uni.createInnerAudioContext();
	}
}

/**
 * 开始录音
 * @param {object} options - 录音参数选项,包含录音时长、采样率等参数
 */
function startRecording(options = {}) {
	// 确保录音管理器已初始化
	initRecorderManager();

	if (process.env.UNI_PLATFORM === 'h5') {
		if (mediaRecorder) {
			mediaRecorder.start();
			console.log("H5 开始录音...");
		} else {
			console.error("无法开始录音:mediaRecorder 不存在或浏览器不支持录音");
		}
	} else {
		const defaultOptions = {
			duration: 60000, // 录音时长(毫秒)
			sampleRate: 44100, // 采样率
			numberOfChannels: 1, // 声道数
			encodeBitRate: 96000, // 编码比特率
			format: "mp3", // 录音格式
		};

		recorderManager.start({
			...defaultOptions,
			...options,
		});
		console.log("开始录音...");
	}
}

/**
 * 暂停录音
 */
function pauseRecording() {
	if (process.env.UNI_PLATFORM === 'h5') {
		if (mediaRecorder && mediaRecorder.state === 'recording') {
			mediaRecorder.pause();
			console.log("H5 暂停录音");
		}
	} else {
		if (recorderManager) {
			recorderManager.pause();
			console.log("暂停录音");
		}
	}
}

/**
 * 继续录音
 */
function resumeRecording() {
	if (process.env.UNI_PLATFORM === 'h5') {
		if (mediaRecorder && mediaRecorder.state === 'paused') {
			mediaRecorder.resume();
			console.log("H5 继续录音");
		}
	} else {
		if (recorderManager) {
			recorderManager.resume();
			console.log("继续录音");
		}
	}
}

/**
 * 停止录音
 * @param {function} callback - 停止录音后返回录音文件路径的回调函数
 */
function stopRecording(callback) {
	if (process.env.UNI_PLATFORM === 'h5') {
		if (mediaRecorder) {
			mediaRecorder.stop();
			console.log("H5 停止录音");

			// 将录音文件路径抛出
			if (typeof callback === 'function') {
				mediaRecorder.onstop = async () => {
					// 先生成 Blob 对象
					audioBlob = new Blob(recordedChunks, { type: 'audio/webm' });
					recordedChunks = [];

					// 转换为 MP3 格式
					const mp3Blob = await convertToMp3(audioBlob);
					recordedFilePath = URL.createObjectURL(mp3Blob);
					console.log("H5 录音停止,文件保存路径:", recordedFilePath);
					callback(recordedFilePath);
				};
			}
		} else {
			console.error("无法停止录音:mediaRecorder 不存在或浏览器不支持录音");
		}
	} else {
		if (recorderManager) {
			recorderManager.stop();
			console.log("停止录音");

			// 非 H5 平台录音停止后将文件路径抛出
			if (typeof callback === 'function') {
				recorderManager.onStop((res) => {
					recordedFilePath = res.tempFilePath;
					console.log("录音停止,文件保存路径:", recordedFilePath);
					callback(recordedFilePath);
				});
			}
		}
	}
}

/**
 * 转换 Blob 对象为 MP3 格式
 * @param {Blob} audioBlob - 原始音频 Blob 对象
 * @returns {Promise<Blob>} - MP3 格式的 Blob 对象
 */
async function convertToMp3(audioBlob) {
	// 使用 Lame.js 库将音频 Blob 转换为 MP3 格式
	// 需要在实际应用中引入 Lame.js 库
	return new Promise((resolve, reject) => {
		// 检查 Lame.js 是否存在
		if (typeof Lame === "undefined") {
			reject(new Error("Lame.js 库未加载"));
			return;
		}

		const reader = new FileReader();
		reader.onload = function(event) {
			const audioData = event.target.result;
			const mp3Encoder = new Lame.Mp3Encoder(1, 44100, 128);
			const mp3Data = [];

			// 使用 Lame.js 库将音频数据编码为 MP3
			const samples = new Int16Array(audioData);
			mp3Data.push(mp3Encoder.encodeBuffer(samples));
			mp3Data.push(mp3Encoder.flush());

			// 生成 MP3 Blob 对象
			const mp3Blob = new Blob(mp3Data, { type: 'audio/mp3' });
			resolve(mp3Blob);
		};
		reader.onerror = function(error) {
			reject(error);
		};
		reader.readAsArrayBuffer(audioBlob);
	});
}


/**
 * 播放音频
 * @param {string} audioUrl - 音频文件 URL
 * @param {function} PlayCallback - 开始播放
 * @param {function} progressCallback - 播放进度的回调函数 (currentTime, duration)
 * @param {function} errorCallback - 播放错误的回调函数 (errorMsg)
 * @param {function} endCallback - 播放完毕的回调函数 ()
 * 
 * playAudio(
*	audioUrl,
*	()=>{
*		console.log("开始播放");
*	},
*	(currentTime, duration) => {
*		console.log(`当前时间: ${currentTime}s, 总时长: ${duration}s`);
*		// 更新UI进度条
*	},
*	(errorMsg) => {
*		console.error("播放错误:", errorMsg);
*		// 显示错误信息
*	},
*	() => {
*		console.log("音频播放结束");
*		// 重置 UI 状态
*	}
*);
 */
const playAudio = (audioUrl, PlayCallback, progressCallback, errorCallback, endCallback) => {
	if (audioUrl) {
		initAudioContext();
		innerAudioContext.src = audioUrl;
		innerAudioContext.play();
		console.log("播放外部音频:", audioUrl);

		innerAudioContext.onPlay(() => {
			console.log('开始播放');
			PlayCallback()
		});

		innerAudioContext.onTimeUpdate(() => {
			progressCallback(innerAudioContext.currentTime, innerAudioContext.duration);
		});

		innerAudioContext.onError((error) => {
			const errorMsg = error.errMsg || "播放错误";
			console.error("播放错误:", errorMsg);
			errorCallback(errorMsg);
		});

		innerAudioContext.onEnded(() => {
			endCallback();
		});
	} else {
		const errorMsg = "音频 URL 不能为空";
		console.error(errorMsg);
		errorCallback(errorMsg);
	}
};

/**
 * 暂停音频播放
 */
function pausePlaying() {
	if (innerAudioContext && innerAudioContext.paused === false) {
		innerAudioContext.pause();
		console.log("暂停播放音频");
	}
}

/**
 * 停止音频播放
 */
function stopPlaying() {
	if (innerAudioContext) {
		innerAudioContext.stop();
		console.log("停止播放音频");
	}
}

// #ifdef H5
// 初始化录音管理器
initRecorderManager();
// #endif
// 导出所有录音相关的工具函数
export {
	startRecording,
	pauseRecording,
	resumeRecording,
	stopRecording,
	playAudio,
	pausePlaying,
	stopPlaying,
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值