diff --git a/examples/jspsych-initialize-microphone.html b/examples/jspsych-initialize-microphone.html
index dc581781..f0a859c1 100644
--- a/examples/jspsych-initialize-microphone.html
+++ b/examples/jspsych-initialize-microphone.html
@@ -17,7 +17,10 @@
let ar = {
type: jsPsychHtmlAudioResponse,
- stimulus: '
Speak!
'
+ stimulus: 'Speak!
',
+ on_finish: (data) => {
+ console.log(data);
+ }
}
jsPsych.run([init_mic, ar]);
diff --git a/packages/plugin-html-audio-response/src/index.ts b/packages/plugin-html-audio-response/src/index.ts
index d8130906..d4c556c3 100644
--- a/packages/plugin-html-audio-response/src/index.ts
+++ b/packages/plugin-html-audio-response/src/index.ts
@@ -9,7 +9,6 @@ const info = {
pretty_name: "Stimulus",
default: undefined,
},
-
/** How long to show the stimulus. */
stimulus_duration: {
type: ParameterType.INT,
@@ -20,7 +19,11 @@ const info = {
trial_duration: {
type: ParameterType.INT,
pretty_name: "Trial duration",
- default: null,
+ default: 2000,
+ },
+ button_label: {
+ type: ParameterType.STRING,
+ default: "Continue",
},
},
};
@@ -37,88 +40,104 @@ class HtmlAudioResponsePlugin implements JsPsychPlugin {
static info = info;
private stimulus_start_time;
private recorder_start_time;
+ private recorder: MediaRecorder;
+ private response;
+ private load_resolver;
constructor(private jsPsych: JsPsych) {}
trial(display_element: HTMLElement, trial: TrialType) {
- const ro = new ResizeObserver((entries) => {
- console.log("ro event");
- this.stimulus_start_time = performance.now();
- });
+ this.recorder = this.jsPsych.pluginAPI.getMicrophoneRecorder();
- ro.observe(display_element);
+ this.setupRecordingEvents(display_element, trial);
- // this.showDisplay(display_element, trial);
- // this.addButtonEvent(display_element, trial);
+ this.startRecording();
- this.startRecording(display_element, trial);
-
- // hide image if timing is set
+ // setup timer for hiding the stimulus
if (trial.stimulus_duration !== null) {
this.jsPsych.pluginAPI.setTimeout(() => {
- display_element.querySelector(
- "#jspsych-html-audio-response-stimulus"
- ).style.visibility = "hidden";
+ this.hideStimulus(display_element);
}, trial.stimulus_duration);
}
- // end trial if time limit is set
+ // setup timer for ending the trial
if (trial.trial_duration !== null) {
this.jsPsych.pluginAPI.setTimeout(() => {
- this.endTrial(display_element, trial);
+ this.stopRecording().then(() => {
+ this.endTrial(display_element, trial);
+ });
}, trial.trial_duration);
}
}
private showDisplay(display_element, trial) {
+ const ro = new ResizeObserver((entries) => {
+ this.stimulus_start_time = performance.now();
+ console.log("ro event");
+ ro.disconnect();
+ });
+
+ ro.observe(display_element);
+
let html = `${trial.stimulus}
`;
- html += ``;
+ html += ``;
display_element.innerHTML = html;
}
+ private hideStimulus(display_element: HTMLElement) {
+ display_element.querySelector(
+ "#jspsych-html-audio-response-stimulus"
+ ).style.visibility = "hidden";
+ }
+
private addButtonEvent(display_element, trial) {
display_element.querySelector("#finish-trial").addEventListener("click", () => {
const end_time = performance.now();
const rt = Math.round(end_time - this.stimulus_start_time);
- this.endTrial(display_element, trial, rt);
+ this.stopRecording().then(() => {
+ this.endTrial(display_element, trial, rt);
+ });
});
}
- private startRecording(display_element, trial) {
- const recorder: MediaRecorder = this.jsPsych.pluginAPI.getMicrophoneRecorder();
+ private setupRecordingEvents(display_element, trial) {
const recorded_data_chunks = [];
- recorder.addEventListener("dataavailable", (e) => {
+ this.recorder.addEventListener("dataavailable", (e) => {
if (e.data.size > 0) {
recorded_data_chunks.push(e.data);
}
- console.log("dataavail event");
});
- recorder.addEventListener("stop", () => {
+ this.recorder.addEventListener("stop", () => {
const url = new Blob(recorded_data_chunks, { type: "audio/webm" });
const reader = new FileReader();
reader.addEventListener("load", () => {
const base64 = (reader.result as string).split(",")[1];
- console.log(base64);
+ this.response = base64;
+ this.load_resolver();
});
reader.readAsDataURL(url);
-
- console.log(this.stimulus_start_time, this.recorder_start_time);
});
- recorder.addEventListener("start", (e) => {
+ this.recorder.addEventListener("start", (e) => {
this.recorder_start_time = e.timeStamp;
this.showDisplay(display_element, trial);
this.addButtonEvent(display_element, trial);
});
+ }
- this.jsPsych.pluginAPI.setTimeout(() => {
- recorder.stop();
- }, 2000);
- recorder.start();
+ private startRecording() {
+ this.recorder.start();
+ }
+
+ private stopRecording() {
+ this.recorder.stop();
+ return new Promise((resolve) => {
+ this.load_resolver = resolve;
+ });
}
private endTrial(display_element, trial, rt: number = null) {
@@ -129,6 +148,8 @@ class HtmlAudioResponsePlugin implements JsPsychPlugin {
var trial_data = {
rt: rt,
stimulus: trial.stimulus,
+ response: this.response,
+ estimated_stimulus_onset: Math.round(this.stimulus_start_time - this.recorder_start_time),
};
// clear the display