录制的音频文件时长未知,如何解决?(附TypeScript代码)
解决MediaRecorder录制音频后文件时长未知的问题
你遇到的时长无法识别问题,核心原因有两个:
- 浏览器的
MediaRecorder原生不支持直接录制MP3格式,你在创建Blob时指定type: 'audio/mp3'仅为文件添加了类型标记,实际录制的音频编码是浏览器默认格式(如Opus封装在WebM容器中),播放器无法解析这种"伪MP3"的时长信息。 - 直接拼接
dataArray中的Blob片段生成的文件,缺少音频文件必需的元数据头部(如MP3的ID3标签、时长索引),播放器无法通过文件头快速读取时长。
具体解决办法
方法一:先按浏览器支持格式录制,再转码为标准MP3
步骤1:适配浏览器支持的编码格式
先检测浏览器支持的音频编码,优先选择带完整元数据的格式录制,再转码为标准MP3:
let recorder: MediaRecorder, dataArray: Blob[] async function InitializeAudio(): Promise<void> { let audioIN = { audio: true } try { const mediastremObj = await navigator.mediaDevices.getUserMedia(audioIN) // 检测并选择浏览器支持的编码格式 const supportedType = MediaRecorder.isTypeSupported('audio/webm; codecs=opus') ? 'audio/webm; codecs=opus' : MediaRecorder.isTypeSupported('audio/mp4; codecs=aac') ? 'audio/mp4; codecs=aac' : 'audio/wav'; // 兜底用无压缩WAV,元数据完整 const mediaRecorder = new MediaRecorder(mediastremObj, { mimeType: supportedType }) recorder = mediaRecorder recorder.ondataavailable = (ev)=>{ dataArray.push(ev.data) } recorder.onstop = async (ev) => { const recordedBlob = new Blob(dataArray, { type: supportedType }) // 转码为带完整元数据的标准MP3 const mp3Blob = await convertToMP3(recordedBlob) const downloadTag = document.querySelector('#file-download') as HTMLAnchorElement const url = window.URL.createObjectURL(mp3Blob) downloadTag.href = url downloadTag.download = `my-${Date.now()}-audio.mp3` downloadTag.click() window.URL.revokeObjectURL(url) dataArray = [] } } catch (e) { throw new Error(e as string) } }
步骤2:用ffmpeg.wasm转码生成标准MP3
借助ffmpeg.wasm处理转码,自动添加MP3必需的元数据:
- 安装依赖:
npm install @ffmpeg/ffmpeg @ffmpeg/core
- 实现转码函数:
import { FFmpeg } from '@ffmpeg/ffmpeg'; import { fetchFile } from '@ffmpeg/util'; const ffmpeg = new FFmpeg(); async function convertToMP3(inputBlob: Blob): Promise<Blob> { // 首次加载ffmpeg核心文件 if (!ffmpeg.loaded) { await ffmpeg.load(); } // 将录制的Blob写入虚拟文件系统 const inputFileName = 'input.webm'; const outputFileName = 'output.mp3'; await ffmpeg.writeFile(inputFileName, await fetchFile(inputBlob)); // 执行转码命令,生成带元数据的MP3 await ffmpeg.exec([ '-i', inputFileName, '-codec:a', 'libmp3lame', '-q:a', '2', // 音质参数,2为高质量,范围0-9 outputFileName ]); // 读取转码后的文件并返回Blob const data = await ffmpeg.readFile(outputFileName); return new Blob([data], { type: 'audio/mp3' }); }
方法二:直接录制为WAV格式(简单但文件体积大)
如果对文件大小要求不高,可以直接录制为WAV格式,WAV是无压缩格式,元数据完整,播放器可直接识别时长:
只需将supportedType设置为'audio/wav',下载文件后缀改为.wav即可,无需转码。
注意事项
- 不要直接给
MediaRecorder指定audio/mp3类型,几乎没有浏览器原生支持该录制格式,强行指定会导致录制失败或生成无效文件。 - ffmpeg.wasm首次加载需下载核心文件,建议在页面初始化时提前加载,优化用户体验。
内容的提问来源于stack exchange,提问作者Jriffs
相关产品推荐
相关产品推荐

