Reputation: 2297
I have this in my React Native Code:
import React, {useState} from 'react';
import {View, StyleSheet} from 'react-native';
import {Text} from 'react-native-paper';
import {TextInput} from 'react-native-paper';
import AsyncStorage from '@react-native-community/async-storage';
import {Button} from 'react-native-paper';
export default function LoginScreen(props) {
const [userId, setUserId] = useState('');
const [loading, setLoading] = useState(false);
const onLogin = async () => {
setLoading(true);
try {
await AsyncStorage.setItem('userId', userId);
setLoading(false);
props.navigation.push('Call');
} catch (err) {
console.log('Error', err);
setLoading(false);
}
};
return (
<View style={styles.root}>
<View style={styles.content}>
<Text style={styles.heading}>Enter your id</Text>
<TextInput
label="Your ID"
onChangeText={text => setUserId(text)}
mode="outlined"
style={styles.input}
/>
<Button
mode="contained"
onPress={onLogin}
loading={loading}
style={styles.btn}
contentStyle={styles.btnContent}
disabled={userId.length === 0}>
Login
</Button>
</View>
</View>
);
}
const styles = StyleSheet.create({
root: {
backgroundColor: '#fff',
flex: 1,
// alignItems: 'center',
justifyContent: 'center',
},
content: {
// alignSelf: 'center',
paddingHorizontal: 20,
justifyContent: 'center',
},
heading: {
fontSize: 18,
marginBottom: 10,
fontWeight: '600',
},
input: {
height: 60,
marginBottom: 10,
},
btn: {
height: 60,
alignItems: 'stretch',
justifyContent: 'center',
fontSize: 18,
},
btnContent: {
alignItems: 'center',
justifyContent: 'center',
height: 60,
},
});
And this to call the peer:
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,
Permissions,
} 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://localhost: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 permissionCheck = async () => {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
};
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
*/
permissionCheck();
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%',
},
});
Why do i keep getting this error:
[Unhandled promise rejection: TypeError:null is not an object (evaluating '_InCallManager.checkCameraPermission')]
After Anik Dey Answer iget this stacktrace:
Error [TypeError: null is not an object (evaluating 'WebRTCModule.peerConnectionInit')]
TypeError: null is not an object (evaluating 'WebRTCModule.peerConnectionInit')
This error is located at:
in CallScreen (at SceneView.tsx:122)
in StaticContainer
in StaticContainer (at SceneView.tsx:115)
in EnsureSingleNavigator (at SceneView.tsx:114)
in SceneView (at useDescriptors.tsx:153)
in RCTView (at View.js:34)
in View (at CardContainer.tsx:245)
in RCTView (at View.js:34)
in View (at CardContainer.tsx:244)
in RCTView (at View.js:34)
in View (at CardSheet.tsx:33)
in ForwardRef(CardSheet) (at Card.tsx:573)
in RCTView (at View.js:34)
in View (at createAnimatedComponent.js:165)
in AnimatedComponent (at createAnimatedComponent.js:215)
in ForwardRef(AnimatedComponentWrapper) (at Card.tsx:555)
in PanGestureHandler (at GestureHandlerNative.tsx:13)
in PanGestureHandler (at Card.tsx:549)
in RCTView (at View.js:34)
in View (at createAnimatedComponent.js:165)
in AnimatedComponent (at createAnimatedComponent.js:215)
in ForwardRef(AnimatedComponentWrapper) (at Card.tsx:544)
in RCTView (at View.js:34)
in View (at Card.tsx:538)
in Card (at CardContainer.tsx:206)
in CardContainer (at CardStack.tsx:620)
in RCTView (at View.js:34)
in View (at Screens.tsx:84)
in MaybeScreen (at CardStack.tsx:613)
in RCTView (at View.js:34)
in View (at Screens.tsx:54)
in MaybeScreenContainer (at CardStack.tsx:495)
in CardStack (at StackView.tsx:462)
in KeyboardManager (at StackView.tsx:458)
in RNCSafeAreaProvider (at SafeAreaContext.tsx:76)
in SafeAreaProvider (at SafeAreaProviderCompat.tsx:42)
in SafeAreaProviderCompat (at StackView.tsx:455)
in GestureHandlerRootView (at GestureHandlerRootView.android.tsx:26)
in GestureHandlerRootView (at StackView.tsx:454)
in StackView (at createStackNavigator.tsx:87)
in StackNavigator (at App.js:15)
in EnsureSingleNavigator (at BaseNavigationContainer.tsx:409)
in ForwardRef(BaseNavigationContainer) (at NavigationContainer.tsx:91)
in ThemeProvider (at NavigationContainer.tsx:90)
in ForwardRef(NavigationContainer) (at App.js:14)
in App (created by ExpoRoot)
in ExpoRoot (at renderApplication.js:45)
in RCTView (at View.js:34)
in View (at AppContainer.js:106)
in RCTView (at View.js:34)
in View (at AppContainer.js:132)
in AppContainer (at renderApplication.js:39)
at node_modules\react-native\Libraries\LogBox\LogBox.js:148:8 in registerError
at node_modules\react-native\Libraries\LogBox\LogBox.js:59:8 in errorImpl
at node_modules\react-native\Libraries\LogBox\LogBox.js:33:4 in console.error
at node_modules\expo\build\environment\react-native-logs.fx.js:27:4 in error
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:104:6 in reportException
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:171:19 in handleException
at node_modules\react-native\Libraries\Core\ReactFiberErrorDialog.js:43:2 in showErrorDialog
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:15257:32 in logCapturedError
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:15361:20 in logError
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:16597:12 in update.callback
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:7106:2 in callCallback
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:7127:20 in commitUpdateQueue
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:15801:25 in commitLifeCycles
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:18744:22 in commitLayoutEffects
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:265:4 in invokeGuardedCallbackImpl
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:476:2 in invokeGuardedCallback
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:18483:29 in commitRootImpl
at [native code]:null in commitRootImpl
at node_modules\scheduler\cjs\scheduler.development.js:653:23 in unstable_runWithPriority
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:18317:17 in commitRoot
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:17697:12 in performSyncWorkOnRoot
at [native code]:null in performSyncWorkOnRoot
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:5321:31 in runWithPriority$argument_1
at node_modules\scheduler\cjs\scheduler.development.js:653:23 in unstable_runWithPriority
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:5316:21 in flushSyncCallbackQueueImpl
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:5304:28 in flushSyncCallbackQueue
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:17125:30 in scheduleUpdateOnFiber
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
Upvotes: 0
Views: 1082