import { JsPsych , JsPsychPlugin , ParameterType , TrialType } from "jspsych" ; const info = < const > { name : "initialize-microphone" , parameters : { /** Function to call */ device_select_message : { type : ParameterType . HTML_STRING , default : `<p>Please select the microphone you would like to use.</p>` , } , /** Is the function call asynchronous? */ button_label : { type : ParameterType . STRING , default : "Use this microphone" , } , } , } ; type Info = typeof info ; author Josh de Leeuw
 *  see https class InitializeMicrophonePlugin implements JsPsychPlugin < Info > { static info = info ; constructor ( private jsPsych ) { } trial ( display_element , trial ) { this . run_trial ( display_element , trial ) . then ( ( id ) => { this . jsPsych . finishTrial ( { device_id : id , } ) ; } ) ; } private async run_trial ( display_element , trial ) { await this . askForPermission ( ) ; this . showMicrophoneSelection ( display_element , trial ) ; this . updateDeviceList ( display_element ) ; 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 } } ) ; this . jsPsych . pluginAPI . initializeMicrophoneRecorder ( stream ) ; return mic_id ; } private async askForPermission ( ) { const stream = await navigator . mediaDevices . getUserMedia ( { audio : true , video : false } ) ; return stream ; } private showMicrophoneSelection ( display_element , trial ) { let html = `
      ${ trial . device_select_message }
      <select name="mic" id="which-mic" style="font-size:14px; font-family: 'Open Sans', 'Arial', sans-serif; padding: 4px;">
      </select>
      <p><button class="jspsych-btn" id="btn-select-mic">${ trial . button_label }</button></p>` ; display_element . innerHTML = html ; } private waitForSelection ( display_element ) { return new Promise ( ( resolve ) => { display_element . querySelector ( "#btn-select-mic" ) . addEventListener ( "click" , ( ) => { const mic = display_element . querySelector ( "#which-mic" ) . value ; resolve ( mic ) ; } ) ; } ) ; } private updateDeviceList ( display_element ) { navigator . mediaDevices . enumerateDevices ( ) . then ( ( devices ) => { const mics = devices . filter ( ( d ) => d . kind === "audioinput" && d . deviceId !== "default" && d . deviceId !== "communications" ) ; const unique_mics = mics . filter ( ( mic , index , arr ) => arr . findIndex ( ( v ) => v . groupId == mic . groupId ) == index ) ; 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 ;