Spaces:
Running
Running
// recorder.js | |
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | |
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | |
return new (P || (P = Promise))(function (resolve, reject) { | |
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | |
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | |
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | |
step((generator = generator.apply(thisArg, _arguments || [])).next()); | |
}); | |
}; | |
const BLOB_TYPE = "video/webm"; | |
class ScreenCastRecorder { | |
/** True if the current browser likely supports screencasts. */ | |
static isSupportedBrowser() { | |
return (navigator.mediaDevices != null && | |
navigator.mediaDevices.getUserMedia != null && | |
navigator.mediaDevices.getDisplayMedia != null && | |
MediaRecorder.isTypeSupported(BLOB_TYPE)); | |
} | |
constructor({ recordAudio, onErrorOrStop }) { | |
this.recordAudio = recordAudio; | |
this.onErrorOrStopCallback = onErrorOrStop; | |
this.inputStream = null; | |
this.recordedChunks = []; | |
this.mediaRecorder = null; | |
} | |
/** | |
* This asynchronous method will initialize the screen recording object asking | |
* for permissions to the user which are needed to start recording. | |
*/ | |
initialize() { | |
return __awaiter(this, void 0, void 0, function* () { | |
const desktopStream = yield navigator.mediaDevices.getDisplayMedia({ | |
video: true, | |
}); | |
let tracks = desktopStream.getTracks(); | |
if (this.recordAudio) { | |
const voiceStream = yield navigator.mediaDevices.getUserMedia({ | |
video: false, | |
audio: true, | |
}); | |
tracks = tracks.concat(voiceStream.getAudioTracks()); | |
} | |
this.recordedChunks = []; | |
this.inputStream = new MediaStream(tracks); | |
this.mediaRecorder = new MediaRecorder(this.inputStream, { | |
mimeType: BLOB_TYPE, | |
}); | |
this.mediaRecorder.ondataavailable = e => this.recordedChunks.push(e.data); | |
}); | |
} | |
getState() { | |
if (this.mediaRecorder) { | |
return this.mediaRecorder.state; | |
} | |
return "inactive"; | |
} | |
/** | |
* This method will start the screen recording if the user has granted permissions | |
* and the mediaRecorder has been initialized | |
* | |
* @returns {boolean} | |
*/ | |
start() { | |
if (!this.mediaRecorder) { | |
console.warn(`ScreenCastRecorder.start: mediaRecorder is null`); | |
return false; | |
} | |
const logRecorderError = (e) => { | |
console.warn(`mediaRecorder.start threw an error: ${e}`); | |
}; | |
this.mediaRecorder.onerror = (e) => { | |
logRecorderError(e); | |
this.onErrorOrStopCallback(); | |
}; | |
this.mediaRecorder.onstop = () => this.onErrorOrStopCallback(); | |
try { | |
this.mediaRecorder.start(); | |
} | |
catch (e) { | |
logRecorderError(e); | |
return false; | |
} | |
return true; | |
} | |
/** | |
* This method will stop recording and then return the generated Blob | |
* | |
* @returns {(Promise|undefined)} | |
* A Promise which will return the generated Blob | |
* Undefined if the MediaRecorder could not initialize | |
*/ | |
stop() { | |
if (!this.mediaRecorder) { | |
return undefined; | |
} | |
let resolver; | |
const promise = new Promise(r => { | |
resolver = r; | |
}); | |
this.mediaRecorder.onstop = () => resolver(); | |
this.mediaRecorder.stop(); | |
if (this.inputStream) { | |
this.inputStream.getTracks().forEach(s => s.stop()); | |
this.inputStream = null; | |
} | |
return promise.then(() => this.buildOutputBlob()); | |
} | |
buildOutputBlob() { | |
return new Blob(this.recordedChunks, { type: BLOB_TYPE }); | |
} | |
} |