Tutorial: Device Change Check

Device Change Check

Feature Description

Starting from v4.6.2, the SDK can detect camera and mic connection/disconnection based on the browser's native devicechange event and automatically resume stream capturing and push at appropriate points of time. Below is the specific logic:

  1. If a camera/mic that is currently pushing a stream is disconnected, the SDK will try to use the remaining available media devices to resume stream capturing and push.
  2. If there are no available media devices after the camera/mic is disconnected, the SDK will detect device connection. When a new available media device is connected, the SDK will try to use it to resume stream capturing and push.
  3. If resumption fails, the error DEVICE_AUTO_RECOVER_FAILED will be thrown.

This document describes how to detect device connection/disconnection based on the browser's native devicechange event and remind the user to check devices at appropriate points of time.

Implementation Process

  1. Use TRTC.getDevices to get a device list.
  2. Listen for the browser's native event: devicechange.
  3. Get anthor device list again when devicechange event fired. And then, compare it with the device list obtained in the first step, you will get the list of added/removed devices.
  4. Use LocalStream.getVideoTrack and MediaStreamTrack.getSettings() to get the camera deviceId of LocalStream, and compare it with the list of removed devices obtained in step 3 to determine whether the currently used device has been removed.

Sample Code

Getting Lists of Added and Removed Devices

When a device changes, the devicechange event will be triggered. By comparing the device lists before and after the devicechange event, you can detect the added or removed devices.

// 1. Save a device list
let prevDevices = await TRTC.getDevices();
// 2. Listen on the device change event
navigator.mediaDevices.addEventListener('devicechange', async () => {
  // 3. Get the changed device list after a device changes for comparison with `prevDevices`
  const devices = await TRTC.getDevices();
  // 4. List of added devices
  const devicesAdded = devices.filter(device => prevDevices.findIndex(({ deviceId }) => device.deviceId === deviceId) < 0);
  // 5. List of removed devices
  const devicesRemoved = prevDevices.filter(prevDevice => devices.findIndex(({ deviceId }) => prevDevice.deviceId === deviceId) < 0);
  if (devicesAdded.length > 0) {
    handleDevicesAdded(devicesAdded);
  }
  if (devicesRemoved.length > 0) {
    handleDevicesRemoved(devicesRemoved);
  }
  prevDevices = devices;
});

Processing Lists of Added and Removed Devices

function handleDevicesAdded(devicesAdded) {
  devicesAdded.forEach(device => {
    if (device.kind === 'audioinput') {
      // Notify the user of the detected newly connected mic. If the user wants to switch to the new device, call the `localStream.switchDevice` API for switch
    } else if (device.kind === 'videoinput') {
      // Notify the user of the detected newly connected camera. If the user wants to switch to the new device, call the `localStream.switchDevice` API for switch
    }
  });
}
function handleDevicesRemoved(devicesRemoved) {
  devicesRemoved.forEach(device => {
    if (device.kind === 'audioinput') {
      // Notify the user of the detected disconnected mic
      if (isCurrentMicrophoneRemoved(device.deviceId)) {
        // The currently used mic is disconnected
      }
    } else if (device.kind === 'videoinput') {
      // Notify the user of the detected disconnected camera
      if (isCurrentCameraRemoved(device.deviceId)) {
        // The currently used camera is disconnected
      }
    }
  });
}

Checking Whether the Currently Used Device Is disconnected

You can use the MediaStreamTrack.getSettings() method to get the deviceId currently used by LocalStream and compare it with deviceId in the devicesRemoved list to check whether currently used device is disconnected.

// Check whether the currently used mic is disconnected
// `microphoneIdRemoved` is the `deviceId` of the disconnected mic
function isCurrentMicrophoneRemoved(microphoneIdRemoved) {
  const audioTrack = localStream.getAudioTrack();
  if (audioTrack && audioTrack.getSettings().deviceId === microphoneIdRemoved) {
    return true;
  } else {
    return false;
  }
}
// Check whether the currently used camera is disconnected
// `cameraIdRemoved` is the `deviceId` of the disconnected camera
function isCurrentCameraRemoved(cameraIdRemoved) {
  const videoTrack = localStream.getVideoTrack();
  if (videoTrack && videoTrack.getSettings().deviceId === cameraIdRemoved) {
    return true;
  } else {
    return false;
  }
}