【问题标题】:Properly using chrome.tabCapture in a manifest v3 extension在清单 v3 扩展中正确使用 chrome.tabCapture
【发布时间】:2021-02-16 02:16:31
【问题描述】:

我正在尝试编写一个用于捕获标签音频的清单 v3 Chrome 扩展程序。但是据我所知,对于 manifest v3,有一些变化使这有点困难:

  • 后台脚本被服务工作者替换。
  • Service Worker 无权访问 chrome.tabCapture API。

尽管如此,我还是设法得到了一些几乎可以作为弹出脚本仍然可以访问chrome.tabCapture 的东西。但是,有一个缺点 - 选项卡的音频已静音,似乎没有办法取消静音。这是我目前所拥有的:

  1. 从弹出脚本中查询 service worker 当前选项卡。
let tabId;

// Fetch tab immediately
chrome.runtime.sendMessage({command: 'query-active-tab'}, (response) => {
    tabId = response.id;
});

这是服务工作者,它使用当前选项卡 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;
        }
        ...
  1. 再次在弹出脚本中,通过键盘快捷键命令,使用 chrome.tabCapture.getMediaStreamId 获取当前选项卡使用的媒体流 ID,并将该流 ID 发送回服务工作者。
// 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
        })
    });
});
  1. Service Worker 将该流 ID 转发到内容脚本。
chrome.runtime.onMessage.addListener(
    (request, sender, 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
            });
        }
    }
);
  1. 内容脚本使用navigator.mediaDevices.getUserMedia 获取流。
// Service worker sent us the stream ID, use it to get the stream
chrome.runtime.onMessage.addListener((request, sender, 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 移动,所以也许这个问题甚至没有意义问 - 但是如果有办法仍然正确使用它我想知道。

【问题讨论】:

  • 这里有任何进度更新吗?我也在努力在 v3 扩展中使用 chrome.tabCapture @R-J
  • @lsimmons 我在 manifest v3 中使用 tapCapture 没有任何进展——我最终降级到 manifest v2。不过,我仍然需要探索下面的答案。
  • 在四处寻找之后,我发现了这个仍然存在的错误:bugs.chromium.org/p/chromium/issues/detail?id=1214847

标签: google-chrome google-chrome-extension web-mediarecorder


【解决方案1】:

我发现您的帖子对我实施音频标签记录器非常有用。

关于您遇到的具体静音问题,我通过查看此处解决了它:Original audio of tab gets muted while using chrome.tabCapture.capture() and MediaRecorder()

// Service worker sent us the stream ID, use it to get the stream
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    navigator.mediaDevices.getUserMedia({
        video: false,
        audio: true,
        audio: {
            mandatory: {
                chromeMediaSource: 'tab',
                chromeMediaSourceId: request.streamId
            }
        }
    })
    .then((stream) => {
        // To resolve original audio muting
        context = new AudioContext();
        var audio = context.createMediaStreamSource(stream);
        audio.connect(context.destination);

        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);
    });
});

【讨论】:

  • 很高兴听到你可以让它工作。正如我刚才对我的原始帖子的回复中提到的,tabCapture 还缺少一个错误:bugs.chromium.org/p/chromium/issues/detail?id=1214847
【解决方案2】:

这可能不是您正在寻找的,但也许它可以提供一些见解。

我尝试通过音频元素播放流,但这似乎无济于事。

具有讽刺意味的是,这就是我设法解决这个问题的方法;通过在弹出窗口本身中创建一个对象。在弹出脚本中使用 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 等的新命名空间,但除此之外我还没有看到任何东西。

【讨论】:

  • 我还阅读了您链接到的帖子: chrome.tabCapture 被移动到 chrome.capture 命名空间。但实际上,它似乎仍然在 MV3 中的 chrome.tabCapture 下。我猜命名空间更改从未发生过,或者已经延迟。
【解决方案3】:

我也遇到了这个问题,我使用 Web Audio API 解决了这个问题。只需创建一个新上下文并使用 captures MediaStream 将其连接到媒体流源,这是一个示例:

avoidSilenceInTab: (desktopStream: MediaStream) => {
 var contextTab = new AudioContext();
 contextTab
   .createMediaStreamSource(desktopStream)
   .connect(contextTab.destination);

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-07-21
    • 2022-11-15
    • 2021-09-30
    • 2021-03-26
    • 2021-09-21
    • 2022-12-14
    • 2021-09-20
    相关资源
    最近更新 更多