***************CONNECTIONS THROUGH WEBRTC******************
WHEN AN USER JOINS, A CONNECTION IS ESTABLISHED INORDER TO CONNECT HIM WITH THE MEETING.
THE CONNECTION IS A PEER-TO-PEER CONNECTION.
socketRef.current.on("user-joined", (id, clients) => {
clients.forEach((socketListId) => {
connections[socketListId] = new RTCPeerConnection(
peerConfigConnections
);
NOW CANDIDATES, SHOULD BE FOUND DURING THIS CONNECTION.
ONICECANDIDATE IS A FUNCTION THAT TRIGGERS WHENEVER A NEW ICE
CANDIDATE IS DISCOVERED.
ICE: INTERACTIVE CONNECTIVITY ESTABLISHMENT
connections[socketListId].onicecandidate = (event) => {
A NETWORK CANDIDATE
if (RTCIceCandidate.event !== null) {
socketRef.current.emit(
"signal",
socketListId,
JSON.stringify({ ice: event.candidate })
);
}
WHENEVER A MEDIA FILE (AUDIO,VIDEO..ETC) ARE ADDED A FUNCITON IS TRIGGERED CALLED ONADDSTREAM (OLDER VERSION DEPRECATED).
(WE WILL TRY ONADDSTREAM FIRST IF IT DOESNOT WORK THEN TRY ONTRACK).
WHENEVER MEDIA IS ADDED IT IS CHECKED IF THERE'S A VIDEO ELEMENT FOR THAT STREAM OR NOT . IF YES IT'S UPDATED ,ELSE A NEW VIDEO IS CREATED.
connections[socketListId].onaddStream = (event) => {
const videoExists = videoRef.current.find(
(video) => (video.socketId === socketListId)
);
if (videoExists) {
setVideo((video) => {
const updatedVideos = videos.map((video) =>
video.socketId === socketListId
? { ...video, stream: video.stream }
: video
);
});
videoRef.current = updatedVideos;
return updateVideos;
} else {
let newVideo = {
socketId: socketListId,
stream: event.stream,
autoPlay: true,
playsinline: true,
};
setVideo((videos) => {
let updatedVideos = [...videos, newVideo];
videoRef.current = updatedVideos;
return updatedVideos;
});
}
};
NOW , IF THE LOCAL STREAM IS AVAILABE , THE STREAM IS ADDED.
LOCAL STREAM REFERS TO THE TYPICAL VIDEO/MIC MEDIA.
A SESSION DESCRIPTION IS ADDED (SDP)
if (
window.localStream !== undefined &&
window.localStream !== null
) {
connections[socketListId].onaddStream(window.localStream);
} else {
//TODO
}
};
});
if (id === socketIdRef.current) {
for (let id2 in connections) {
if (id2 === socketIdRef.current) {
continue;
}
try {
connections[id2].onaddStream(window.localStream);
} catch (e) {
console.log(e);
}
USED TO INITIATE WEBRTC CONNECTION
connections[id2].createOffer().then((description) => {
connections[id2]
.setLocalDescription(description)
.then(() => {
socketRef.current.emit(
"signal",
id2,
JSON.stringify({
"sdp": connections[id2].LocalDescription,
})
);
})
.catch((e) => {
console.log(e);
});
});
}
VIDEOCONFERENCE.JSX
import React, { useEffect, useRef, useState } from "react";
import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
import { io } from "socket.io-client";
import "../styles/VC.css";
const server_Url = "http://localhost:8080";
let connections = {};
const peerConfigConnections = {
iceServers: [{ urls: "stun.doublerobotics.com:3478" }],
};
export default function VideoConference() {
const socketRef = useRef();
let socketIdRef = useRef();
let localVideoRef = useRef();
let [videoAvailable, setVideoAvailable] = useState(true);
let [audioAvailable, setAudioAvailable] = useState(true);
let [video, setVideo] = useState();
let [audio, setAudio] = useState();
let [screen, setScreen] = useState();
let [messages, setMessages] = useState([]);
let [message, setMessage] = useState("");
let [screenAvailable, setScreenAvailable] = useState();
let [newMessages, setNewMessages] = useState(0);
let [askForUsername, setAskForUsername] = useState(true);
let [username, setUsername] = useState("");
let [videos, setVideos] = useState([]);
const videoRef = useRef([]);
useEffect(() => {
getPermissions();
}, []);
let getUserMediaSuccess = (stream) => {};
let getUserMedia = () => {
if ((video && videoAvailable) || (audio && audioAvailable)) {
navigator.mediaDevices
.getUserMedia({ video: video, audio: audio })
.then(getUserMediaSuccess)
.then((stream) => {})
.catch((e) => {
console.log(e);
});
} else {
try {
let tracks = localVideoRef.current.srcObject.getTracks();
tracks.forEach((track) => track.stop());
} catch (e) {}
}
};
useEffect(() => {
if (video !== undefined || audio !== undefined) {
getUserMedia();
}
}, [audio, video]);
let gotMessageFromServer = (Id, Message) => {};
let connectToSocketServer = () => {
socketRef.current = io(server_Url, { secure: false });
socketRef.current.on("signal", gotMessageFromServer);
socketRef.current.on("connect", () => {
socketRef.current.emit("join-call", window.location.href);
socketIdRef.current = socketRef.current.id;
socketRef.current.on("chat-message", addMessage);
socketRef.current.on("user-left", (id) => {
setVideo((videos) => {
videos.filter((video) => video.socketId !== id);
});
});
socketRef.current.on("user-joined", (id, clients) => {
clients.forEach((socketListId) => {
connections[socketListId] = new RTCPeerConnection(
peerConfigConnections
);
connections[socketListId].onicecandidate = (event) => {
if (RTCIceCandidate.event !== null) {
socketRef.current.emit(
"signal",
socketListId,
JSON.stringify({ ice: event.candidate })
);
}
//ontrack
connections[socketListId].onaddStream = (event) => {
const videoExists = videoRef.current.find(
(video) => (video.socketId === socketListId)
);
if (videoExists) {
setVideo((video) => {
const updatedVideos = videos.map((video) =>
video.socketId === socketListId
? { ...video, stream: video.stream }
: video
);
});
videoRef.current = updatedVideos;
return updateVideos;
} else {
let newVideo = {
socketId: socketListId,
stream: event.stream,
autoPlay: true,
playsinline: true,
};
setVideo((videos) => {
let updatedVideos = [...videos, newVideo];
videoRef.current = updatedVideos;
return updatedVideos;
});
}
};
if (
window.localStream !== undefined &&
window.localStream !== null
) {
connections[socketListId].onaddStream(window.localStream);
} else {
}
};
});
if (id === socketIdRef.current) {
for (let id2 in connections) {
if (id2 === socketIdRef.current) {
continue;
}
try {
connections[id2].onaddStream(window.localStream);
} catch (e) {
console.log(e);
}
connections[id2].createOffer().then((description) => {
connections[id2]
.setLocalDescription(description)
.then(() => {
socketRef.current.emit(
"signal",
id2,
JSON.stringify({
"sdp": connections[id2].LocalDescription,
})
);
})
.catch((e) => {
console.log(e);
});
});
}
}
});
});
};
let getMedia = () => {
setVideo(videoAvailable);
setAudio(audioAvailable);
connectToSocketServer();
};
let connect = () => {
setAskForUsername(false);
getMedia();
getUserMedia();
};
const getPermissions = async () => {
try {
const videoPermission = await navigator.mediaDevices.getUserMedia({
video: true,
});
if (videoPermission) {
setVideoAvailable(true);
} else {
setVideoAvailable(false);
}
const audioPermission = await navigator.mediaDevices.getUserMedia({
audio: true,
});
if (audioPermission) {
setAudioAvailable(true);
} else {
setAudioAvailable(false);
}
if (navigator.mediaDevices.getDisplayMedia) {
setScreenAvailable(true);
} else {
setScreenAvailable(false);
}
if (videoAvailable || audioAvailable) {
const userMediaStream = await navigator.mediaDevices.getUserMedia({
video: videoAvailable,
audio: audioAvailable,
});
if (userMediaStream) {
window.localStream = userMediaStream;
if (localVideoRef.current) {
localVideoRef.current.srcObject = userMediaStream;
}
}
}
} catch (e) {
console.log(e);
}
};
return (
<>
{askForUsername === true ? (
<div>
<h2>Enter into lobby</h2>
<TextField
className="inputsRequired"
id="outlined-basic"
label="Username"
value={username}
variant="outlined"
onChange={(e) => setUsername(e.target.value)}
/>
<Button variant="contained" onClick={connect}>
Connect
</Button>
<div>
<video ref={localVideoRef} autoPlay muted></video>
</div>
</div>
) : (
<div></div>
)}
</>
);
}
Comments
Post a Comment