问题描述
我正在尝试编写一个 manifest v3 Chrome 扩展程序来捕获选项卡音频。但是,据我所知,在 manifest v3 中,有一些更改使这有点困难:
- 后台脚本被 Service Worker 取代。
- Service Worker 无权访问
chrome.tabCapture
API。
尽管如此,我还是设法获得了一些几乎可以工作的东西,因为弹出脚本仍然可以访问 chrome.tabCapture
。但是,有一个缺点 - 选项卡的音频被静音,并且似乎没有办法取消静音。这是我目前所拥有的:
- 从弹出脚本中查询 Service Worker 当前选项卡。
let tabId;
// Fetch tab immediately
chrome.runtime.sendMessage({command: 'query-active-tab'},(response) => {
tabId = response.id;
});
这是 Service Worker,它使用当前选项卡 ID 进行响应。
chrome.runtime.onMessage.addListener(
(request,sender,sendResponse) => {
// Popup asks for current tab
if (request.command === 'query-active-tab') {
chrome.tabs.query({active: true},(tabs) => {
if (tabs.length > 0) {
sendResponse({id: tabs[0].id});
}
});
return true;
}
...
- 再次在弹出脚本中,通过键盘快捷键命令,使用
chrome.tabCapture.getMediaStreamId
获取当前选项卡要使用的媒体流 ID,并将该流 ID 发送回 Service Worker。
// On command,get the stream ID and forward it back to the service worker
chrome.commands.onCommand.addListener((command) => {
chrome.tabCapture.getMediaStreamId({consumerTabId: tabId},(streamId) => {
chrome.runtime.sendMessage({
command: 'tab-media-stream',tabId: tabId,streamId: streamId
})
});
});
- Service Worker 将该流 ID 转发给内容脚本。
chrome.runtime.onMessage.addListener(
(request,sendResponse) => {
...
// Popup sent back media stream ID,forward it to the content script
if (request.command === 'tab-media-stream') {
chrome.tabs.sendMessage(request.tabId,{
command: 'tab-media-stream',streamId: request.streamId
});
}
}
);
// Service worker sent us the stream ID,use it to get the stream
chrome.runtime.onMessage.addListener((request,sendResponse) => {
navigator.mediaDevices.getUserMedia({
video: false,audio: true,audio: {
mandatory: {
chromeMediaSource: 'tab',chromeMediaSourceId: request.streamId
}
}
})
.then((stream) => {
// Once we're here,the audio in the tab is muted
// However,recording the audio works!
const recorder = new MediaRecorder(stream);
const chunks = [];
recorder.ondataavailable = (e) => {
chunks.push(e.data);
};
recorder.onstop = (e) => savetoFile(new Blob(chunks),"test.wav");
recorder.start();
setTimeout(() => recorder.stop(),5000);
});
});
这是实现上述的代码:https://github.com/killergerbah/-test-tab-capture-extension
这实际上确实产生了 MediaStream
,但缺点是选项卡的声音被静音了。我尝试通过音频元素播放流,但似乎没有任何作用。
有没有办法在不使标签中的音频静音的情况下获取清单 v3 扩展中的标签音频流?
我怀疑这种方法可能完全错误,因为它太迂回了,但这是我在阅读文档和各种 StackOverflow 帖子后能想到的最好方法。
我还读到 tabCapture
API 将在某个时候为 manifest v3 移动,所以也许这个问题甚至没有意义 - 但是如果有办法仍然正确使用它我想知道。
解决方法
这可能不是您正在寻找的内容,但也许可以提供一些见解。
我尝试通过音频元素播放流,但似乎没有任何作用。
具有讽刺意味的是,这就是我设法解决这个问题的方法;通过在弹出窗口本身中创建一个对象。在弹出脚本中使用 tabCapture 时,它返回流,我将音频 srcObject 设置为该流。
HTML:
<audio id="audioObject" autoplay> No source detected </audio>
JS:
chrome.tabCapture.capture({audio: true,video: false},function(stream) {
var audio = document.getElementById("audioObject");
audio.srcObject = stream
})
根据 Manifest V3 上的 this post,chrome.capture 将成为 tabCapture 等的新命名空间,但除此之外我还没有看到任何东西。