如何用JavaScript获取WebM/Opus原始音频时长?loadedmetadata未触发
解决Audio元素loadedmetadata事件不触发的问题
问题核心原因
你的代码存在两个关键问题:
- 直接将完整的Data URI字符串传入Blob,而非解码后的二进制音频数据
- 创建Blob时未指定正确的MIME类型,浏览器无法识别音频格式,导致无法解析元数据
修复方案
1. 正确解码Data URI为二进制Blob
先从Data URI中剥离前缀,解码base64内容为二进制数据,再生成带正确MIME类型的Blob:
function dataUriToBlob(dataUri) { // 拆分Data URI,提取MIME类型和base64数据 const [typeSection, dataSection] = dataUri.split(','); const mimeType = typeSection.match(/:(.*?);/)[1]; // 解码base64为二进制字符串 const byteString = atob(dataSection); // 转换为ArrayBuffer const arrayBuffer = new ArrayBuffer(byteString.length); const uint8Array = new Uint8Array(arrayBuffer); for (let i = 0; i < byteString.length; i++) { uint8Array[i] = byteString.charCodeAt(i); } // 生成指定MIME类型的Blob return new Blob([arrayBuffer], { type: mimeType }); }
2. 修正音频加载逻辑,确保触发元数据加载
创建Audio元素后主动调用load()方法,同时添加错误监听排查潜在问题:
const onDrop = (audioBlob) => { const audio = document.createElement("audio"); audio.src = URL.createObjectURL(audioBlob); audio.crossOrigin = "anonymous"; // 监听错误事件,快速定位格式/解码问题 audio.addEventListener("error", (e) => { console.error("音频加载失败:", e.target.error); }); audio.addEventListener("loadedmetadata", () => { console.log("loadedmetadata"); console.log("音频时长:", audio.duration); // 释放ObjectURL资源,避免内存泄漏 URL.revokeObjectURL(audio.src); }); // 主动触发音频加载流程 audio.load(); }; // 处理音频数据并调用加载逻辑 const processedBlob = dataUriToBlob(Card.audios.explain[0]); onDrop(processedBlob);
额外排查点
如果修复后事件仍不触发,检查以下内容:
- 音频文件本身是否损坏:可以直接将Data URI粘贴到浏览器地址栏,验证是否能正常播放
- 浏览器是否支持该格式:WebM/Opus是主流浏览器支持的格式,但部分旧版本浏览器可能存在兼容问题
内容的提问来源于stack exchange,提问作者soroosh azadi
相关产品推荐
相关产品推荐

