如何修改Chrome扩展代码同时捕获标签页音视频与麦克风输入
如何在Chrome扩展中同时录制标签页音视频和麦克风输入
问题背景
我正在为学校项目开发一款Chrome扩展,用于捕获会议的音视频内容。目前参考了Chrome官方的屏幕捕获相关代码,但核心问题是当前仅能录制标签页音频,无法捕获用户麦克风输入。已通过option.js获取了麦克风权限,需要修改代码实现同时捕获两者的功能。
修改方案
要实现同时录制标签页音视频和麦克风输入,需要分别获取标签页流和麦克风流,再将两个音频轨道合并,最终录制合并后的MediaStream。以下是各文件的修改代码:
1. Service Worker代码(仅调整注释说明)
chrome.action.onClicked.addListener(async (tab) => { const existingContexts = await chrome.runtime.getContexts({}); const offscreenDocument = existingContexts.find( (c) => c.contextType === 'OFFSCREEN_DOCUMENT' ); // 如果未打开离屏文档,创建一个 if (!offscreenDocument) { await chrome.offscreen.createDocument({ url: 'offscreen.html', reasons: ['USER_MEDIA'], justification: '同时录制标签页音视频与麦克风输入', }); } // 获取当前标签页的媒体流ID const streamId = await chrome.tabCapture.getMediaStreamId({ targetTabId: tab.id }); // 将流ID发送到离屏文档,启动录制流程 chrome.runtime.sendMessage({ type: 'start-recording', target: 'offscreen', data: streamId }); });
2. Offscreen Document代码(核心修改:合并双音频流)
这里需要先获取标签页的音视频流,再获取麦克风音频流,然后将两者的音频轨道合并到同一个MediaStream中,最后使用MediaRecorder进行录制:
chrome.runtime.onMessage.addListener(async (message) => { if (message.target !== 'offscreen') return; if (message.type === 'start-recording') { try { // 1. 获取标签页的音视频流 const tabStream = await navigator.mediaDevices.getUserMedia({ audio: { mandatory: { chromeMediaSource: "tab", chromeMediaSourceId: message.data, }, }, video: { mandatory: { chromeMediaSource: "tab", chromeMediaSourceId: message.data, }, }, }); // 2. 获取麦克风音频流(已通过option.js获取权限) const micStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false }); // 3. 合并两个音频轨道到标签页流中 const micAudioTrack = micStream.getAudioTracks()[0]; tabStream.addTrack(micAudioTrack); // 播放合并后的音频给用户(可选) const output = new AudioContext(); const source = output.createMediaStreamSource(tabStream); source.connect(output.destination); // 4. 初始化MediaRecorder开始录制 const recorder = new MediaRecorder(tabStream, { mimeType: 'video/webm; codecs=vp9,opus' }); const chunks = []; recorder.ondataavailable = (e) => chunks.push(e.data); recorder.onstop = () => { const blob = new Blob(chunks, { type: 'video/webm' }); // 处理录制完成的Blob,示例为下载到本地 const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = '会议录制_' + new Date().toISOString() + '.webm'; a.click(); URL.revokeObjectURL(url); }; recorder.start(); // 示例:录制10秒后自动停止(可根据需求调整) setTimeout(() => recorder.stop(), 10000); } catch (err) { console.error('录制启动失败:', err); alert('录制启动失败,请检查权限设置'); } } });
3. option.js代码(优化权限处理逻辑)
document.getElementById('requestPermission').addEventListener('click', () => { navigator.mediaDevices.getUserMedia({ audio: true }) .then(stream => { // 获取权限后释放临时流 stream.getTracks().forEach(track => track.stop()); alert('麦克风权限已获取'); }) .catch(err => { alert('权限获取失败: ' + err); }); });
关键说明
- 合并流时,通过
addTrack方法将麦克风的音频轨道添加到标签页的MediaStream中,录制的视频会同时包含标签页和麦克风的音频。 - 必须确保用户已授予麦克风权限(通过option.js的按钮触发),否则
getUserMedia({audio: true})会执行失败。 - 录制格式选用
video/webm,这是Chrome原生支持的通用格式,兼容性较好。
内容的提问来源于stack exchange,提问作者TINTIN
相关产品推荐
相关产品推荐

