import { useRef } from "react" import { useOnScreen } from "@/hooks/useOnScreen" import { isRef, useArtifactUrl } from "@/lib/media" import { cn } from "@/lib/utils" import { useBoundValue } from "./dataContext" import { config, text } from "./ui/core/config" import type { WidgetProps } from "./widgets" /** * What a message's bytes look like: a frame, a clip, a segment. * * Media never travels as a message — the reference does. The bytes come down * the socket in front of it where the engine is holding the frame in memory, * and are fetched from the artifact store otherwise; either way this tile only * asks for what it is drawing. A camera serving its own stream is still played * from source: point `stream_url` at it and the browser does the work. */ export function MediaWidget({ widget }: WidgetProps) { const cfg = config(widget) return ( ) } /** * The tile's body, for anywhere a message's media is shown. * * Frames are asked for only while the tile is on screen, in a tab being * looked at: a camera is only sent while somebody watches it, and a tile * scrolled away or behind another tab is nobody. A clip keeps playing either * way. */ export function MediaView({ message, stream = "", dtype = "", fit = "cover", autoplay = false, label, }: { message: string stream?: string dtype?: string fit?: "cover" | "contain" autoplay?: boolean label?: string }) { const box = useRef(null) const shown = useOnScreen(box) const live = useBoundValue(message || undefined) const value = live?.value const ref = isRef(value) ? value : null const kind = (ref?.media_type ?? dtype).split("/")[0] const playing = kind === "audio" || kind === "video" const active = shown || playing const url = useArtifactUrl( active ? ref : null, active ? message || undefined : undefined, ) const objectFit = fit === "contain" ? "object-contain" : "object-cover" const alt = label || ref?.name || message return (
{body()}
) function body() { // A camera serving its own stream is played from source: the engine // carries references at whatever rate the flow publishes them, which is // not video. if (stream && kind !== "audio") { return ( {alt} ) } if (!message && !stream) { return

Pick a message.

} if (!ref) { return

Nothing published yet.

} if (!url) { return

Loading…

} if (kind === "audio") { return ( ) } if (kind === "video") { return ( ) } return ( {alt} ) } }