When using WebRTC, you must first obtain camera/microphone permissions using getUserMedia to invoke the mediaDevices related interface

Version 1: Obtain permissions directly

/ / release mediaStream
const stopStreamTracks = stream= > {
  if(! stream || ! stream.getTracks) {return;
  }
  try {
    const tracks = stream.getTracks();
    tracks.forEach(it= > {
      try {
        it.stop();
      } catch (errMsg) {
        // debugger;}}); }catch (errMsg) {
    // debugger;}};Copy the code
// Request camera/microphone permissions
const requestPermission = async() = > {try {
    const stream = await global.navigator.mediaDevices.getUserMedia({ video: true.audio: true });
    stopStreamTracks(stream);
    if (stream) {
      return true; }}catch (errMsg) {
    if (errMsg && 'NotAllowedError' === errMsg.name) {
      return false; }}return true;
};
Copy the code

GetUserMedia rejected.getUsermedia rejected.getUsermedia rejected.getUsermedia rejected.getUsermedia rejected.getUsermedia rejected.getUsermedia rejected.getUsermedia rejected.getUsermedia rejected.getUsermedia rejected.getUsermedia rejected.getUsermedia rejected

Version 2: Filters the device list and dynamically requests device permissions

// Get the device list
const enumerateDevices = async() = > {try {
    const devices = await global.navigator.mediaDevices.enumerateDevices();
    return devices;
  } catch (errMsg) {
    return[]; }};// Request camera/microphone permissions
const requestPermission = async() = > {const devices = await enumerateDevices();
  const constraints = devices.reduce(
    (info, device) = > {
      if(! device) {return info;
      }
      if ('videoinput' === device.kind) {
        return { video: true.audio: info.audio };
      }
      if ('audioinput' === device.kind) {
        return { audio: true.video: info.video };
      }
      return info;
    },
    { video: false.audio: false});try {
    const stream = await global.navigator.mediaDevices.getUserMedia(constraints);
    stopStreamTracks(stream);
  } catch (errMsg) {
    if (errMsg && 'NotAllowedError' === errMsg.name) {
      return false; }}return true;
};
Copy the code

This version also worked well for a while, until we encountered customers using PCIE collection cards under Linux, because enumerateDevices was called before getUserMedia, using 4-way PCIE collection cards in Chrome under Linux, The device deviceId returned from the device list was empty and had only one device, which was not expected. Version 3 was developed based on this problem.

Version 3: Roll back gradually and check multiple times

  • Step 1: Try to obtain both camera and microphone permissions. If NotAllowedError is abnormal, the user refuses to provide permissions. Otherwise, go to the next step
  • Step 2: Obtain the microphone permission separately (the microphone is more important than the camera). If the exception occurs, go to the next step
  • Step 3: Obtain the camera permission separately and check the exception cause
  • Step 4: If none of the three exceptions is caused by NotAllowedError, then consider it a device exception and do not prompt the user for insufficient permissions
// Request camera/microphone permissions
const requestPermission = async() = > {// Step 1: Try to get both camera and microphone permissions
  try {
    const stream = await global.navigator.mediaDevices.getUserMedia({ video: true.audio: true });
    stopStreamTracks(stream);
    if (stream) {
      return true; }}catch (errMsg) {
    if (errMsg && 'NotAllowedError' === errMsg.name) {
      return false; }}try {
    const stream = await global.navigator.mediaDevices.getUserMedia({ video: false.audio: true });
    stopStreamTracks(stream);
    if (stream) {
      return true; }}catch (errMsg) {
    if (errMsg && 'NotAllowedError' === errMsg.name) {
      return false; }}try {
    const stream = await global.navigator.mediaDevices.getUserMedia({ video: true.audio: false });
    stopStreamTracks(stream);
    if (stream) {
      return true; }}catch (errMsg) {
    if (errMsg && 'NotAllowedError' === errMsg.name) {
      return false; }}return true;
};
Copy the code

No problems have been found in version 3. Follow-up updates will continue if problems occur.

Slightly optimized the code

function getDevicePermission(constraints) {
  return global.navigator.mediaDevices
    .getUserMedia(constraints)
    .then(stream= > {
      if (stream) {
        stopStreamTracks(stream);
        return true;
      }
      return Promise.reject(new Error('EmptyStreamError'));
    })
    .catch(errMsg= > {
      if (errMsg && 'NotAllowedError' === errMsg.name) {
        return false;
      }
      return Promise.reject(errMsg);
    });
}

function requestPermission() {
  return getDevicePermission({ video: true.audio: true })
    .catch(() = > getDevicePermission({ video: false.audio: true }))
    .catch(() = > getDevicePermission({ video: true.audio: false }))
    .catch(() = > true);
}
Copy the code