This commit is contained in:
2024-07-03 18:57:18 +05:00
parent bf669a4d59
commit 9a8998501f
17 changed files with 515 additions and 260 deletions
+91
View File
@@ -0,0 +1,91 @@
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable no-empty */
import { useEffect, useRef, useState } from "react";
import {
Config,
AllSettings,
PixelStreaming,
} from "@epicgames-ps/lib-pixelstreamingfrontend-ue5.5";
export interface PixelStreamingWrapperProps {
initialSettings?: Partial<AllSettings>;
}
export const PixelStreamingWrapper2 = ({
initialSettings,
}: PixelStreamingWrapperProps) => {
// A reference to parent div element that the Pixel Streaming library attaches into:
const videoParent = useRef<HTMLDivElement>(null);
// Pixel streaming library instance is stored into this state variable after initialization:
const [pixelStreaming, setPixelStreaming] = useState<PixelStreaming>();
// A boolean state variable that determines if the Click to play overlay is shown:
const [clickToPlayVisible, setClickToPlayVisible] = useState(false);
// Run on component mount:
useEffect(() => {
if (videoParent.current) {
// Attach Pixel Streaming library to videoParent element:
const config = new Config({ initialSettings });
const streaming = new PixelStreaming(config, {
videoElementParent: videoParent.current,
});
// register a playStreamRejected handler to show Click to play overlay if needed:
streaming.addEventListener("playStreamRejected", () => {
setClickToPlayVisible(true);
});
// Save the library instance into component state so that it can be accessed later:
setPixelStreaming(streaming);
// Clean up on component unmount:
return () => {
try {
streaming.disconnect();
} catch {}
};
}
}, []);
return (
<div
style={{
width: "100%",
height: "100%",
position: "relative",
}}
>
<div
style={{
width: "100%",
height: "100%",
}}
ref={videoParent}
/>
{clickToPlayVisible && (
<div
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
cursor: "pointer",
}}
onClick={() => {
pixelStreaming?.play();
setClickToPlayVisible(false);
}}
>
<div>Click to play</div>
</div>
)}
</div>
);
};
-13
View File
@@ -10,7 +10,6 @@ import { Trans } from "react-i18next";
import i18n from "../i18n";
import { useState } from "react";
import LoaderIcon from "./icons/LoaderIcon";
import api from "../utils/api";
function SidebarTab4() {
const {
@@ -28,17 +27,6 @@ function SidebarTab4() {
const [isLoading, setIsLoading] = useState<boolean>(false);
async function sendInvite(email: string, link: string) {
try {
const reuslt: any = await api
.post("sendInvite", { json: { email, link } })
.json();
console.log("reuslt", reuslt);
} catch (error) {
console.log({ error: (error as Error).message });
}
}
async function handleClickSignUp() {
if (!selectedTime || !selectedDay) {
return;
@@ -63,7 +51,6 @@ function SidebarTab4() {
})
.json();
sendInvite(email, result.url);
setUrl(result.url);
setCurrentTab(currentTab + 1);
setIsLoading(false);
-5
View File
@@ -1,5 +0,0 @@
function ToastContainer() {
return <div></div>;
}
export default ToastContainer;
-69
View File
@@ -1,69 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable react-hooks/exhaustive-deps */
import { useRoomContext } from "@livekit/components-react";
import { Track } from "livekit-client";
import { useEffect, useState } from "react";
import MicroOnIcon from "./icons/MicroOnIcon";
import MicroOffIcon from "./icons/MicroOffIcon";
function ToggleMic({ socket, handleUpdate }: any) {
const room = useRoomContext();
const [muted, setMuted] = useState(true);
function toggleMic(value: boolean) {
const audioTrack = room.localParticipant.getTrack(Track.Source.Microphone);
if (!audioTrack) return;
if (value) {
audioTrack.mute();
} else {
audioTrack.unmute();
}
setMuted(!audioTrack.isMuted);
}
useEffect(() => {
if (!socket) return;
socket.on("update", (socketId: string, data: { [key: string]: any }) => {
if (
socket.id === socketId &&
Object.prototype.hasOwnProperty.call(data, "muted")
) {
toggleMic(data.muted);
}
});
}, [socket]);
useEffect(() => {
// room.on(RoomEvent.TrackMuted, (_, participant) => {
// console.log(participant);
// });
// room.on(RoomEvent.TrackUnmuted, (_, participant) => {
// console.log(participant);
// });
room.on("localTrackPublished", () => {
room.localParticipant.getTrack(Track.Source.Microphone)?.mute();
});
}, []);
return (
<button
onClick={() =>
handleUpdate(room.localParticipant.identity, {
muted: !room.localParticipant.getTrack(Track.Source.Microphone)
?.isMuted,
})
}
className="relative group outline-none bg-[#131313] rounded-full shadow-lg shadow-[#131313] p-2 opacity-90"
>
{!muted ? <MicroOnIcon /> : <MicroOffIcon />}
</button>
);
}
export default ToggleMic;
+35
View File
@@ -0,0 +1,35 @@
import { useEffect, useRef } from "react";
import useIsAudioActive from "use-is-audio-active";
interface Props {
mediaStream: MediaStream | null;
muted: boolean;
}
function Video({ mediaStream, muted }: Props) {
const remoteVideoRef = useRef<HTMLVideoElement>(null);
const isSpeaking = useIsAudioActive({ source: mediaStream });
useEffect(() => {
if (!remoteVideoRef.current) return;
remoteVideoRef.current.srcObject = mediaStream;
remoteVideoRef.current.onloadedmetadata = () => {
remoteVideoRef.current?.play();
};
}, [mediaStream]);
return (
<video
ref={remoteVideoRef}
className={`aspect-video bg-black lg:w-[216px] lg:h-[162px] w-[112px] h-[84px] rounded-lg object-cover ring-2 ${
isSpeaking ? "ring-green-500" : "ring-transparent"
}`}
playsInline
autoPlay
muted={muted}
></video>
);
}
export default Video;
+20
View File
@@ -0,0 +1,20 @@
function CameraOffIcon() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="size-6"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="m15.75 10.5 4.72-4.72a.75.75 0 0 1 1.28.53v11.38a.75.75 0 0 1-1.28.53l-4.72-4.72M12 18.75H4.5a2.25 2.25 0 0 1-2.25-2.25V9m12.841 9.091L16.5 19.5m-1.409-1.409c.407-.407.659-.97.659-1.591v-9a2.25 2.25 0 0 0-2.25-2.25h-9c-.621 0-1.184.252-1.591.659m12.182 12.182L2.909 5.909M1.5 4.5l1.409 1.409"
/>
</svg>
);
}
export default CameraOffIcon;
+20
View File
@@ -0,0 +1,20 @@
function CameraOnIcon() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="size-6"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="m15.75 10.5 4.72-4.72a.75.75 0 0 1 1.28.53v11.38a.75.75 0 0 1-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 0 0 2.25-2.25v-9a2.25 2.25 0 0 0-2.25-2.25h-9A2.25 2.25 0 0 0 2.25 7.5v9a2.25 2.25 0 0 0 2.25 2.25Z"
/>
</svg>
);
}
export default CameraOnIcon;