openreplay/frontend/app/utils/screenRecorder.ts
2022-11-30 11:46:57 +01:00

91 lines
2.6 KiB
TypeScript

const FILE_TYPE = 'video/webm';
const FRAME_RATE = 30;
function createFileRecorder (stream: MediaStream, mimeType: string) {
let ended = false;
let recordedChunks: BlobPart[] = [];
const SAVE_INTERVAL_MS = 200;
const mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = function (e) {
if (e.data.size > 0) {
recordedChunks.push(e.data);
}
};
function onEnd() {
if (ended) return;
ended = true;
saveFile(recordedChunks, mimeType);
recordedChunks = [];
};
// sometimes we get race condition or the onstop won't trigger at all,
// this is why we have to make it twice to make sure that stream is saved
// plus we want to be able to handle both, native and custom button clicks
mediaRecorder.stream.getTracks().forEach(track => track.onended = onEnd);
mediaRecorder.onstop = () => {
onEnd();
mediaRecorder.stream.getTracks().forEach(track => track.stop());
}
mediaRecorder.start(SAVE_INTERVAL_MS);
return mediaRecorder;
}
function saveFile(recordedChunks: BlobPart[], mimeType: string) {
const blob = new Blob(recordedChunks, {
type: mimeType,
});
const filename = +new Date() + '.' + mimeType.split('/')[1];
const downloadLink = document.createElement('a');
downloadLink.href = URL.createObjectURL(blob);
downloadLink.download = filename;
document.body.appendChild(downloadLink);
downloadLink.click();
URL.revokeObjectURL(downloadLink.href); // clear from memory
document.body.removeChild(downloadLink);
}
async function recordScreen() {
return await navigator.mediaDevices.getDisplayMedia({
audio: true,
video: { frameRate: FRAME_RATE },
// potential chrome hack
// @ts-ignore
preferCurrentTab: true,
});
};
/**
* Creates a screen recorder that sends the media stream to MediaRecorder
* which then saves the stream to a file.
*
* Supported Browsers:
*
* Windows: Chrome v91+, Edge v90+ - FULL SUPPORT;
* *Nix: Chrome v91+, Edge v90+ - LIMITED SUPPORT - (audio only captured from current tab)
*
* @returns a promise that resolves to a function that stops the recording
*/
export async function screenRecorder() {
try {
const stream = await recordScreen();
const mediaRecorder = createFileRecorder(stream, FILE_TYPE);
return () => mediaRecorder.stop();
} catch (e) {
console.log(e)
}
}
// @ts-ignore
window.recordSceenSample = screenRecorder;
// NOT SUPPORTED:
// macOS: chrome and edge only support capturing current tab's audio
// windows: chrome and edge supports all audio
// other: not supported