***************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

Popular posts from this blog

MIDDLEWARE.JS

MODELS

AUTHENTICATION PAGE