Tutorial: Environment and Device Check Before Calls

Environment and Device Check Before Calls

Browser Environment Check

Before calling the communication capabilities of the SDK, we recommend you use the checkSystemRequirements() API to check whether the SDK supports the current browser first, and if not, please recommend the user to use a supported browser based on the device type.

TRTC.checkSystemRequirements().then(checkResult => {
  if (checkResult.result) {
    // Check whether room entry is supported
    if (checkResult.isH264DecodeSupported) {
    	// Check whether stream pull is supported
    }
    if (checkResult.isH264EncodeSupported) {
    	// Check whether stream push is supported
    }
  }
})

⚠️ If the user uses a browser supported by the SDK, but the check result returned by TRTC.checkSystemRequirements is false, this may be because:

Scenario 1: please check whether the link meets one of the following three conditions:

  • localhost domain (Firefox supports access to localhost and local IPs)
  • Domains with HTTPS enabled
  • Local files opened over the file:/// protocol

Scenario 2: after the Firefox browser is installed, the H.264 codec needs to be loaded dynamically; therefore, the check result will be false temporarily. Please wait for a while and try again or use another recommended browser to open the link.

Known Use Limits on Browsers

Firefox

  • Firefox supports only the frame rate of 30 fps. If you need to set the frame rate, please use another browser supported by the SDK.

QQ Browser

  • The NotFoundError error may be thrown when localStream.initialize() is called in a localhost environment on certain Windows devices with normal cameras and mics.

Audio/Video Device Test

To ensure that users can have a good user experience with the TRTC SDK, we recommend you check the user's device and network conditions and provide troubleshooting suggestions before the user enters a TRTC room.

You can quickly integrate the device and network check features by referring to the following methods:

rtc-detect Library

You can use rtc-detect to check the support of the current environment for the TRTC SDK and view the details of the current environment.

Installation

npm install rtc-detect

How to use

import RTCDetect from 'rtc-detect';
// Initialize the detection module
const detect = new RTCDetect();
// Get the detection result of the current environment
const result = await detect.getReportAsync();
// `result` contains the current environment system information, API support, codec support, and device information
console.log('result is: ' + result);

API

(async) isTRTCSupported()

This API is used to check whether the current environment supports TRTC.

const detect = new RTCDetect();
const data = await detect.isTRTCSupported();
if (data.result) {
  console.log('current browser supports TRTC.')
} else {
  console.log(`current browser does not support TRTC, reason: ${data.reason}.`)
}

getSystem()

This API is used to get the current system environment parameters.

Item Type Description
UA string user agent
OS string system
browser object browser infomation: { name, version }
displayResolution object resulution: { width, height }
getHardwareConcurrency number current device CPU core count
const detect = new RTCDetect();
const result = detect.getSystem();

getAPISupported()

This API is used to get the API support of the current environment.

Item Type Description
isUserMediaSupported boolean whether to support getting user media from media device
isWebRTCSupported boolean whether to support WebRTC
isWebSocketSupported boolean whether to support WebSocket
isWebAudioSupported boolean whether to support WebAudio
isScreenCaptureAPISupported boolean whether to support getting media steam from screen
isCanvasCapturingSupported boolean whether to support getting media stream from canvas element
isVideoCapturingSupported boolean whether to support getting media stream from video element
isRTPSenderReplaceTracksSupported boolean whether to support not renegotiating with peerConnection when replacing track
isApplyConstraintsSupported boolean whether to support changing the resolution of the camera without re-calling getUserMedia
const detect = new RTCDetect();
const result = detect.getAPISupported();

(async) getDevicesAsync()

This API is used to get the available devices in the current environment.

Item Type Description
hasWebCamPermissions boolean Whether the user camera data can be obtained
hasMicrophonePermission boolean Whether the user mic data can be obtained
cameras array User's camera device list, including information about the camera's supported resolutions, maximum width and height, and maximum frame rate (maximum frame rate is not supported by some browsers)
microphones array A list of user mics
speakers array A list of user speakers

CameraItem

Item Type Description
deviceId string Device ID, which is usually unique and can be used to capture identifying devices
groupId string Group identifier, two devices have the same group identifier if they belong to the same physical device
kind string Camera device type: 'videoinput'
label string Label describing this device
resolution object Information about the camera's supported resolutions, maximum width and height, and maximum frame rate, eg: {maxWidth: 1280, maxHeight: 720, maxFrameRate: 30}

DeviceItem

Item Type Description
deviceId string Device ID, which is usually unique and can be used to capture identifying devices
groupId string Group identifier, two devices have the same group identifier if they belong to the same physical device
kind string Physical device type, eg: 'audioinput', 'audiooutput'
label string Label describing this device
const detect = new RTCDetect();
const result = await detect.getDevicesAsync();

(async) getCodecAsync()

This API is used to get the codec support of the current environment.

