import {
mediaDevices,
RTCPeerConnection,
RTCView,
RTCIceCandidate,
RTCSessionDescription,
MediaStream,
} from 'react-native-webrtc';
import styles from './callPageStyle';
import { useEffect, useState, useRef } from "react";
const CallPage = ({ route, navigation }) => {
// const navigation = useNavigation();
const userData = useSelector((state) => state.userData);
const dispatch = useDispatch();
const { callerId, calleeId, calleeName, isVideo, isCreator } = route.params;
const [localStream, setLocalStream] = useState(null);
const [remoteStream, setRemoteStream] = useState(null);
const [callStarted, setCallStarted] = useState(false);
const peerConnectionRef = useRef(null);
const remoteRTCMessage = useRef(null);
useEffect(() => {
const recipientID = isCreator ? calleeId : callerId;
webSocketService.registerSendCallMessageCallback(recipientID, onNewCall);
webSocketService.registerAnswerCallMessageCallback(recipientID, onCallAnswered);
webSocketService.registerICECandidateMessageCallback(recipientID, onICEcandidate);
const initLocalStream = async () => {
const stream = await mediaDevices.getUserMedia({ audio: true, video: true });
setLocalStream(stream);
};
const delayProcessCall = setTimeout(() => {
if (!isCreator) {
startCall();
} else {
initLocalStream();
}
}, 2000);
return () => {
clearTimeout(delayProcessCall);
if (localStream) {
localStream.getTracks().forEach((track) => track.stop());
}
};
}, []);
const createPeerConnection = async () => {
const configuration = {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'stun:stun1.l.google.com:19302' },
{ urls: 'stun:stun2.l.google.com:19302' },
],
};
const peerConnection = new RTCPeerConnection(configuration);
// Use a promise to wait for getUserMedia to complete
const stream = await mediaDevices.getUserMedia({ audio: true, video: true });
stream.getTracks().forEach((track) => peerConnection.addTrack(track, stream));
setLocalStream(stream);
return new Promise((resolve) => {
peerConnection.onicecandidate = (event) => {
if (event.candidate) {
webSocketService.sendICECandidateToPeerServer(userData.id, isCreator ? calleeId : callerId, {
calleeId: isCreator ? calleeId : callerId,
rtcMessage: {
label: event.candidate.sdpMLineIndex,
id: event.candidate.sdpMid,
candidate: event.candidate.candidate,
},
});
} else {
console.log("End of candidates.");
}
};
peerConnection.ontrack = (event) => {
setRemoteStream(event.streams[0]);
};
peerConnectionRef.current = peerConnection;
resolve();
});
};
const startCall = async () => {
try {
console.log("=========sendNewCallToPeerServer===========");
await createPeerConnection();
const offer = await peerConnectionRef.current.createOffer();
await peerConnectionRef.current.setLocalDescription(offer);
webSocketService.sendNewCallToPeerServer(userData.id, isCreator ? calleeId : callerId, {
calleeId: isCreator ? calleeId : callerId,
rtcMessage: offer,
});
console.log("=========sendNewCallToPeerServer===========");
} catch (error) {
console.error('Error creating offer:', error);
}
};
const handleAnswer = async () => {
try {
const answer = await peerConnectionRef.current.createAnswer();
await peerConnectionRef.current.setLocalDescription(answer);
webSocketService.sendAnswerCallToPeerServer(userData.id, isCreator ? calleeId : callerId, {
calleeId: isCreator ? calleeId : callerId,
rtcMessage: answer,
});
setCallStarted(true);
} catch (error) {
console.error('Error creating answer:', error);
}
};
const onNewCall = async (payload) => {
console.log("On New Call !!!");
const bigData = JSON.parse(payload.body);
const data = JSON.parse(bigData.data);
remoteRTCMessage.current = data.rtcMessage;
await createPeerConnection();
peerConnectionRef.current.setRemoteDescription(
new RTCSessionDescription(remoteRTCMessage.current)
);
handleAnswer();
};
const onCallAnswered = (payload) => {
console.log("onCallAnswered !!!");
const bigData = JSON.parse(payload.body);
const data = JSON.parse(bigData.data);
remoteRTCMessage.current = data.rtcMessage;
peerConnectionRef.current.setRemoteDescription(
new RTCSessionDescription(remoteRTCMessage.current)
);
setCallStarted(true);
};
const onICEcandidate = (payload) => {
console.log("onICEcandidate !!!");
const bigData = JSON.parse(payload.body);
const data = JSON.parse(bigData.data);
let message = data.rtcMessage;
if (peerConnectionRef.current) {
peerConnectionRef.current
.addIceCandidate(new RTCIceCandidate({candidate: message.candidate, sdpMLineIndex: message.label, sdpMid: message.id}))
.then((data) => {
console.log("SUCCESS");
})
.catch((err) => {
console.log("Error", err);
});
}
};
This is my source code implementing video call feature in react-native expo app.
I am currently using libraries for react-native-webrtc below.
@config-plugins/react-native-webrtc": "^7.0.0
react-native-webrtc": "^111.0.3,
I am using Android emulator like this:
- API level 34
- image: system-images/android-34/google_apis/x86_x64
All the logic for getting connection between peers is working well. But have problems with video streaming. Help me with correcting the source code or giving any advice. Thanks.
I also faced that kind of problem before. Implementing Video call wit WebRTC streaming contains such a complex process. There is more easier way implementing video call without using basic libraries. I suggest to use 'agora-rn-uikit' library in React Native.
More details instructions here:
https://www.npmjs.com/package/agora-rn-uikit
Installation Command:
Sample Code:
Easy to use and faster development speed.