add customization of labels; refresh list of mics based on live availability

This commit is contained in:
Josh de Leeuw 2021-11-22 10:38:05 -05:00
parent 49f5cf4b02
commit aa660ad597

View File

@ -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;