Item Type Description
isH264EncodeSupported boolean whether to support h264 uplink
isH264DecodeSupported boolean whether to support h264 downlink
isVp8EncodeSupported boolean whether to support vp8 uplink
isVp8DecodeSupported boolean whether to support vp8 downlink
const detect = new RTCDetect();
const result = await detect.getCodecAsync();

(async) getReportAsync()

This API is used to get the detection report of the current environment.

Item Type Description
system object same as getSystem() result
APISupported object same as getAPISupported() result
codecsSupported object same as getCodecAsync() result
devices object same as getDevicesAsync() result
const detect = new RTCDetect();
const result = await detect.getReportAsync();

(async) isHardWareAccelerationEnabled()

This API is used to check whether hardware acceleration is enabled on the Chrome browser.

Note: the implementation of this API depends on the native WebRTC API. We recommend you call this API for check after calling isTRTCSupported. The check can take up to 30 seconds as tested below:

  1. If hardware acceleration is enabled, this API will take about 2 seconds on Windows and 10 seconds on macOS.
  2. If hardware acceleration is disabled, this API will take about 30 seconds on both Windows and macOS.
const detect = new RTCDetect();
const data = await detect.isTRTCSupported();
if (data.result) {
  const result = await detect.isHardWareAccelerationEnabled();
  console.log(`is hardware acceleration enabled: ${result}`);
} else {
  console.log(`current browser does not support TRTC, reason: ${data.reason}.`)
}

React Component for Device Check

Device check UI component features

  1. Device connection and check logic processing

  2. Network check logic processing

  3. Optional network check tab

  4. Support for Chinese and English

Device check UI component links

For more information on how to use the component's npm package, please see rtc-device-detector-react.

For more information on how to debug the component's source code, please see github/rtc-device-detector.

For more information on how to import the component, please see WebRTC API Example.

Device check UI component page

img

Device and network check logic

1) Device connection

​ The purpose of device connection is to check whether the device used by the user has a camera, mic, and speaker and is connected to the network. If the camera and mic exist, the system will try to get the audio/video streams and prompt the user to grant the camera and mic access permissions.

  • Check whether the device has a camera, mic, and speaker

    import TRTC from 'trtc-js-sdk';
    const cameraList = await TRTC.getCameras();
    const micList = await TRTC.getMicrophones();
    const speakerList = await TRTC.getSpeakers();
    const hasCameraDevice = cameraList.length > 0;
    const hasMicrophoneDevice = micList.length > 0;
    const hasSpeakerDevice = speakerList.length > 0;
    
  • Get the camera and mic access permissions

    navigator.mediaDevices
      .getUserMedia({ video: hasCameraDevice, audio: hasMicrophoneDevice })
      .then((stream) => {
      	// The audio/video streams are successfully obtained
        // ...
      	// Release the camera and mic
       	stream.getTracks().forEach(track => track.stop());
      })
      .catch((error) => {
        // Failed to get the audio/video streams
      });
    
  • Check whether the device is connected to the network

    export function isOnline() {
      const url = 'https://web.sdk.qcloud.com/trtc/webrtc/assets/trtc-logo.png';
      return new Promise((resolve) => {
        try {
          const xhr = new XMLHttpRequest();
          xhr.onload = function () {
            resolve(true);
          };
          xhr.onerror = function () {
            resolve(false);
          };
          xhr.open('GET', url, true);
          xhr.send();
        } catch (err) {
          // console.log(err);
        }
      });
    }
    const isOnline = await isOnline();
    

2) Camera check

​ Camera check is to render the video stream captured by the selected camera to help the user determine whether the camera can be used normally.

  • Get the camera list. The first device in the list is used by default

    import TRTC from 'trtc-js-sdk';
    let cameraList = await TRTC.getCameras();
    let cameraId = cameraList[0].deviceId;
    
  • Initialize the video stream and play it back in the dom element whose ID is camera-video

    const localStream = TRTC.createStream({
      video: true,
      audio: false,
      cameraId,
    });
    await localStream.initialize();
    localStream.play('camera-video');
    
  • Update the stream after the user switches the camera

    localStream.switchDevice('video', cameraId);
    
  • Listen on device plugging/unplugging

    navigator.mediaDevices.addEventListener('devicechange', async () => {
      cameraList = await TRTC.getCameras();
        cameraId = cameraList[0].deviceId; 
      localStream.switchDevice('video', cameraId);
    })
    
  • Release the camera after the check is completed

    localStream.close();
    

3) Mic check

​Mic check is to render the volume of the audio stream captured by the selected mic to help the user determine whether the mic can be used normally.

  • Get the mic list. The first device in the list is used by default

    import TRTC from 'trtc-js-sdk';
    let microphoneList = await TRTC.getMicrophones();
    let microphoneId = microphoneList[0].deviceId;
    
  • Initialize the audio stream and play it back in the dom element whose ID is audio-container

    const localStream = TRTC.createStream({
      video: false,
      audio: true,
      microphoneId,
    });
    await localStream.initialize();
    localStream.play('audio-container');
    timer = setInterval(() => {
      const volume = localStream.getAudioLevel();
    }, 100);
    
  • Update the stream after the user switches the mic

    // Get the new `microphoneId` selected by the user
    localStream.switchDevice('audio', microphoneId);
    
  • Listen on device plugging/unplugging

    navigator.mediaDevices.addEventListener('devicechange', async () => {
      microphoneList = await TRTC.getMicrophones();
        microphoneId = microphoneList[0].deviceId;
      localStream.switchDevice('audio', microphoneId);
    })
    
  • Release the mic after the check is completed and stop listening on the volume

    localStream.close();
    clearInterval(timer);
    

4) Speaker check

​ Speaker check provides an audio player for the user to play back the audio and check whether the selected speaker can be used normally.

  • Provide an MP3 player and prompt the user to increase the device playback volume and play back an MP3 file to check whether the speaker is normal

    <audio id="audio-player" src="xxxxx" controls></audio>
    
  • Stop playback after the check is completed

    const audioPlayer = document.getElementById('audio-player');
    if (!audioPlayer.paused) {
        audioPlayer.pause();
    }
    audioPlayer.currentTime = 0;
    

5) Network check

  • Call TRTC.createClient to create two clients: uplinkClient and downlinkClient.

  • Make the two clients enter the same room.

  • Use uplinkClient to push a stream. Listen on the NETWORK_QUALITY event to check the upstream network quality.

  • Use downlinkClient to pull a stream. Listen on the NETWORK_QUALITY event to check the downstream network quality.

  • The whole process lasts for about 15 seconds, and the average network quality is taken eventually to evaluate the upstream and downstream network quality.

The check process may incur a small amount of basic service fee. If the push resolution is not specified, the stream will be pushed at a resolution of 640x480 by default.

let uplinkClient = null; // Check the upstream network quality
let downlinkClient = null; // Check the downstream network quality
let localStream = null; // Stream for test
let testResult = {
  // Record the upstream network quality data
  uplinkNetworkQualities: [],
  // Record the downstream network quality data
  downlinkNetworkQualities: [],
  average: {
    uplinkNetworkQuality: 0,
    downlinkNetworkQuality: 0
  }
}
// 1. Check the upstream network quality
async function testUplinkNetworkQuality() {
  uplinkClient = TRTC.createClient({
    sdkAppId: 0, // Enter `sdkAppId`
    userId: 'user_uplink_test',
    userSig: '', // `userSig` of `uplink_test`
    mode: 'rtc'
  });
  localStream = TRTC.createStream({ audio: true, video: true });
  // Set the video profile based on the actual business scenario
  localStream.setVideoProfile('480p'); 
  await localStream.initialize();
  uplinkClient.on('network-quality', event => {
    const { uplinkNetworkQuality } = event;
    testResult.uplinkNetworkQualities.push(uplinkNetworkQuality);
  });
  // Enter the room for test. The room ID must be random to avoid conflicts
  await uplinkClient.join({ roomId: 8080 }); 
  await uplinkClient.publish(localStream);
}
// 2. Check the downstream network quality
async function testDownlinkNetworkQuality() {
  downlinkClient = TRTC.createClient({
    sdkAppId: 0, // Enter `sdkAppId`
    userId: 'user_downlink_test',
    userSig: '', // userSig
    mode: 'rtc'
  });
  downlinkClient.on('stream-added', async event => {
    await downlinkClient.subscribe(event.stream, { audio: true, video: true });
		// Start listening on the network quality event after successful subscription
    downlinkClient.on('network-quality', event => {
      const { downlinkNetworkQuality } = event;
      testResult.downlinkNetworkQualities.push(downlinkNetworkQuality);
    });
  })
  // Enter the room for test. The room ID must be random to avoid conflicts
  await downlinkClient.join({ roomId: 8080 });
}
// 3. Start the check
testUplinkNetworkQuality();
testDownlinkNetworkQuality();
// 4. Stop the check after 15 seconds and calculate the average network quality
setTimeout(() => {
  // Calculate the average upstream network quality
  if (testResult.uplinkNetworkQualities.length > 0) {
    testResult.average.uplinkNetworkQuality = Math.ceil(
      testResult.uplinkNetworkQualities.reduce((value, current) => value + current, 0) / testResult.uplinkNetworkQualities.length
    );
  }
  if (testResult.downlinkNetworkQualities.length > 0) {
    // Calculate the average downstream network quality
    testResult.average.downlinkNetworkQuality = Math.ceil(
      testResult.downlinkNetworkQualities.reduce((value, current) => value + current, 0) / testResult.downlinkNetworkQualities.length
    );
  }
  // The check ends. Clear the relevant status.
  uplinkClient.leave();
  downlinkClient.leave();
  localStream.close();
}, 15 * 1000);

TRTC Compatibility Check Page

You can use the TRTC check page to check your current environment where you want to use the TRTC SDK. You can also click Generate Report to get the current environment report for environment check and troubleshooting.