You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chrome中MediaRecorder调用stop触发两次dataavailable事件的处理问询

问题分析与解决方案

这是Chrome浏览器对MediaRecorder实现的已知兼容性问题,Firefox的实现更符合规范,不会出现该现象。问题根源在于使用timeslice参数时,Chrome在暂停录制后会缓存未导出的数据,调用stop()时会同时导出缓存数据和结束标记,导致两次dataavailable事件触发,且此时录制器状态已变为inactive。

1. 不移除timeslice参数的情况下规避两次触发

可以在调用pause()后主动调用requestData(),该方法会立即导出当前缓存的所有录制数据,后续调用stop()时就只会触发一次dataavailable事件(对应录制结束的最终块)。

修改后的示例代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">    
    <title>Testing MediaRecorder</title>
</head>
<body>
<script>
    const recordButton = document.createElement('button');
    document.body.appendChild(recordButton);
    recordButton.innerHTML = 'start';
    recordButton.onclick = async function () {
        const cameraStream = await navigator.mediaDevices.getUserMedia({'audio': true, 'video': true});
        const mediaRecorder = new MediaRecorder(cameraStream);
        console.log('Starting media recording')
        mediaRecorder.ondataavailable = async (event) => {
            console.log(`Event size ${event.data.size}, recorder state: ${mediaRecorder.state}`);
        };
        mediaRecorder.start(5000);
        setTimeout(() => {
            console.log('Pausing');
            mediaRecorder.pause();
            // 主动导出暂停时的缓存数据
            mediaRecorder.requestData();
            setTimeout(() => {
                console.log('Stopping');
                mediaRecorder.stop();
            }, 4000);
        }, 7000);
    };
</script>
</body>
</html>

2. 判断最终数据块的方法

如果无法规避两次触发的情况,可以通过状态标记结合stop事件来判断最终数据:

  • 维护两个状态变量:isStopping(标记即将停止录制)和isStopped(标记录制已完全停止)。
  • 在ondataavailable回调中收集所有Blob数据,直到stop事件触发后,统一处理收集到的所有数据,此时所有在停止流程中触发的dataavailable事件对应的Blob合并后即为完整的录制内容。

示例代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">    
    <title>Testing MediaRecorder</title>
</head>
<body>
<script>
    const recordButton = document.createElement('button');
    document.body.appendChild(recordButton);
    recordButton.innerHTML = 'start';
    recordButton.onclick = async function () {
        const cameraStream = await navigator.mediaDevices.getUserMedia({'audio': true, 'video': true});
        const mediaRecorder = new MediaRecorder(cameraStream);
        const recordedBlobs = [];
        let isStopping = false;
        let isStopped = false;

        mediaRecorder.ondataavailable = (event) => {
            recordedBlobs.push(event.data);
            console.log(`Event size ${event.data.size}, recorder state: ${mediaRecorder.state}`);
            // 录制完全停止后处理最终数据
            if (isStopped) {
                processFinalRecording();
            }
        };

        mediaRecorder.onstop = () => {
            isStopped = true;
            // 确保所有数据都被处理
            processFinalRecording();
        };

        mediaRecorder.start(5000);
        setTimeout(() => {
            console.log('Pausing');
            mediaRecorder.pause();
            setTimeout(() => {
                console.log('Stopping');
                isStopping = true;
                mediaRecorder.stop();
            }, 4000);
        }, 7000);

        function processFinalRecording() {
            if (recordedBlobs.length === 0) return;
            // 合并所有Blob为最终录制文件
            const finalBlob = new Blob(recordedBlobs, { type: mediaRecorder.mimeType });
            console.log('最终录制数据已生成,大小:', finalBlob.size);
            // 重置状态与数据缓存
            recordedBlobs.length = 0;
            isStopping = false;
            isStopped = false;
        }
    };
</script>
</body>
</html>

内容的提问来源于stack exchange,提问作者fblundun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 00:15:27