Commit 3de600df authored by Suryaprasadh M's avatar Suryaprasadh M 🏸
Browse files

jitsi

parent b54a843e
Loading
Loading
Loading
Loading
+2 −30
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ import { useEffect, useMemo } from "react";
import useTeamsMeeting from "./hooks/teams-provider/useTeamsMeeting";
import useZoomMeeting from "./hooks/zoom-provider/useZoomMeeting";
// import useWebexMeeting from "./hooks/webex-provider/useWebexMeeting";
import useJitsiMeeting from "./hooks/jitsi-provider/useJitsiMeeting";
import Router from "next/router";

const inter = Inter({ subsets: ["latin"] });
@@ -53,6 +54,7 @@ const useMeetingConnector = {
  teams: useTeamsMeeting,
  zoom: useZoomMeeting,
  // webex: useWebexMeeting,
  jitsi: useJitsiMeeting,
};

export default function ConferenceScreen({
@@ -110,36 +112,6 @@ export default function ConferenceScreen({
      >
        End Meeting
      </button>
      <button
        style={{
          margin: "20px",
          padding: "10px 20px",
          backgroundColor: "red",
          cursor: "pointer",
          border: "none",
          borderRadius: "10px",
        }}
        onClick={() => {
          stopShare();
        }}
      >
        Stop Share
      </button>
      <button
        style={{
          margin: "20px",
          padding: "10px 20px",
          backgroundColor: "red",
          cursor: "pointer",
          border: "none",
          borderRadius: "10px",
        }}
        onClick={() => {
          startShare();
        }}
      >
        Start Share
      </button>
    </div>
  );
}
+330 −0
Original line number Diff line number Diff line
/* eslint-disable no-undef */
import { useEffect, useRef, useState } from "react";

function defaultMeetingState(isShare) {
  return {
    loading: true,
    error: false,
    message: isShare ? "Connecting to Ving Share" : "Connecting to Ving Meet",
    meetingConnected: false,
    isSharing: false,
    connectionStatusCode: 0,
    remoteHostMeetingEnd: false,
  };
}

// Multistream is enabled by default now and it causes issues during share screen
// Manually disabling it
// https://github.com/jitsi/lib-jitsi-meet/pull/2116/files
const initOptions = {};
const options = {
  hosts: {
    domain: "meet.jit.si",
    muc: "conference.meet.jit.si",
    focus: "focus.meet.jit.si",
  },
  externalConnectUrl: "https://meet.jit.si/http-pre-bind",
  enableP2P: true,
  p2p: {
    enabled: true,
    preferH264: true,
    disableH264: true,
    useStunTurn: true,
  },
  useStunTurn: true,
  clientNode: "http://jitsi.org/jitsimeet",
};
let connection;
let room;
let localTracks = [];
let selectedWindowId;

function setupDisplayMediaStream() {
  if (!window.vingElectron) {
    return;
  }
  window.JitsiMeetScreenObtainer = {
    openDesktopPicker(options, onSourceChoose) {
      const typeIndex = selectedWindowId.indexOf(":");
      const type =
        typeIndex >= 0 ? selectedWindowId.substring(0, typeIndex) : null;

      onSourceChoose(selectedWindowId, type);
    },
  };
}

function onConferenceJoined(setMeetingStatus) {
  setMeetingStatus((prev) => ({
    ...prev,
    meetingConnected: true,
    error: false,
    loading: false,
    connectionStatusCode: 1,
    message: "Connected",
  }));
}

function transformRemoteParticipants(participants) {
  if (!participants.length) {
    return [];
  }

  return participants.map((participant) => {
    return {
      id: participant._id,
      participantName: participant._displayName,
      isHost: false,
      profileUrl: "",
      isLocalParticipant: false,
      isInLobby: false,
    };
  });
}

function transformLocalParticipant(room, name) {
  return {
    id: room.myUserId(),
    participantName: name,
    isHost: room.isModerator(),
    profileUrl: "",
    isLocalParticipant: true,
    isInLobby: false,
  };
}

function onConnectionSuccess(props) {
  const { setMeetingStatus, roomName, name, setParticipants } = props;

  try {
    room = connection.initJitsiConference(roomName, {});
    window.room = room;
    room.on(JitsiMeetJS.events.conference.CONFERENCE_JOINED, () => {
      console.log("jitsiConnectionEvents====> JOINED");
      onConferenceJoined(setMeetingStatus);
      let participants = transformRemoteParticipants(room.getParticipants());
      participants.push(transformLocalParticipant(room, name));
      setParticipants(participants);
    });

    room.on(JitsiMeetJS.events.conference.USER_JOINED, () => {
      let participants = transformRemoteParticipants(room.getParticipants());
      participants.push(transformLocalParticipant(room, name));
      setParticipants(participants);
    });

    room.on(JitsiMeetJS.events.conference.USER_LEFT, () => {
      let participants = transformRemoteParticipants(room.getParticipants());
      participants.push(transformLocalParticipant(room, name));
      setParticipants(participants);
    });

    room.setDisplayName(name);
    room.join();
  } catch (e) {
    console.log("e", e);
    setMeetingStatus((prev) => ({
      ...prev,
      error: true,
      message: "Something went wrong while joining room",
      connectionStatusCode: 0,
    }));
  }
}

function jitsiConnectionEvents(props) {
  const { setMeetingStatus } = props;
  console.log("jitsiConnectionEvents====>");
  connection.addEventListener(
    JitsiMeetJS.events.connection.CONNECTION_ESTABLISHED,
    () => {
      onConnectionSuccess(props);
    }
  );

  connection.addEventListener(
    JitsiMeetJS.events.connection.CONNECTION_FAILED,
    (res) => {
      console.log("res CONNECTION_FAILED", res);
      setMeetingStatus((prev) => ({
        ...prev,
        error: true,
        message: res || "Connection Failed",
        connectionStatusCode: 0,
      }));
    }
  );

  connection.addEventListener(
    JitsiMeetJS.events.connection.otherError,
    (res) => {
      console.log("connection.otherError===>", res);
      setMeetingStatus((prev) => ({
        ...prev,
        error: true,
        message: res || "Connection Failed",
        connectionStatusCode: 0,
      }));
    }
  );
  connection.addEventListener(
    JitsiMeetJS.events.connection.CONNECTION_DISCONNECTED,
    (res) => {
      console.log("res CONNECTION_DISCONNECTED", res);
      setMeetingStatus((prev) => ({
        ...prev,
        error: true,
        message: "Disconnected",
        connectionStatusCode: 0,
      }));
    }
  );
}

async function onLocalTracks(tracks, setMeetingStatus) {
  try {
    const audioTracks = tracks.filter((track) => track.getType() === "audio");
    const audioTrack = audioTracks[0];

    if (audioTrack) {
      await room.addTrack(audioTrack);
    }

    const shareTracks = tracks.filter((track) => track.videoType === "desktop");
    const shareTrack = shareTracks[0];

    if (shareTrack) {
      await room.addTrack(shareTrack);
    }

    tracks[0].addEventListener(
      JitsiMeetJS.events.track.LOCAL_TRACK_STOPPED,
      () => {
        disposeTracks(setMeetingStatus);
      }
    );
    // Share Track will be saved in our localTrack variable
    localTracks.push(tracks[0]);

    // While Sharing Tab with audio, share track and also tab audio track will come, both the tracks need to be saved
    // tracks[0] - audio track & tracks[1] - share track

    if (tracks[1]) {
      localTracks.push(tracks[1]);
    }
  } catch (error) {
    console.log("onLocalTracks catch error:", error);
  }
}

function disposeTracks(setMeetingStatus) {
  try {
    localTracks.forEach(async (track) => {
      if (track.type === "audio") {
        room.removeTrack(room.getLocalTracks()[0]);
        track.dispose();
      }
      if (track.videoType === "desktop") {
        track.dispose();
      }
    });

    localTracks = [];
    setMeetingStatus((prev) => ({ ...prev, isSharing: false }));
  } catch (error) {
    console.log("error", error);
  }
}

function initAndConnect(props) {
  const { roomName } = props;
  JitsiMeetJS.init(initOptions);
  JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.ERROR); //Error LOGS
  options.serviceUrl = `https://meet.jit.si/http-bind?room=${roomName}`;
  connection = new JitsiMeetJS.JitsiConnection(null, null, options);
  jitsiConnectionEvents(props);

  setTimeout(() => connection.connect(), 5000);
}

async function startBrowserShare(room, setMeetingStatus) {
  const shareTracks = await JitsiMeetJS.createLocalTracks({
    devices: ["desktop"],
  });
  setMeetingStatus((prev) => ({ ...prev, isSharing: true }));
  await onLocalTracks(shareTracks, setMeetingStatus);
}

async function startShare(room, setMeetingStatus) {
  try {
    if (window.vingElectron?.getApplicationShareWindows) {
      await setupDisplayMediaStream();
    }
    await startBrowserShare(room, setMeetingStatus);
  } catch (err) {
    setMeetingStatus((prev) => ({
      ...prev,
      isSharing: false,
      message: "Couldn't share",
    }));
    room.getLocalTracks()[1]?.dispose();
  }
}

function useJitsiMeeting(
  roomName,
  passcode,
  name,
  login,
  isShare,
  isStartMeeting,
  setOpenShareScreen
) {
  const [meetingStatus, setMeetingStatus] = useState(
    defaultMeetingState(isShare)
  );
  const [participants, setParticipants] = useState([]);
  const props = {
    setMeetingStatus,
    setParticipants,
    roomName,
    name,
    isShare,
  };

  useEffect(() => {
    initAndConnect(props);

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return {
    meetingStatus,
    setMeetingStatus,
    participants,
    leaveMeeting: () => {
      room
        ?.leave()
        .then(() =>
          setMeetingStatus((prev) => ({ ...prev, meetingConnected: false }))
        )
        .catch((e) => console.log(e));
    },
    startShare: (id) => {
      const isValidId = typeof id === "string";

      if (window.vingElectron && !isValidId) {
        setOpenShareScreen(true);
      } else {
        selectedWindowId = id;
        startShare(room, setMeetingStatus, localTracks, onLocalTracks);
      }
    },
    stopShare: () => {
      disposeTracks(setMeetingStatus);
    },
    removeParticipant: (participantId) => room.kickParticipant(participantId),
  };
}

export default useJitsiMeeting;
+1 −1
Original line number Diff line number Diff line
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  reactStrictMode: false,
  env: {
    REACT_APP_HTTP_BASE_URL: process.env.REACT_APP_HTTP_BASE_URL,
  }
+9 −3
Original line number Diff line number Diff line
import '../styles/globals.css'

import "../styles/globals.css";
import Script from "next/script";

export default function App({ Component, pageProps }) {
  return <Component {...pageProps} />
  return (
    <>
      <Script src="https://code.jquery.com/jquery-3.5.1.min.js" />
      <Script src="https://meet.jit.si/libs/lib-jitsi-meet.min.js" />
      <Component {...pageProps} />
    </>
  );
}