Route not clearing when setting new route - reactjs

I'm using Google Maps Directions API to draw routes on a map. It does what I want on the first call of DirectionsRenderer.setDirections(response), but on the second call, it persists the previous route and uses the new one on top of it. How can I clear the previous route?
Code:
export async function testRouteCalculation(
directionsService: google.maps.DirectionsService,
directionsRenderer: google.maps.DirectionsRenderer,
withWaypoints: boolean,
numWaypointsToInclude: number
) {
let request: google.maps.DirectionsRequest = {
origin: testOrigin,
destination: testDestination,
travelMode: google.maps.TravelMode["DRIVING"],
unitSystem: google.maps.UnitSystem.METRIC,
provideRouteAlternatives: false,
// region is specified for region biasing
region: "za",
waypoints: [],
};
if (withWaypoints) {
for (let i = 0; i < numWaypointsToInclude; i++) {
request!.waypoints!.push(testWaypoints[i]);
}
}
try {
const response = await directionsService.route(request);
return response;
} catch (err) {
throw err;
}
The map component:
const Map = () => {
const ref = React.useRef<HTMLDivElement>(null);
const [map, setMap] = React.useState<google.maps.Map>();
const [directionsRenderer, setDirectionsRenderer] =
React.useState<google.maps.DirectionsRenderer>();
const [directionsService, setDirectionsService] =
React.useState<google.maps.DirectionsService>();
React.useEffect(() => {
let newMap = null;
if (ref.current && !map) {
newMap = new window.google.maps.Map(ref.current, {
center: capeTownCoordinates,
zoom: 13,
streetViewControl: false,
mapTypeControl: false,
});
setMap(newMap);
}
const newDirectionsRenderer = new google.maps.DirectionsRenderer();
newDirectionsRenderer.setMap(newMap);
setDirectionsRenderer(newDirectionsRenderer);
setDirectionsService(new google.maps.DirectionsService());
}, [ref, map]);
if (map && directionsRenderer && !directionsRenderer.getMap()) {
directionsRenderer.setMap(map);
}
const handleClick = async () => {
if (directionsRenderer && directionsService) {
try {
const response = await testRouteCalculation(
directionsService,
directionsRenderer,
true,
2
);
directionsRenderer.setDirections(response);
} catch (err) {
console.log(err);
}
} else {
console.log("no directionsRenderer or directionsService object");
}
};
return (
<>
<div id="map" style={{ height: "300px", width: "400px" }} ref={ref}></div>
<button onClick={handleClick} className={styles["floating-button"]}>
Get route
</button>
</>
);
};
I searched up and saw proposed solutions like directionsRenderer.setDirections(null) or directionsRenderer.setMap(null) before setting the new directions, and a couple of others, but none of them worked for me. I would think that .setDirections() would overwrite previous routes, but it seems that the routes drawn on the map and the directions stored in the directionRenderer are decoupled.

I found that calling directionsRenderer({routes: []}) achieved what I was looking for.

Related

Why doesn't the effect get current from the link?

I need to get localMediaStream in one effect, while it is set in another effect. Please tell me why in this context it is always null (if you do not set it in the same effect), but in this case I have a duplicate userMedia. Consequences - the camera does not go out when I call track.stop(). Based on this package
const peerConnections = useRef({});
const localMediaStream = useRef(null);
const peerMediaElements = useRef({
[LOCAL_VIDEO]: null,
});
useEffect(() => {
async function handleNewPeer({peerID, createOffer}) {
if (peerID in peerConnections.current) {
return console.warn(`Already connected to peer ${peerID}`);
}
peerConnections.current[peerID] = new RTCPeerConnection({
iceServers: freeice(),
});
peerConnections.current[peerID].onicecandidate = event => {
if (event.candidate) {
socket.emit(ACTIONS.RELAY_ICE, {
peerID,
iceCandidate: event.candidate,
});
}
}
let tracksNumber = 0;
peerConnections.current[peerID].ontrack = ({streams: [remoteStream]}) => {
tracksNumber++
if (tracksNumber === 2) { // video & audio tracks received
tracksNumber = 0;
addNewClient(peerID, () => {
if (peerMediaElements.current[peerID]) {
peerMediaElements.current[peerID].srcObject = remoteStream;
} else {
// FIX LONG RENDER IN CASE OF MANY CLIENTS
let settled = false;
const interval = setInterval(() => {
if (peerMediaElements.current[peerID]) {
peerMediaElements.current[peerID].srcObject = remoteStream;
settled = true;
}
if (settled) {
clearInterval(interval);
}
}, 1000);
}
});
}
}
/*localMediaStream.current = await navigator.mediaDevices.getUserMedia({
audio: audio,
video: video
})*/
localMediaStream.current.getTracks().forEach(track => { // localMediaStream null
peerConnections.current[peerID].addTrack(track, localMediaStream.current);
});
if (createOffer) {
const offer = await peerConnections.current[peerID].createOffer();
await peerConnections.current[peerID].setLocalDescription(offer);
socket.emit(ACTIONS.RELAY_SDP, {
peerID,
sessionDescription: offer,
});
}
}
socket.on(ACTIONS.ADD_PEER, handleNewPeer);
return () => {
socket.off(ACTIONS.ADD_PEER);
}
}, []);
// The installation, everything is as in the source, it did not work until I added the crutch above, but when it came to stopping the video stream, a bug appeared with the camera always on
useEffect(() => {
async function startCapture() {
console.log('start capture');
localMediaStream.current = await navigator.mediaDevices.getUserMedia({
audio: audio,
video: video
}).catch(console.log);
addNewClient(LOCAL_VIDEO, () => {
const localVideoElement = peerMediaElements.current[LOCAL_VIDEO];
if (localVideoElement) {
localVideoElement.volume = 0;
localVideoElement.srcObject = localMediaStream.current;
}
});
}
startCapture().then((data) => socket.emit(ACTIONS.JOIN, {room: roomID})).catch((e) => console.error(e)).finally(() => console.log('finally'));
console.log(roomID);
return () => {
localMediaStream.current.getTracks().forEach(track => track.stop());
socket.emit(ACTIONS.LEAVE);
};
}, [roomID]);
Thanks you very much.

Problem with network timeout on PayPal SDK integration react-paypal-button-v2

Hello I am having an error implementing PayPal for my practice website. The error is shown below. Code otherwise works unless I click on smart button then leave it sitting. How can I error handle this? I am using react-paypal-button-v2. Button code is also shown here.
STATE CODE
function OrderScreen() {
...
const addPayPalScript = () => {
const script = document.createElement('script')
script.type = 'text/javascript'
// const ClIENT_ID = process.env.REACT_APP_PAYPAL_CLIENT_ID
script.src = `https://www.paypal.com/sdk/js?client-id=${CLIENT_ID}`
script.async = true
script.onload = () => {
setSdkReady(true)
}
document.body.appendChild(script)
}
useEffect(() => {
if(!order || successPay || order._id !== Number(orderId)) {
dispatch({type: ORDER_PAY_RESET})
dispatch(getOrderDetails(orderId))
} else if (!order.isPaid) {
if(!window.paypal) {
addPayPalScript()
} else {
setSdkReady(true)
}
}
if(error?.includes('token not valid')) {
dispatch(logout())
dispatch('login')
}
}, [dispatch, order, orderId, error, successPay])
const successPaymentHandler = (paymentResult) => {
dispatch(payOrder(orderId, paymentResult))
}
BUTTON CODE
{!sdkReady ? (
<Loader />
) : (
<PayPalButton
createOrder={(data, actions) => {
return actions.order.create({
purchase_units: [{
amount: {
currency_code: "USD",
value: order.totalPrice
},
...
}
}],
application_context: {
locale: 'us-US',
shipping_preference: 'SET_PROVIDED_ADDRESS',
}
});
}}
onSuccess={successPaymentHandler}
onError={(err)=>setErrorPayPal(err)}
/>
)}
</List
Most likely that 'stats' request is being blocked by some adblock or browser anti-tracking mechanism. Regardless of the specifics it's not a problem, ignore it completely.
Separately, react-paypal-button-v2 is not an official package. Consider using react-paypal-js instead.

Problem with STUN/TURN servers in WEBRTC video app made in MERN stack

I have hosted a peer to peer meeting react app on netlify. I have used Peerjs for my video purpose. Everything is working as expected except the video. For some networks the video of the the remote person is working and for some others it is not working. I looked up and found out that it may be a STUN/TURN issue. I then implemented all the STUN/TURN servers in my code. However the video is still not getting setup in some cases. In some cases it is working fine, in others the video is not showing up. Herewith, I am attaching th code for the video and the link to the site.
import React,{useEffect,useState} from 'react';
import {io} from "socket.io-client";
import {useParams} from 'react-router-dom';
import {Grid} from "#material-ui/core";
import Peer from 'peerjs';
var connectionOptions = {
"force new connection" : true,
"reconnectionAttempts": "Infinity",
"timeout" : 10000,
"transports" : ["websocket"]
};
const Videobox = ({isVideoMute,isAudioMute}) => {
var myPeer = new Peer(
{
config: {'iceServers': [
{urls:'stun:stun01.sipphone.com'},
{urls:'stun:stun.ekiga.net'},
{urls:'stun:stun.fwdnet.net'},
{urls:'stun:stun.ideasip.com'},
{urls:'stun:stun.iptel.org'},
{urls:'stun:stun.rixtelecom.se'},
{urls:'stun:stun.schlund.de'},
{urls:'stun:stun.l.google.com:19302'},
{urls:'stun:stun1.l.google.com:19302'},
{urls:'stun:stun2.l.google.com:19302'},
{urls:'stun:stun3.l.google.com:19302'},
{urls:'stun:stun4.l.google.com:19302'},
{urls:'stun:stunserver.org'},
{urls:'stun:stun.softjoys.com'},
{urls:'stun:stun.voiparound.com'},
{urls:'stun:stun.voipbuster.com'},
{urls:'stun:stun.voipstunt.com'},
{urls:'stun:stun.voxgratia.org'},
{urls:'stun:stun.xten.com'},
{
urls: 'turn:numb.viagenie.ca',
credential: 'muazkh',
username: 'webrtc#live.com'
},
{
urls: 'turn:192.158.29.39:3478?transport=udp',
credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
username: '28224511:1379330808'
},
{
urls: 'turn:192.158.29.39:3478?transport=tcp',
credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
username: '28224511:1379330808'
}
]} /* Sample servers, please use appropriate ones */
}
);
const peers = {}
const [socket, setSocket] = useState()
const {id:videoId} = useParams();
const videoGrid = document.getElementById('video-grid')
useEffect(()=> {
const s=io("https://weconnectbackend.herokuapp.com",connectionOptions);
setSocket(s);
return () => {
s.disconnect();
}
},[])
// let myVideoStream;
const [myVideoStream, setmyVideoStream] = useState()
const muteUnmute = () => {
const enabled = myVideoStream.getAudioTracks()[0].enabled;
if (enabled) {
myVideoStream.getAudioTracks()[0].enabled = false;
//setUnmuteButton();
} else {
//setMuteButton();
myVideoStream.getAudioTracks()[0].enabled = true;
}
}
const playStop = () => {
//console.log('object')
let enabled = myVideoStream.getVideoTracks()[0].enabled;
if (enabled) {
myVideoStream.getVideoTracks()[0].enabled = false;
//setPlayVideo()
} else {
//setStopVideo()
myVideoStream.getVideoTracks()[0].enabled = true;
}
}
useEffect(() => {
if(myVideoStream)
playStop()
}, [isVideoMute])
useEffect(() => {
if(myVideoStream)
muteUnmute()
}, [isAudioMute])
useEffect(() => {
if(socket== null)
return;
myPeer.on('open',id=>{
socket.emit('join-room',videoId,id);
})
const myVideo = document.createElement('video')
myVideo.muted = true
navigator.mediaDevices.getUserMedia({
video: true,
audio: true
}).then(stream => {
// myVideoStream = stream;
window.localStream=stream;
setmyVideoStream(stream);
console.log(myVideoStream,"myvideostream");
addVideoStream(myVideo, stream)
myPeer.on('call', call => {
call.answer(stream)
const video = document.createElement('video')
call.on('stream', userVideoStream => {
addVideoStream(video, userVideoStream)
})
})
socket.on('user-connected',userId =>{
connectToNewUser(userId, stream)
})
socket.on('user-disconnected', userId => {
if (peers[userId]) peers[userId].close()
})
})
}, [socket,videoId])
function addVideoStream(video, stream) {
video.srcObject = stream
video.addEventListener('loadedmetadata', () => {
video.play()
})
videoGrid.append(video)
}
function connectToNewUser(userId, stream) {
const call = myPeer.call(userId, stream)
const video = document.createElement('video')
call.on('stream', userVideoStream => {
addVideoStream(video, userVideoStream)
})
call.on('close', () => {
video.remove()
})
peers[userId] = call
}
return (
<div id="video-grid" className="videoStyleFromDiv">
{/* <Video srcObject={srcObject}/> */}
</div>
)
}
export default Videobox
Website Link
The TURN servers you are using have been out of commission for a couple of years in the case of the ones taken from https://www.html5rocks.com/en/tutorials/webrtc/infrastructure/
Copying credentials from random places is not how TURN works, you will need to run your own servers.

WebRTC react stream multiple tracks issue. Camera + Screen Share

I am working on a new website. You can join room calls and make a voicecall so use your webcam but you can also share your screen.
The problem is when i add the track to the stream the peer doesn't work more... I don't know how to solve this. I also tried to change the code from adding the track to adding a new stream or anything else but cannot find a solution. Can anyone help me?
Client:
export default function Meeting(props) {
const userVideo = useRef();
const partnerVideo = useRef();
const screenShare = useRef();
const peerRef = useRef();
const socketRef = useRef();
const otherUser = useRef();
const userStream = useRef();
const userScreen = useRef();
useEffect(() => {
navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then(stream => {
userVideo.current.srcObject = stream;
userStream.current = stream;
socketRef.current = socketIOClient.connect(ENDPOINT);
socketRef.current.emit("join room", props.room);
socketRef.current.on('other user', userID => {
callUser(userID);
otherUser.current = userID;
});
socketRef.current.on("user joined", userID => {
otherUser.current = userID;
});
socketRef.current.on("offer", handleRecieveCall);
socketRef.current.on("answer", handleAnswer);
socketRef.current.on("ice-candidate", handleNewICECandidateMsg);
});
}, []);
function callUser(userID) {
console.log("call user - - -d-s-d-s-d--sd-sdd-sd-ssd-sd-sd--");
peerRef.current = createPeer(userID);
userStream.current.getTracks().forEach(track => peerRef.current.addTrack(track, userStream.current));
}
function createPeer(userID) {
const peer = new RTCPeerConnection({
//sdpSemantics: 'unified-plan',
iceServers: [
{
urls: "stun:stun.stunprotocol.org"
},
{
urls: 'turn:numb.viagenie.ca',
credential: 'muazkh',
username: 'webrtc#live.com'
},
]
});
peer.onicecandidate = handleICECandidateEvent;
peer.ontrack = handleTrackEvent;
peer.onnegotiationneeded = () => {
if (peer.signalingState != "stable") return;
handleNegotiationNeededEvent(userID);
}
return peer;
}
function handleNegotiationNeededEvent(userID) {
console.log("negotiationsad-das-d-as-d-asd--asd-a-sd-a-sd-");
peerRef.current.createOffer().then(offer => {
return peerRef.current.setLocalDescription(offer);
}).then(() => {
const payload = {
target: userID,
type: "video-offer",
caller: socketRef.current.id,
sdp: peerRef.current.localDescription
};
socketRef.current.emit("offer", payload);
}).catch(e => console.log(e));
}
function handleRecieveCall(incoming) {
peerRef.current = createPeer();
const desc = new RTCSessionDescription(incoming.sdp);
peerRef.current.setRemoteDescription(desc).then(() => {
userStream.current.getTracks().forEach(track => peerRef.current.addTrack(track, userStream.current));
}).then(() => {
return peerRef.current.createAnswer();
}).then(answer => {
return peerRef.current.setLocalDescription(answer);
}).then(() => {
const payload = {
target: incoming.caller,
type: "video-offer",
caller: socketRef.current.id,
sdp: peerRef.current.localDescription
}
socketRef.current.emit("answer", payload);
})
}
function handleAnswer(message) {
const desc = new RTCSessionDescription(message.sdp);
peerRef.current.setRemoteDescription(desc).catch(e => console.log(e));
}
function handleICECandidateEvent(e) {
if (e.candidate) {
const payload = {
target: otherUser.current,
candidate: e.candidate,
}
socketRef.current.emit("ice-candidate", payload);
}
}
function handleNewICECandidateMsg(incoming) {
const candidate = new RTCIceCandidate(incoming);
if (peerRef.current && candidate) {
peerRef.current.addIceCandidate(candidate).catch(e => console.log(e));
}
}
function handleTrackEvent(e) {
var stream = e.streams[0];
var tracks = stream.getTracks();
var lun = tracks.length;
console.log(tracks);
if (lun === 2) {
partnerVideo.current.srcObject = stream;
} else if (lun === 1) {
screenShare.current.srcObject = stream;
}
};
function shareScreen() {
navigator.mediaDevices.getDisplayMedia({ cursor: true }).then(stream => {
screenShare.current.srcObject = stream;
userScreen.current = stream;
const screenTrack = stream.getTracks()[0];
callUser(otherUser.current);
peerRef.current.addTrack(screenTrack, stream);
screenTrack.onended = function () {
peerRef.current.removeTrack(screenTrack);
}
})
}
return (
<div>
<video controls style={{ height: 500, width: 500 }} autoPlay ref={userVideo} />
<video controls style={{ height: 500, width: 500 }} autoPlay ref={partnerVideo} />
<video controls style={{ height: 500, width: 500 }} autoPlay ref={screenShare} />
<button onClick={shareScreen}>Share screen</button>
</div>
);
};
In shareScreen you're adding a second track to the existing peer connection with addTrack, which triggers renegotiation (causes your onnegotiationneeded handler to run again). This is correct so far, and triggers a second offer/answer exchange, which is needed for media track additions.
You're just not set up to handle renegotiation correctly, because you've mixed initialization code in with your (re)negotiation code, causing a new RTCPeerConnection object to be created when you already have one.
Renegotiation is going to happen whenever you add tracks or stop their underlying transceivers, so you don't want initialization code in your negotiation code. Instead do this:
Move the creation of your RTCPeerConnection out of handleReceiveCall. Create it on page load instead.
Move the addition of tracks out of handleReceiveCall as well if you can, or at least skip re-adding them if they've already been added.
Your ontrack is going to fire again with the screen-sharing track, so you need to add code to handle that. You can differentiate it from the camera track by event.streams[0].id and event.transceiver.mid being different, or simply from this being the third track.

agora.io screen-sharing web sdk getDisplayMedia

I'm using Agora to create screen-sharing action and I'm stuck not being able to get it to work on Safari/MacOS. The code below is working for Chrome and Firefox in both Mac/Windows. Every time I click on this IconButton, the error message is in the screenshot below.
What could be the issue? I've compared this to Agora's sample code, but cannot figure what caused this bug.
<IconButton color='primary' onClick={shareScreenClient ? clearScreenStream : startScreenStream}>
{shareScreenClient ? <StopScreenShareOutlinedIcon fontSize='large' /> : <ScreenShareOutlinedIcon fontSize='large' />}</IconButton>
//here's the def of startScreenStream.
const startScreenStream = (e) => {
e.preventDefault();
screenClient.current = AgoraRTC.createClient(agoraClientObj);
const channel = classroom;
const token = null;
screenClient.current.init(appID, () => {
screenClient.current.join(
token,
channel,
null,
(screenUid) => {
// Create the screen-sharing stream, screenStream.
setScreenStreamObj((x) => ({
...x,
streamId: screenUid,
}));
let screenStreamObj = {
streamID: screenUid,
audio: false,
video: false,
screen: true,
screenAudio: true,
};
if (audioDeviceId) screenStreamObj.microphoneId = audioDeviceId;
if (videoDeviceId) screenStreamObj.cameraId = videoDeviceId;
if (isFirefox) screenStreamObj.mediaSource = 'screen';
screenStream.current = AgoraRTC.createStream(screenStreamObj);
screenStream.current.setScreenProfile('480p_1');
screenStream.current.init(
() => {
screenStream.current.play('screen-share', { fit: 'cover' }, () => {
console.log('sharing screen');
setShareScreenClient(true);
});
screenClient.current.publish(screenStream.current, (err) => {
console.error('publish failed', err);
//clearScreenStream();
});
},
(err) => {
screenStream.current = null;
setScreenStreamObj({});
console.error('could not init stream', err);
}
);
},
(err) => {
screenClient.current = null;
console.error('Could not join channel', err);
}
);
});
}

Resources