What you need:
- A Twilio Account
- Server-side implementation (node.js)
- Client-side implementation with the module — react-native-twilio-video-webrtc
Twiilio Account
We will be using Twilio, so you should signup here and retrieve the essential keys - API KEY SID, ACCOUNT SID, API KEY SECRET.
After that, navigate to Settings => API Keys
click add a new api key, for type, select the dropdown and choose main.
The api secret will only be shown once. You should copy and paste somewhere safe as you will need all keys for server-side implementation.
Server-side implementation
The step here is quite simple. Implement ur regular node express and add this route:
import 'dotenv/config';
import express from 'express';
import twilio from 'twilio';
const AccessToken = twilio.jwt.AccessToken;
const VideoGrant = AccessToken.VideoGrant;
const app = express();
app.get('/getToken', (req, res) => {
if (!req.query || !req.query.room || !req.query.username) {
return res.status(400).send('username and room 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
const grant = new VideoGrant();
accessToken.identity = req.query.username;// Grant access to Video
grant.room = req.query.room;
accessToken.addGrant(grant); // Serialize the token as a JWT
const jwt = accessToken.toJwt();
return res.send(jwt);
});
For this endpoint, we get a username as string and a room as string in the body of the query. We create a room and add the user to that room awaiting other participants.
Client-side implementation
Now we can add twilio video webrtc module to our project
yarn add https://github.com/blackuy/react-native-twilio-video-webrtc
Then, you follow the simple installation instructions here for both android and iOS.
import React, { useState, useRef } from "react";
import {
Alert,
AppRegistry,
StyleSheet,
Text,
TextInput,
View,
Button,
PermissionsAndroid,
Platform,
TouchableOpacity,
} from "react-native";
import {
TwilioVideoLocalView,
TwilioVideoParticipantView,
TwilioVideo,
} from "react-native-twilio-video-webrtc";
import styleSheet from "./styles";
const styles = StyleSheet.create(styleSheet);
const App = (props) => {
const [isAudioEnabled, setIsAudioEnabled] = useState(true);
const [isVideoEnabled, setIsVideoEnabled] = useState(true);
const [status, setStatus] = useState("disconnected");
const [participants, setParticipants] = useState(new Map());
const [videoTracks, setVideoTracks] = useState(new Map());
const [room, setRoom] = useState("");
const [username, setUsername] = useState("");
const twilioVideo = useRef(null);
const fetchToken = async () => {
try {
const res = await fetch(
`https://<your_base_url>/getToken?username=${username}&room=${room}`
);
if (!res.ok) {
console.log("error", error);
Alert.alert("API not available");
return null;
}
const jwt = await res.text();
return jwt;
} catch (error) {
console.log("error", error);
Alert.alert("An Error occurred");
return null;
}
};
const _onConnectButtonPress = async () => {
if (Platform.OS === "android") {
await _requestAudioPermission();
await _requestCameraPermission();
}
const token = await fetchToken();
if (!token) {
return;
}
twilioVideo.current.connect({
accessToken: token,
enableNetworkQualityReporting: true,
dominantSpeakerEnabled: true,
});
setStatus("connecting");
};
const _onEndButtonPress = () => {
twilioVideo.current.disconnect();
};
const _onMuteButtonPress = () => {
twilioVideo.current
.setLocalAudioEnabled(!isAudioEnabled)
.then((isEnabled) => setIsAudioEnabled(isEnabled));
};
const _onFlipButtonPress = () => {
twilioVideo.current.flipCamera();
};
const _onRoomDidConnect = () => {
setStatus("connected");
};
const _onRoomDidDisconnect = ({ error }) => {
console.log("ERROR: ", error);
setStatus("disconnected");
};
const _onRoomDidFailToConnect = (error) => {
console.log("ERROR: ", error);
setStatus("disconnected");
};
const _onParticipantAddedVideoTrack = ({ participant, track }) => {
console.log("onParticipantAddedVideoTrack: ", participant, track);
setVideoTracks(
new Map([
...videoTracks,
[
track.trackSid,
{ participantSid: participant.sid, videoTrackSid: track.trackSid },
],
])
);
};
const _onParticipantRemovedVideoTrack = ({ participant, track }) => {
console.log("onParticipantRemovedVideoTrack: ", participant, track);
const videoTracks = new Map(videoTracks);
videoTracks.delete(track.trackSid);
setVideoTracks(videoTracks);
};
const _onNetworkLevelChanged = ({ participant, isLocalUser, quality }) => {
console.log(
"Participant",
participant,
"isLocalUser",
isLocalUser,
"quality",
quality
);
};
const _onDominantSpeakerDidChange = ({ roomName, roomSid, participant }) => {
console.log(
"onDominantSpeakerDidChange",
`roomName: ${roomName}`,
`roomSid: ${roomSid}`,
"participant:",
participant
);
};
const _requestAudioPermission = () => {
return PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
{
title: "Need permission to access microphone",
message:
"To run this demo we need permission to access your microphone",
buttonNegative: "Cancel",
buttonPositive: "OK",
}
);
};
const _requestCameraPermission = () => {
return PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA, {
title: "Need permission to access camera",
message: "To run this demo we need permission to access your camera",
buttonNegative: "Cancel",
buttonPositive: "OK",
});
};
return (
<View style={styles.container}>
{status === "disconnected" && (
<View>
<Text style={styles.welcome}>React Native Twilio Video</Text>
<TextInput
style={styles.input}
autoCapitalize="none"
value={username}
onChangeText={(text) => setUsername(text)}
/>
<TextInput
style={styles.input}
autoCapitalize="none"
value={room}
onChangeText={(text) => setRoom(text)}
/>
<Button
title="Connect"
style={styles.button}
onPress={_onConnectButtonPress}
></Button>
</View>
)}
{(status === "connected" || status === "connecting") && (
<View style={styles.callContainer}>
{status === "connected" && (
<View style={styles.remoteGrid}>
{Array.from(videoTracks, ([trackSid, trackIdentifier]) => {
return (
<TwilioVideoParticipantView
style={styles.remoteVideo}
key={trackSid}
trackIdentifier={trackIdentifier}
/>
);
})}
</View>
)}
<View style={styles.optionsContainer}>
<TouchableOpacity
style={styles.optionButton}
onPress={_onEndButtonPress}
>
<Text style={{ fontSize: 12 }}>End</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.optionButton}
onPress={_onMuteButtonPress}
>
<Text style={{ fontSize: 12 }}>
{isAudioEnabled ? "Mute" : "Unmute"}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.optionButton}
onPress={_onFlipButtonPress}
>
<Text style={{ fontSize: 12 }}>Flip</Text>
</TouchableOpacity>
<TwilioVideoLocalView enabled={true} style={styles.localVideo} />
</View>
</View>
)}
<TwilioVideo
ref={twilioVideo}
onRoomDidConnect={_onRoomDidConnect}
onRoomDidDisconnect={_onRoomDidDisconnect}
onRoomDidFailToConnect={_onRoomDidFailToConnect}
onParticipantAddedVideoTrack={_onParticipantAddedVideoTrack}
onParticipantRemovedVideoTrack={_onParticipantRemovedVideoTrack}
onNetworkQualityLevelsChanged={_onNetworkLevelChanged}
onDominantSpeakerDidChange={_onDominantSpeakerDidChange}
/>
</View>
);
};
export default App;
copy and paste the above code in ur react native project, enter a room and a username and hit the connect button to start your video call.
Oh. and make sure you have at least two devices to test and see that it actually works.
After implementing a a basic video call in react native using Twilio , implementing both server-side and client side, the next step can be to add advanced features and help improve your skills like building a WhatsApp clone which include standard calling features such as:
Ringing another participant or multiple participant video calling rooms, group calls, managing and displaying participant status such as busy, declined call or not answered call.
You should checkout QuickComponent for a proper Video calling app where all this features has been added. You find the React Native WhatsApp Clone previously mentioned and more React native apps like, Dating app, UberEats clone, and more with complete video calling feature.
Top comments (0)