Skip to content

Commit

Permalink
Refactoring, code improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
toresbe committed Jul 12, 2023
1 parent e7360a5 commit 4bf46bb
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 91 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@emotion/styled": "^11.11.0",
"@hookform/error-message": "^2.0.1",
"@hookform/resolvers": "^3.1.1",
"@mui/material": "^5.13.7",
"@mui/material": "^5.14.0",
"@tanstack/react-query": "^4.29.19",
"classnames": "^2.3.2",
"date-fns": "^2.30.0",
Expand All @@ -27,10 +27,10 @@
"zod": "^3.21.4"
},
"devDependencies": {
"@types/jest": "^29.5.2",
"@types/jest": "^29.5.3",
"@types/react": "^18.2.14",
"@types/react-dom": "^18.2.6",
"@vitejs/plugin-react": "^4.0.2",
"@vitejs/plugin-react": "^4.0.3",
"autoprefixer": "^10.4.14",
"jest": "^29.6.1",
"jest-environment-jsdom": "^29.6.1",
Expand All @@ -39,6 +39,6 @@
"tailwindcss": "^3.3.2",
"ts-jest": "^29.1.1",
"typescript": "^5.1.6",
"vite": "^4.4.1"
"vite": "^4.4.3"
}
}
81 changes: 78 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,93 @@
import "./App.css";
import { MonitoringStream } from "./MonitoringStream";
import { ATEMControl } from "./AtemControl";
import { ATEMButtons, ATEMControl } from "./AtemControl";
import { TextSlideEditorDialog } from "./TextSlideEditor";
import { useState } from "react";
import { Dispatch, SetStateAction, useEffect, useState } from "react";
import { Playout } from "./Playout.js";
import { MuteIcon } from "./MuteIcon";
import cx from "classnames";

const API_BASE = import.meta.env.VITE_ATEM_URL;
const useAtemAux = (auxIndex: number) => {
const [input, setInputState] = useState<number>(-1);

useEffect(() => {
fetch(API_BASE + "/aux/" + auxIndex)
.then((res) => res.json())
.then(({ inputId }) => setInputState(inputId));
}, []);

const setInput = async (index: number) => {
await fetch(API_BASE + "/aux/" + auxIndex, {
method: "put",
credentials: "include",
headers: { "content-type": "application/json" },
body: JSON.stringify({ inputId: index }),
});
setInputState(index);
};

return { input, setInput };
};

const MonitoringStreamControl = ({
muted,
setMuted,
}: {
muted: boolean;
setMuted: Dispatch<SetStateAction<boolean>>;
}) => {
const { input: aux1Input, setInput: setAux1Input } = useAtemAux(1);
return (
<div
className={"bg-gray-300 p-2 lg:p-4 flex items-center gap-4 select-none"}
>
<div
className={"rounded-md p-3 h-12 w-12 cursor-pointer "}
onClick={() => {
setMuted((muted) => !muted);
}}
>
<MuteIcon
className={cx("aspect-square h-full w-full", {
"stroke-gray-800": !muted,
"stroke-red-400": muted,
})}
/>
</div>
Kildevalg
<ATEMButtons
inputs={[
{
name: "PGM",
index: 10010,
},
{
name: "PVW",
index: 10011,
},
{
name: "Multi",
index: 8,
},
]}
activeIndex={aux1Input}
onChange={async (idx) => await setAux1Input(idx)}
/>
</div>
);
};

