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

Chrome扩展:停止录制后音频轨道未终止,麦克风仍被占用

Chrome扩展屏幕录制器麦克风无法停止的问题修复

你的核心问题是存在多份未被正确终止的音频流实例,导致Chrome认为麦克风仍在被占用。以下是针对性的修复方案:

问题根源

你的代码中至少有3处会创建音频流,但停止录制时只处理了录制相关的mediaStream,遗漏了:

  • 初始化设备列表时创建的currentAudioStream和window.streamReference
  • 每个音频输入源对应的audioStreams中的流
  • 录制时单独创建的audioStream(虽合并到mediaStream,但原流可能仍有未释放的引用)

具体修复步骤

1. 重写停止录制函数,覆盖所有流清理

修改stopScreenRecording,确保所有可能占用麦克风的流都被终止:

function stopScreenRecording() {
    // 停止录制器
    if (mediaRecorder && mediaRecorder.state !== "inactive") {
        mediaRecorder.stop();
    }

    // 终止录制用的媒体流
    if (mediaStream) {
        mediaStream.getTracks().forEach(track => track.stop());
        mediaStream = null;
    }

    // 终止初始化时的音频流
    if (currentAudioStream) {
        currentAudioStream.getTracks().forEach(track => track.stop());
        currentAudioStream = null;
    }
    if (window.streamReference) {
        window.streamReference.getTracks().forEach(track => track.stop());
        window.streamReference = null;
    }

    // 终止所有音频上下文对应的流
    Object.values(audioStreams).forEach(stream => {
        stream.getTracks().forEach(track => track.stop());
    });
    audioStreams = {};

    // 关闭所有音频上下文
    Object.values(audioContexts).forEach(context => context.close());
    audioContexts = {};
    analyzerNodes = {};
}

2. 同步Chrome停止共享的处理逻辑

修改startScreenRecording中的屏幕流结束事件,调用完整的停止函数:

const videoStream = screenStream.getVideoTracks()[0];
videoStream.addEventListener('ended', () => {
    ended = true;
    stopScreenRecording(); // 替换原有的mediaRecorder.stop(),用完整清理逻辑
    chrome.storage.local.set({ state: 'prerecording' })
});

3. 录制前清理旧音频流

在startScreenRecording开头添加旧流清理,避免重复占用麦克风:

async function startScreenRecording() {
    try {
        // 录制前先清理所有可能存在的旧音频流
        if (currentAudioStream) {
            currentAudioStream.getTracks().forEach(track => track.stop());
        }
        Object.values(audioStreams).forEach(stream => {
            stream.getTracks().forEach(track => track.stop());
        });
        audioStreams = {};

        // 原有录制逻辑...
        const screenStream = await navigator.mediaDevices.getDisplayMedia({ video: {frameRate: { max: 10 }, width: { max: 1280 }, height: { max: 720 }}});
        const audioStream = await navigator.mediaDevices.getUserMedia({ audio: true });
        // ...后续代码保持不变
    } catch (error) {
        console.error("Error starting screen recording:", error);
    }
}

4. 优化设备初始化逻辑(可选)

如果只是为了获取设备标签,枚举完成后可立即停止临时流,避免长期占用:

async function listAudioInputSources () {
    try {
        let tempStream;
        try {
            tempStream = await navigator.mediaDevices.getUserMedia({audio: true});
            window.streamReference = tempStream;
        } catch (e) {
            // 处理无麦克风权限的情况
        }
        
        const devices = await navigator.mediaDevices.enumerateDevices();
        audioInputs = devices.filter(device => device.kind === 'audioinput').map(device => ({
            deviceId: device.deviceId,
            label: device.label,
            volumeLevels: Array(10).fill(false)
        }));
        
        if(audioInputs.length > 0) {
            audioInputs.forEach(input => setupAudioContext(input.deviceId));
        }

        // 枚举完成后停止临时流(若不需要实时监听音量)
        if (tempStream) {
            tempStream.getTracks().forEach(track => track.stop());
            window.streamReference = null;
        }

        // 原有消息发送逻辑...
    } catch (error) {
        console.error('Error accessing audio devices:', error);
        audioError = true;
        chrome.runtime.sendMessage({ action: "audio-sources-updated", micMsg: audioError });
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 19:33:08