Skip to content

Instantly share code, notes, and snippets.

@jamsea
Last active April 9, 2024 06:40
Show Gist options
  • Save jamsea/c617274305228d7fc98b5369df6120a2 to your computer and use it in GitHub Desktop.
Save jamsea/c617274305228d7fc98b5369df6120a2 to your computer and use it in GitHub Desktop.
VCS test
import * as React from "react";
import { Box, Video } from "#vcs-react/components";
import { useGrid } from "#vcs-react/hooks";
import * as layoutFuncs from "../layouts.js";
import VideoSingle from "./VideoSingle.js";
import decorateVideoSplitItem from "./overrides/decorateVideoSplitItem.js";
import { PositionCorner } from "../constants.js";
import { debug } from "#vcs-stdlib/components";
import { RoomContext } from "#vcs-react/contexts";
const textSize_gu = 1;
const headerH_gu = textSize_gu * 10;
function body(parentFrame, params, layoutCtx) {
let { x, y, w, h } = parentFrame;
const pxPerGu = layoutCtx.pixelsPerGridUnit;
const headerH_px = headerH_gu * pxPerGu;
y += headerH_px;
h -= headerH_px;
return { x, y, w, h };
}
export default function AugmentedSplit(props) {
const { participantDescs = [] } = props;
const base = <VideoSplit {...props} />;
let pipOverlay;
if (participantDescs.length > 2) {
pipOverlay = <SimplePip participant={participantDescs[2]} />;
}
let otherOverlays;
if (participantDescs.length > 3) {
otherOverlays = <PipRow participantDescs={participantDescs.slice(3)} />;
}
const room = React.useContext(RoomContext);
return (
<Box>
{base}
{pipOverlay}
{otherOverlays}
<debug.RoomPrintout layout={[body]} room={room} bgOpacity={0.5} headerTextColor="rgba(255, 255, 255, 0.68)" textSize_gu={1} />
</Box>
);
}
// a simple picture-in-picture with hardcoded settings
// using the same layout function as VideoPip.js
//
function SimplePip({ participant }) {
const { videoId, displayName = "", paused } = participant;
const pxPerGu = useGrid().pixelsPerGridUnit;
const pipSize_gu = 10;
const layoutProps = {
positionCorner: PositionCorner.TOP_RIGHT,
aspectRatio: 1,
height_gu: pipSize_gu,
margin_gu: 2,
};
const layout = [layoutFuncs.pip, layoutProps];
const videoStyle = {
cornerRadius_px: (pipSize_gu / 2) * pxPerGu, // mask to circle
};
const outlineStyle = {
...videoStyle,
strokeWidth_px: pxPerGu / 3, // the outline for the video
strokeColor: "white",
};
return (
<Box id="pipOutline" style={outlineStyle} layout={layout}>
<Video id="pipVideo" src={videoId} scaleMode="fill" style={videoStyle} />
</Box>
);
}
// a row of picture-in-picture videos, using an inline layout function
//
function PipRow({ participantDescs }) {
const pxPerGu = useGrid().pixelsPerGridUnit;
const pipSize_gu = 6;
const margin_gu = 2;
const interval_gu = 1;
const videoStyle = {
cornerRadius_px: (pipSize_gu / 2) * pxPerGu, // mask to circle
};
const outlineStyle = {
...videoStyle,
strokeWidth_px: 2, // the outline for the video
strokeColor: "rgba(255, 255, 210, 0.9)",
};
function rowLayoutFn(parentFrame, params) {
const { idx } = params;
let { x, y, w, h } = parentFrame;
const margin = margin_gu * pxPerGu;
const interval = interval_gu * pxPerGu;
w = h = pipSize_gu * pxPerGu;
x += margin + (interval + w) * idx;
y += parentFrame.h - margin - h;
return { x, y, w, h };
}
return participantDescs.map((pd, idx) => {
const { videoId } = pd;
return (
<Box key={idx} style={outlineStyle} layout={[rowLayoutFn, { idx }]}>
<Video src={videoId} scaleMode="fill" style={videoStyle} />
</Box>
);
});
}
// this is the original VideoSplit function from the baseline composition
//
function VideoSplit(props) {
const { participantDescs = [], margin_gu = 0, splitDirection } = props;
// Make sure we have exactly one or two boxes
const totalItems = Math.max(1, Math.min(participantDescs.length, 2));
let layoutFn;
switch (splitDirection) {
default:
layoutFn = layoutFuncs.splitAcrossLongerDimension;
break;
case "horizontal":
layoutFn = layoutFuncs.splitHorizontal;
break;
case "vertical":
layoutFn = layoutFuncs.splitVertical;
break;
}
function makeItem(itemIdx) {
const key = "videosplit_item" + itemIdx;
const participant = participantDescs[itemIdx];
// override point for custom decorations on split videos.
// we use a VideoSingle component to actually render these,
// so get the decoration here and pass it as an override to VideoSingle.
const overrideDecoration = decorateVideoSplitItem(
itemIdx,
participant,
props
);
return (
<Box
key={key}
id={key}
layout={[layoutFn, { index: itemIdx, margin_gu, pos: 1 / totalItems }]}
>
<VideoSingle
enableParticipantOverride={true}
overrideParticipant={participant}
overrideDecoration={overrideDecoration}
{...props}
/>
</Box>
);
}
if (totalItems === 1) {
return <Box id="videosplit">{[makeItem(0)]}</Box>;
} else {
return <Box id="videosplit">{[makeItem(0), makeItem(1)]}</Box>;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment