From 211bfe0cdf7f9501220750f0ee35331c10bacc15 Mon Sep 17 00:00:00 2001 From: CJ Green <44074998+okaycj@users.noreply.github.com> Date: Mon, 6 May 2024 14:14:22 -0400 Subject: [PATCH] Session recording --- packages/video/src/index.ts | 4 +++- packages/video/src/recorder.ts | 31 ++++++++++++++++--------------- packages/video/src/start.ts | 29 +++++++++++++++++++++++++++++ packages/video/src/stop.ts | 28 ++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 packages/video/src/start.ts create mode 100644 packages/video/src/stop.ts diff --git a/packages/video/src/index.ts b/packages/video/src/index.ts index 5d01c66e..711b9994 100644 --- a/packages/video/src/index.ts +++ b/packages/video/src/index.ts @@ -1,3 +1,5 @@ +import StartRecordPlugin from "./start"; +import StopRecordPlugin from "./stop"; import TrialRecordExtension from "./trial"; -export default { TrialRecordExtension }; +export default { TrialRecordExtension, StartRecordPlugin, StopRecordPlugin }; diff --git a/packages/video/src/recorder.ts b/packages/video/src/recorder.ts index d672d646..78e8e12d 100644 --- a/packages/video/src/recorder.ts +++ b/packages/video/src/recorder.ts @@ -2,16 +2,12 @@ import autoBind from "auto-bind"; import { JsPsych } from "jspsych"; /** - * + * Video Recorder */ export default class Recorder { - private _recorder?: MediaRecorder; private blobs: Blob[] = []; - /** - * - * @param jsPsych - */ + /** @param jsPsych */ constructor(private jsPsych: JsPsych) { autoBind(this); } @@ -20,26 +16,31 @@ export default class Recorder { * */ private get recorder() { - if (!this._recorder) { - this._recorder = this.jsPsych.pluginAPI.getCameraRecorder(); - this.recorder.addEventListener("dataavailable", this.handleDataAvailable); - this.recorder.addEventListener("stop", this.handleStop); - } - return this._recorder; + return this.jsPsych.pluginAPI.getCameraRecorder(); + } + + /** + * + */ + private get stream() { + return this.jsPsych.pluginAPI.getCameraStream(); } /** * */ public start() { + this.recorder.addEventListener("dataavailable", this.handleDataAvailable); + this.recorder.addEventListener("stop", this.handleStop); this.recorder.start(); } + /** * */ public stop() { this.recorder.stop(); - this.recorder.stream.getTracks().map((t) => t.stop()); + this.stream.getTracks().map((t: MediaStreamTrack) => t.stop()); } /** Handle recorder's stop event. */ @@ -56,14 +57,14 @@ export default class Recorder { this.blobs.push(event.data); } - /** Temp method to download data uri. */ + /** Temp method to download data url. */ private async download() { const data = (await this.bytesToBase64DataUrl( new Blob(this.blobs), )) as string; const link = document.createElement("a"); link.href = data; - link.download = `something_${new Date().getTime()} .webm`; + link.download = `something_${new Date().getTime()}.webm`; link.click(); } diff --git a/packages/video/src/start.ts b/packages/video/src/start.ts new file mode 100644 index 00000000..30430b9a --- /dev/null +++ b/packages/video/src/start.ts @@ -0,0 +1,29 @@ +import { JsPsych, JsPsychPlugin, TrialType } from "jspsych"; +import Recorder from "./recorder"; + +const info = { name: "start-record-plugin", parameters: {} }; +type Info = typeof info; + +/** + * + */ +export default class StartRecordPlugin implements JsPsychPlugin { + public static readonly info = info; + recorder: Recorder; + /** @param jsPsych */ + constructor(private jsPsych: JsPsych) { + this.recorder = new Recorder(this.jsPsych); + } + + /** + * @param _display_element + * @param _trial + */ + trial( + _display_element: HTMLElement, + _trial: TrialType, + ): void | Promise { + this.recorder.start(); + setTimeout(() => this.jsPsych.finishTrial(), 1000); + } +} diff --git a/packages/video/src/stop.ts b/packages/video/src/stop.ts new file mode 100644 index 00000000..65961c25 --- /dev/null +++ b/packages/video/src/stop.ts @@ -0,0 +1,28 @@ +import { JsPsych, JsPsychPlugin, TrialType } from "jspsych"; +import Recorder from "./recorder"; + +const info = { name: "stop-record-plugin", parameters: {} }; +type Info = typeof info; + +/** + * + */ +export default class StopRecordPlugin implements JsPsychPlugin { + public static readonly info = info; + private recorder: Recorder; + /** @param jsPsych */ + constructor(private jsPsych: JsPsych) { + this.recorder = new Recorder(this.jsPsych); + } + + /** + * @param _display_element + * @param _trial + */ + trial( + _display_element: HTMLElement, + _trial: TrialType, + ): void | Promise { + setTimeout(() => this.recorder.stop(), 1000); + } +}