If this is repeated question please let me know for this post to be deleted. I am having an error in react-native-webrtc where I get 3 weird things happening.
-
All calls get a remote stream of a black screen. I know it has Audio and Video but just see black.
-
On the second call I get a warning that addIceCandidate failed.
-
On the third call I just start getting errors saying that it is unable to add an offer because the state is stable
here is my hook implementation
import { useEffect, useState, useRef } from 'react';
import { RTCPeerConnection, RTCIceCandidate, RTCSessionDescription, mediaDevices, MediaStream } from 'react-native-webrtc';
import { useSharedConnection } from '../context/SignalingContext';
import { CertRequesNoEnct, EasyCall, decryptAESWithJson, encryptJsonWithAES } from './certRequest';
import { useAuthContext } from '../context/AuthContext';
import RNCallKeep from 'react-native-callkeep';
import { Soundi } from '../screens/vcs/callScreen';
const useWebRTCHook = () => {
const [localStream, setLocalStream] = useState(null)
const [remoteStream, setRemoteStream] = useState(null)
const [uuid, setUUID] = useState(null)
const peerConnection = useRef(null);
const target = useRef(null);
const UU = useRef(null);
const { user, setIsInCall, setCallParams } = useAuthContext()
const { connection } = useSharedConnection()
const remoteCandidates = useRef([]);
const [offerCreated, setOfferCreated] = useState(false);
var Sound = new Soundi("cbs.mp3")
const start = async (targetUserId, isVideo = "0", type = "caller",) => {
if (!offerCreated) {
let peerConstraints = {
iceServers: [
{
urls: "stun:XXXXX",
},
{
urls: "turn:XXXX",
username: "cw1",
credential: "XXXX"
}
]
};
peerConnection.current = new RTCPeerConnection(peerConstraints);
const mediaStream = await mediaDevices.getUserMedia({
audio: true,
video: true
});
mediaStream.getTracks().forEach(track => peerConnection.current.addTrack(track, mediaStream));
setLocalStream(mediaStream);
console.log('c-------------------->>>', targetUserId)
let DataToSend = await encryptJsonWithAES({ Pid: "Practitioner/" + user.pracid.toString(), Uuid: targetUserId }, user.s_aes, user.s_iv)
let req = await CertRequesNoEnct(DataToSend, user.token, "", "", "/communications/who-is-calling", user.certificate)
let res = await decryptAESWithJson(req.replace(""", ""), user.s_aes, user.s_iv)
let i = JSON.parse(res)
console.log('c-------------------->>>', targetUserId)
console.log('c-------------------->>>', i.target)
target.current = i.target
UU.current = targetUserId
if (type === "caller") {
let offer = await peerConnection.current.createOffer()
await peerConnection.current.setLocalDescription(offer)
console.log('SendOffer', target.current, offer, peerConnection.current.localDescription, 'video')
await connection.invoke('SendOffer', target.current, offer, peerConnection.current.localDescription, "video");
setOfferCreated(true);
}
}
};
async function handleRemoteCandidate(iceCandidate) {
console.log(iceCandidate)
iceCandidate = new RTCIceCandidate(iceCandidate);
console.log(iceCandidate)
if (peerConnection.current.remoteDescription == null) return remoteCandidates.current.push(iceCandidate);
return await peerConnection.current.addIceCandidate(iceCandidate);
};
async function processCandidates() {
if (remoteCandidates.current.length < 1) { return; };
remoteCandidates.current.map(candidate => peerConnection.current.addIceCandidate(candidate));
remoteCandidates.current = [];
};
useEffect(() => {
if (connection) {
console.log("dd", peerConnection.current)
connection.on('receiveoffer', async (userId, offer, description, type) => {
if (peerConnection.current && target.current && !peerConnection.current.remoteDescription && !peerConnection.current.localDescription) {
const offerDescription = new RTCSessionDescription(offer)
await peerConnection.current.setRemoteDescription(offerDescription)
const answerDescription = await peerConnection.current.createAnswer();
await peerConnection.current.setLocalDescription(answerDescription);
console.log('SendAnswer', target.current, answerDescription)
await connection.invoke('SendAnswer', target.current, answerDescription);
// Process candidates after setting remote description
await processCandidates();
}
})
//connection
connection.on("receiveicecandidate", async (userId, event) => {
if (peerConnection.current && target.current) {
console.log("receivedIce")
if (!event.candidate || !event.sdpMLineIndex || !event.sdpMid) return;
await handleRemoteCandidate(event);
}
})
connection.on('ReceiveAnswer', async (userId, description) => {
if (peerConnection.current && target.current) {
const answerDescription = new RTCSessionDescription(description);
await peerConnection.current.setRemoteDescription(answerDescription);
await processCandidates()
}
})
connection.on('uuidreject', (uuid) => hangleUp(uuid))
}
return () => {
if (connection) {
connection.off("'ReceiveAnswer")
connection.off("'receiveoffer")
connection.off("'SendAnswer")
connection.off("'receiveicecandidate")
connection.off("'uuidreject")
}
}
}, [connection])
useEffect(() => {
if (peerConnection.current && connection) {
peerConnection.current.addEventListener('icecandidate', event => SendICe(event));
peerConnection.current.addEventListener('negotiationneeded', event => NegotiationNeeded(event));
peerConnection.current.addEventListener('track', async event => await SetTrack(event));
peerConnection.current.addEventListener('iceconnectionstatechange', event => {
switch (peerConnection.current.iceConnectionState) {
case 'connected':
console.log("ice and pc connected")
case 'completed':
console.log("pc completed")
break;
};
});
}
}, [connection, peerConnection.current])
async function SendICe(event) {
if (!event.candidate) { return; };
console.log('SendIceCandidate', target.current, event.candidate)
await connection.invoke('SendIceCandidate', target.current, event.candidate);
}
async function NegotiationNeeded(event) {
console.log("negotiationneeded")
}
async function SetTrack(event) {
console.log("remoteTrack------------------", event.streams)
// setRemoteStream(event.streams[0])
console.log("new track")
console.log(event)
if (event.streams[0].getVideoTracks().length > 0 && event.streams[0].getAudioTracks().length > 0) {
setRemoteStream(event.streams[0])
}
}
const hangleUp = async (uuid) => {
try {
if (localStream) {
localStream.getTracks().forEach(track => track.stop());
}
setLocalStream(null);
setRemoteStream(null);
setIsInCall(false)
setCallParams(() => null)
RNCallKeep.endCall(uuid);
await EasyCall(UU.current + ".Pat" + user.pracid, "/communications/reject-call")
setOfferCreated(false)
peerConnection.current.removeEventListener('icecandidate', event => SendICe(event));
peerConnection.current.removeEventListener('negotiationneeded', event => NegotiationNeeded(event));
peerConnection.current.removeEventListener('track', event => SetTrack(event));
peerConnection.current.removeEventListener('iceconnectionstatechange', event => SetTrack(event));
peerConnection.current.close();
peerConnection.current = null; // Set peerConnection.current to null
} catch (err) {
console.log(err)
}
}
const endCalli = async (id, uuid) => {
try {
if (localStream) {
localStream.getTracks().forEach(track => track.stop());
setLocalStream(null);
setRemoteStream(null);
}
setOfferCreated(false)
peerConnection.current.removeEventListener('icecandidate', event => SendICe(event));
peerConnection.current.removeEventListener('negotiationneeded', event => NegotiationNeeded(event));
peerConnection.current.removeEventListener('track', event => SetTrack(event));
peerConnection.current.removeEventListener('iceconnectionstatechange', event => SetTrack(event));
peerConnection.current.close();
} catch (err) {
console.log(err)
}
}
const initiateCall = (targetUserId, userid, isVideoCall, uuid) => {
connection.invoke('RequestVideoCall', targetUserId, userid.toString(), isVideoCall, uuid, "medux");
};
return { initiateCall, start, remoteStream, localStream, endCalli, hangleUp, setLocalStream, setRemoteStream };
};
export default useWebRTCHook;
Can someone help me with what am I doing wrong?
cheers