javascripthtmlaudionavigatormediadevices

How to change audio input source when external microphone is attached or removed


Code to detect available cameras and mic

function gotDevices(deviceInfos) {
  const values = selectors.map(select => select.value);
  selectors.forEach(select => {
    while (select.firstChild) {
      select.removeChild(select.firstChild);
    }
  });
  for (let i = 0; i !== deviceInfos.length; ++i) {
    const deviceInfo = deviceInfos[i];
    const option = document.createElement('option');
    option.value = deviceInfo.deviceId;
    if (deviceInfo.kind === 'audioinput') {
      option.text = deviceInfo.label || `microphone ${audioInputSelect.length + 1}`;
      audioInputSelect.appendChild(option);
      // console.log('audio source device: ', deviceInfo );
    }else if (deviceInfo.kind === 'videoinput') {
      option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
      videoSelect.appendChild(option);
    } else {
      // console.log('Some other kind of source/device: ', deviceInfo);
    }
  }
  selectors.forEach((select, selectorIndex) => {
    if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
      select.value = values[selectorIndex];
    }
  });
}

function handleError(){
        console.log("Something went wrong while fetching the input devices!!!");
}

navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);

When audio source changes i update the available devices and republish the stream, Now the main problem here is when i start the stream with external MIC it is taking audio input from the external MIC and when i remove it is taking audio input from Laptop's MIC but when i again insert external MIC it is not changing the audio input source which should be external MIC.

navigator.mediaDevices.ondevicechange = function(event) {
     navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);
    republish( document.getElementById('uid').getAttribute('value') );
}

function republish(uid){
  clearAllStreams(uid);
  getMediaStream().then((stream) => {
      publishStream("camera", stream , uid);
  });
}

function clearAllStreams(uid){
    console.log(" i am clearing streams");
    let selfStream = participants[uid].stream;
    if(selfStream){
        selfStream.getTracks().forEach((track) => {
            track.stop();
        });
        console.log("all tracks stopped.");
    }
    if(publication){
        publication.stop();
        console.log("publication stopped.");
    }
}


 function getMediaStream(config = { audio: true,  video: { facingMode: "user" } }) {
    let _fetchStreamFromDevice = () => {
        return navigator.mediaDevices.getUserMedia(config);
    };

    return new Promise(async(resolve, reject) => {
        let  stream = await (_fetchStreamFromDevice()).then(stream =>{
        resolve(stream);
        }).catch(err =>{
          console.log(err);
            reject(err);
        });
    });

}

Solution

  • I have did the following changes in getMediaStream function and it worked very fine.

      const  config = {
          audio: {  deviceId :audioDeviceId ? { exact : audioDeviceId } : undefined },
          video: {  facingMode : "user" }
        };