function App() {
const [isOpen, setOpen] = useState<boolean>(false);
const [muted, setMuted] = useState<boolean>(true);

return (
<div className={"bg-gray-200 lg:p-8 flex-col flex lg:gap-4 lg:flex-row"}>
<div className={"grow"}>
<div className={"text-center py-1 text-2xl"}>Monitor</div>
<MonitoringStream />
<MonitoringStream muted={muted} />
<MonitoringStreamControl muted={muted} setMuted={setMuted} />
</div>
<div>
<div className={"text-center py-1 text-2xl"}>Bildemiks</div>
Expand Down
12 changes: 6 additions & 6 deletions src/AtemControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ const API_BASE = import.meta.env.VITE_ATEM_URL;

export const ATEM_INPUTS: MixEffectsBusInput[] = [
{ index: 2, name: "TX1" },
{ index: 3, name: "TX2" },
{ index: 1, name: "TX3" },
{ index: 1, name: "TX2" },
{ index: 3, name: "TX3" },
{ index: 5, name: "RX1" },
{ index: 3010, name: "Still 1" },
{ index: 1000, name: "Color bars" },
Expand Down Expand Up @@ -59,20 +59,20 @@ export const ATEMControl = () => {

const setProgram = async (index: number) => {
await fetch(API_BASE + "/program", {
method: "post",
method: "put",
credentials: "include",
headers: { "content-type": "application/json" },
body: JSON.stringify({ inputIndex: index }),
body: JSON.stringify({ inputId: index }),
});
setProgramInput(index);
};

const setPreview = async (index: number) => {
await fetch(API_BASE + "/preview", {
method: "post",
method: "put",
credentials: "include",
headers: { "content-type": "application/json" },
body: JSON.stringify({ inputIndex: index }),
body: JSON.stringify({ inputId: index }),
});
setPreviewInput(index);
};
Expand Down
57 changes: 30 additions & 27 deletions src/MonitoringStream.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,46 @@
import React, { useEffect, useRef, useState } from "react";
import { useEffect, useRef } from "react";
import JSMpeg from "@cycjimmy/jsmpeg-player";

export const MonitoringStream = () => {
const [videoElement, setVideoElement] = useState<
JSMpeg.VideoElement | undefined
>(undefined);
export const MonitoringStream = ({ muted }: { muted: boolean }) => {
const playerRef = useRef<JSMpeg.VideoElement | null>(null);
const containerRef = useRef<HTMLDivElement>(null);

useEffect(() => {
console.log({ muted });
if (!playerRef.current) return;
playerRef.current.player.setVolume(muted ? 0 : 1);
}, [muted]);

if (!import.meta.env.VITE_STREAM_URL?.length)
return <div>Error: VITE_STREAM_URL not set</div>;

useEffect(() => {
if (containerRef.current == null) return;

if (!videoElement)
setVideoElement(
new JSMpeg.VideoElement(
containerRef.current,
import.meta.env.VITE_STREAM_URL || "",
{
videoBufferSize: 512 * 1024 * 20,
audioBufferSize: 128 * 1024 * 20,
}
)
const timer = setTimeout(() => {
if (playerRef.current != null) return;
if (containerRef.current == null) return;

playerRef.current = new JSMpeg.VideoElement(
containerRef.current,
import.meta.env.VITE_STREAM_URL || "",
{
videoBufferSize: 512 * 1024 * 20,
audioBufferSize: 128 * 1024 * 20,
}
);
playerRef.current.player.setVolume(muted ? 0 : 1);
}, 100);

return () => {
videoElement?.destroy();
clearTimeout(timer);
if (playerRef.current == null) return;
playerRef.current.destroy();
playerRef.current = null;
};
}, [videoElement]);

const toggleMute = () => {
if (!videoElement?.player) return;

const { player } = videoElement;
player.setVolume(player.getVolume() > 0 ? 0 : 1);
};
}, []);

return (
<div className={"aspect-video"} ref={containerRef} onClick={toggleMute} />
<div className={"aspect-video"}>
<div ref={containerRef} className="w-full h-full" />
</div>
);
};
53 changes: 53 additions & 0 deletions src/MuteIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
export const MuteIcon = ({ className }: { className?: string }) => {
return (
<svg
height={"1em"}
className={className}
enable-background="new 0
0 50 50"
id="Layer_1"
version="1.1"
viewBox="-3 0 50 50"
xmlSpace="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
>
<line
fill="none"
strokeLinecap="round"
strokeMiterlimit="10"
strokeWidth="2"
x1="32"
x2="42"
y1="20"
y2="30"
/>
<line
fill="none"
strokeLinecap="round"
strokeMiterlimit="10"
strokeWidth="2"
x1="42"
x2="32"
y1="20"
y2="30"
/>
<path
d="M10,33H3 c-1.103,0-2-0.898-2-2V19c0-1.102,0.897-2,2-2h7"
fill="none"
stroke-linejoin="round"
strokeMiterlimit="10"
strokeWidth="2.08"
/>
<path
d="M9.604,32.43
C9.256,32.129,9,31.391,9,30.754V19.247c0-0.637,0.256-1.388,0.604-1.689L22.274,4.926C23.905,3.27,26,3.898,26,6.327v36.988
c0,2.614-1.896,3.604-3.785,1.686L9.604,32.43z"
fill="none"
stroke-linejoin="round"
strokeMiterlimit="10"
strokeWidth="1.9797"
/>
</svg>
);
};
Loading

0 comments on commit 4bf46bb

Please sign in to comment.