From 7220867bec8c8d5652f640223cf78fc0cd31d038 Mon Sep 17 00:00:00 2001 From: Arjun Patel Date: Sat, 22 Jan 2022 21:22:03 -0800 Subject: [PATCH] maybe working full? --- components/Dashboard/Office.tsx | 86 ++++++++++++++++++++++++++++++- components/OfficeCard.tsx | 40 +++++++++------ package-lock.json | 23 --------- package.json | 1 - services/agoraService.ts | 90 +++++++++++++++++++++++++++++---- services/officeRoomService.tsx | 56 ++++---------------- 6 files changed, 201 insertions(+), 95 deletions(-) diff --git a/components/Dashboard/Office.tsx b/components/Dashboard/Office.tsx index 2bb9fe6..e6c4d3a 100644 --- a/components/Dashboard/Office.tsx +++ b/components/Dashboard/Office.tsx @@ -1,3 +1,9 @@ +import { + ClientConfig, + IAgoraRTC, + IAgoraRTCClient, + IMicrophoneAudioTrack, +} from "agora-rtc-sdk-ng"; import { Tooltip } from "antd"; import { collection, @@ -7,9 +13,11 @@ import { where, } from "firebase/firestore"; import { useEffect, useState } from "react"; +import toast from "react-hot-toast"; import { useAuth } from "../../contexts/authContext"; import { useTeamDashboardContext } from "../../contexts/teamDashboardContext"; import OfficeRoom from "../../models/officeRoom"; +import { appId } from "../../services/agoraService"; import { Collections } from "../../services/collections"; import OfficeRoomService from "../../services/officeRoomService"; import OfficeCard from "../OfficeCard"; @@ -18,9 +26,18 @@ const db = getFirestore(); const officeRoomService = new OfficeRoomService(); +const config: ClientConfig = { + mode: "rtc", + codec: "vp8", +}; + export default function Office() { const { currUser } = useAuth(); const { team } = useTeamDashboardContext(); + const [agoraRtc, setAgoraRtc] = useState(null); + const [agoraRtcClient, setAgoraRtcClient] = useState(null); + const [localAudioTrack, setLocalAudioTrack] = + useState(null); const [officeRoomsMap, setOfficeRoomsMap] = useState>( new Map() @@ -66,6 +83,68 @@ export default function Office() { }); }, []); + // set up agora stuff + useEffect(() => { + (async function () { + // dynamic import as the server side import doesn't work + const AgoraRTC = (await import("agora-rtc-sdk-ng")).default; + const agoraClient = AgoraRTC.createClient(config); + + setAgoraRtcClient(agoraClient); + setAgoraRtc(AgoraRTC); + })(); + }, []); + + async function handleJoinChannel(channelName: string, agoraToken: string) { + const localTrack: IMicrophoneAudioTrack = + await agoraRtc.createMicrophoneAudioTrack(); + + setLocalAudioTrack(localTrack); + + let init = async (chanName: string) => { + agoraRtcClient.on("user-published", async (user, mediaType) => { + await agoraRtcClient.subscribe(user, mediaType); + console.log("subscribe success"); + + if (mediaType === "audio") { + user.audioTrack?.play(); + } + }); + + agoraRtcClient.on("user-unpublished", async (user, type) => { + console.log("unpublished", user, type); + if (type === "audio") { + user.audioTrack?.stop(); + } + + await agoraRtcClient.unsubscribe(user); + }); + + agoraRtcClient.on("user-left", (user) => { + console.log("user left", user); + }); + + await agoraRtcClient.join(appId, chanName, agoraToken, null); + if (localTrack) await agoraRtcClient.publish(localTrack); + }; + + if (localTrack) { + console.log("init ready"); + init(channelName); + } else { + toast.error("Not ready for joining call"); + return; + } + } + + async function handleLeaveChannel() { + // destroy local track + localAudioTrack?.close(); + + // leave all channels + await agoraRtcClient.leave(); + } + const allOfficeRooms = Array.from(officeRoomsMap.values()); allOfficeRooms.sort((a, b) => { @@ -98,7 +177,12 @@ export default function Office() { {/* all office rooms */} {allOfficeRooms.map((officeRoom) => ( - + ))} {/* */} diff --git a/components/OfficeCard.tsx b/components/OfficeCard.tsx index 59054e4..1dc726f 100644 --- a/components/OfficeCard.tsx +++ b/components/OfficeCard.tsx @@ -7,17 +7,16 @@ import OfficeRoom, { OfficeRoomState } from "../models/officeRoom"; import { User } from "../models/user"; import OfficeRoomService from "../services/officeRoomService"; import { VscDebugDisconnect } from "react-icons/vsc"; -import { - AgoraVideoPlayer, - createClient, - createMicrophoneAudioTrack, -} from "agora-rtc-react"; +import AgoraService from "../services/agoraService"; interface IOfficeCard { officeRoom: OfficeRoom; + handleJoinChannel: Function; + handleLeaveChannel: Function; } const officeRoomService = new OfficeRoomService(); +const agoraService = new AgoraService(); export default function OfficeCard(props: IOfficeCard) { const { currUser } = useAuth(); @@ -48,36 +47,43 @@ export default function OfficeCard(props: IOfficeCard) { } try { - // todo: pass in the right channel name based on the office room id - const agoraToken = await officeRoomService.getAgoraToken(); + // agora token from CF + const agoraToken = await agoraService.getAgoraToken(props.officeRoom.id); - console.log(agoraToken); + // // function to do it all + // await officeRoomService.joinOfficeRoom(props.officeRoom, currUser.uid); - // join right channel on agora + // handle joining agora channel + await props.handleJoinChannel(props.officeRoom.id, agoraToken); - // const newMembers = [...props.officeRoom.members, currUser.uid]; - // await officeRoomService.updateMembersInOfficeRoom( - // props.officeRoom.id, - // newMembers - // ); + // update firestore to add ourselves in the office room + const newMembers = [...props.officeRoom.members, currUser.uid]; + await officeRoomService.updateMembersInOfficeRoom( + props.officeRoom.id, + newMembers + ); } catch (error) { console.error(error); toast.error("problem joining office room"); } toast.dismiss(); + toast.success("joined office room"); } async function handleLeaveOfficeRoom() { - // leave the channel for agora + toast.loading("leaving"); - // leave from firestore database if (!props.officeRoom.members.includes(currUser.uid)) { toast.error("You are not in this office room!"); return; } try { + // leave agora channel + await props.handleLeaveChannel(); + + // leave from firestore database const newMembersInRoom = props.officeRoom.members.filter( (memberId) => memberId != currUser.uid ); @@ -90,6 +96,8 @@ export default function OfficeCard(props: IOfficeCard) { console.error(error); toast.error("problem leaving office room"); } + toast.dismiss(); + toast.success("left office room"); } // check if user is in the office room diff --git a/package-lock.json b/package-lock.json index 3594f9b..73091d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,6 @@ "": { "name": "nirvana", "dependencies": { - "agora-rtc-react": "^1.1.0", "agora-rtc-sdk-ng": "^4.8.1", "antd": "^4.18.3", "firebase": "^9.6.2", @@ -2584,20 +2583,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "optional": true }, - "node_modules/agora-rtc-react": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/agora-rtc-react/-/agora-rtc-react-1.1.0.tgz", - "integrity": "sha512-+cvK3gXcUC2FzXkrN9L/nE5B6FqgP2w7fWid5wpsdtzmBMf/gehzN1cDhMSDz2oI3Jq/9zo9R4iVswPx+QtAGA==", - "dependencies": { - "agora-rtc-sdk-ng": "^4.3.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17" - } - }, "node_modules/agora-rtc-sdk-ng": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/agora-rtc-sdk-ng/-/agora-rtc-sdk-ng-4.8.1.tgz", @@ -11296,14 +11281,6 @@ } } }, - "agora-rtc-react": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/agora-rtc-react/-/agora-rtc-react-1.1.0.tgz", - "integrity": "sha512-+cvK3gXcUC2FzXkrN9L/nE5B6FqgP2w7fWid5wpsdtzmBMf/gehzN1cDhMSDz2oI3Jq/9zo9R4iVswPx+QtAGA==", - "requires": { - "agora-rtc-sdk-ng": "^4.3.0" - } - }, "agora-rtc-sdk-ng": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/agora-rtc-sdk-ng/-/agora-rtc-sdk-ng-4.8.1.tgz", diff --git a/package.json b/package.json index e92c7ca..224d8ad 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,6 @@ "lint": "next lint" }, "dependencies": { - "agora-rtc-react": "^1.1.0", "agora-rtc-sdk-ng": "^4.8.1", "antd": "^4.18.3", "firebase": "^9.6.2", diff --git a/services/agoraService.ts b/services/agoraService.ts index ebb960a..f0f5a96 100644 --- a/services/agoraService.ts +++ b/services/agoraService.ts @@ -1,22 +1,94 @@ -import { +import AgoraRTC, { ClientConfig, IAgoraRTCRemoteUser, ICameraVideoTrack, IMicrophoneAudioTrack, } from "agora-rtc-sdk-ng"; -import { - AgoraVideoPlayer, - createClient, - createMicrophoneAndCameraTracks, - createMicrophoneAudioTrack, -} from "agora-rtc-react"; +// import { +// AgoraVideoPlayer, +// createClient, +// createMicrophoneAndCameraTracks, +// createMicrophoneAudioTrack, +// } from "agora-rtc-react"; +import { getFunctions, httpsCallable } from "firebase/functions"; +import toast from "react-hot-toast"; const config: ClientConfig = { mode: "rtc", codec: "vp8", }; -const useClient = createClient(config); -const useMicrophoneTracks = createMicrophoneAudioTrack(); + +// const useClient = createClient(config); +// const useMicrophoneTracks = createMicrophoneAudioTrack(); // TODO: move this to env file const appId: string = "c8dfd65deb5c4741bd564085627139d0"; //ENTER APP ID HERE + +export default class AgoraService { + private functions = getFunctions(); + // private rtcClient = useClient(); + + async getAgoraToken(channelName: string): Promise { + const cfResult = httpsCallable(this.functions, "agoraToken"); + + return await cfResult({ channelName }) + .then((result: { data: { token: string } }) => { + const data = result.data; + + if (!data.token) { + throw new Error("No token retrieved from agora"); + } + + return data.token; + }) + .catch((error) => { + // Getting the Error details. + const code = error.code; + const message = error.message; + const details = error.details; + throw error; + }); + } + + // async handleJoinChannel(channelName: string, agoraToken: string) { + // const localTrack: IMicrophoneAudioTrack = + // await AgoraRTC.createMicrophoneAudioTrack(); + + // let init = async (name: string) => { + // this.rtcClient.on("user-published", async (user, mediaType) => { + // await this.rtcClient.subscribe(user, mediaType); + // console.log("subscribe success"); + + // if (mediaType === "audio") { + // user.audioTrack?.play(); + // } + // }); + + // this.rtcClient.on("user-unpublished", async (user, type) => { + // console.log("unpublished", user, type); + // if (type === "audio") { + // user.audioTrack?.stop(); + // } + + // await this.rtcClient.unsubscribe(user); + // }); + + // this.rtcClient.on("user-left", (user) => { + // console.log("user left", user); + // }); + + // await this.rtcClient.join(appId, name, agoraToken, null); + // if (localTrack) await this.rtcClient.publish(localTrack); + // }; + + // if (localTrack) { + // console.log("init ready"); + // init(channelName); + // } else { + // toast.error("Not ready for joining call"); + // return; + // } + // } +} + +export { appId }; diff --git a/services/officeRoomService.tsx b/services/officeRoomService.tsx index 90b8ef4..1f8d658 100644 --- a/services/officeRoomService.tsx +++ b/services/officeRoomService.tsx @@ -10,17 +10,14 @@ import { writeBatch, } from "firebase/firestore"; import OfficeRoom, { OfficeRoomState } from "../models/officeRoom"; +// import AgoraService from "./agoraService"; import { Collections } from "./collections"; -import { getFunctions, httpsCallable } from "firebase/functions"; - -interface IAgoraTokenResult { - data: { token: string }; -} export default class OfficeRoomService { private db: Firestore = getFirestore(); private batch = writeBatch(this.db); - private functions = getFunctions(); + + // private agoraService = new AgoraService(); async createInitialOfficeRooms(createdByUserId: string, teamId: string) { const entrance = new OfficeRoom("Entrance", teamId, createdByUserId); @@ -51,47 +48,16 @@ export default class OfficeRoomService { await this.batch.commit(); } - // async createOrUpdateRoom(room: Room) { - // if (room.id) { - // //update - // await this.updateRoom(room); - // } else { - // //create - // const roomDocRef = await addDoc(collection(this.db, Collections.rooms), { - // ...room, - // createdDate: serverTimestamp(), - // }); - // } - // } + async joinOfficeRoom(officeRoom: OfficeRoom, userId: string) { + // get agoraToken + // const agoraToken = await this.agoraService.getAgoraToken(); - async getAgoraToken(): Promise { - // const agoraToken = await fetch("/api/agora/token", { - // method: "post", - // headers: { - // "Content-Type": "application/json", - // }, - // body: JSON.stringify({ channelName: "testChannel" }), - // }); + // join channel + // await this.agoraService.handleJoinChannel(officeRoom.id, agoraToken); - const cfResult = httpsCallable(this.functions, "agoraToken"); - - return await cfResult({ channelName: "testChannel" }) - .then((result: IAgoraTokenResult) => { - const data = result.data; - - if (!data.token) { - throw new Error("No token retrieved from agora"); - } - - return data.token; - }) - .catch((error) => { - // Getting the Error details. - const code = error.code; - const message = error.message; - const details = error.details; - throw error; - }); + // update members list in firestore + const newMembers = [...officeRoom.members, userId]; + await this.updateMembersInOfficeRoom(officeRoom.id, newMembers); } async updateMembersInOfficeRoom(