I'm building social media application using node js and react js, I have problem when it comes to video / audio calls; case 1: i call from computer to mobile phone and both are in same network, it works-- case 2: i call from mobile phone browser to computer and both are in same network, remote stream does not work-- case 3: i call from different network, remote stream does not work;--
i tried to change turn and stun servers but it did not work either;
The code;
function createPeer(userID: string, type: 'audio' | 'video') {
const peer = new RTCPeerConnection(configuration);
peer.ontrack = onTrackEvent;
peer.onicecandidate = onIceCandidateEvent(userID);
return peer;
}
function onTrackEvent(e: RTCTrackEvent) {
if (remoteStream.current) {
e.streams[0].getTracks().forEach((track) => {
remoteStream.current!.addTrack(track)
});
}
}
function onIceCandidateEvent (userID: string) {
return (e: RTCPeerConnectionIceEvent) => {
if (e.candidate) {
socket.emit('ice-candidate', {
userID,
candidate: e.candidate.candidate,
sdpMLineIndex: e.candidate.sdpMLineIndex,
sdpMid: e.candidate.sdpMid
})
}
}
}
function handlingAnswer({ sdp, myData, type }: { sdp: RTCSessionDescriptionInit, myData: any, type: 'audio' | 'video' } ) {
if (peerConnection.current) {
const desciption = new RTCSessionDescription(sdp);
peerConnection.current.setRemoteDescription(desciption)
.then(() => {
if (type === 'video') {
dispatch(callActions.gettingAnswerVideoCall(myData));
}
if (type === 'audio') {
dispatch(callActions.gettingAnswerVoiceCall(myData));
}
})
}
}
const makeCall = async (userID: string, type: 'audio' | 'video') => {
let constraints: MediaStreamConstraints = {};
if (type === 'video') {
constraints = {
video: true, audio: true
}
}
if (type === 'audio') {
constraints = {
audio: true
}
}
try {
const stream = await navigator.mediaDevices.getUserMedia(constraints);
localStream.current = stream;
remoteStream.current = new MediaStream();
peerConnection.current = createPeer(userID, type);
localStream.current.getTracks().forEach((track) => {
peerConnection.current!.addTrack(track, localStream.current!)
});
const sdp = await peerConnection.current!.createOffer();
await peerConnection.current!.setLocalDescription(sdp);
const payload = {
to: userID,
caller: {
_id: userData!._id,
name: userData!.name,
username: userData!.username,
picture: userData!.picture
},
sdp,
type
}
dispatch(callActions.callUser({
callType: type,
userID
}))
socket.emit('offer', payload)
} catch (error) {
console.log(error);
}
}
async function acceptCall(userID: string, sdp: RTCSessionDescriptionInit, type: 'video' | 'audio') {
let constraints: MediaStreamConstraints = {};
if (type === 'video') {
constraints = { video: true, audio: true }
}
if (type === 'audio') {
constraints = { audio: true }
}
try {
const stream = await navigator.mediaDevices.getUserMedia(constraints);
localStream.current = stream;
remoteStream.current = new MediaStream();
peerConnection.current = createPeer(userID, type);
localStream.current.getTracks().forEach((track) => {
peerConnection.current!.addTrack(track, localStream.current!)
})
const sessionDescription = new RTCSessionDescription(sdp);
await peerConnection.current.setRemoteDescription(sessionDescription);
const answer = await peerConnection.current.createAnswer();
await peerConnection.current.setLocalDescription(answer)
if (type === 'audio') {
dispatch(callActions.acceptVoiceCall())
}
if (type === 'video') {
dispatch(callActions.acceptVideoCall())
}
const payload = {
caller: userID,
sdp: answer,
myData: {
_id: userData!._id,
name: userData!.name,
username: userData!.username,
picture: userData!.picture
},
type
}
socket.emit('answer', payload)
} catch (error) {
alert(JSON.stringify(error))
}
}
socket.on('offer', handlingOffer);
socket.on('answer', handlingAnswer);
socket.on('ice-candidate', async ({ candidate, sdpMLineIndex, sdpMid }) => {
if (peerConnection.current) {
const rtcIceCandidate = new RTCIceCandidate({ candidate, sdpMLineIndex, sdpMid });
await peerConnection.current.addIceCandidate(rtcIceCandidate)
}
})
// In the Call Component
function CallComponent() {
useEffect(() => {
remoteVideoRef.current.srcObject = remoteStream.current
myVideoRef.current.srcObject = localStream.current
}, [])
return JSX .............................
}