mirror of
https://github.com/jspsych/jsPsych.git
synced 2025-05-10 19:20:55 +00:00
add customization of labels; refresh list of mics based on live availability
This commit is contained in:
parent
49f5cf4b02
commit
aa660ad597
@ -4,14 +4,14 @@ const info = <const>{
|
|||||||
name: "initialize-microphone",
|
name: "initialize-microphone",
|
||||||
parameters: {
|
parameters: {
|
||||||
/** Function to call */
|
/** Function to call */
|
||||||
func: {
|
device_select_message: {
|
||||||
type: ParameterType.BOOL,
|
type: ParameterType.HTML_STRING,
|
||||||
default: true,
|
default: `<p>Please select the microphone you would like to use.</p>`,
|
||||||
},
|
},
|
||||||
/** Is the function call asynchronous? */
|
/** Is the function call asynchronous? */
|
||||||
async: {
|
button_label: {
|
||||||
type: ParameterType.BOOL,
|
type: ParameterType.STRING,
|
||||||
default: false,
|
default: "Use this microphone",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -32,27 +32,25 @@ class InitializeMicrophonePlugin implements JsPsychPlugin<Info> {
|
|||||||
constructor(private jsPsych: JsPsych) {}
|
constructor(private jsPsych: JsPsych) {}
|
||||||
|
|
||||||
trial(display_element: HTMLElement, trial: TrialType<Info>) {
|
trial(display_element: HTMLElement, trial: TrialType<Info>) {
|
||||||
this.run_trial(display_element).then((id) => {
|
this.run_trial(display_element, trial).then((id) => {
|
||||||
this.jsPsych.finishTrial({
|
this.jsPsych.finishTrial({
|
||||||
device_id: id,
|
device_id: id,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async run_trial(display_element) {
|
private async run_trial(display_element: HTMLElement, trial: TrialType<Info>) {
|
||||||
await this.askForPermission();
|
await this.askForPermission();
|
||||||
|
|
||||||
const devices = await navigator.mediaDevices.enumerateDevices();
|
this.showMicrophoneSelection(display_element, trial);
|
||||||
const mics = devices.filter(
|
|
||||||
(d) => d.kind === "audioinput" && d.deviceId !== "default" && d.deviceId !== "communications"
|
|
||||||
);
|
|
||||||
|
|
||||||
// remove entries with duplicate groupID
|
this.updateDeviceList(display_element);
|
||||||
const unique_mics = mics.filter(
|
|
||||||
(mic, index, arr) => arr.findIndex((v) => v.groupId == mic.groupId) == index
|
|
||||||
);
|
|
||||||
|
|
||||||
const mic_id = await this.showMicrophoneSelection(display_element, unique_mics);
|
navigator.mediaDevices.ondevicechange = (e) => {
|
||||||
|
this.updateDeviceList(display_element);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mic_id = await this.waitForSelection(display_element);
|
||||||
|
|
||||||
const stream = await navigator.mediaDevices.getUserMedia({ audio: { deviceId: mic_id } });
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: { deviceId: mic_id } });
|
||||||
|
|
||||||
@ -66,17 +64,16 @@ class InitializeMicrophonePlugin implements JsPsychPlugin<Info> {
|
|||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
private showMicrophoneSelection(display_element, devices: MediaDeviceInfo[]) {
|
private showMicrophoneSelection(display_element, trial: TrialType<Info>) {
|
||||||
let html = `
|
let html = `
|
||||||
<p>Please select the microphone you would like to use.</p>
|
${trial.device_select_message}
|
||||||
<select name="mic" id="which-mic" style="font-size:14px; font-family: 'Open Sans', 'Arial', sans-serif; padding: 4px;">`;
|
<select name="mic" id="which-mic" style="font-size:14px; font-family: 'Open Sans', 'Arial', sans-serif; padding: 4px;">
|
||||||
for (const d of devices) {
|
</select>
|
||||||
html += `<option value="${d.deviceId}">${d.label}</option>`;
|
<p><button class="jspsych-btn" id="btn-select-mic">${trial.button_label}</button></p>`;
|
||||||
}
|
|
||||||
html += "</select>";
|
|
||||||
html += '<p><button class="jspsych-btn" id="btn-select-mic">Use this microphone</button></p>';
|
|
||||||
display_element.innerHTML = html;
|
display_element.innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
private waitForSelection(display_element) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
display_element.querySelector("#btn-select-mic").addEventListener("click", () => {
|
display_element.querySelector("#btn-select-mic").addEventListener("click", () => {
|
||||||
const mic = display_element.querySelector("#which-mic").value;
|
const mic = display_element.querySelector("#which-mic").value;
|
||||||
@ -84,6 +81,31 @@ class InitializeMicrophonePlugin implements JsPsychPlugin<Info> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateDeviceList(display_element) {
|
||||||
|
navigator.mediaDevices.enumerateDevices().then((devices) => {
|
||||||
|
const mics = devices.filter(
|
||||||
|
(d) =>
|
||||||
|
d.kind === "audioinput" && d.deviceId !== "default" && d.deviceId !== "communications"
|
||||||
|
);
|
||||||
|
|
||||||
|
// remove entries with duplicate groupID
|
||||||
|
const unique_mics = mics.filter(
|
||||||
|
(mic, index, arr) => arr.findIndex((v) => v.groupId == mic.groupId) == index
|
||||||
|
);
|
||||||
|
|
||||||
|
// reset the list by clearing all current options
|
||||||
|
display_element.querySelector("#which-mic").innerHTML = "";
|
||||||
|
|
||||||
|
unique_mics.forEach((d) => {
|
||||||
|
let el = document.createElement("option");
|
||||||
|
el.value = d.deviceId;
|
||||||
|
el.innerHTML = d.label;
|
||||||
|
|
||||||
|
display_element.querySelector("#which-mic").appendChild(el);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default InitializeMicrophonePlugin;
|
export default InitializeMicrophonePlugin;
|
||||||
|
Loading…
Reference in New Issue
Block a user