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)
const message = text(cfg.message)
const stream = text(cfg.stream_url)
const live = useBoundValue(message || undefined)
const value = live?.value
const ref = isRef(value) ? value : null
const url = useArtifactUrl(ref, message || undefined)
const kind = (ref?.media_type ?? text(cfg.dtype)).split("/")[0]
const fit = text(cfg.fit) === "contain" ? "object-contain" : "object-cover"
const label = widget.title || ref?.name || message
// 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 (
)
}
if (!message && !stream) {
return
Pick a message.
} if (!ref) { returnNothing published yet.
} if (!url) { returnLoading…
} if (kind === "audio") { return ( ) } if (kind === "video") { return ( ) } return (