开发过程中遇到一套代码要编译到几个平台,到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,
};