Skip to content

Instantly share code, notes, and snippets.

@LFSCamargo
Last active December 27, 2018 17:49
Show Gist options
  • Save LFSCamargo/3e03c53c538206ae42d01b6f208791be to your computer and use it in GitHub Desktop.
Save LFSCamargo/3e03c53c538206ae42d01b6f208791be to your computer and use it in GitHub Desktop.
Code for the webRTC on React native
// @flow
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
Dimensions,
TouchableOpacity,
Image,
StatusBar,
AsyncStorage,
} from 'react-native';
import {
RTCPeerConnection,
RTCIceCandidate,
RTCSessionDescription,
RTCView,
MediaStreamTrack,
getUserMedia,
} from 'react-native-webrtc';
import { connect } from 'react-redux';
import { NavigationInjectedProps } from 'react-navigation';
import sendRemoteMessage from '../../actions/Messaging/SendRemoteMessage';
import Colors from '../../config/Colors';
import { Messaging } from '../../reducers/Messaging/Messaging';
const { width, height } = Dimensions.get('window');
const peerVideoHeight = Math.round(height * 0.2);
type Props = {
sendRemoteMessage: (message: Messaging) => void,
candidate: string,
description: string,
hasReceivedDescription: boolean,
} & NavigationInjectedProps;
type State = {
muted: boolean,
videoEnabled: boolean,
videoURL: string,
remoteVideoURL: string,
isFront: boolean,
username: string,
};
class Video extends Component<Props, State> {
constructor(props: Props) {
super(props);
const configuration = {
iceServers: [
{
username: 'f2e4e42e-eaa4-11e8-bfaf-ee023c3d6cbc',
url: 'stun:sp-turn1.xirsys.com',
credential: 'f2e4e49c-eaa4-11e8-9904-278c135c7895',
},
{
username: 'f2e4e42e-eaa4-11e8-bfaf-ee023c3d6cbc',
url: 'turn:sp-turn1.xirsys.com:80?transport=udp',
credential: 'f2e4e49c-eaa4-11e8-9904-278c135c7895',
},
{
username: 'f2e4e42e-eaa4-11e8-bfaf-ee023c3d6cbc',
url: 'turn:sp-turn1.xirsys.com:3478?transport=udp',
credential: 'f2e4e49c-eaa4-11e8-9904-278c135c7895',
},
{
username: 'f2e4e42e-eaa4-11e8-bfaf-ee023c3d6cbc',
url: 'turn:sp-turn1.xirsys.com:80?transport=tcp',
credential: 'f2e4e49c-eaa4-11e8-9904-278c135c7895',
},
{
username: 'f2e4e42e-eaa4-11e8-bfaf-ee023c3d6cbc',
url: 'turn:sp-turn1.xirsys.com:3478?transport=tcp',
credential: 'f2e4e49c-eaa4-11e8-9904-278c135c7895',
},
{
username: 'f2e4e42e-eaa4-11e8-bfaf-ee023c3d6cbc',
url: 'turns:sp-turn1.xirsys.com:443?transport=tcp',
credential: 'f2e4e49c-eaa4-11e8-9904-278c135c7895',
},
{
username: 'f2e4e42e-eaa4-11e8-bfaf-ee023c3d6cbc',
url: 'turns:sp-turn1.xirsys.com:5349?transport=tcp',
credential: 'f2e4e49c-eaa4-11e8-9904-278c135c7895',
},
],
};
this.pc = new RTCPeerConnection(configuration);
this.state = {
username: '',
muted: false,
videoEnabled: false,
videoURL: '',
remoteVideoURL: '',
isFront: true,
remoteDescriptionSet: false,
};
}
pc: RTCPeerConnection = {};
componentDidUpdate(prevProps: Props) {
const { calling } = this.props.navigation.state.params;
if (!calling) {
if (this.props.hasReceivedDescription) {
if (prevProps.candidate !== this.props.candidate) {
this.setIceCandidate(this.props.candidate);
}
}
}
if (calling) {
if (
!this.state.remoteDescriptionSet &&
prevProps.description !== this.props.description &&
this.props.description
) {
this.setRemoteDescription(this.props.description);
}
}
}
async componentDidMount() {
console.log(this.props);
const { calling, callingTo } = this.props.navigation.state.params;
const username = await AsyncStorage.getItem('username');
this.setState({
username,
});
MediaStreamTrack.getSources(sourceInfos => {
console.log(sourceInfos);
let videoSourceId;
sourceInfos.forEach(element => {
videoSourceId = element.id;
});
getUserMedia(
{
audio: true,
video: {
mandatory: {
minWidth: 500,
minHeight: 300,
minFrameRate: 30,
},
facingMode: this.state.isFront ? 'user' : 'environment',
optional: videoSourceId ? [{ sourceId: videoSourceId }] : [],
},
},
stream => {
this.pc.addStream(stream);
this.setState({
videoURL: stream.toURL(),
});
},
e => console.log(e),
);
});
if (calling) {
console.log('Ligando', calling);
this.pc.createOffer(
desc => {
this.pc.setLocalDescription(
desc,
() => {
console.log('Offer', desc);
this.props.sendRemoteMessage({
to: callingTo,
from: username,
payload: {
description: JSON.stringify(desc),
},
});
this.props.sendRemoteMessage({
to: callingTo,
from: username,
payload: {
text: 'Is calling you',
},
});
},
e => {
throw e;
},
);
},
e => {
throw e;
},
);
}
if (!calling) {
console.log('Ligando', calling);
this.setRemoteDescription(this.props.description);
this.pc.createAnswer(
desc => {
this.pc.setLocalDescription(
desc,
() => {
console.log('Answer', JSON.stringify(desc));
this.props.sendRemoteMessage({
to: callingTo,
from: username,
payload: {
description: JSON.stringify(desc),
},
});
},
e => {
throw e;
},
);
},
e => {
throw e;
},
);
}
this.pc.onicecandidate = e => {
if (e.candidate) {
this.props.sendRemoteMessage({
to: callingTo,
from: username,
payload: {
candidate: JSON.stringify(e.candidate),
},
});
}
};
this.pc.oniceconnectionstatechange = () => {
console.log('Ice Connection State', this.pc.iceConnectionState);
};
this.pc.onaddstream = e => {
if (e) {
console.log(e.stream);
this.pc.addStream(e.stream);
this.setState({
remoteVideoURL: e.strem.toURL(),
});
}
};
}
setRemoteDescription = (remoteDesc: string) => {
console.log('Remote Description', remoteDesc);
this.setState({
remoteDescriptionSet: true,
});
const remoteDescription = new RTCSessionDescription(JSON.parse(remoteDesc));
this.pc.setRemoteDescription(remoteDescription);
const { calling, callingTo } = this.props.navigation.state.params;
if (calling) {
this.props.sendRemoteMessage({
to: callingTo,
from: this.state.username,
payload: {
hasReceivedDescription: true,
},
});
}
};
setIceCandidate = candidate => {
console.log('ICE Candidate', candidate);
const iceCandidate = new RTCIceCandidate(JSON.parse(candidate));
this.pc.addIceCandidate(iceCandidate);
};
setVideoEnabled = () => {
const { videoEnabled } = this.state;
this.setState({
videoEnabled: !videoEnabled,
});
};
setMuted = () => {
const { muted } = this.state;
this.setState({
muted: !muted,
});
};
render() {
console.log('PROPS UPDATED', this.props);
const { callingTo } = this.props.navigation.state.params;
const { muted, videoEnabled, videoURL, remoteVideoURL } = this.state;
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" />
<RTCView streamURL={remoteVideoURL} style={styles.remoteVideoContainer} />
<RTCView streamURL={videoURL} style={styles.videoContainer} />
<View style={styles.textContainer}>
<Text style={styles.username}>{callingTo}</Text>
<Text style={styles.time}>00:00</Text>
</View>
<View style={styles.buttonsContainer}>
<TouchableOpacity onPress={this.setMuted} style={styles.actionButtons}>
{muted ? (
<Image style={styles.icon} source={require('../../images/videoicon.png')} />
) : (
<Image style={styles.icon} source={require('../../images/videoofficon.png')} />
)}
</TouchableOpacity>
<TouchableOpacity onPress={this.hangup} style={styles.hangupButton}>
<Image style={styles.callIcon} source={require('../../images/phoneicon.png')} />
</TouchableOpacity>
<TouchableOpacity onPress={this.setVideoEnabled} style={styles.actionButtons}>
{videoEnabled ? (
<Image style={styles.icon} source={require('../../images/micicon.png')} />
) : (
<Image style={styles.icon} source={require('../../images/micofficon.png')} />
)}
</TouchableOpacity>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
icon: {
width: 24,
height: 24,
tintColor: 'black',
},
callIcon: {
width: 30,
height: 11,
},
hangupButton: {
width: 70,
height: 70,
borderRadius: 70 / 2,
backgroundColor: Colors.red,
alignItems: 'center',
justifyContent: 'center',
},
actionButtons: {
width: 70,
height: 70,
borderRadius: 70 / 2,
backgroundColor: Colors.white,
alignItems: 'center',
justifyContent: 'center',
},
container: {
flex: 1,
},
videoContainer: {
width: (peerVideoHeight * 9) / 16,
height: peerVideoHeight,
borderRadius: 10,
backgroundColor: 'black',
position: 'absolute',
bottom: 120,
right: 30,
transform: [
{
rotateY: '180deg',
},
],
},
remoteVideoContainer: {
transform: [
{
rotateY: '180deg',
},
],
width,
height,
backgroundColor: 'black',
position: 'absolute',
top: 0,
bottom: 0,
right: 0,
left: 0,
},
username: {
fontSize: 25,
color: Colors.white,
},
time: {
fontSize: 20,
color: Colors.white,
},
textContainer: {
position: 'absolute',
left: 30,
right: 30,
top: 90,
width: width - 60,
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
},
buttonsContainer: {
position: 'absolute',
left: 30,
right: 30,
bottom: 30,
width: width - 60,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
});
const mapDispatchToProps = dispatch => ({
sendRemoteMessage: (message: Messaging) => dispatch(sendRemoteMessage(message)),
});
const mapStateToProps = state => ({
description: state.messaging.description,
candidate: state.messaging.candidate,
hasReceivedDescription: state.messaging.hasReceivedDescription,
});
export default connect(
mapStateToProps,
mapDispatchToProps,
)(Video);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment