option to turn on audio for video recordings

This commit is contained in:
Josh de Leeuw 2022-07-12 10:33:27 -04:00
parent 71b3706753
commit 1381f575f5
3 changed files with 30 additions and 11 deletions

View File

@ -14,6 +14,7 @@
const init_camera = { const init_camera = {
type: jsPsychInitializeCamera, type: jsPsychInitializeCamera,
width: 320, width: 320,
include_audio: true
} }
const record = { const record = {

View File

@ -338,9 +338,9 @@ export class MediaAPI {
private camera_stream: MediaStream = null; private camera_stream: MediaStream = null;
private camera_recorder: MediaRecorder = null; private camera_recorder: MediaRecorder = null;
initializeCameraRecorder(stream: MediaStream) { initializeCameraRecorder(stream: MediaStream, opts?: MediaRecorderOptions) {
this.camera_stream = stream; this.camera_stream = stream;
const recorder = new MediaRecorder(stream, { mimeType: 'video/webm;codecs="vp9"' }); const recorder = new MediaRecorder(stream, opts);
this.camera_recorder = recorder; this.camera_recorder = recorder;
} }

View File

@ -3,16 +3,19 @@ import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from "jspsych";
const info = <const>{ const info = <const>{
name: "initialize-camera", name: "initialize-camera",
parameters: { parameters: {
/** Function to call */
device_select_message: { device_select_message: {
type: ParameterType.HTML_STRING, type: ParameterType.HTML_STRING,
default: `<p>Please select the camera you would like to use.</p>`, default: `<p>Please select the camera you would like to use.</p>`,
}, },
/** Is the function call asynchronous? */ /** */
button_label: { button_label: {
type: ParameterType.STRING, type: ParameterType.STRING,
default: "Use this camera", default: "Use this camera",
}, },
include_audio: {
type: ParameterType.BOOL,
default: false,
},
width: { width: {
type: ParameterType.INT, type: ParameterType.INT,
default: null, default: null,
@ -21,6 +24,10 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
default: null, default: null,
}, },
mime_type: {
type: ParameterType.STRING,
default: null,
},
}, },
}; };
@ -49,7 +56,7 @@ class InitializeCameraPlugin implements JsPsychPlugin<Info> {
} }
private async run_trial(display_element: HTMLElement, trial: TrialType<Info>) { private async run_trial(display_element: HTMLElement, trial: TrialType<Info>) {
await this.askForPermission(); await this.askForPermission(trial);
this.showCameraSelection(display_element, trial); this.showCameraSelection(display_element, trial);
@ -69,16 +76,27 @@ class InitializeCameraPlugin implements JsPsychPlugin<Info> {
if (trial.height) { if (trial.height) {
constraints.video.height = trial.height; constraints.video.height = trial.height;
} }
if (trial.include_audio) {
constraints.audio = true;
}
const stream = await navigator.mediaDevices.getUserMedia(constraints); const stream = await navigator.mediaDevices.getUserMedia(constraints);
this.jsPsych.pluginAPI.initializeCameraRecorder(stream); const recorder_options: MediaRecorderOptions = {};
if (trial.mime_type) {
recorder_options.mimeType = trial.mime_type;
}
this.jsPsych.pluginAPI.initializeCameraRecorder(stream, recorder_options);
return camera_id; return camera_id;
} }
private async askForPermission() { private async askForPermission(trial: TrialType<Info>) {
const stream = await navigator.mediaDevices.getUserMedia({ audio: false, video: true }); const stream = await navigator.mediaDevices.getUserMedia({
audio: trial.include_audio,
video: true,
});
return stream; return stream;
} }
@ -102,14 +120,14 @@ class InitializeCameraPlugin implements JsPsychPlugin<Info> {
private updateDeviceList(display_element) { private updateDeviceList(display_element) {
navigator.mediaDevices.enumerateDevices().then((devices) => { navigator.mediaDevices.enumerateDevices().then((devices) => {
const mics = devices.filter( const cams = devices.filter(
(d) => (d) =>
d.kind === "videoinput" && d.deviceId !== "default" && d.deviceId !== "communications" d.kind === "videoinput" && d.deviceId !== "default" && d.deviceId !== "communications"
); );
// remove entries with duplicate groupID // remove entries with duplicate groupID
const unique_cameras = mics.filter( const unique_cameras = cams.filter(
(mic, index, arr) => arr.findIndex((v) => v.groupId == mic.groupId) == index (cam, index, arr) => arr.findIndex((v) => v.groupId == cam.groupId) == index
); );
// reset the list by clearing all current options // reset the list by clearing all current options