COVID-19 महामारी के दौरान वीडियो कॉलिंग एक आवश्यक दैनिक गतिविधि बन गई है। चैट ऐप्स, ऑडियो कॉलिंग और वीडियो कॉलिंग जैसी सुविधाओं का उपयोग करके, हम अपने दोस्तों और परिवार के साथ जुड़े रहने में सक्षम हैं।
अब, अपना खुद का रिएक्ट नेटिव ऐप बनाते हैं जो हमें वीडियो कॉल करने देगा।
इस ट्यूटोरियल में, हम सीखेंगे कि ट्विलियो प्रोग्रामेबल वीडियो कॉल एपीआई का उपयोग करके रिएक्ट नेटिव ऐप में वीडियो कॉलिंग फीचर को कैसे लागू किया जाए।
प्रक्रिया काफी सीधी है। हम बस एक वीडियो कॉन्फ़्रेंस रूम बनाएंगे और अन्य लोगों को उस रूम में शामिल होने के लिए आमंत्रित करेंगे। ऐसा करने के लिए, हमें कैमरा और माइक्रोफ़ोन तक पहुंच की आवश्यकता होगी। इसलिए हमें परीक्षण उद्देश्यों के लिए एक वास्तविक स्मार्टफोन डिवाइस का उपयोग करने की आवश्यकता होगी।
Twilio API को एक्सेस करने के लिए हम जिस मुख्य पैकेज का उपयोग करने जा रहे हैं, वह है रिएक्ट-नेटिव-टवीलियो-वीडियो-वेबआरटीसी पैकेज।
आवश्यकताएं
- ट्विलियो खाता
- परीक्षण के लिए कम से कम दो आईओएस या एंड्रॉइड डिवाइस।
- रिएक्टिव नेटिव एनवायरनमेंट सेटअप।
आरंभ करें!
अपनी Twilio API कुंजी कैसे प्राप्त करें
अपनी Twilio API कुंजी प्राप्त करने के लिए, आपको एक Twilio खाते की आवश्यकता होगी। उसके लिए इस यूआरएल पर जाएं। अपना खाता सेट करने के बाद, आपको नीचे स्क्रीनशॉट द्वारा निर्देशित स्थान पर जाना होगा:
एक्सेस टोकन प्राप्त करने के लिए सर्वर को कैसे सेटअप करें
एक्सेस टोकन लाने के लिए, हमें एक नया नोड सर्वर प्रोजेक्ट बनाना होगा। उसके लिए, हमें निम्न कमांड चलाकर आवश्यक पैकेज स्थापित करने की आवश्यकता है:
yarn add dotenv express ngrok nodemon twilio
इसके बाद, हमें पर्यावरण चर फ़ाइल में Twilio क्रेडेंशियल जोड़ने की आवश्यकता है - .env, जैसा कि नीचे दिए गए कोड स्निपेट में दिखाया गया है:
PORT=3000
ACCOUNT_SID=AC5ceb0847c50c91b143ce07
API_KEY_SID=SKa173c10de99a26fd86969b
API_KEY_SECRET=Czv7IjNIZJis8s7jb5FePi
अब हमें एक एपीआई एंडपॉइंट बनाने की जरूरत है। सबसे पहले, हमें आवश्यक पैकेज आयात करने और नीचे दिए गए कोड स्निपेट में निर्देशित एक्सेस टोकन प्राप्त करने के लिए ऑब्जेक्ट इंस्टेंस बनाने की आवश्यकता है:
import 'dotenv/config';
import express from 'express';
import twilio from 'twilio';
import ngrok from 'ngrok';
const AccessToken = twilio.jwt.AccessToken;
const VideoGrant = AccessToken.VideoGrant;
const app = express();
यहां, हम एक्सेस टोकन प्राप्त करने के लिए एक एपीआई एंडपॉइंट बनाने जा रहे हैं। एक्सप्रेस इंस्टेंस द्वारा प्रदान की गई विधि का उपयोग करके, हमें एक एंडपॉइंट फ़ंक्शन बनाने की आवश्यकता होती है जो एक्सेस टोकन के साथ प्रतिक्रिया करता है।
फ़ंक्शन के अंदर, हमें Twillio क्रेडेंशियल के साथ एक नया उदाहरण बनाने की आवश्यकता है। फिर, हमें मोबाइल डिवाइस पर रजिस्टर स्क्रीन से प्राप्त उपयोगकर्ता नाम को एक पहचान विशेषता के रूप में जोड़ना होगा।
अंत में, हम उपयोगकर्ता को एक्सेस प्रदान करेंगे ताकि वे वीडियो का उपयोग कर सकें और फिर जेडब्ल्यूटी टोकन को डिवाइस पर वापस कर सकें। नीचे दिए गए स्निपेट में यह सब करने के लिए कोड है:
app.get('/getToken', (req, res) => {
if (!req.query || !req.query.userName) {
return res.status(400).send('Username parameter is required');
}
const accessToken = new AccessToken(
process.env.ACCOUNT_SID,
process.env.API_KEY_SID,
process.env.API_KEY_SECRET,
);
// Set the Identity of this token
accessToken.identity = req.query.userName;
// Grant access to Video
var grant = new VideoGrant();
accessToken.addGrant(grant);
// Serialize the token as a JWT
var jwt = accessToken.toJwt();
return res.send(jwt);
});
हम पूर्व पहुंच के लिए इंटरनेट पर बनाए गए एंडपॉइंट एपीआई को भी उजागर करते हैं। उसके लिए, हम निम्नलिखित कोड स्निपेट से कोड का उपयोग कर सकते हैं:
app.listen(process.env.PORT, () =>
console.log(`Server listening on port ${process.env.PORT}!`),
);
ngrok.connect(process.env.PORT).then((url) => {
console.log(`Server forwarded to public url ${url}`);
});
अंत में, हमें सर्वर को चलाने की आवश्यकता है जैसा कि नीचे स्क्रीनशॉट में दिखाया गया है:
यहां, हमने एक्सेस टोकन वापस करने के लिए सफलतापूर्वक एक एपीआई एंडपॉइंट बनाया है।
हमारी प्रतिक्रिया मूल परियोजना को कैसे कॉन्फ़िगर करें
हमारे रिएक्ट नेटिव प्रोजेक्ट में, हमें पैकेज को मैन्युअल रूप से सेट करने के साथ-साथ एंड्रॉइड और आईओएस दोनों प्लेटफॉर्म के लिए कैमरा और माइक्रोफ़ोन तक पहुंचने के लिए अनुमतियों को कॉन्फ़िगर करने की आवश्यकता है।
लेकिन पहले, हमें आवश्यक पैकेजों को स्थापित करने की आवश्यकता है, जो कि react-navigation
. हैं और react-native-twilio-video-webrtc
, हमारे प्रोजेक्ट टर्मिनल में निम्न कमांड चलाकर:
yarn add @react-navigation/native @react-navigation/stack react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view react-native-dotenv react-native-permissions <https://github.com/blackuy/react-native-twilio-video-webrtc>
iOS के लिए सेटअप
IOS के लिए, हमें पैकेज को मैन्युअल रूप से सेट करना होगा। सबसे पहले, हमें पॉडफाइल पर IOS लक्ष्य को 11 तक बढ़ाना होगा . यह आवश्यक है क्योंकि Twilio के नेटिव वीडियो SDK में केवल iOS 11.0+ के लिए समर्थन है:
platform :ios, '11.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
पॉडफाइल में, हमें नीचे दिए गए कोड स्निपेट में निर्देशानुसार एक अनुमति अनुरोध सेट करना होगा:
permissions_path = '../node_modules/react-native-permissions/ios'
pod 'Permission-Camera', :path => "#{permissions_path}/Camera.podspec"
pod 'Permission-Microphone', :path => "#{permissions_path}/Microphone.podspec"
फिर, हमें नीचे दिए गए कोड स्निपेट में निर्देशानुसार कैमरा और माइक्रोफ़ोन एक्सेस की अनुमति के अनुरोध के लिए info.plist को खोलना होगा और कोड जोड़ना होगा:
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>NSCameraUsageDescription</key>
<string>We require your permission to access the camera while in a video call</string>
<key>NSMicrophoneUsageDescription</key>
<string>We require your permission to access the microphone while in a video call</string>
अब हम अपने iOS सेटअप के साथ कर चुके हैं।
Android के लिए सेटअप
सबसे पहले और सबसे महत्वपूर्ण, हमें कोड की निम्न पंक्ति को ./android/settings.gradle में जोड़ना होगा फ़ाइल:
project(':react-native-twilio-video-webrtc').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-twilio-video-webrtc/android')
साथ ही, हमें पैकेज कार्यान्वयन कोड को ./android/app/build.gradle में जोड़ना होगा फ़ाइल:
implementation project(':react-native-twilio-video-webrtc')
अंत में, हमें इसे MainApplication.java . में आयात करना होगा फ़ाइल भी:
import com.twiliorn.library.TwilioPackage;
फिर, हमें निम्नलिखित कोड का उपयोग करके पैकेज को सक्रिय करने की आवश्यकता है:
@Override
protected List getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List packages = new PackageList(this).getPackages();
// add the following code
packages.add(new TwilioPackage());
return packages;
}
रजिस्टर रूम स्क्रीन कैसे बनाएं
यहां, हम "रजिस्टर रूम" नामक एक स्क्रीन बनाने जा रहे हैं जो हमें हमारे वीडियो कॉलिंग रिएक्ट नेटिव ऐप में एक कमरे में पंजीकरण करने की अनुमति देगा।
सबसे पहले, हमें आवश्यक पैकेज आयात करने की आवश्यकता है जैसा कि नीचे दिए गए कोड स्निपेट में दिखाया गया है:
import React, {useState, useRef, useEffect, useContext} from 'react';
import {
StyleSheet,
View,
Text,
StatusBar,
TouchableOpacity,
TextInput,
Alert,
KeyboardAvoidingView,
Platform,
ScrollView,
Dimensions,
} from 'react-native';
import {
TwilioVideoLocalView,
TwilioVideoParticipantView,
TwilioVideo,
} from 'react-native-twilio-video-webrtc';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
- प्रतिक्रिया-नेविगेशन:रजिस्टर स्क्रीन और वीडियो कॉल स्क्रीन के नेविगेशन को संभालने के लिए।
- प्रतिक्रिया-मूल:यह पैकेज हमें कैमरा और माइक्रोफ़ोन तक पहुँचने के लिए अनुमतियों को संभालने की अनुमति देता है।
- react-native-twilio-video-webrtc:यह हमें Twilio के वीडियो कॉल प्रोग्रामयोग्य API तक पहुंचने की अनुमति देता है।
इंस्टेंस और वैरिएबल कैसे शुरू करें
सबसे पहले, हम प्रतिक्रिया-नेविगेशन के लिए एक उदाहरण बनाने जा रहे हैं। फिर, हम राज्यों को वितरित करने के लिए राज्यों के साथ-साथ संदर्भ चर शुरू करने जा रहे हैं जैसा कि नीचे दिए गए कोड स्निपेट में दिखाया गया है:
const Stack = createStackNavigator();
const initialState = {
isAudioEnabled: true,
status: 'disconnected',
participants: new Map(),
videoTracks: new Map(),
userName: '',
roomName: '',
token: '',
};
const AppContext = React.createContext(initialState);
const dimensions = Dimensions.get('window');
बूटस्ट्रैप नेविगेशन
App.js . में फ़ाइल, हम एक नेविगेशन कंटेनर स्टैक बनाने जा रहे हैं। Stack
. का उपयोग करना घटक हम नीचे दिए गए कोड स्निपेट में निर्देशित संदर्भ का उपयोग करके प्रत्येक स्क्रीन पर राज्य वितरित करने जा रहे हैं:
export default () => {
const [props, setProps] = useState(initialState);
return (
<>
<StatusBar barStyle="dark-content" />
<AppContext.Provider value={{props, setProps}}>
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Video Call" component={VideoCallScreen} />
</Stack.Navigator>
</NavigationContainer>
</AppContext.Provider>
</>
);
};
रजिस्टर स्क्रीन कैसे बनाएं
उपयोगकर्ता के क्रेडेंशियल प्राप्त करने और उपयोगकर्ताओं को वीडियो कॉल रूम में शामिल होने की अनुमति देने के लिए रजिस्टर स्क्रीन में एक मोडल डायलॉग होगा।
सबसे पहले, हमें प्रॉप्स को संदर्भ से register.js . में लाना होगा फ़ाइल जैसा कि नीचे दिए गए कोड स्निपेट में दिखाया गया है:
import React, {useState, useRef, useEffect, useContext} from 'react';
import {
checkMultiple,
request,
requestMultiple,
PERMISSIONS,
RESULTS,
} from 'react-native-permissions';
const RegisterScreen = ({navigation}) => {
const {props, setProps} = useContext(AppContext);
अगला, हमें कैमरा और माइक्रोफ़ोन अनुमतियों को संभालने के लिए एक फ़ंक्शन बनाने की आवश्यकता है। फ़ंक्शन के लिए कोड नीचे दिए गए कोड स्निपेट में दिया गया है:
const _checkPermissions = (callback) => {
const iosPermissions = [PERMISSIONS.IOS.CAMERA, PERMISSIONS.IOS.MICROPHONE];
const androidPermissions = [
PERMISSIONS.ANDROID.CAMERA,
PERMISSIONS.ANDROID.RECORD_AUDIO,
];
checkMultiple(
Platform.OS === 'ios' ? iosPermissions : androidPermissions,
).then((statuses) => {
const [CAMERA, AUDIO] =
Platform.OS === 'ios' ? iosPermissions : androidPermissions;
if (
statuses[CAMERA] === RESULTS.UNAVAILABLE ||
statuses[AUDIO] === RESULTS.UNAVAILABLE
) {
Alert.alert(
'Error',
'Hardware to support video calls is not available',
);
} else if (
statuses[CAMERA] === RESULTS.BLOCKED ||
statuses[AUDIO] === RESULTS.BLOCKED
) {
Alert.alert(
'Error',
'Permission to access hardware was blocked, please grant manually',
);
} else {
if (
statuses[CAMERA] === RESULTS.DENIED &&
statuses[AUDIO] === RESULTS.DENIED
) {
requestMultiple(
Platform.OS === 'ios' ? iosPermissions : androidPermissions,
).then((newStatuses) => {
if (
newStatuses[CAMERA] === RESULTS.GRANTED &&
newStatuses[AUDIO] === RESULTS.GRANTED
) {
callback && callback();
} else {
Alert.alert('Error', 'One of the permissions was not granted');
}
});
} else if (
statuses[CAMERA] === RESULTS.DENIED ||
statuses[AUDIO] === RESULTS.DENIED
) {
request(statuses[CAMERA] === RESULTS.DENIED ? CAMERA : AUDIO).then(
(result) => {
if (result === RESULTS.GRANTED) {
callback && callback();
} else {
Alert.alert('Error', 'Permission not granted');
}
},
);
} else if (
statuses[CAMERA] === RESULTS.GRANTED ||
statuses[AUDIO] === RESULTS.GRANTED
) {
callback && callback();
}
}
});
};
फिर, हमें हर बार ऐप शुरू होने पर इस अनुमति-जांच फ़ंक्शन को कॉल करने की आवश्यकता होती है। उसके लिए, हमें फंक्शन को useEffect
. के अंदर कॉल करना होगा नीचे दिए गए कोड स्निपेट में बताए अनुसार हुक करें:
useEffect(() => {
_checkPermissions();
}, []);
अंत में, हमें दो इनपुट के साथ एक साधारण फॉर्म बनाना होगा जो कमरे के नाम और उपयोगकर्ता नाम को स्वीकार करता है। फिर, हमें Twilio API पर पंजीकरण करने के लिए सर्वर को इनपुट भेजने की आवश्यकता है। इसके लिए कोड नीचे दिए गए कोड स्निपेट में दिया गया है:
return (
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={styles.container}>
<ScrollView contentContainerStyle={styles.container}>
<View style={styles.form}>
<View style={styles.formGroup}>
<Text style={styles.text}>User Name</Text>
<TextInput
style={styles.textInput}
autoCapitalize="none"
value={props.userName}
onChangeText={(text) => setProps({...props, userName: text})}
/>
</View>
<View style={styles.formGroup}>
<Text style={styles.text}>Room Name</Text>
<TextInput
style={styles.textInput}
autoCapitalize="none"
value={props.roomName}
onChangeText={(text) => setProps({...props, roomName: text})}
/>
</View>
<View style={styles.formGroup}>
<TouchableOpacity
disabled={false}
style={styles.button}
onPress={() => {
_checkPermissions(() => {
fetch(`https://ae7a722dc260.ngrok.io/getToken?userName=${props.userName}`)
.then((response) => {
if (response.ok) {
response.text().then((jwt) => {
setProps({...props, token: jwt});
navigation.navigate('Video Call');
return true;
});
} else {
response.text().then((error) => {
Alert.alert(error);
});
}
})
.catch((error) => {
console.log('error', error);
Alert.alert('API not available');
});
});
}}>
<Text style={styles.buttonText}>Connect to Video Call</Text>
</TouchableOpacity>
</View>
</View>
</ScrollView>
</KeyboardAvoidingView>
);
हम परिणाम प्राप्त करेंगे जैसा कि नीचे एमुलेटर स्क्रीनशॉट में दिखाया गया है:
यहां, हम अपने रजिस्टर रूम स्क्रीन को एक मोडल फॉर्म के साथ देख सकते हैं जहां हम सर्वर पर चल रहे ट्विलियो एपीआई में रजिस्टर करने के लिए कमरे का नाम और उपयोगकर्ता नाम इनपुट कर सकते हैं।
वीडियो कॉल स्क्रीन कैसे बनाएं
वीडियो कॉल स्क्रीन में, हमारे पास दो विंडो होंगी - एक हमारे अपने कैमरे के दृश्य को प्रदर्शित करने के लिए, और दूसरी प्राप्तकर्ता के कैमरे के दृश्य को प्रदर्शित करने के लिए।
सबसे पहले, हमें राज्यों को स्वीकार करने के लिए संदर्भ को प्रारंभ करने की आवश्यकता है। फिर हम useRef
. का उपयोग करके एक संदर्भ चर बनाएंगे नीचे दिए गए कोड स्निपेट में बताए अनुसार राज्यों तक पहुंचने के लिए हुक:
const VideoCallScreen = ({navigation}) => {
const twilioVideo = useRef(null);
const {props, setProps} = useContext(AppContext);
इसके बाद, हमें connect
. का उपयोग करके कनेक्शन को इनिशियलाइज़ करना होगा twilioVideo
. से विधि ऑब्जेक्ट, कमरे का नाम और एक्सेस टोकन प्रदान करना जैसा कि नीचे दिए गए कोड स्निपेट में निर्देशित है:
useEffect(() => {
twilioVideo.current.connect({
roomName: props.roomName,
accessToken: props.token,
});
setProps({...props, status: 'connecting'});
return () => {
_onEndButtonPress();
};
}, []);
अब, हमें वीडियो कॉल स्क्रीन के लिए मुख्य बॉडी टेम्प्लेट बनाने की आवश्यकता है। यहां, हम प्रतिभागी का कैमरा दृश्य तभी दिखाते हैं जब कनेक्शन स्थापित हो और सशर्त रेंडरिंग का उपयोग करके स्ट्रीमिंग हो। इसके लिए समग्र कोड नीचे दिए गए कोड स्निपेट में दिया गया है:
{(props.status === 'connected' || props.status === 'connecting') && (
<View style={styles.callWrapper}>
{props.status === 'connected' && (
<View style={styles.grid}>
{Array.from(props.videoTracks, ([trackSid, trackIdentifier]) => (
<TwilioVideoParticipantView
style={styles.remoteVideo}
key={trackSid}
trackIdentifier={trackIdentifier}
/>
))}
</View>
)}
</View>
)}
इसके बाद, हमें इन-वीडियो सुविधाओं जैसे एंड कॉल, म्यूट और स्विचिंग फ्रंट और बैक कैमरा को नियंत्रित करने के लिए फ़ंक्शन बनाने की आवश्यकता है। आवश्यक कार्यों का कोडिंग कार्यान्वयन नीचे दिए गए कोड स्निपेट में दिया गया है:
const _onEndButtonPress = () => {
twilioVideo.current.disconnect();
setProps(initialState);
};
const _onMuteButtonPress = () => {
twilioVideo.current
.setLocalAudioEnabled(!props.isAudioEnabled)
.then((isEnabled) => setProps({...props, isAudioEnabled: isEnabled}));
};
const _onFlipButtonPress = () => {
twilioVideo.current.flipCamera();
};
यहां, हमने disconnect
. का उपयोग किया है , setLocalAudioEnabled
और flipCamera
twilioVideo
. द्वारा प्रदान की गई विधियां आवश्यक इन-वीडियो सुविधाओं को ट्रिगर करने के लिए उदाहरण।
अब हमें कार्यों को ट्रिगर करने के लिए कुछ बटन प्रस्तुत करने की आवश्यकता है। उसके लिए, हमें निम्नलिखित कोड स्निपेट से कोड का उपयोग करना होगा:
<View style={styles.optionsContainer}>
<TouchableOpacity style={styles.button} onPress={_onEndButtonPress}>
<Text style={styles.buttonText}>End</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={_onMuteButtonPress}>
<Text style={styles.buttonText}>
{props.isAudioEnabled ? 'Mute' : 'Unmute'}
</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={_onFlipButtonPress}>
<Text style={styles.buttonText}>Flip</Text>
</TouchableOpacity>
</View>
TwilioVideo
. को जोड़ने का अंतिम चरण है घटक जो सभी वीडियो कॉलिंग घटनाओं को संभालने और देखने के लिए कॉन्फ़िगर किया गया है। समग्र रूप से कॉन्फ़िगर किया गया TwilioVideo
घटक नीचे दिए गए कोड स्निपेट में दिया गया है:
<TwilioVideo
ref={twilioVideo}
onRoomDidConnect={() => {
setProps({...props, status: 'connected'});
}}
onRoomDidDisconnect={() => {
setProps({...props, status: 'disconnected'});
navigation.goBack();
}}
onRoomDidFailToConnect={(error) => {
Alert.alert('Error', error.error);
setProps({...props, status: 'disconnected'});
navigation.goBack();
}}
onParticipantAddedVideoTrack={({participant, track}) => {
if (track.enabled) {
setProps({
...props,
videoTracks: new Map([
...props.videoTracks,
[
track.trackSid,
{
participantSid: participant.sid,
videoTrackSid: track.trackSid,
},
],
]),
});
}
}}
onParticipantRemovedVideoTrack={({track}) => {
const videoTracks = props.videoTracks;
videoTracks.delete(track.trackSid);
setProps({...props, videoTracks});
}}
/>
यदि हम एक कमरे में उपयोगकर्ताओं के बीच उचित संबंध स्थापित करने में सक्षम होते हैं तो हमें निम्नलिखित परिणाम प्राप्त होंगे:
ऊपर दिए गए स्क्रीनशॉट एक कमरे में दो प्रतिभागियों के बीच वीडियो कॉलिंग को प्रदर्शित करते हैं।
इसके साथ, हमने अपने रिएक्ट नेटिव ऐप में वीडियो कॉलिंग फीचर को सफलतापूर्वक लागू किया है।
निष्कर्ष
इस ट्यूटोरियल का उद्देश्य रिएक्ट नेटिव ऐप में वीडियो कॉलिंग को सेटअप करने के तरीके पर एक शुरुआती स्तर का शिक्षण संसाधन प्रदान करना है। हमने ऐसा Twilio के प्रोग्रामयोग्य वीडियो कॉल API का उपयोग करके किया।
हमने न केवल रिएक्ट नेटिव हिस्से को बल्कि एक अलग नोड सर्वर प्रोजेक्ट में समग्र एपीआई कार्यान्वयन को भी कवर किया है।
अब, अगला कदम उन्नत सुविधाओं को जोड़ना हो सकता है जैसे कि एक अनाम कॉल शुरू करना या कई प्रतिभागी वीडियो कॉलिंग रूम।
फीचर प्रेरणा और एक उचित वीडियो कॉलिंग ऐप के लिए, आप instamobile.io देख सकते हैं जो शक्तिशाली सुविधाओं के साथ एक वीडियो चैट ऐप की स्थिति प्रदान करता है।
अगली बार मिलते हैं दोस्तों, हैप्पी कोडिंग!