Created
May 20, 2020 08:15
-
-
Save Sahil5963/61b9503fecfe29b1f1ef6e895ec618a4 to your computer and use it in GitHub Desktop.
webrtcApp/CallScreen
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, {useEffect, useState, useCallback} from 'react'; | |
import {View, StyleSheet, Alert} from 'react-native'; | |
import {Text} from 'react-native-paper'; | |
import {Button} from 'react-native-paper'; | |
import AsyncStorage from '@react-native-community/async-storage'; | |
import {TextInput} from 'react-native-paper'; | |
import {useFocusEffect} from '@react-navigation/native'; | |
import InCallManager from 'react-native-incall-manager'; | |
import { | |
RTCPeerConnection, | |
RTCIceCandidate, | |
RTCSessionDescription, | |
RTCView, | |
MediaStream, | |
MediaStreamTrack, | |
mediaDevices, | |
registerGlobals, | |
} from 'react-native-webrtc'; | |
export default function CallScreen({navigation, ...props}) { | |
let name; | |
let connectedUser; | |
const [userId, setUserId] = useState(''); | |
const [socketActive, setSocketActive] = useState(false); | |
const [calling, setCalling] = useState(false); | |
// Video Scrs | |
const [localStream, setLocalStream] = useState({toURL: () => null}); | |
const [remoteStream, setRemoteStream] = useState({toURL: () => null}); | |
const [conn, setConn] = useState(new WebSocket('ws://3.20.188.26:8080')); | |
const [yourConn, setYourConn] = useState( | |
//change the config as you need | |
new RTCPeerConnection({ | |
iceServers: [ | |
{ | |
urls: 'stun:stun.l.google.com:19302', | |
}, { | |
urls: 'stun:stun1.l.google.com:19302', | |
}, { | |
urls: 'stun:stun2.l.google.com:19302', | |
} | |
], | |
}), | |
); | |
const [offer, setOffer] = useState(null); | |
const [callToUsername, setCallToUsername] = useState(null); | |
useFocusEffect( | |
useCallback(() => { | |
AsyncStorage.getItem('userId').then(id => { | |
console.log(id); | |
if (id) { | |
setUserId(id); | |
} else { | |
setUserId(''); | |
navigation.push('Login'); | |
} | |
}); | |
}, [userId]), | |
); | |
useEffect(() => { | |
navigation.setOptions({ | |
title: 'Your ID - ' + userId, | |
headerRight: () => ( | |
<Button mode="text" onPress={onLogout} style={{paddingRight: 10}}> | |
Logout | |
</Button> | |
), | |
}); | |
}, [userId]); | |
/** | |
* Calling Stuff | |
*/ | |
useEffect(() => { | |
if (socketActive && userId.length > 0) { | |
try { | |
InCallManager.start({media: 'audio'}); | |
InCallManager.setForceSpeakerphoneOn(true); | |
InCallManager.setSpeakerphoneOn(true); | |
} catch (err) { | |
console.log('InApp Caller ---------------------->', err); | |
} | |
console.log(InCallManager); | |
send({ | |
type: 'login', | |
name: userId, | |
}); | |
} | |
}, [socketActive, userId]); | |
const onLogin = () => {}; | |
useEffect(() => { | |
/** | |
* | |
* Sockets Signalling | |
*/ | |
conn.onopen = () => { | |
console.log('Connected to the signaling server'); | |
setSocketActive(true); | |
}; | |
//when we got a message from a signaling server | |
conn.onmessage = msg => { | |
let data; | |
if (msg.data === 'Hello world') { | |
data = {}; | |
} else { | |
data = JSON.parse(msg.data); | |
console.log('Data --------------------->', data); | |
switch (data.type) { | |
case 'login': | |
console.log('Login'); | |
break; | |
//when somebody wants to call us | |
case 'offer': | |
handleOffer(data.offer, data.name); | |
console.log('Offer'); | |
break; | |
case 'answer': | |
handleAnswer(data.answer); | |
console.log('Answer'); | |
break; | |
//when a remote peer sends an ice candidate to us | |
case 'candidate': | |
handleCandidate(data.candidate); | |
console.log('Candidate'); | |
break; | |
case 'leave': | |
handleLeave(); | |
console.log('Leave'); | |
break; | |
default: | |
break; | |
} | |
} | |
}; | |
conn.onerror = function(err) { | |
console.log('Got error', err); | |
}; | |
/** | |
* Socjket Signalling Ends | |
*/ | |
let isFront = false; | |
mediaDevices.enumerateDevices().then(sourceInfos => { | |
let videoSourceId; | |
for (let i = 0; i < sourceInfos.length; i++) { | |
const sourceInfo = sourceInfos[i]; | |
if ( | |
sourceInfo.kind == 'videoinput' && | |
sourceInfo.facing == (isFront ? 'front' : 'environment') | |
) { | |
videoSourceId = sourceInfo.deviceId; | |
} | |
} | |
mediaDevices | |
.getUserMedia({ | |
audio: true, | |
video: { | |
mandatory: { | |
minWidth: 500, // Provide your own width, height and frame rate here | |
minHeight: 300, | |
minFrameRate: 30, | |
}, | |
facingMode: isFront ? 'user' : 'environment', | |
optional: videoSourceId ? [{sourceId: videoSourceId}] : [], | |
}, | |
}) | |
.then(stream => { | |
// Got stream! | |
setLocalStream(stream); | |
// setup stream listening | |
yourConn.addStream(stream); | |
}) | |
.catch(error => { | |
// Log error | |
}); | |
}); | |
yourConn.onaddstream = event => { | |
console.log('On Add Stream', event); | |
setRemoteStream(event.stream); | |
}; | |
// Setup ice handling | |
yourConn.onicecandidate = event => { | |
if (event.candidate) { | |
send({ | |
type: 'candidate', | |
candidate: event.candidate, | |
}); | |
} | |
}; | |
}, []); | |
const send = message => { | |
//attach the other peer username to our messages | |
if (connectedUser) { | |
message.name = connectedUser; | |
console.log('Connected iser in end----------', message); | |
} | |
conn.send(JSON.stringify(message)); | |
}; | |
const onCall = () => { | |
setCalling(true); | |
connectedUser = callToUsername; | |
console.log('Caling to', callToUsername); | |
// create an offer | |
yourConn.createOffer().then(offer => { | |
yourConn.setLocalDescription(offer).then(() => { | |
console.log('Sending Ofer'); | |
console.log(offer); | |
send({ | |
type: 'offer', | |
offer: offer, | |
}); | |
// Send pc.localDescription to peer | |
}); | |
}); | |
}; | |
//when somebody sends us an offer | |
const handleOffer = async (offer, name) => { | |
console.log(name + ' is calling you.'); | |
console.log('Accepting Call===========>', offer); | |
connectedUser = name; | |
try { | |
await yourConn.setRemoteDescription(new RTCSessionDescription(offer)); | |
const answer = await yourConn.createAnswer(); | |
await yourConn.setLocalDescription(answer); | |
send({ | |
type: 'answer', | |
answer: answer, | |
}); | |
} catch (err) { | |
console.log('Offerr Error', err); | |
} | |
}; | |
//when we got an answer from a remote user | |
const handleAnswer = answer => { | |
yourConn.setRemoteDescription(new RTCSessionDescription(answer)); | |
}; | |
//when we got an ice candidate from a remote user | |
const handleCandidate = candidate => { | |
setCalling(false); | |
console.log('Candidate ----------------->', candidate); | |
yourConn.addIceCandidate(new RTCIceCandidate(candidate)); | |
}; | |
//hang up | |
const hangUp = () => { | |
send({ | |
type: 'leave', | |
}); | |
handleLeave(); | |
}; | |
const handleLeave = () => { | |
connectedUser = null; | |
setRemoteStream({toURL: () => null}); | |
yourConn.close(); | |
// yourConn.onicecandidate = null; | |
// yourConn.onaddstream = null; | |
}; | |
const onLogout = () => { | |
// hangUp(); | |
AsyncStorage.removeItem('userId').then(res => { | |
navigation.push('Login'); | |
}); | |
}; | |
const acceptCall = async () => { | |
console.log('Accepting Call===========>', offer); | |
connectedUser = offer.name; | |
try { | |
await yourConn.setRemoteDescription(new RTCSessionDescription(offer)); | |
const answer = await yourConn.createAnswer(); | |
await yourConn.setLocalDescription(answer); | |
send({ | |
type: 'answer', | |
answer: answer, | |
}); | |
} catch (err) { | |
console.log('Offerr Error', err); | |
} | |
}; | |
const rejectCall = async () => { | |
send({ | |
type: 'leave', | |
}); | |
``; | |
setOffer(null); | |
handleLeave(); | |
}; | |
/** | |
* Calling Stuff Ends | |
*/ | |
return ( | |
<View style={styles.root}> | |
<View style={styles.inputField}> | |
<TextInput | |
label="Enter Friends Id" | |
mode="outlined" | |
style={{marginBottom: 7}} | |
onChangeText={text => setCallToUsername(text)} | |
/> | |
<Button | |
mode="contained" | |
onPress={onCall} | |
loading={calling} | |
// style={styles.btn} | |
contentStyle={styles.btnContent} | |
disabled={!(socketActive && userId.length > 0)}> | |
Call | |
</Button> | |
</View> | |
<View style={styles.videoContainer}> | |
<View style={[styles.videos, styles.localVideos]}> | |
<Text>Your Video</Text> | |
<RTCView streamURL={localStream.toURL()} style={styles.localVideo} /> | |
</View> | |
<View style={[styles.videos, styles.remoteVideos]}> | |
<Text>Friends Video</Text> | |
<RTCView | |
streamURL={remoteStream.toURL()} | |
style={styles.remoteVideo} | |
/> | |
</View> | |
</View> | |
</View> | |
); | |
} | |
const styles = StyleSheet.create({ | |
root: { | |
backgroundColor: '#fff', | |
flex: 1, | |
padding: 20, | |
}, | |
inputField: { | |
marginBottom: 10, | |
flexDirection: 'column', | |
}, | |
videoContainer: { | |
flex: 1, | |
minHeight: 450, | |
}, | |
videos: { | |
width: '100%', | |
flex: 1, | |
position: 'relative', | |
overflow: 'hidden', | |
borderRadius: 6, | |
}, | |
localVideos: { | |
height: 100, | |
marginBottom: 10, | |
}, | |
remoteVideos: { | |
height: 400, | |
}, | |
localVideo: { | |
backgroundColor: '#f2f2f2', | |
height: '100%', | |
width: '100%', | |
}, | |
remoteVideo: { | |
backgroundColor: '#f2f2f2', | |
height: '100%', | |
width: '100%', | |
}, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment