chrome-extensions-samples/functional-samples/sample.tabcapture-recorder/offscreen.js

95 строки
3.1 KiB
JavaScript

// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
chrome.runtime.onMessage.addListener(async (message) => {
if (message.target === 'offscreen') {
switch (message.type) {
case 'start-recording':
startRecording(message.data);
break;
case 'stop-recording':
stopRecording();
break;
default:
throw new Error('Unrecognized message:', message.type);
}
}
});
let recorder;
let data = [];
async function startRecording(streamId) {
if (recorder?.state === 'recording') {
throw new Error('Called startRecording while recording is in progress.');
}
const media = await navigator.mediaDevices.getUserMedia({
audio: {
mandatory: {
chromeMediaSource: 'tab',
chromeMediaSourceId: streamId
}
},
video: {
mandatory: {
chromeMediaSource: 'tab',
chromeMediaSourceId: streamId
}
}
});
// Continue to play the captured audio to the user.
const output = new AudioContext();
const source = output.createMediaStreamSource(media);
source.connect(output.destination);
// Start recording.
recorder = new MediaRecorder(media, { mimeType: 'video/webm' });
recorder.ondataavailable = (event) => data.push(event.data);
recorder.onstop = () => {
const blob = new Blob(data, { type: 'video/webm' });
window.open(URL.createObjectURL(blob), '_blank');
// Clear state ready for next recording
recorder = undefined;
data = [];
};
recorder.start();
// Record the current state in the URL. This provides a very low-bandwidth
// way of communicating with the service worker (the service worker can check
// the URL of the document and see the current recording state). We can't
// store that directly in the service worker as it may be terminated while
// recording is in progress. We could write it to storage but that slightly
// increases the risk of things getting out of sync.
window.location.hash = 'recording';
}
async function stopRecording() {
recorder.stop();
// Stopping the tracks makes sure the recording icon in the tab is removed.
recorder.stream.getTracks().forEach((t) => t.stop());
// Update current state in URL
window.location.hash = '';
// Note: In a real extension, you would want to write the recording to a more
// permanent location (e.g IndexedDB) and then close the offscreen document,
// to avoid keeping a document around unnecessarily. Here we avoid that to
// make sure the browser keeps the Object URL we create (see above) and to
// keep the sample fairly simple to follow.
}