| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- /****** H5录音 ******/
- 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,
- };
-
-
-
|