Add tabCapture sample (#933)
* Add tabCapture sample * Add README * Update receiver.html * Fix variable loss caused by idle * Use windows.create * Remove unnecessary logs * Update README * Update api-samples/tabCapture/README.md Co-authored-by: Oliver Dunk <oliver@oliverdunk.com> * Update api-samples/tabCapture/README.md Co-authored-by: amysteamdev <37001393+AmySteam@users.noreply.github.com> * Update api-samples/tabCapture/README.md Co-authored-by: amysteamdev <37001393+AmySteam@users.noreply.github.com> * Update api-samples/tabCapture/README.md Co-authored-by: amysteamdev <37001393+AmySteam@users.noreply.github.com> * Rename background.js * Remove unnecessary async function * Move the script to the body * Update api-samples/tabCapture/README.md Co-authored-by: amysteamdev <37001393+AmySteam@users.noreply.github.com> * Update README.md * Update api-samples/tabCapture/manifest.json Co-authored-by: Oliver Dunk <oliver@oliverdunk.com> --------- Co-authored-by: Oliver Dunk <oliver@oliverdunk.com> Co-authored-by: amysteamdev <37001393+AmySteam@users.noreply.github.com>
This commit is contained in:
Родитель
ee2c6fcad0
Коммит
961028b1bf
|
@ -0,0 +1,21 @@
|
||||||
|
# chrome.tabCapture
|
||||||
|
|
||||||
|
A sample that demonstrates how to use the [`chrome.tabCapture`](https://developer.chrome.com/docs/extensions/reference/tabCapture/) API.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
In this sample, the `chrome.tabCapture` API captures the contents of the active tab. The captured stream is displayed in a new window.
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
Use [`tabCapture.getMediaStreamId`](https://developer.chrome.com/docs/extensions/reference/tabCapture/#method-getMediaStreamId) to capture specific tabs.
|
||||||
|
|
||||||
|
The `targetTabId` and `consumerTabId` are obtained in the Service Worker, and then passed to the receiver page through the [`tabs.sendMessage`](https://developer.chrome.com/docs/extensions/reference/tabs/#method-sendMessage) method.
|
||||||
|
|
||||||
|
See the [Audio recording and Screen capture guide](https://developer.chrome.com/docs/extensions/mv3/screen_capture/#audio-and-video) for a more detailed implementation.
|
||||||
|
|
||||||
|
## Running this extension
|
||||||
|
|
||||||
|
1. Clone this repository.
|
||||||
|
2. Load this directory in Chrome as an [unpacked extension](https://developer.chrome.com/docs/extensions/mv3/getstarted/development-basics/#load-unpacked).
|
||||||
|
3. Click the extension's action icon.
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 3.0 KiB |
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"name": "Tab Capture Example",
|
||||||
|
"description": "Capture a tab and play in a <video> element in a separate window.",
|
||||||
|
"version": "1",
|
||||||
|
"manifest_version": 3,
|
||||||
|
"action": {
|
||||||
|
"default_icon": "icon.png"
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"service_worker": "service-worker.js"
|
||||||
|
},
|
||||||
|
"permissions": ["tabs", "tabCapture"]
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>receiver</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<p id="echo-msg"></p>
|
||||||
|
<video id="player" width="100%"></video>
|
||||||
|
<script src="./receiver.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,91 @@
|
||||||
|
let currentStream = null;
|
||||||
|
|
||||||
|
function printErrorMessage(message) {
|
||||||
|
const element = document.getElementById('echo-msg');
|
||||||
|
element.innerText = message;
|
||||||
|
console.error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop video play-out and stop the MediaStreamTracks.
|
||||||
|
function shutdownReceiver() {
|
||||||
|
if (!currentStream) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const player = document.getElementById('player');
|
||||||
|
player.srcObject = null;
|
||||||
|
const tracks = currentStream.getTracks();
|
||||||
|
for (let i = 0; i < tracks.length; ++i) {
|
||||||
|
tracks[i].stop();
|
||||||
|
}
|
||||||
|
currentStream = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start video play-out of the captured MediaStream.
|
||||||
|
function playCapturedStream(stream) {
|
||||||
|
if (!stream) {
|
||||||
|
printErrorMessage(
|
||||||
|
'Error starting tab capture: ' +
|
||||||
|
(chrome.runtime.lastError.message || 'UNKNOWN')
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (currentStream != null) {
|
||||||
|
shutdownReceiver();
|
||||||
|
}
|
||||||
|
currentStream = stream;
|
||||||
|
const player = document.getElementById('player');
|
||||||
|
player.addEventListener(
|
||||||
|
'canplay',
|
||||||
|
function () {
|
||||||
|
this.volume = 0.75;
|
||||||
|
this.muted = false;
|
||||||
|
this.play();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
once: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
player.setAttribute('controls', '1');
|
||||||
|
player.srcObject = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetMediaStreamId(targetTabId, consumerTabId) {
|
||||||
|
chrome.tabCapture.getMediaStreamId(
|
||||||
|
{ targetTabId, consumerTabId },
|
||||||
|
function (streamId) {
|
||||||
|
if (typeof streamId !== 'string') {
|
||||||
|
printErrorMessage(
|
||||||
|
'Failed to get media stream id: ' +
|
||||||
|
(chrome.runtime.lastError.message || 'UNKNOWN')
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
navigator.webkitGetUserMedia(
|
||||||
|
{
|
||||||
|
audio: false,
|
||||||
|
video: {
|
||||||
|
mandatory: {
|
||||||
|
chromeMediaSource: 'tab', // The media source must be 'tab' here.
|
||||||
|
chromeMediaSourceId: streamId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function (stream) {
|
||||||
|
playCapturedStream(stream);
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
printErrorMessage(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
chrome.runtime.onMessage.addListener(function (request) {
|
||||||
|
const { targetTabId, consumerTabId } = request;
|
||||||
|
testGetMediaStreamId(targetTabId, consumerTabId);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('beforeunload', shutdownReceiver);
|
|
@ -0,0 +1,36 @@
|
||||||
|
async function closePrevReceiverTab() {
|
||||||
|
const tabs = await chrome.tabs.query({
|
||||||
|
url: chrome.runtime.getURL('receiver.html')
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(tabs.map((tab) => chrome.tabs.remove(tab.id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
chrome.action.onClicked.addListener(async (tab) => {
|
||||||
|
const currentTabId = tab.id;
|
||||||
|
|
||||||
|
await closePrevReceiverTab();
|
||||||
|
|
||||||
|
// Open a new tab with the receiver.html page
|
||||||
|
const { tabs } = await chrome.windows.create({
|
||||||
|
url: chrome.runtime.getURL('receiver.html')
|
||||||
|
});
|
||||||
|
|
||||||
|
const receiverTabId = tabs[0].id;
|
||||||
|
|
||||||
|
// Wait for the receiver tab to load
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
chrome.tabs.onUpdated.addListener(function listener(tabId, info) {
|
||||||
|
if (tabId === receiverTabId && info.status === 'complete') {
|
||||||
|
chrome.tabs.onUpdated.removeListener(listener);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send a message to the receiver tab
|
||||||
|
chrome.tabs.sendMessage(receiverTabId, {
|
||||||
|
targetTabId: currentTabId,
|
||||||
|
consumerTabId: receiverTabId
|
||||||
|
});
|
||||||
|
});
|
Загрузка…
Ссылка в новой задаче