UNPKG

@videosdk.live/react-native-sdk

Version:

<h1 align="center"> <img src="https://static.videosdk.live/videosdk_logo_website_black.png"/><br/> <p align="center"> Video SDK React Native App <br/> <a href="https://videosdk.live/">videosdk.live</a> </p> </h1>

365 lines (339 loc) 10.6 kB
import { useEffect } from "react"; import { NativeModules, Platform, NativeEventEmitter, DeviceEventEmitter, PermissionsAndroid, } from "react-native"; import { MicrophoneDeviceInfo as AudioDeviceInfo, CameraDeviceInfo as OldCameraDeviceInfo, Constants, } from "@videosdk.live/react-sdk"; import InCallManager from "@videosdk.live/react-native-incallmanager"; /** * * @param {{ * onAudioDeviceChanged?: Function | undefined, * }} * * * @returns {{ * getDevices: () => Promise<Array<DeviceInfo>>; * getAudioDeviceList: () => Promise<Array<AudioDeviceInfo>>; * getCameras: () => Promise<Array<CameraDeviceInfo>>; * checkPermission: (permission? : Permission) => Promise<Map<string, boolean>>; * requestPermission: (permission? : Permission) => Promise<Map<string, boolean>>; * checkBlueToothPermission:()=> Promise<boolean> * requestBluetoothPermission:()=> Promise<boolean> * }} * */ const useMediaDevice = ({ onAudioDeviceChanged = (data) => {} } = {}) => { var eventEmitter; if (Platform.OS == "ios") { const { InCallManager } = NativeModules; eventEmitter = new NativeEventEmitter(InCallManager); } useEffect(() => { InCallManager.start({ media: "video" }); const callback = async (data) => { const devices = await getAudioDeviceList(); if (Platform.OS == "ios") { if (data["selectedAudioDevice"].includes("Headphone")) { data["selectedAudioDevice"] = "WIRED_HEADSET"; } else if (data["selectedAudioDevice"].includes("Bluetooth")) { data["selectedAudioDevice"] = "BLUETOOTH"; } else if (data["selectedAudioDevice"].includes("Speaker")) { data["selectedAudioDevice"] = "SPEAKER_PHONE"; } else if ( data["selectedAudioDevice"].includes("Microphone") || data["selectedAudioDevice"].includes("Receiver") ) { data["selectedAudioDevice"] = "EARPIECE"; } } data["availableDevices"] = devices; devices.forEach((element) => { if (element["deviceId"] == data["selectedAudioDevice"]) { data["selectedAudioDevice"] = element; } }); onAudioDeviceChanged(data); return data; }; if (Platform.OS == "ios") { eventEmitter.addListener("onAudioDeviceChanged", callback); return () => { eventEmitter.removeAllListeners("onAudioDeviceChanged"); }; } else { DeviceEventEmitter.addListener("onAudioDeviceChanged", callback); return () => { DeviceEventEmitter.removeAllListeners("onAudioDeviceChanged"); }; } }, []); /** * * @param {Permission} permission * @returns {Promise<Map<string, boolean>>} */ async function checkPermission(permission) { if (!permission) { permission = Constants.permission.AUDIO_AND_VIDEO; } const permissionMap = new Map(); if ( permission.includes(Constants.permission.VIDEO) || permission.includes(Constants.permission.AUDIO_AND_VIDEO) ) { let allowed = true; try { const res = await InCallManager.checkCameraPermission(); // 'granted' | 'denied' if (res == "denied" || res == "undetermined") { allowed = false; } } catch (e) { allowed = false; throw Error("Device does not support camera permission check", e); } permissionMap.set(Constants.permission.VIDEO, allowed); } if ( permission.includes(Constants.permission.AUDIO) || permission.includes(Constants.permission.AUDIO_AND_VIDEO) ) { let allowed = true; try { const res = await InCallManager.checkRecordPermission(); // 'granted' | 'denied' if (res == "denied" || res == "undetermined") { allowed = false; } } catch (e) { allowed = false; throw Error("Device does not support microphone permission check", e); } permissionMap.set(Constants.permission.AUDIO, allowed); } return permissionMap; } /** * * @param {Permission} permission * @returns {Promise<Map<string, boolean>>} */ async function requestPermission(permission) { if (!permission) { permission = Constants.permission.AUDIO_AND_VIDEO; } const permissionMap = new Map(); if ( permission.includes(Constants.permission.VIDEO) || permission.includes(Constants.permission.AUDIO_AND_VIDEO) ) { let videoMediaStream; const constraints = { audio: false, video: true }; let permissionGranted = true; try { videoMediaStream = await navigator.mediaDevices.getUserMedia( constraints ); } catch (ex) { permissionGranted = false; let message; if (ex.name === "SecurityError") { message = "Oops! It seems like camera access was denied or dismissed. To proceed, kindly grant access through your App settings."; } else if (ex.name === "DOMException") { message = "Please ensure your camera is connected and turned on, and that the camera driver is installed and up-to-date."; } else { message = `Something unexpected occur, Exception info: ${ex}`; } throw new Error(message); } if (videoMediaStream) { videoMediaStream.getTracks().forEach(function (track) { track.stop(); }); } permissionMap.set(Constants.permission.VIDEO, permissionGranted); } if ( permission.includes(Constants.permission.AUDIO) || permission.includes(Constants.permission.AUDIO_AND_VIDEO) ) { let audioMediaStream; const constraints = { audio: true, video: false }; let permissionGranted = true; try { audioMediaStream = await navigator.mediaDevices.getUserMedia( constraints ); } catch (ex) { permissionGranted = false; let message; if (ex.name === "SecurityError") { message = "Oops! It seems like mic access was denied or dismissed. To proceed, kindly grant access through your App settings."; } else if (ex.name === "DOMException") { message = "Please ensure your mic is connected and turned on."; } else { message = `Something unexpected occur, Exception info: ${ex}`; } throw new Error(message); } if (audioMediaStream) { audioMediaStream.getTracks().forEach(function (track) { track.stop(); }); } permissionMap.set(Constants.permission.AUDIO, permissionGranted); } return permissionMap; } /** * * @returns {Promise<boolean>} */ async function checkBlueToothPermission() { if (Platform.OS == "ios") { throw Error( "checkBlueToothPermission() method is not supported on the iOS platform" ); } let permission = Platform.Version >= 31 ? "android.permission.BLUETOOTH_CONNECT" : "android.permission.BLUETOOTH"; return PermissionsAndroid.check(permission) .then((status) => { return status; }) .catch((ex) => { throw Error("Exception in Bluetooth checking permission", ex); }); } /** * * @returns {Promise<boolean>} */ async function requestBluetoothPermission() { if (Platform.OS == "ios") { throw Error( "requestBluetoothPermission() method is not supported on the iOS platform" ); } let permissionGranted = false; let permission = Platform.Version >= 31 ? "android.permission.BLUETOOTH_CONNECT" : "android.permission.BLUETOOTH"; try { const granted = await PermissionsAndroid.request(permission, { title: "This Permission will help you to communicate over Bluetooth Peripherals", buttonNegative: "Cancel", buttonPositive: "OK", }); if (granted === PermissionsAndroid.RESULTS.GRANTED) { permissionGranted = true; } else { console.log("Bluetooth Connect Permission Denied"); } } catch (ex) { throw Error("Exception in Bluetooth requesting permission", ex); } return permissionGranted; } /** * * @returns {Promise<Array<DeviceInfo>>} */ async function getDevices() { let audioDeviceList = await getAudioDeviceList(); const devices = []; audioDeviceList.forEach((element) => { devices.push(element); }); const cameraDeviceList = await getCameras(); cameraDeviceList.forEach((element) => { devices.push(element); }); return devices; } /** * * @returns {Promise<Array<AudioDeviceInfo>>} */ async function getAudioDeviceList() { let devices = await InCallManager.getAudioDeviceList(); const audioDevices = []; if (devices) { if (devices.length > 0) { if ( devices.includes("WIRED_HEADSET") || devices.includes("BLUETOOTH") ) { removeItemFromArray(devices, "EARPIECE"); } for (const device of devices) { audioDevices.push(new AudioDeviceInfo(device, "", "audio", device)); } } } return audioDevices; } function removeItemFromArray(arr, value) { var index = arr.indexOf(value); if (index > -1) { arr.splice(index, 1); } return arr; } /** * * @returns {Promise<Array<CameraDeviceInfo>>} */ async function getCameras() { try { const devices = await navigator.mediaDevices.enumerateDevices(); const cameras = []; for (const device of devices) { if (device.kind == "videoinput") { cameras.push( new CameraDeviceInfo( device.deviceId, device.groupId, "video", device.label, device.facing == "environment" ? "back" : device.facing ) ); } } return cameras; } catch (error) { console.error(`An error occurred in getCameras(), ${error.message}`); } } return { getDevices, getAudioDeviceList, getCameras, checkPermission, requestPermission, checkBlueToothPermission, requestBluetoothPermission, }; }; class CameraDeviceInfo extends OldCameraDeviceInfo { constructor(deviceId, groupId, kind, label, facing) { super(deviceId, groupId, kind, label); /** * @type {string} */ this.facingMode = facing; } } export default useMediaDevice;