This commit is contained in:
2024-02-09 19:46:26 +05:00
parent 42f07f410e
commit 8f43e95057
33 changed files with 970 additions and 230 deletions
+76 -112
View File
@@ -1,4 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable no-empty */
// Copyright Epic Games, Inc. All Rights Reserved.
import { useEffect, useRef, useState } from "react";
@@ -6,16 +8,17 @@ import {
Config,
AllSettings,
PixelStreaming,
LatencyTestResults,
} from "@epicgames-ps/lib-pixelstreamingfrontend-ue5.3";
import { Trans } from "react-i18next";
import LoaderIcon from "./icons/LoaderIcon";
export interface PixelStreamingWrapperProps {
initialSettings?: Partial<AllSettings>;
onVideoInitialized?: () => void;
}
export const PixelStreamingWrapper = ({
initialSettings,
onVideoInitialized,
}: PixelStreamingWrapperProps) => {
// A reference to parent div element that the Pixel Streaming library attaches into:
const videoParent = useRef<HTMLDivElement>(null);
@@ -24,10 +27,10 @@ export const PixelStreamingWrapper = ({
const [pixelStreaming, setPixelStreaming] = useState<PixelStreaming>();
// A boolean state variable that determines if the Click to play overlay is shown:
const [clickToPlayVisible, setClickToPlayVisible] = useState<boolean>(false);
const [videoInitialized, setVideoInitialized] = useState<boolean>(false);
const videoInitializedRef = useRef<boolean>();
videoInitializedRef.current = videoInitialized;
const [clickToPlayVisible, setClickToPlayVisible] = useState(false);
const [latencyTestResult, setLatencyTestResult] =
useState<LatencyTestResults>();
// Run on component mount:
useEffect(() => {
@@ -38,132 +41,93 @@ export const PixelStreamingWrapper = ({
videoElementParent: videoParent.current,
});
streaming.addEventListener("videoInitialized", () => {
setVideoInitialized(true);
});
// register a playStreamRejected handler to show Click to play overlay if needed:
streaming.addEventListener("playStreamRejected", () => {
setClickToPlayVisible(true);
});
streaming.addEventListener("videoInitialized", () => {
onVideoInitialized && onVideoInitialized();
});
streaming.addEventListener("latencyTestResult", (e) => {
setLatencyTestResult(e.data.latencyTimings);
// console.log("Data", e.data.latencyTimings);
});
setInterval(() => {
streaming.requestLatencyTest();
}, 500);
// Save the library instance into component state so that it can be accessed later:
setPixelStreaming(streaming);
document.getElementById("hiddenInput")?.remove();
document.getElementById("editTextButton")?.remove();
setTimeout(() => {
if (!videoInitializedRef.current) {
window.location.reload();
}
}, 10000);
// Clean up on component unmount:
return () => {
try {
streaming.disconnect();
} catch {
//
}
} catch {}
};
}
}, []);
return (
<div className="relative w-screen h-screen">
<div className="w-full h-[100svh]" ref={videoParent} />
{!videoInitialized && (
<div className="absolute top-0 left-0 w-full h-full flex justify-center items-center gap-4">
<LoaderIcon className="animate-spin w-8 h-8" />
<Trans i18nKey="streamBuffering">Буферизация потока</Trans>
</div>
)}
<div
style={{
width: "100%",
height: "100%",
position: "relative",
}}
>
<div
style={{
width: "100%",
height: "100%",
}}
ref={videoParent}
/>
{clickToPlayVisible && (
<div className="absolute top-0 left-0 w-full h-full flex justify-center items-center z-10 bg-[#131317]">
<div className="flex flex-col justify-center items-center w-[400px] p-10 space-y-10 rounded-lg">
<div className="space-y-4 text-center">
<p className="text-4xl font-gilroy">
<Trans i18nKey="demoStarted">Демонстрация начата</Trans>
</p>
<p className="text-[#C5C7CE]">
<Trans i18nKey="clickToContinue">
Нажмите, чтобы продолжить
</Trans>
</p>
</div>
<button
onClick={() => {
pixelStreaming?.play();
setClickToPlayVisible(false);
}}
>
<svg
width="88"
height="88"
viewBox="0 0 88 88"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g filter="url(#filter0_b_0_1121)">
<path
d="M55.6667 43.9999L34.6668 57.9999L34.6668 30L55.6667 43.9999Z"
fill="#F2F2F2"
stroke="#F2F2F2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<rect
x="0.5"
y="0.5"
width="87"
height="87"
rx="43.5"
stroke="url(#paint0_linear_0_1121)"
/>
</g>
<defs>
<filter
id="filter0_b_0_1121"
x="-20"
y="-20"
width="128"
height="128"
filterUnits="userSpaceOnUse"
colorInterpolationFilters="sRGB"
>
<feFlood floodOpacity="0" result="BackgroundImageFix" />
<feGaussianBlur in="BackgroundImageFix" stdDeviation="10" />
<feComposite
in2="SourceAlpha"
operator="in"
result="effect1_backgroundBlur_0_1121"
/>
<feBlend
mode="normal"
in="SourceGraphic"
in2="effect1_backgroundBlur_0_1121"
result="shape"
/>
</filter>
<linearGradient
id="paint0_linear_0_1121"
x1="88"
y1="-2.6226e-06"
x2="2.6226e-06"
y2="88"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#BC75FF" />
<stop offset="1" stopColor="#798FFF" />
</linearGradient>
</defs>
</svg>
</button>
</div>
<div
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
cursor: "pointer",
color: "#fff",
}}
onClick={() => {
pixelStreaming?.play();
setClickToPlayVisible(false);
}}
>
<div>Click to play</div>
</div>
)}
<div className="absolute bottom-0 left-0 p-4 text-white text-xs bg-black">
{latencyTestResult &&
Object.entries(latencyTestResult).map(([key, value], i) => {
if (
[
"EncodeMs",
"CaptureToSendMs",
"latencyExcludingDecode",
"networkLatency",
"testStartTimeMs",
].includes(key)
)
return (
<div key={i}>
{key}: {value}
</div>
);
})}
</div>
</div>
);
};