如何实现Base64编码音频数组逐个播放 解决同时播放异常问题
问题根因
你现有代码的逻辑本身是符合顺序播放的设计,出现所有音频同时播放的核心原因是playAudio方法的Promise异常场景覆盖不全:audio.play()是浏览器提供的异步方法,会返回Promise,当遇到浏览器自动播放拦截、音频解码失败等异常情况时,播放流程被打断,onended事件永远不会触发,Promise一直处于pending状态,await逻辑失效,循环会直接进入下一轮,就会出现多个音频同时触发播放的情况。
优化后的代码实现
修改playAudio方法
补充错误监听和异常捕获,避免Promise悬停:
async playAudio(encodedAudio: string) { return new Promise<void>((resolve, reject) => { const audio = new Audio("data:audio/wav;base64," + encodedAudio); // 播放正常结束后resolve audio.onended = () => resolve(); // 音频加载/播放出错时reject,避免Promise永远挂起 audio.onerror = (error) => reject(error); // 处理play方法的异步异常,比如浏览器自动播放策略拦截 audio.play().catch((error) => reject(error)); }) }
修改sayChunks方法
增加异常捕获,避免单个音频播放出错打断整个播放序列:
async sayChunks() { try { const ttsResponses = await this.getTestJson(); console.log("ttsResponses:", ttsResponses); for (const ttsResponse of ttsResponses) { console.log("playing audio chunk"); const encodedAudio = ttsResponse.base64Audio.replace(/['"]+/g, '') await this.playAudio(encodedAudio); console.log("stopped playing audio chunk"); } } catch (error) { console.error("音频播放序列出错:", error); } }
注意事项
- 浏览器自动播放策略要求音频播放必须由用户交互行为(点击、触摸等事件)回调内触发,如果你是页面加载完成后直接调用
sayChunks大概率会被拦截,建议将触发逻辑绑定到按钮点击等用户操作的回调中。 - 如果音频片段较短对播放连贯性要求高,可以提前预创建所有Audio对象完成解码,避免实时解码base64带来的延迟。
内容的提问来源于stack exchange,提问作者DiracSpace
相关产品推荐
相关产品推荐

