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
相关产品推荐
相关产品推荐

