Introduction

Before diving into the depth of video calls, imagine giving your setup a quick check-up, like a tech-savvy doctor making sure all systems are in order. It's essentially a pre-call experience—it's like your extensive debug session before the main code execution—a critical step in ensuring your application's performance is optimal.

As users increasingly rely on video conferencing for both personal and professional interactions, the importance of a well-structured on-premise experience cannot be overstated. It serves as a safeguard against potential technical hiccups that could disrupt the flow of communication.

In this article, we'll explore the importance of implementing the pre-call feature in React Native apps, guiding developers through the steps needed to create a robust and user-friendly setup. By prioritizing this preliminary phase, developers can enhance user trust and satisfaction, paving the way for successful and engaging video calls.

Why is it Necessary?

Why to invest time and effort into crafting a precall experience, you wonder? Well, picture this scenario: your users eagerly join a video call, only to encounter a myriad of technical difficulties—muted microphones, pixelated cameras, and laggy connections. Not exactly the smooth user experience you had in mind, right?

By integrating a robust precall process into your app, developers become the unsung heroes, preemptively addressing potential pitfalls and ensuring that users step into their video calls with confidence.

Step-by-Step Guide: Integrating Precall Feature​

Step 1: Check Permissions

  • Begin by ensuring that your application has the necessary permissions to access user devices such as cameras, microphones
  • Utilize the checkPermission() and checkBluetoothPermission() methods of the useMediaDevice hook to verify if permissions are granted.
import { useMediaDevice } from "@videosdk.live/react-native-sdk";

const { checkPermission } = useMediaDevice();

const checkMediaPermission = async () => {
  //These methods return a Promise that resolve to a Map<string, boolean> object.
  const checkAudioPermission = await checkPermission("audio"); //For getting audio permission
  const checkVideoPermission = await checkPermission("video"); //For getting video permission
  const checkAudioVideoPermission = await checkPermission("audio_video"); //For getting both audio and video permissions
  const checkBTPermission = await checkBlueToothPermission(); // For getting bluetooth permission
  // Output: Map object for both audio and video permission:
  /*
        Map(2)
        0 : {"audio" => true}
            key: "audio"
            value: true
        1 : {"video" => true}
            key: "video"
            value: true
    */
};

Step 2: Request Permissions

If permissions are not granted, use the requestPermission() and requestBluetoothPermission methods of the useMediaDevice hook to prompt users to grant access to their devices.

const requestAudioVideoPermission = async () => {
  try {
    //These methods return a Promise that resolve to a Map<string, boolean> object.
    const requestAudioPermission = await requestPermission("audio"); //For Requesting Audio Permission
    const requestVideoPermission = await requestPermission("video"); //For Requesting Video Permission
    const requestAudioVideoPermission = await requestPermission("audio_video"); //For Requesting Audio and Video Permissions

    // Applicable only to Android; not required for iOS
    const checkBTPermission = await requestBluetoothPermission(); //For requesting Bluetooth Permission.
  } catch (ex) {
    console.log("Error in requestPermission ", ex);
  }
};

Step 3: Render Device List

Once you have the necessary permissions, Fetch and render a list of available cameras, microphone, and list of all devices using the getCameras(), getAudioDeviceList() and getDevices() methods of the useMediaDevice hook respectively.

const getMediaDevices = async () => {
  try {
    //Method to get all available webcams.
    //It returns a Promise that is resolved with an array of CameraDeviceInfo objects describing the video input devices.
    let webcams = await getCameras();
    console.log("List of Devices:", webcams);
    //Method to get all available Microphones.
    //It returns a Promise that is resolved with an array of MicrophoneDeviceInfo objects describing the audio input devices.
    const mics = await getAudioDeviceList();
    console.log("List of Microphone:", mics);
    //Method to get all available cameras and playback devices.
    //It returns a list of the currently available media input and output devices, such as microphones, cameras, headsets, and so forth
    let deivces = await getDevices();
    console.log("List of Cameras:", devices);
  } catch (err) {
    console.log("Error in getting audio or video devices", err);
  }
};

Step 4: Handle Device Changes​

  • Implement the onAudioDeviceChanged callback of the useMediaDevice hook to dynamically re-render device lists whenever new devices are attached or removed from the system.
  • Ensure that users can seamlessly interact with newly connected devices without disruptions.
const {
    ...
  } = useMediaDevice({ onAudioDeviceChanged });

//Fetch camera, mic and speaker devices again using this function.
function onAudioDeviceChanged(device) {
    console.log("Device Changed", device)
}

Step 5: Create Media Tracks

Create media tracks for the selected microphone and camera using the createMicrophoneAudioTrack() and createCameraVideoTrack() methods.

Ensure that these tracks originate from the user-selected devices for accurate testing.

import {
  createCameraVideoTrack,
  createMicrophoneAudioTrack,
} from "@videosdk.live/react-native-sdk";

//For Getting Audio Tracks
const getMediaTracks = async () => {
  try {
    //Returns a MediaStream object, containing the Audio Stream from the selected Mic Device.
    let customTrack = await createMicrophoneAudioTrack({
      encoderConfig: "speech_standard",
      noiseConfig: {
        noiseSuppression: true,
        echoCancellation: true,
        autoGainControl: true,
      },
    });
  } catch (error) {
    console.log("Error in getting Audio Track", error);
  }

  //For Getting Video Tracks
  try {
    //Returns a MediaStream object, containing the Video Stream from the selected Webcam Device.
    let customVideoTrack = await createCameraVideoTrack({
      optimizationMode: "motion",
      encoderConfig: "h720p_w1280p",
      facingMode: "user",
    });
    //To retrive video tracks that will be displayed to the user from the stream.
    const videoTracks = stream?.getVideoTracks();
    const videoTrack = videoTracks.length ? videoTracks[0] : null;
  } catch (error) {
    console.log("Error in getting Video Track", error);
  }
};

Step 6: Passing States to Meeting

Ensure that all relevant states, such as microphone and camera status (on/off), and selected devices, are passed into the meeting from the precall screen.

This can be accomplished by passing these crucial states and media streams onto the VideoSDK MeetingProvider.

By ensuring this integration, users can seamlessly transition from the precall setup to the actual meeting while preserving their preferred settings.

<MeetingProvider
    config={
        {
            ...
            //Status of Mircophone Device as selected by the user (On/Off).
            micEnabled: micOn,
            //Status of Webcam Device as selected by the user (On/Off).
            webcamEnabled: webcamOn,
            //customVideoStream has to be the Video Stream of the user's selected Webcam device as created in Step-5.
            customCameraVideoTrack: customVideoStream,
            //customAudioStream has to be the Audio Stream of the user's selected Microphone device as created in Step-5.
            customMicrophoneAudioTrack: customAudioStream
        }
    } >
</MeetingProvider>

Conclusion

The step-by-step guide provided in this article equips developers with the tools and knowledge needed to implement a comprehensive pre-call process, turning potential frustrations into a smooth, enjoyable experience.

Incorporating precall features into your React Native apps is not only a best practice; it's a necessity. By addressing potential issues—such as device permissions, connectivity, and media track management—you empower users to confidently join their video calls.

As you embark on this journey, remember that a little preparation goes a long way in ensuring that your users can focus on what matters; meaningful conversations and connections. Adopt the pre-call experience and watch your application thrive in an increasingly competitive landscape.