Safari MediaRecorder API首暂停/恢复周期无dataavailable事件问题
Safari MediaRecorder 首次暂停/恢复触发空dataavailable事件问题解答
1. 问题原因
- 这是Safari移动端MediaRecorder的初始化资源处理bug:首次录制会话时,MediaRecorder的音频编码缓冲区尚未完成初始化,暂停操作触发的
dataavailable事件自然没有有效数据;而停止会话后重新创建实例,底层音频编码上下文已经完成预热,缓冲区能正常累积音频数据,此时暂停就会输出预期内容。 - 另外,Safari首次启动MediaRecorder时,需要短时间完成音频轨道的编码协商流程,若首次暂停发生在协商完成前,就会生成空的Blob对象。
2. 解决方案与最佳实践
- 延迟首次暂停操作:启动录制后,等待200-300ms再允许执行暂停,确保编码上下文完成初始化。示例代码:
let isRecorderReady = false; mediaRecorder.start(); // 标记录制就绪状态 setTimeout(() => { isRecorderReady = true; }, 300); function handlePause() { if (isRecorderReady) { mediaRecorder.pause(); } }
- 过滤空Blob数据:在
dataavailable事件回调中,判断Blob的大小是否大于0,仅处理非空数据:
mediaRecorder.addEventListener('dataavailable', (event) => { if (event.data.size > 0) { recordedChunks.push(event.data); } });
- 预初始化预热:页面加载完成后,创建临时MediaRecorder实例并快速启动/停止,提前完成编码上下文的预热,后续正式录制即可避免首次暂停的问题:
async function warmUpRecorder() { try { const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); const tempRecorder = new MediaRecorder(stream); tempRecorder.start(); setTimeout(() => tempRecorder.stop(), 100); tempRecorder.addEventListener('stop', () => { stream.getTracks().forEach(track => track.stop()); }); } catch (err) { // 处理权限或设备错误 } } // 页面初始化时执行预热 warmUpRecorder();
- 使用timeslice参数:如果业务场景允许,启动MediaRecorder时设置
timeslice参数,让实例定期触发dataavailable事件,确保首次暂停前已有有效数据生成:
// 每1000ms触发一次dataavailable mediaRecorder.start(1000);
内容的提问来源于stack exchange,提问作者Ric
相关产品推荐
相关产品推荐

