@daydreamlive/react 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +29 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +267 -20
- package/dist/index.d.ts +267 -20
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -1
- package/package.json +10 -4
package/dist/index.cjs
CHANGED
|
@@ -20,7 +20,19 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
BaseDaydreamError: () => import_browser3.BaseDaydreamError,
|
|
24
|
+
Broadcast: () => import_browser5.Broadcast,
|
|
23
25
|
CompositorProvider: () => CompositorProvider,
|
|
26
|
+
ConnectionError: () => import_browser3.ConnectionError,
|
|
27
|
+
DEFAULT_AUDIO_BITRATE: () => import_browser4.DEFAULT_AUDIO_BITRATE,
|
|
28
|
+
DEFAULT_ICE_SERVERS: () => import_browser4.DEFAULT_ICE_SERVERS,
|
|
29
|
+
DEFAULT_VIDEO_BITRATE: () => import_browser4.DEFAULT_VIDEO_BITRATE,
|
|
30
|
+
NetworkError: () => import_browser3.NetworkError,
|
|
31
|
+
Player: () => import_browser5.Player,
|
|
32
|
+
StreamNotFoundError: () => import_browser3.StreamNotFoundError,
|
|
33
|
+
UnauthorizedError: () => import_browser3.UnauthorizedError,
|
|
34
|
+
createCompositor: () => import_browser5.createCompositor,
|
|
35
|
+
livepeerResponseHandler: () => import_browser5.livepeerResponseHandler,
|
|
24
36
|
useBroadcast: () => useBroadcast2,
|
|
25
37
|
useCompositor: () => useCompositor,
|
|
26
38
|
usePlayer: () => usePlayer2,
|
|
@@ -233,6 +245,11 @@ function usePlayer(options, factory) {
|
|
|
233
245
|
};
|
|
234
246
|
}
|
|
235
247
|
|
|
248
|
+
// src/index.ts
|
|
249
|
+
var import_browser3 = require("@daydreamlive/browser");
|
|
250
|
+
var import_browser4 = require("@daydreamlive/browser");
|
|
251
|
+
var import_browser5 = require("@daydreamlive/browser");
|
|
252
|
+
|
|
236
253
|
// src/useCompositor.tsx
|
|
237
254
|
var import_react3 = require("react");
|
|
238
255
|
var import_browser = require("@daydreamlive/browser");
|
|
@@ -430,7 +447,19 @@ function usePlayer2(options) {
|
|
|
430
447
|
}
|
|
431
448
|
// Annotate the CommonJS export names for ESM import in node:
|
|
432
449
|
0 && (module.exports = {
|
|
450
|
+
BaseDaydreamError,
|
|
451
|
+
Broadcast,
|
|
433
452
|
CompositorProvider,
|
|
453
|
+
ConnectionError,
|
|
454
|
+
DEFAULT_AUDIO_BITRATE,
|
|
455
|
+
DEFAULT_ICE_SERVERS,
|
|
456
|
+
DEFAULT_VIDEO_BITRATE,
|
|
457
|
+
NetworkError,
|
|
458
|
+
Player,
|
|
459
|
+
StreamNotFoundError,
|
|
460
|
+
UnauthorizedError,
|
|
461
|
+
createCompositor,
|
|
462
|
+
livepeerResponseHandler,
|
|
434
463
|
useBroadcast,
|
|
435
464
|
useCompositor,
|
|
436
465
|
usePlayer,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/useBroadcast.ts","../src/usePlayer.ts","../src/useCompositor.tsx","../src/useSource.ts"],"sourcesContent":["import { createBroadcast, createPlayer } from \"@daydreamlive/browser\";\nimport {\n useBroadcast as baseUseBroadcast,\n type UseBroadcastOptions,\n type UseBroadcastReturn,\n type UseBroadcastStatus,\n} from \"./useBroadcast\";\nimport {\n usePlayer as baseUsePlayer,\n type UsePlayerOptions,\n type UsePlayerReturn,\n type UsePlayerStatus,\n} from \"./usePlayer\";\n\nexport function useBroadcast(options: UseBroadcastOptions): UseBroadcastReturn {\n return baseUseBroadcast(options, createBroadcast);\n}\n\nexport function usePlayer(options: UsePlayerOptions): UsePlayerReturn {\n return baseUsePlayer(options, createPlayer);\n}\n\nexport type {\n UseBroadcastOptions,\n UseBroadcastReturn,\n UseBroadcastStatus,\n UsePlayerOptions,\n UsePlayerReturn,\n UsePlayerStatus,\n};\n\nexport type {\n AudioConfig,\n BroadcastState,\n PlayerState,\n ReconnectConfig,\n ReconnectInfo,\n VideoConfig,\n DaydreamError,\n DaydreamErrorCode,\n // Compositor types\n Compositor,\n CompositorOptions,\n CompositorEvent,\n CompositorEventMap,\n Source,\n VideoSource,\n CanvasSource,\n Size,\n FitMode,\n ContentHint,\n Ctx2D,\n} from \"@daydreamlive/browser\";\n\nexport {\n CompositorProvider,\n useCompositor,\n type CompositorApi,\n type CompositorProviderProps,\n} from \"./useCompositor\";\n\nexport {\n useSource,\n type UseSourceOptions,\n type UseSourceReturn,\n} from \"./useSource\";\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type {\n AudioConfig,\n Broadcast,\n BroadcastOptions,\n BroadcastState,\n DaydreamError,\n ReconnectConfig,\n ReconnectInfo,\n VideoConfig,\n} from \"@daydreamlive/browser\";\n\nexport interface UseBroadcastOptions {\n whipUrl: string;\n reconnect?: ReconnectConfig;\n video?: VideoConfig;\n audio?: AudioConfig;\n iceServers?: RTCIceServer[];\n connectionTimeout?: number;\n onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n}\n\nexport type BroadcastFactory = (options: BroadcastOptions) => Broadcast;\n\nexport type UseBroadcastStatus =\n | { state: \"idle\" }\n | { state: \"connecting\" }\n | { state: \"live\"; whepUrl: string }\n | { state: \"reconnecting\"; whepUrl: string; reconnectInfo: ReconnectInfo }\n | { state: \"ended\" }\n | { state: \"error\"; error: DaydreamError };\n\nexport interface UseBroadcastReturn {\n status: UseBroadcastStatus;\n start: (stream: MediaStream) => Promise<void>;\n stop: () => Promise<void>;\n setMaxFramerate: (fps?: number) => void;\n}\n\nexport function useBroadcast(\n options: UseBroadcastOptions,\n factory: BroadcastFactory,\n): UseBroadcastReturn {\n const [status, setStatus] = useState<UseBroadcastStatus>({ state: \"idle\" });\n const broadcastRef = useRef<Broadcast | null>(null);\n const whepUrlRef = useRef<string | null>(null);\n const optionsRef = useRef(options);\n const factoryRef = useRef(factory);\n\n useEffect(() => {\n optionsRef.current = options;\n }, [options]);\n\n useEffect(() => {\n factoryRef.current = factory;\n }, [factory]);\n\n useEffect(() => {\n return () => {\n broadcastRef.current?.stop();\n };\n }, []);\n\n const updateStatus = useCallback((newState: BroadcastState, error?: DaydreamError) => {\n const whepUrl = whepUrlRef.current;\n switch (newState) {\n case \"connecting\":\n setStatus({ state: \"connecting\" });\n break;\n case \"live\":\n setStatus({ state: \"live\", whepUrl: whepUrl! });\n break;\n case \"reconnecting\":\n // reconnectInfo will be set by the reconnect event\n break;\n case \"ended\":\n setStatus({ state: \"ended\" });\n break;\n case \"error\":\n setStatus({ state: \"error\", error: error! });\n break;\n }\n }, []);\n\n const start = useCallback(async (stream: MediaStream) => {\n if (broadcastRef.current) {\n await broadcastRef.current.stop();\n broadcastRef.current = null;\n }\n\n setStatus({ state: \"connecting\" });\n\n const broadcast = factoryRef.current({\n stream,\n ...optionsRef.current,\n });\n\n broadcastRef.current = broadcast;\n\n broadcast.on(\"stateChange\", (newState) => {\n // Guard against events from stopped broadcast\n if (broadcastRef.current !== broadcast) return;\n if (newState === \"live\" || newState === \"reconnecting\") {\n whepUrlRef.current = broadcast.whepUrl;\n }\n updateStatus(newState);\n });\n\n broadcast.on(\"error\", (err) => {\n if (broadcastRef.current !== broadcast) return;\n updateStatus(\"error\", err);\n });\n\n broadcast.on(\"reconnect\", (info) => {\n if (broadcastRef.current !== broadcast) return;\n setStatus({\n state: \"reconnecting\",\n whepUrl: whepUrlRef.current!,\n reconnectInfo: info,\n });\n });\n\n try {\n await broadcast.connect();\n if (broadcastRef.current !== broadcast) return;\n whepUrlRef.current = broadcast.whepUrl;\n updateStatus(broadcast.state);\n } catch (err) {\n if (broadcastRef.current !== broadcast) return;\n setStatus({ state: \"error\", error: err as DaydreamError });\n throw err;\n }\n }, [updateStatus]);\n\n const stop = useCallback(async () => {\n await broadcastRef.current?.stop();\n broadcastRef.current = null;\n whepUrlRef.current = null;\n setStatus({ state: \"idle\" });\n }, []);\n\n const setMaxFramerate = useCallback((fps?: number) => {\n broadcastRef.current?.setMaxFramerate(fps);\n }, []);\n\n return {\n status,\n start,\n stop,\n setMaxFramerate,\n };\n}\n","import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type RefObject,\n} from \"react\";\nimport type {\n Player,\n PlayerOptions,\n PlayerState,\n DaydreamError,\n ReconnectConfig,\n ReconnectInfo,\n} from \"@daydreamlive/browser\";\n\nexport interface UsePlayerOptions {\n whepUrl: string | null;\n reconnect?: ReconnectConfig;\n iceServers?: RTCIceServer[];\n connectionTimeout?: number;\n skipIceGathering?: boolean;\n autoPlay?: boolean;\n onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n}\n\nexport type PlayerFactory = (\n whepUrl: string,\n options?: PlayerOptions,\n) => Player;\n\nexport type UsePlayerStatus =\n | { state: \"idle\" }\n | { state: \"connecting\" }\n | { state: \"playing\" }\n | { state: \"buffering\"; reconnectInfo: ReconnectInfo }\n | { state: \"ended\" }\n | { state: \"error\"; error: DaydreamError };\n\nexport interface UsePlayerReturn {\n status: UsePlayerStatus;\n play: () => Promise<void>;\n stop: () => Promise<void>;\n videoRef: RefObject<HTMLVideoElement | null>;\n}\n\nexport function usePlayer(\n options: UsePlayerOptions,\n factory: PlayerFactory,\n): UsePlayerReturn {\n const [status, setStatus] = useState<UsePlayerStatus>({ state: \"idle\" });\n const playerRef = useRef<Player | null>(null);\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const optionsRef = useRef(options);\n const factoryRef = useRef(factory);\n\n useEffect(() => {\n optionsRef.current = options;\n }, [options]);\n\n useEffect(() => {\n factoryRef.current = factory;\n }, [factory]);\n\n useEffect(() => {\n return () => {\n playerRef.current?.stop();\n };\n }, []);\n\n const updateStatus = useCallback(\n (newState: PlayerState, error?: DaydreamError) => {\n switch (newState) {\n case \"connecting\":\n setStatus({ state: \"connecting\" });\n break;\n case \"playing\":\n setStatus({ state: \"playing\" });\n break;\n case \"buffering\":\n // reconnectInfo will be set by the reconnect event\n break;\n case \"ended\":\n setStatus({ state: \"ended\" });\n break;\n case \"error\":\n setStatus({ state: \"error\", error: error! });\n break;\n }\n },\n [],\n );\n\n const play = useCallback(async () => {\n const currentWhepUrl = optionsRef.current.whepUrl;\n if (!currentWhepUrl) {\n return;\n }\n\n if (playerRef.current) {\n await playerRef.current.stop();\n playerRef.current = null;\n }\n\n setStatus({ state: \"connecting\" });\n\n const player = factoryRef.current(currentWhepUrl, {\n reconnect: optionsRef.current?.reconnect,\n iceServers: optionsRef.current?.iceServers,\n connectionTimeout: optionsRef.current?.connectionTimeout,\n skipIceGathering: optionsRef.current?.skipIceGathering,\n onStats: optionsRef.current?.onStats,\n statsIntervalMs: optionsRef.current?.statsIntervalMs,\n });\n\n playerRef.current = player;\n\n player.on(\"stateChange\", (newState) => {\n // Guard against events from stopped player\n if (playerRef.current !== player) return;\n updateStatus(newState);\n // Re-attach stream after reconnect\n if (newState === \"playing\" && videoRef.current && player.stream) {\n if (videoRef.current.srcObject !== player.stream) {\n player.attachTo(videoRef.current);\n }\n }\n });\n\n player.on(\"error\", (err) => {\n if (playerRef.current !== player) return;\n updateStatus(\"error\", err);\n });\n\n player.on(\"reconnect\", (info) => {\n if (playerRef.current !== player) return;\n setStatus({ state: \"buffering\", reconnectInfo: info });\n });\n\n try {\n await player.connect();\n if (playerRef.current !== player) return;\n updateStatus(player.state);\n\n if (videoRef.current) {\n player.attachTo(videoRef.current);\n if (optionsRef.current?.autoPlay !== false) {\n try {\n await videoRef.current.play();\n } catch {\n // Autoplay blocked\n }\n }\n }\n } catch (err) {\n if (playerRef.current !== player) return;\n setStatus({ state: \"error\", error: err as DaydreamError });\n throw err;\n }\n }, [updateStatus]);\n\n const stop = useCallback(async () => {\n await playerRef.current?.stop();\n playerRef.current = null;\n setStatus({ state: \"idle\" });\n }, []);\n\n return {\n status,\n play,\n stop,\n videoRef,\n };\n}\n","\"use client\";\n\nimport {\n createContext,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type PropsWithChildren,\n} from \"react\";\nimport {\n createCompositor,\n type Compositor,\n type CompositorOptions,\n type Size,\n type Source,\n} from \"@daydreamlive/browser\";\n\nexport interface CompositorApi {\n // Registry\n register(id: string, source: Source): void;\n unregister(id: string): void;\n get(id: string): Source | undefined;\n has(id: string): boolean;\n list(): Array<{ id: string; source: Source }>;\n\n /**\n * Register a source, activate it, and return an unregister function.\n * Convenience method that combines register + activate with automatic cleanup.\n *\n * @example\n * ```tsx\n * useEffect(() => {\n * const unregister = compositor.use(\"camera\", {\n * kind: \"video\",\n * element: videoRef.current,\n * fit: \"cover\",\n * });\n * return unregister;\n * }, [compositor]);\n * ```\n */\n use(id: string, source: Source): () => void;\n\n // Active source\n /**\n * Activate a registered source.\n * @param id - The source ID to activate\n */\n activate(id: string): void;\n deactivate(): void;\n readonly activeId: string | null;\n\n // Output (reactive)\n readonly stream: MediaStream | null;\n readonly size: Size;\n setSize(width: number, height: number, dpr?: number): void;\n\n // FPS (reactive)\n readonly fps: number;\n setFps(fps: number): void;\n readonly sendFps: number;\n setSendFps(fps: number): void;\n\n // Audio\n addAudioTrack(track: MediaStreamTrack): void;\n removeAudioTrack(trackId: string): void;\n unlockAudio(): Promise<boolean>;\n\n // Events\n on: Compositor[\"on\"];\n}\n\nconst CompositorContext = createContext<CompositorApi | null>(null);\n\nexport interface CompositorProviderProps\n extends PropsWithChildren,\n Partial<Omit<CompositorOptions, \"onSendFpsChange\">> {}\n\nexport function CompositorProvider({\n children,\n width = 512,\n height = 512,\n fps: initialFps = 30,\n sendFps: initialSendFps,\n dpr,\n keepalive,\n autoUnlockAudio,\n unlockEvents,\n disableSilentAudio = true,\n}: CompositorProviderProps) {\n const compositorRef = useRef<Compositor | null>(null);\n const [stream, setStream] = useState<MediaStream | null>(null);\n const [size, setSize] = useState<Size>({\n width,\n height,\n dpr: Math.min(\n 2,\n dpr ?? (typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1),\n ),\n });\n const [fps, setFpsState] = useState(initialFps);\n const [sendFps, setSendFpsState] = useState(initialSendFps ?? initialFps);\n\n // Create compositor once\n useLayoutEffect(() => {\n const compositor = createCompositor({\n width,\n height,\n fps: initialFps,\n sendFps: initialSendFps,\n dpr,\n keepalive,\n autoUnlockAudio,\n unlockEvents,\n disableSilentAudio,\n onSendFpsChange: (newFps) => setSendFpsState(newFps),\n });\n\n compositorRef.current = compositor;\n setStream(compositor.stream);\n setSize(compositor.size);\n\n return () => {\n compositor.destroy();\n compositorRef.current = null;\n };\n }, []);\n\n // Sync size changes\n useEffect(() => {\n const compositor = compositorRef.current;\n if (!compositor) return;\n\n compositor.resize(size.width, size.height, size.dpr);\n setStream(compositor.stream);\n }, [size.width, size.height, size.dpr]);\n\n // Sync fps changes\n useEffect(() => {\n const compositor = compositorRef.current;\n if (!compositor) return;\n\n compositor.setFps(fps);\n setStream(compositor.stream);\n }, [fps]);\n\n // Sync sendFps changes\n useEffect(() => {\n const compositor = compositorRef.current;\n if (!compositor) return;\n\n compositor.setSendFps(sendFps);\n }, [sendFps]);\n\n // Memoized API\n const api = useMemo<CompositorApi>(\n () => ({\n // Registry\n register: (id, source) => compositorRef.current?.register(id, source),\n unregister: (id) => compositorRef.current?.unregister(id),\n get: (id) => compositorRef.current?.get(id),\n has: (id) => compositorRef.current?.has(id) ?? false,\n list: () => compositorRef.current?.list() ?? [],\n use: (id, source) => {\n compositorRef.current?.register(id, source);\n compositorRef.current?.activate(id);\n return () => compositorRef.current?.unregister(id);\n },\n\n // Active source\n activate: (id) => compositorRef.current?.activate(id),\n deactivate: () => compositorRef.current?.deactivate(),\n get activeId() {\n return compositorRef.current?.activeId ?? null;\n },\n\n // Stream & size\n stream,\n size,\n setSize: (w, h, d) =>\n setSize({ width: w, height: h, dpr: d ?? size.dpr }),\n\n // FPS\n fps,\n setFps: setFpsState,\n sendFps,\n setSendFps: setSendFpsState,\n\n // Audio\n addAudioTrack: (t) => compositorRef.current?.addAudioTrack(t),\n removeAudioTrack: (id) => compositorRef.current?.removeAudioTrack(id),\n unlockAudio: () =>\n compositorRef.current?.unlockAudio() ?? Promise.resolve(false),\n\n // Events\n on: (event, cb) => compositorRef.current?.on(event, cb) ?? (() => {}),\n }),\n [stream, size, fps, sendFps],\n );\n\n return (\n <CompositorContext.Provider value={api}>\n {children}\n </CompositorContext.Provider>\n );\n}\n\nexport function useCompositor(): CompositorApi {\n const ctx = useContext(CompositorContext);\n if (!ctx) {\n throw new Error(\"useCompositor must be used within <CompositorProvider>\");\n }\n return ctx;\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState, useCallback, useMemo } from \"react\";\nimport type { Source, FitMode, ContentHint } from \"@daydreamlive/browser\";\nimport { useCompositor } from \"./useCompositor\";\n\nexport interface UseSourceOptions {\n kind: \"video\" | \"canvas\";\n contentHint?: ContentHint;\n fit?: FitMode;\n}\n\nexport interface UseSourceReturn<\n T extends HTMLVideoElement | HTMLCanvasElement,\n> {\n ref: React.RefObject<T>;\n isActive: boolean;\n activate: () => void;\n deactivate: () => void;\n}\n\nexport function useSource<\n T extends HTMLVideoElement | HTMLCanvasElement =\n | HTMLVideoElement\n | HTMLCanvasElement,\n>(id: string, options: UseSourceOptions): UseSourceReturn<T> {\n const compositor = useCompositor();\n const compositorRef = useRef(compositor);\n compositorRef.current = compositor;\n\n const ref = useRef<T>(null);\n const [isActive, setIsActive] = useState(false);\n const registeredRef = useRef(false);\n const idRef = useRef(id);\n idRef.current = id;\n\n const { kind, contentHint, fit } = options;\n\n const optionsRef = useRef({ kind, contentHint, fit });\n optionsRef.current = { kind, contentHint, fit };\n\n const registerSource = useCallback((element: T) => {\n const { kind, contentHint, fit } = optionsRef.current;\n const source =\n kind === \"video\"\n ? {\n kind: \"video\" as const,\n element: element as HTMLVideoElement,\n contentHint,\n fit,\n }\n : {\n kind: \"canvas\" as const,\n element: element as HTMLCanvasElement,\n contentHint,\n };\n\n compositorRef.current.register(idRef.current, source);\n registeredRef.current = true;\n }, []);\n\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n registerSource(element);\n }, [id, kind, contentHint, fit, registerSource]);\n\n useEffect(() => {\n const currentId = id;\n return () => {\n if (registeredRef.current) {\n registeredRef.current = false;\n setIsActive(false);\n compositorRef.current.unregister(currentId);\n }\n };\n }, [id]);\n\n useEffect(() => {\n setIsActive(compositor.activeId === id);\n }, [compositor.activeId, id]);\n\n const activate = useCallback(() => {\n const element = ref.current;\n if (!element) return;\n\n if (!registeredRef.current) {\n registerSource(element);\n }\n\n compositorRef.current.activate(idRef.current);\n setIsActive(true);\n }, [registerSource]);\n\n const deactivate = useCallback(() => {\n if (compositorRef.current.activeId === idRef.current) {\n compositorRef.current.deactivate();\n setIsActive(false);\n }\n }, []);\n\n return useMemo(\n () => ({\n ref,\n isActive,\n activate,\n deactivate,\n }),\n [isActive, activate, deactivate],\n );\n}\n"],"mappings":"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","names":["useBroadcast","usePlayer","import_browser","import_react","import_react","import_react","kind","contentHint","fit","useBroadcast","usePlayer"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/useBroadcast.ts","../src/usePlayer.ts","../src/useCompositor.tsx","../src/useSource.ts"],"sourcesContent":["/**\n * @daydreamlive/react - React hooks and components for WebRTC broadcasting and playback.\n *\n * @example\n * ```tsx\n * import { useBroadcast, usePlayer, CompositorProvider, useCompositor, useSource } from \"@daydreamlive/react\";\n *\n * // Broadcasting\n * const { status, start, stop } = useBroadcast({ whipUrl: \"...\" });\n *\n * // Playback\n * const { status, play, videoRef } = usePlayer({ whepUrl: \"...\" });\n *\n * // Compositor with React\n * <CompositorProvider width={1280} height={720}>\n * <SourceComponent />\n * </CompositorProvider>\n * ```\n *\n * @packageDocumentation\n */\n\nimport { createBroadcast, createPlayer } from \"@daydreamlive/browser\";\nimport {\n useBroadcast as baseUseBroadcast,\n type UseBroadcastOptions,\n type UseBroadcastReturn,\n type UseBroadcastStatus,\n} from \"./useBroadcast\";\nimport {\n usePlayer as baseUsePlayer,\n type UsePlayerOptions,\n type UsePlayerReturn,\n type UsePlayerStatus,\n} from \"./usePlayer\";\n\n/**\n * React hook for managing a WebRTC broadcast session.\n *\n * @param options - Broadcast configuration including WHIP URL\n * @returns Broadcast status and control functions\n *\n * @example\n * ```tsx\n * function BroadcastComponent() {\n * const { status, start, stop } = useBroadcast({\n * whipUrl: \"https://livepeer.studio/webrtc/...\",\n * });\n *\n * const handleStart = async () => {\n * const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });\n * await start(stream);\n * };\n *\n * return (\n * <div>\n * <p>Status: {status.state}</p>\n * {status.state === \"live\" && <p>Playback URL: {status.whepUrl}</p>}\n * <button onClick={status.state === \"idle\" ? handleStart : stop}>\n * {status.state === \"idle\" ? \"Start\" : \"Stop\"}\n * </button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useBroadcast(options: UseBroadcastOptions): UseBroadcastReturn {\n return baseUseBroadcast(options, createBroadcast);\n}\n\n/**\n * React hook for managing a WebRTC playback session.\n *\n * @param options - Player configuration including WHEP URL\n * @returns Player status, control functions, and video element ref\n *\n * @example\n * ```tsx\n * function PlayerComponent({ whepUrl }) {\n * const { status, play, stop, videoRef } = usePlayer({\n * whepUrl,\n * autoPlay: true,\n * });\n *\n * useEffect(() => {\n * if (whepUrl) play();\n * }, [whepUrl, play]);\n *\n * return (\n * <div>\n * <video ref={videoRef} autoPlay muted playsInline />\n * <p>Status: {status.state}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function usePlayer(options: UsePlayerOptions): UsePlayerReturn {\n return baseUsePlayer(options, createPlayer);\n}\n\nexport type {\n UseBroadcastOptions,\n UseBroadcastReturn,\n UseBroadcastStatus,\n UsePlayerOptions,\n UsePlayerReturn,\n UsePlayerStatus,\n};\n\nexport {\n BaseDaydreamError,\n NetworkError,\n ConnectionError,\n StreamNotFoundError,\n UnauthorizedError,\n} from \"@daydreamlive/browser\";\n\nexport {\n DEFAULT_ICE_SERVERS,\n DEFAULT_VIDEO_BITRATE,\n DEFAULT_AUDIO_BITRATE,\n} from \"@daydreamlive/browser\";\n\nexport {\n createCompositor,\n livepeerResponseHandler,\n Broadcast,\n Player,\n} from \"@daydreamlive/browser\";\n\nexport type {\n AudioConfig,\n BroadcastState,\n BroadcastOptions,\n BroadcastConfig,\n BroadcastEventMap,\n LivepeerBroadcastOptions,\n VideoConfig,\n WHIPResponseResult,\n PlayerState,\n PlayerOptions,\n PlayerConfig,\n PlayerEventMap,\n ReconnectConfig,\n ReconnectInfo,\n DaydreamError,\n DaydreamErrorCode,\n // Compositor types\n Compositor,\n CompositorOptions,\n CompositorEvent,\n CompositorEventMap,\n Source,\n VideoSource,\n CanvasSource,\n Size,\n FitMode,\n ContentHint,\n Ctx2D,\n} from \"@daydreamlive/browser\";\n\nexport {\n CompositorProvider,\n useCompositor,\n type CompositorApi,\n type CompositorProviderProps,\n} from \"./useCompositor\";\n\nexport {\n useSource,\n type UseSourceOptions,\n type UseSourceReturn,\n} from \"./useSource\";\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type {\n Broadcast,\n BroadcastOptions,\n BroadcastState,\n DaydreamError,\n ReconnectInfo,\n} from \"@daydreamlive/browser\";\n\n/**\n * Options for the useBroadcast hook.\n * Same as BroadcastOptions but without `stream` (passed to `start()`) and `onResponse` (pre-configured).\n */\nexport type UseBroadcastOptions = Omit<BroadcastOptions, \"stream\" | \"onResponse\">;\n\n/**\n * Factory function type for creating Broadcast instances.\n * @internal\n */\nexport type BroadcastFactory = (options: BroadcastOptions) => Broadcast;\n\n/**\n * Status returned by the useBroadcast hook.\n * Discriminated union based on the `state` property.\n *\n * @example\n * ```tsx\n * const { status } = useBroadcast({ whipUrl });\n *\n * if (status.state === \"live\") {\n * console.log(\"Playback URL:\", status.whepUrl);\n * } else if (status.state === \"error\") {\n * console.error(\"Error:\", status.error);\n * }\n * ```\n */\nexport type UseBroadcastStatus =\n | { state: \"idle\" }\n | { state: \"connecting\" }\n | { state: \"live\"; whepUrl: string }\n | { state: \"reconnecting\"; whepUrl: string; reconnectInfo: ReconnectInfo }\n | { state: \"ended\" }\n | { state: \"error\"; error: DaydreamError };\n\n/**\n * Return value of the useBroadcast hook.\n */\nexport interface UseBroadcastReturn {\n /** Current broadcast status. */\n status: UseBroadcastStatus;\n /** Start broadcasting with the given MediaStream. */\n start: (stream: MediaStream) => Promise<void>;\n /** Stop broadcasting. */\n stop: () => Promise<void>;\n /** Set the maximum frame rate for the video track. */\n setMaxFramerate: (fps?: number) => void;\n}\n\n/**\n * React hook for managing a WebRTC broadcast session.\n *\n * Provides reactive state management, automatic cleanup, and a simple API\n * for starting and stopping broadcasts.\n *\n * @param options - Broadcast configuration options\n * @param factory - Factory function for creating Broadcast instances\n * @returns Broadcast status and control functions\n *\n * @example\n * ```tsx\n * function BroadcastComponent() {\n * const { status, start, stop } = useBroadcast({ whipUrl: \"...\" });\n *\n * const handleStart = async () => {\n * const stream = await navigator.mediaDevices.getUserMedia({ video: true });\n * await start(stream);\n * };\n *\n * return (\n * <div>\n * <p>Status: {status.state}</p>\n * {status.state === \"idle\" && <button onClick={handleStart}>Start</button>}\n * {status.state === \"live\" && <button onClick={stop}>Stop</button>}\n * </div>\n * );\n * }\n * ```\n *\n * @internal Use the re-exported `useBroadcast` from the package root instead.\n */\nexport function useBroadcast(\n options: UseBroadcastOptions,\n factory: BroadcastFactory,\n): UseBroadcastReturn {\n const [status, setStatus] = useState<UseBroadcastStatus>({ state: \"idle\" });\n const broadcastRef = useRef<Broadcast | null>(null);\n const whepUrlRef = useRef<string | null>(null);\n const optionsRef = useRef(options);\n const factoryRef = useRef(factory);\n\n useEffect(() => {\n optionsRef.current = options;\n }, [options]);\n\n useEffect(() => {\n factoryRef.current = factory;\n }, [factory]);\n\n useEffect(() => {\n return () => {\n broadcastRef.current?.stop();\n };\n }, []);\n\n const updateStatus = useCallback((newState: BroadcastState, error?: DaydreamError) => {\n const whepUrl = whepUrlRef.current;\n switch (newState) {\n case \"connecting\":\n setStatus({ state: \"connecting\" });\n break;\n case \"live\":\n setStatus({ state: \"live\", whepUrl: whepUrl! });\n break;\n case \"reconnecting\":\n // reconnectInfo will be set by the reconnect event\n break;\n case \"ended\":\n setStatus({ state: \"ended\" });\n break;\n case \"error\":\n setStatus({ state: \"error\", error: error! });\n break;\n }\n }, []);\n\n const start = useCallback(async (stream: MediaStream) => {\n if (broadcastRef.current) {\n await broadcastRef.current.stop();\n broadcastRef.current = null;\n }\n\n setStatus({ state: \"connecting\" });\n\n const broadcast = factoryRef.current({\n stream,\n ...optionsRef.current,\n });\n\n broadcastRef.current = broadcast;\n\n broadcast.on(\"stateChange\", (newState) => {\n // Guard against events from stopped broadcast\n if (broadcastRef.current !== broadcast) return;\n if (newState === \"live\" || newState === \"reconnecting\") {\n whepUrlRef.current = broadcast.whepUrl;\n }\n updateStatus(newState);\n });\n\n broadcast.on(\"error\", (err) => {\n if (broadcastRef.current !== broadcast) return;\n updateStatus(\"error\", err);\n });\n\n broadcast.on(\"reconnect\", (info) => {\n if (broadcastRef.current !== broadcast) return;\n setStatus({\n state: \"reconnecting\",\n whepUrl: whepUrlRef.current!,\n reconnectInfo: info,\n });\n });\n\n try {\n await broadcast.connect();\n if (broadcastRef.current !== broadcast) return;\n whepUrlRef.current = broadcast.whepUrl;\n updateStatus(broadcast.state);\n } catch (err) {\n if (broadcastRef.current !== broadcast) return;\n setStatus({ state: \"error\", error: err as DaydreamError });\n throw err;\n }\n }, [updateStatus]);\n\n const stop = useCallback(async () => {\n await broadcastRef.current?.stop();\n broadcastRef.current = null;\n whepUrlRef.current = null;\n setStatus({ state: \"idle\" });\n }, []);\n\n const setMaxFramerate = useCallback((fps?: number) => {\n broadcastRef.current?.setMaxFramerate(fps);\n }, []);\n\n return {\n status,\n start,\n stop,\n setMaxFramerate,\n };\n}\n","import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type RefObject,\n} from \"react\";\nimport type {\n Player,\n PlayerOptions,\n PlayerState,\n DaydreamError,\n ReconnectInfo,\n} from \"@daydreamlive/browser\";\n\n/**\n * Options for the usePlayer hook.\n * Extends PlayerOptions with WHEP URL and autoPlay settings.\n */\nexport type UsePlayerOptions = PlayerOptions & {\n /** WHEP endpoint URL. Set to null to disable playback. */\n whepUrl: string | null;\n /** Whether to automatically start playback when connected. Defaults to true. */\n autoPlay?: boolean;\n};\n\n/**\n * Factory function type for creating Player instances.\n * @internal\n */\nexport type PlayerFactory = (\n whepUrl: string,\n options?: PlayerOptions,\n) => Player;\n\n/**\n * Status returned by the usePlayer hook.\n * Discriminated union based on the `state` property.\n *\n * @example\n * ```tsx\n * const { status } = usePlayer({ whepUrl });\n *\n * if (status.state === \"buffering\") {\n * console.log(\"Reconnecting:\", status.reconnectInfo.attempt);\n * } else if (status.state === \"error\") {\n * console.error(\"Error:\", status.error);\n * }\n * ```\n */\nexport type UsePlayerStatus =\n | { state: \"idle\" }\n | { state: \"connecting\" }\n | { state: \"playing\" }\n | { state: \"buffering\"; reconnectInfo: ReconnectInfo }\n | { state: \"ended\" }\n | { state: \"error\"; error: DaydreamError };\n\n/**\n * Return value of the usePlayer hook.\n */\nexport interface UsePlayerReturn {\n /** Current player status. */\n status: UsePlayerStatus;\n /** Start playback. */\n play: () => Promise<void>;\n /** Stop playback. */\n stop: () => Promise<void>;\n /** Ref to attach to a video element for displaying the stream. */\n videoRef: RefObject<HTMLVideoElement | null>;\n}\n\n/**\n * React hook for managing a WebRTC playback session.\n *\n * Provides reactive state management, automatic cleanup, and a video element ref\n * for displaying the received stream.\n *\n * @param options - Player configuration options including WHEP URL\n * @param factory - Factory function for creating Player instances\n * @returns Player status, control functions, and video element ref\n *\n * @example\n * ```tsx\n * function PlayerComponent({ whepUrl }) {\n * const { status, play, stop, videoRef } = usePlayer({ whepUrl });\n *\n * useEffect(() => {\n * if (whepUrl) play();\n * }, [whepUrl, play]);\n *\n * return (\n * <div>\n * <video ref={videoRef} autoPlay muted />\n * <p>Status: {status.state}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @internal Use the re-exported `usePlayer` from the package root instead.\n */\nexport function usePlayer(\n options: UsePlayerOptions,\n factory: PlayerFactory,\n): UsePlayerReturn {\n const [status, setStatus] = useState<UsePlayerStatus>({ state: \"idle\" });\n const playerRef = useRef<Player | null>(null);\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const optionsRef = useRef(options);\n const factoryRef = useRef(factory);\n\n useEffect(() => {\n optionsRef.current = options;\n }, [options]);\n\n useEffect(() => {\n factoryRef.current = factory;\n }, [factory]);\n\n useEffect(() => {\n return () => {\n playerRef.current?.stop();\n };\n }, []);\n\n const updateStatus = useCallback(\n (newState: PlayerState, error?: DaydreamError) => {\n switch (newState) {\n case \"connecting\":\n setStatus({ state: \"connecting\" });\n break;\n case \"playing\":\n setStatus({ state: \"playing\" });\n break;\n case \"buffering\":\n // reconnectInfo will be set by the reconnect event\n break;\n case \"ended\":\n setStatus({ state: \"ended\" });\n break;\n case \"error\":\n setStatus({ state: \"error\", error: error! });\n break;\n }\n },\n [],\n );\n\n const play = useCallback(async () => {\n const currentWhepUrl = optionsRef.current.whepUrl;\n if (!currentWhepUrl) {\n return;\n }\n\n if (playerRef.current) {\n await playerRef.current.stop();\n playerRef.current = null;\n }\n\n setStatus({ state: \"connecting\" });\n\n const player = factoryRef.current(currentWhepUrl, {\n reconnect: optionsRef.current?.reconnect,\n iceServers: optionsRef.current?.iceServers,\n connectionTimeout: optionsRef.current?.connectionTimeout,\n skipIceGathering: optionsRef.current?.skipIceGathering,\n onStats: optionsRef.current?.onStats,\n statsIntervalMs: optionsRef.current?.statsIntervalMs,\n });\n\n playerRef.current = player;\n\n player.on(\"stateChange\", (newState) => {\n // Guard against events from stopped player\n if (playerRef.current !== player) return;\n updateStatus(newState);\n // Re-attach stream after reconnect\n if (newState === \"playing\" && videoRef.current && player.stream) {\n if (videoRef.current.srcObject !== player.stream) {\n player.attachTo(videoRef.current);\n }\n }\n });\n\n player.on(\"error\", (err) => {\n if (playerRef.current !== player) return;\n updateStatus(\"error\", err);\n });\n\n player.on(\"reconnect\", (info) => {\n if (playerRef.current !== player) return;\n setStatus({ state: \"buffering\", reconnectInfo: info });\n });\n\n try {\n await player.connect();\n if (playerRef.current !== player) return;\n updateStatus(player.state);\n\n if (videoRef.current) {\n player.attachTo(videoRef.current);\n if (optionsRef.current?.autoPlay !== false) {\n try {\n await videoRef.current.play();\n } catch {\n // Autoplay blocked\n }\n }\n }\n } catch (err) {\n if (playerRef.current !== player) return;\n setStatus({ state: \"error\", error: err as DaydreamError });\n throw err;\n }\n }, [updateStatus]);\n\n const stop = useCallback(async () => {\n await playerRef.current?.stop();\n playerRef.current = null;\n setStatus({ state: \"idle\" });\n }, []);\n\n return {\n status,\n play,\n stop,\n videoRef,\n };\n}\n","\"use client\";\n\nimport {\n createContext,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type PropsWithChildren,\n} from \"react\";\nimport {\n createCompositor,\n type Compositor,\n type CompositorOptions,\n type Size,\n type Source,\n} from \"@daydreamlive/browser\";\n\n/**\n * API provided by the CompositorProvider context.\n * Combines compositor functionality with React state management.\n *\n * @example\n * ```tsx\n * function VideoSource() {\n * const compositor = useCompositor();\n * const videoRef = useRef<HTMLVideoElement>(null);\n *\n * useEffect(() => {\n * if (videoRef.current) {\n * compositor.register(\"camera\", { kind: \"video\", element: videoRef.current });\n * compositor.activate(\"camera\");\n * }\n * return () => compositor.unregister(\"camera\");\n * }, [compositor]);\n *\n * return <video ref={videoRef} />;\n * }\n * ```\n */\nexport interface CompositorApi {\n // Registry\n /** Register a source with a unique ID. */\n register(id: string, source: Source): void;\n /** Unregister a source by ID. */\n unregister(id: string): void;\n /** Get a registered source by ID. */\n get(id: string): Source | undefined;\n /** Check if a source is registered. */\n has(id: string): boolean;\n /** List all registered sources. */\n list(): Array<{ id: string; source: Source }>;\n\n /**\n * Register a source, activate it, and return an unregister function.\n * Convenience method that combines register + activate with automatic cleanup.\n *\n * @example\n * ```tsx\n * useEffect(() => {\n * const unregister = compositor.use(\"camera\", {\n * kind: \"video\",\n * element: videoRef.current,\n * fit: \"cover\",\n * });\n * return unregister;\n * }, [compositor]);\n * ```\n */\n use(id: string, source: Source): () => void;\n\n // Active source\n /**\n * Activate a registered source.\n * @param id - The source ID to activate\n */\n activate(id: string): void;\n /** Deactivate the current source. */\n deactivate(): void;\n /** ID of the currently active source, or null if none. */\n readonly activeId: string | null;\n\n // Output (reactive)\n /** The composited output MediaStream. Reactive - updates when stream changes. */\n readonly stream: MediaStream | null;\n /** Current output size. Reactive - updates when size changes. */\n readonly size: Size;\n /** Resize the output canvas. */\n setSize(width: number, height: number, dpr?: number): void;\n\n // FPS (reactive)\n /** Current rendering frame rate. Reactive. */\n readonly fps: number;\n /** Set the rendering frame rate. */\n setFps(fps: number): void;\n /** Current send frame rate. Reactive. */\n readonly sendFps: number;\n /** Set the send frame rate. */\n setSendFps(fps: number): void;\n\n // Audio\n /** Add an audio track to the output stream. */\n addAudioTrack(track: MediaStreamTrack): void;\n /** Remove an audio track by track ID. */\n removeAudioTrack(trackId: string): void;\n /** Manually unlock the audio context. */\n unlockAudio(): Promise<boolean>;\n\n // Events\n /** Subscribe to compositor events. */\n on: Compositor[\"on\"];\n}\n\nconst CompositorContext = createContext<CompositorApi | null>(null);\n\n/**\n * Props for the CompositorProvider component.\n * Inherits all CompositorOptions except onSendFpsChange (managed internally).\n */\nexport interface CompositorProviderProps\n extends PropsWithChildren,\n Partial<Omit<CompositorOptions, \"onSendFpsChange\">> {}\n\n/**\n * React context provider for the Compositor.\n * Creates and manages a Compositor instance, providing it to child components via context.\n *\n * @example\n * ```tsx\n * function App() {\n * return (\n * <CompositorProvider width={1280} height={720} fps={30}>\n * <VideoSource />\n * <BroadcastButton />\n * </CompositorProvider>\n * );\n * }\n * ```\n */\nexport function CompositorProvider({\n children,\n width = 512,\n height = 512,\n fps: initialFps = 30,\n sendFps: initialSendFps,\n dpr,\n keepalive,\n autoUnlockAudio,\n unlockEvents,\n disableSilentAudio = true,\n}: CompositorProviderProps) {\n const compositorRef = useRef<Compositor | null>(null);\n const [stream, setStream] = useState<MediaStream | null>(null);\n const [size, setSize] = useState<Size>({\n width,\n height,\n dpr: Math.min(\n 2,\n dpr ?? (typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1),\n ),\n });\n const [fps, setFpsState] = useState(initialFps);\n const [sendFps, setSendFpsState] = useState(initialSendFps ?? initialFps);\n\n // Create compositor once\n useLayoutEffect(() => {\n const compositor = createCompositor({\n width,\n height,\n fps: initialFps,\n sendFps: initialSendFps,\n dpr,\n keepalive,\n autoUnlockAudio,\n unlockEvents,\n disableSilentAudio,\n onSendFpsChange: (newFps) => setSendFpsState(newFps),\n });\n\n compositorRef.current = compositor;\n setStream(compositor.stream);\n setSize(compositor.size);\n\n return () => {\n compositor.destroy();\n compositorRef.current = null;\n };\n }, []);\n\n // Sync size changes\n useEffect(() => {\n const compositor = compositorRef.current;\n if (!compositor) return;\n\n compositor.resize(size.width, size.height, size.dpr);\n setStream(compositor.stream);\n }, [size.width, size.height, size.dpr]);\n\n // Sync fps changes\n useEffect(() => {\n const compositor = compositorRef.current;\n if (!compositor) return;\n\n compositor.setFps(fps);\n setStream(compositor.stream);\n }, [fps]);\n\n // Sync sendFps changes\n useEffect(() => {\n const compositor = compositorRef.current;\n if (!compositor) return;\n\n compositor.setSendFps(sendFps);\n }, [sendFps]);\n\n // Memoized API\n const api = useMemo<CompositorApi>(\n () => ({\n // Registry\n register: (id, source) => compositorRef.current?.register(id, source),\n unregister: (id) => compositorRef.current?.unregister(id),\n get: (id) => compositorRef.current?.get(id),\n has: (id) => compositorRef.current?.has(id) ?? false,\n list: () => compositorRef.current?.list() ?? [],\n use: (id, source) => {\n compositorRef.current?.register(id, source);\n compositorRef.current?.activate(id);\n return () => compositorRef.current?.unregister(id);\n },\n\n // Active source\n activate: (id) => compositorRef.current?.activate(id),\n deactivate: () => compositorRef.current?.deactivate(),\n get activeId() {\n return compositorRef.current?.activeId ?? null;\n },\n\n // Stream & size\n stream,\n size,\n setSize: (w, h, d) =>\n setSize({ width: w, height: h, dpr: d ?? size.dpr }),\n\n // FPS\n fps,\n setFps: setFpsState,\n sendFps,\n setSendFps: setSendFpsState,\n\n // Audio\n addAudioTrack: (t) => compositorRef.current?.addAudioTrack(t),\n removeAudioTrack: (id) => compositorRef.current?.removeAudioTrack(id),\n unlockAudio: () =>\n compositorRef.current?.unlockAudio() ?? Promise.resolve(false),\n\n // Events\n on: (event, cb) => compositorRef.current?.on(event, cb) ?? (() => {}),\n }),\n [stream, size, fps, sendFps],\n );\n\n return (\n <CompositorContext.Provider value={api}>\n {children}\n </CompositorContext.Provider>\n );\n}\n\n/**\n * Hook to access the Compositor API from context.\n * Must be used within a CompositorProvider.\n *\n * @returns The CompositorApi for managing sources and output\n * @throws {Error} If used outside of CompositorProvider\n *\n * @example\n * ```tsx\n * function BroadcastButton() {\n * const compositor = useCompositor();\n * const { start } = useBroadcast({ whipUrl: \"...\" });\n *\n * const handleClick = async () => {\n * if (compositor.stream) {\n * await start(compositor.stream);\n * }\n * };\n *\n * return <button onClick={handleClick}>Start Broadcast</button>;\n * }\n * ```\n */\nexport function useCompositor(): CompositorApi {\n const ctx = useContext(CompositorContext);\n if (!ctx) {\n throw new Error(\"useCompositor must be used within <CompositorProvider>\");\n }\n return ctx;\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState, useCallback, useMemo } from \"react\";\nimport type { Source, FitMode, ContentHint } from \"@daydreamlive/browser\";\nimport { useCompositor } from \"./useCompositor\";\n\n/**\n * Options for the useSource hook.\n */\nexport interface UseSourceOptions {\n /** Type of source element: \"video\" for HTMLVideoElement, \"canvas\" for HTMLCanvasElement. */\n kind: \"video\" | \"canvas\";\n /** Content hint for encoding optimization. */\n contentHint?: ContentHint;\n /** How to fit the source content within the output canvas. Only applies to video sources. */\n fit?: FitMode;\n}\n\n/**\n * Return value of the useSource hook.\n */\nexport interface UseSourceReturn<\n T extends HTMLVideoElement | HTMLCanvasElement,\n> {\n /** Ref to attach to the source element. */\n ref: React.RefObject<T>;\n /** Whether this source is currently active. Reactive. */\n isActive: boolean;\n /** Activate this source for rendering. */\n activate: () => void;\n /** Deactivate this source (if it's currently active). */\n deactivate: () => void;\n}\n\n/**\n * React hook for managing a compositor source.\n *\n * Automatically registers the source element with the compositor and provides\n * methods for activation/deactivation. Cleans up on unmount.\n *\n * @typeParam T - The element type (HTMLVideoElement or HTMLCanvasElement)\n * @param id - Unique identifier for this source\n * @param options - Source configuration\n * @returns Source state and control functions\n *\n * @example\n * ```tsx\n * function CameraSource() {\n * const { ref, isActive, activate } = useSource<HTMLVideoElement>(\"camera\", {\n * kind: \"video\",\n * fit: \"cover\",\n * });\n *\n * useEffect(() => {\n * navigator.mediaDevices.getUserMedia({ video: true })\n * .then(stream => {\n * if (ref.current) {\n * ref.current.srcObject = stream;\n * activate();\n * }\n * });\n * }, [activate]);\n *\n * return <video ref={ref} autoPlay muted />;\n * }\n * ```\n */\nexport function useSource<\n T extends HTMLVideoElement | HTMLCanvasElement =\n | HTMLVideoElement\n | HTMLCanvasElement,\n>(id: string, options: UseSourceOptions): UseSourceReturn<T> {\n const compositor = useCompositor();\n const compositorRef = useRef(compositor);\n compositorRef.current = compositor;\n\n const ref = useRef<T>(null);\n const [isActive, setIsActive] = useState(false);\n const registeredRef = useRef(false);\n const idRef = useRef(id);\n idRef.current = id;\n\n const { kind, contentHint, fit } = options;\n\n const optionsRef = useRef({ kind, contentHint, fit });\n optionsRef.current = { kind, contentHint, fit };\n\n const registerSource = useCallback((element: T) => {\n const { kind, contentHint, fit } = optionsRef.current;\n const source =\n kind === \"video\"\n ? {\n kind: \"video\" as const,\n element: element as HTMLVideoElement,\n contentHint,\n fit,\n }\n : {\n kind: \"canvas\" as const,\n element: element as HTMLCanvasElement,\n contentHint,\n };\n\n compositorRef.current.register(idRef.current, source);\n registeredRef.current = true;\n }, []);\n\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n registerSource(element);\n }, [id, kind, contentHint, fit, registerSource]);\n\n useEffect(() => {\n const currentId = id;\n return () => {\n if (registeredRef.current) {\n registeredRef.current = false;\n setIsActive(false);\n compositorRef.current.unregister(currentId);\n }\n };\n }, [id]);\n\n useEffect(() => {\n setIsActive(compositor.activeId === id);\n }, [compositor.activeId, id]);\n\n const activate = useCallback(() => {\n const element = ref.current;\n if (!element) return;\n\n if (!registeredRef.current) {\n registerSource(element);\n }\n\n compositorRef.current.activate(idRef.current);\n setIsActive(true);\n }, [registerSource]);\n\n const deactivate = useCallback(() => {\n if (compositorRef.current.activeId === idRef.current) {\n compositorRef.current.deactivate();\n setIsActive(false);\n }\n }, []);\n\n return useMemo(\n () => ({\n ref,\n isActive,\n activate,\n deactivate,\n }),\n [isActive, activate, deactivate],\n );\n}\n"],"mappings":"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","names":["useBroadcast","usePlayer","import_browser","import_react","import_browser","import_react","import_react","kind","contentHint","fit","useBroadcast","usePlayer"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { AudioConfig, BroadcastState, CanvasSource, Compositor, CompositorEvent, CompositorEventMap, CompositorOptions, ContentHint, Ctx2D, DaydreamError, DaydreamErrorCode, FitMode, PlayerState, ReconnectConfig, ReconnectInfo, Size, Source, VideoConfig, VideoSource } from '@daydreamlive/browser';
|
|
1
|
+
import { BroadcastOptions, ReconnectInfo, DaydreamError, PlayerOptions, CompositorOptions, Source, Size, Compositor, ContentHint, FitMode } from '@daydreamlive/browser';
|
|
2
|
+
export { AudioConfig, BaseDaydreamError, Broadcast, BroadcastConfig, BroadcastEventMap, BroadcastOptions, BroadcastState, CanvasSource, Compositor, CompositorEvent, CompositorEventMap, CompositorOptions, ConnectionError, ContentHint, Ctx2D, DEFAULT_AUDIO_BITRATE, DEFAULT_ICE_SERVERS, DEFAULT_VIDEO_BITRATE, DaydreamError, DaydreamErrorCode, FitMode, LivepeerBroadcastOptions, NetworkError, Player, PlayerConfig, PlayerEventMap, PlayerOptions, PlayerState, ReconnectConfig, ReconnectInfo, Size, Source, StreamNotFoundError, UnauthorizedError, VideoConfig, VideoSource, WHIPResponseResult, createCompositor, livepeerResponseHandler } from '@daydreamlive/browser';
|
|
3
3
|
import { RefObject, PropsWithChildren } from 'react';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Options for the useBroadcast hook.
|
|
8
|
+
* Same as BroadcastOptions but without `stream` (passed to `start()`) and `onResponse` (pre-configured).
|
|
9
|
+
*/
|
|
10
|
+
type UseBroadcastOptions = Omit<BroadcastOptions, "stream" | "onResponse">;
|
|
11
|
+
/**
|
|
12
|
+
* Status returned by the useBroadcast hook.
|
|
13
|
+
* Discriminated union based on the `state` property.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* const { status } = useBroadcast({ whipUrl });
|
|
18
|
+
*
|
|
19
|
+
* if (status.state === "live") {
|
|
20
|
+
* console.log("Playback URL:", status.whepUrl);
|
|
21
|
+
* } else if (status.state === "error") {
|
|
22
|
+
* console.error("Error:", status.error);
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
16
26
|
type UseBroadcastStatus = {
|
|
17
27
|
state: "idle";
|
|
18
28
|
} | {
|
|
@@ -30,23 +40,45 @@ type UseBroadcastStatus = {
|
|
|
30
40
|
state: "error";
|
|
31
41
|
error: DaydreamError;
|
|
32
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* Return value of the useBroadcast hook.
|
|
45
|
+
*/
|
|
33
46
|
interface UseBroadcastReturn {
|
|
47
|
+
/** Current broadcast status. */
|
|
34
48
|
status: UseBroadcastStatus;
|
|
49
|
+
/** Start broadcasting with the given MediaStream. */
|
|
35
50
|
start: (stream: MediaStream) => Promise<void>;
|
|
51
|
+
/** Stop broadcasting. */
|
|
36
52
|
stop: () => Promise<void>;
|
|
53
|
+
/** Set the maximum frame rate for the video track. */
|
|
37
54
|
setMaxFramerate: (fps?: number) => void;
|
|
38
55
|
}
|
|
39
56
|
|
|
40
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Options for the usePlayer hook.
|
|
59
|
+
* Extends PlayerOptions with WHEP URL and autoPlay settings.
|
|
60
|
+
*/
|
|
61
|
+
type UsePlayerOptions = PlayerOptions & {
|
|
62
|
+
/** WHEP endpoint URL. Set to null to disable playback. */
|
|
41
63
|
whepUrl: string | null;
|
|
42
|
-
|
|
43
|
-
iceServers?: RTCIceServer[];
|
|
44
|
-
connectionTimeout?: number;
|
|
45
|
-
skipIceGathering?: boolean;
|
|
64
|
+
/** Whether to automatically start playback when connected. Defaults to true. */
|
|
46
65
|
autoPlay?: boolean;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Status returned by the usePlayer hook.
|
|
69
|
+
* Discriminated union based on the `state` property.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```tsx
|
|
73
|
+
* const { status } = usePlayer({ whepUrl });
|
|
74
|
+
*
|
|
75
|
+
* if (status.state === "buffering") {
|
|
76
|
+
* console.log("Reconnecting:", status.reconnectInfo.attempt);
|
|
77
|
+
* } else if (status.state === "error") {
|
|
78
|
+
* console.error("Error:", status.error);
|
|
79
|
+
* }
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
50
82
|
type UsePlayerStatus = {
|
|
51
83
|
state: "idle";
|
|
52
84
|
} | {
|
|
@@ -62,18 +94,52 @@ type UsePlayerStatus = {
|
|
|
62
94
|
state: "error";
|
|
63
95
|
error: DaydreamError;
|
|
64
96
|
};
|
|
97
|
+
/**
|
|
98
|
+
* Return value of the usePlayer hook.
|
|
99
|
+
*/
|
|
65
100
|
interface UsePlayerReturn {
|
|
101
|
+
/** Current player status. */
|
|
66
102
|
status: UsePlayerStatus;
|
|
103
|
+
/** Start playback. */
|
|
67
104
|
play: () => Promise<void>;
|
|
105
|
+
/** Stop playback. */
|
|
68
106
|
stop: () => Promise<void>;
|
|
107
|
+
/** Ref to attach to a video element for displaying the stream. */
|
|
69
108
|
videoRef: RefObject<HTMLVideoElement | null>;
|
|
70
109
|
}
|
|
71
110
|
|
|
111
|
+
/**
|
|
112
|
+
* API provided by the CompositorProvider context.
|
|
113
|
+
* Combines compositor functionality with React state management.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```tsx
|
|
117
|
+
* function VideoSource() {
|
|
118
|
+
* const compositor = useCompositor();
|
|
119
|
+
* const videoRef = useRef<HTMLVideoElement>(null);
|
|
120
|
+
*
|
|
121
|
+
* useEffect(() => {
|
|
122
|
+
* if (videoRef.current) {
|
|
123
|
+
* compositor.register("camera", { kind: "video", element: videoRef.current });
|
|
124
|
+
* compositor.activate("camera");
|
|
125
|
+
* }
|
|
126
|
+
* return () => compositor.unregister("camera");
|
|
127
|
+
* }, [compositor]);
|
|
128
|
+
*
|
|
129
|
+
* return <video ref={videoRef} />;
|
|
130
|
+
* }
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
72
133
|
interface CompositorApi {
|
|
134
|
+
/** Register a source with a unique ID. */
|
|
73
135
|
register(id: string, source: Source): void;
|
|
136
|
+
/** Unregister a source by ID. */
|
|
74
137
|
unregister(id: string): void;
|
|
138
|
+
/** Get a registered source by ID. */
|
|
75
139
|
get(id: string): Source | undefined;
|
|
140
|
+
/** Check if a source is registered. */
|
|
76
141
|
has(id: string): boolean;
|
|
142
|
+
/** List all registered sources. */
|
|
77
143
|
list(): Array<{
|
|
78
144
|
id: string;
|
|
79
145
|
source: Source;
|
|
@@ -100,39 +166,220 @@ interface CompositorApi {
|
|
|
100
166
|
* @param id - The source ID to activate
|
|
101
167
|
*/
|
|
102
168
|
activate(id: string): void;
|
|
169
|
+
/** Deactivate the current source. */
|
|
103
170
|
deactivate(): void;
|
|
171
|
+
/** ID of the currently active source, or null if none. */
|
|
104
172
|
readonly activeId: string | null;
|
|
173
|
+
/** The composited output MediaStream. Reactive - updates when stream changes. */
|
|
105
174
|
readonly stream: MediaStream | null;
|
|
175
|
+
/** Current output size. Reactive - updates when size changes. */
|
|
106
176
|
readonly size: Size;
|
|
177
|
+
/** Resize the output canvas. */
|
|
107
178
|
setSize(width: number, height: number, dpr?: number): void;
|
|
179
|
+
/** Current rendering frame rate. Reactive. */
|
|
108
180
|
readonly fps: number;
|
|
181
|
+
/** Set the rendering frame rate. */
|
|
109
182
|
setFps(fps: number): void;
|
|
183
|
+
/** Current send frame rate. Reactive. */
|
|
110
184
|
readonly sendFps: number;
|
|
185
|
+
/** Set the send frame rate. */
|
|
111
186
|
setSendFps(fps: number): void;
|
|
187
|
+
/** Add an audio track to the output stream. */
|
|
112
188
|
addAudioTrack(track: MediaStreamTrack): void;
|
|
189
|
+
/** Remove an audio track by track ID. */
|
|
113
190
|
removeAudioTrack(trackId: string): void;
|
|
191
|
+
/** Manually unlock the audio context. */
|
|
114
192
|
unlockAudio(): Promise<boolean>;
|
|
193
|
+
/** Subscribe to compositor events. */
|
|
115
194
|
on: Compositor["on"];
|
|
116
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Props for the CompositorProvider component.
|
|
198
|
+
* Inherits all CompositorOptions except onSendFpsChange (managed internally).
|
|
199
|
+
*/
|
|
117
200
|
interface CompositorProviderProps extends PropsWithChildren, Partial<Omit<CompositorOptions, "onSendFpsChange">> {
|
|
118
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* React context provider for the Compositor.
|
|
204
|
+
* Creates and manages a Compositor instance, providing it to child components via context.
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```tsx
|
|
208
|
+
* function App() {
|
|
209
|
+
* return (
|
|
210
|
+
* <CompositorProvider width={1280} height={720} fps={30}>
|
|
211
|
+
* <VideoSource />
|
|
212
|
+
* <BroadcastButton />
|
|
213
|
+
* </CompositorProvider>
|
|
214
|
+
* );
|
|
215
|
+
* }
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
119
218
|
declare function CompositorProvider({ children, width, height, fps: initialFps, sendFps: initialSendFps, dpr, keepalive, autoUnlockAudio, unlockEvents, disableSilentAudio, }: CompositorProviderProps): react_jsx_runtime.JSX.Element;
|
|
219
|
+
/**
|
|
220
|
+
* Hook to access the Compositor API from context.
|
|
221
|
+
* Must be used within a CompositorProvider.
|
|
222
|
+
*
|
|
223
|
+
* @returns The CompositorApi for managing sources and output
|
|
224
|
+
* @throws {Error} If used outside of CompositorProvider
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```tsx
|
|
228
|
+
* function BroadcastButton() {
|
|
229
|
+
* const compositor = useCompositor();
|
|
230
|
+
* const { start } = useBroadcast({ whipUrl: "..." });
|
|
231
|
+
*
|
|
232
|
+
* const handleClick = async () => {
|
|
233
|
+
* if (compositor.stream) {
|
|
234
|
+
* await start(compositor.stream);
|
|
235
|
+
* }
|
|
236
|
+
* };
|
|
237
|
+
*
|
|
238
|
+
* return <button onClick={handleClick}>Start Broadcast</button>;
|
|
239
|
+
* }
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
120
242
|
declare function useCompositor(): CompositorApi;
|
|
121
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Options for the useSource hook.
|
|
246
|
+
*/
|
|
122
247
|
interface UseSourceOptions {
|
|
248
|
+
/** Type of source element: "video" for HTMLVideoElement, "canvas" for HTMLCanvasElement. */
|
|
123
249
|
kind: "video" | "canvas";
|
|
250
|
+
/** Content hint for encoding optimization. */
|
|
124
251
|
contentHint?: ContentHint;
|
|
252
|
+
/** How to fit the source content within the output canvas. Only applies to video sources. */
|
|
125
253
|
fit?: FitMode;
|
|
126
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* Return value of the useSource hook.
|
|
257
|
+
*/
|
|
127
258
|
interface UseSourceReturn<T extends HTMLVideoElement | HTMLCanvasElement> {
|
|
259
|
+
/** Ref to attach to the source element. */
|
|
128
260
|
ref: React.RefObject<T>;
|
|
261
|
+
/** Whether this source is currently active. Reactive. */
|
|
129
262
|
isActive: boolean;
|
|
263
|
+
/** Activate this source for rendering. */
|
|
130
264
|
activate: () => void;
|
|
265
|
+
/** Deactivate this source (if it's currently active). */
|
|
131
266
|
deactivate: () => void;
|
|
132
267
|
}
|
|
268
|
+
/**
|
|
269
|
+
* React hook for managing a compositor source.
|
|
270
|
+
*
|
|
271
|
+
* Automatically registers the source element with the compositor and provides
|
|
272
|
+
* methods for activation/deactivation. Cleans up on unmount.
|
|
273
|
+
*
|
|
274
|
+
* @typeParam T - The element type (HTMLVideoElement or HTMLCanvasElement)
|
|
275
|
+
* @param id - Unique identifier for this source
|
|
276
|
+
* @param options - Source configuration
|
|
277
|
+
* @returns Source state and control functions
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```tsx
|
|
281
|
+
* function CameraSource() {
|
|
282
|
+
* const { ref, isActive, activate } = useSource<HTMLVideoElement>("camera", {
|
|
283
|
+
* kind: "video",
|
|
284
|
+
* fit: "cover",
|
|
285
|
+
* });
|
|
286
|
+
*
|
|
287
|
+
* useEffect(() => {
|
|
288
|
+
* navigator.mediaDevices.getUserMedia({ video: true })
|
|
289
|
+
* .then(stream => {
|
|
290
|
+
* if (ref.current) {
|
|
291
|
+
* ref.current.srcObject = stream;
|
|
292
|
+
* activate();
|
|
293
|
+
* }
|
|
294
|
+
* });
|
|
295
|
+
* }, [activate]);
|
|
296
|
+
*
|
|
297
|
+
* return <video ref={ref} autoPlay muted />;
|
|
298
|
+
* }
|
|
299
|
+
* ```
|
|
300
|
+
*/
|
|
133
301
|
declare function useSource<T extends HTMLVideoElement | HTMLCanvasElement = HTMLVideoElement | HTMLCanvasElement>(id: string, options: UseSourceOptions): UseSourceReturn<T>;
|
|
134
302
|
|
|
303
|
+
/**
|
|
304
|
+
* @daydreamlive/react - React hooks and components for WebRTC broadcasting and playback.
|
|
305
|
+
*
|
|
306
|
+
* @example
|
|
307
|
+
* ```tsx
|
|
308
|
+
* import { useBroadcast, usePlayer, CompositorProvider, useCompositor, useSource } from "@daydreamlive/react";
|
|
309
|
+
*
|
|
310
|
+
* // Broadcasting
|
|
311
|
+
* const { status, start, stop } = useBroadcast({ whipUrl: "..." });
|
|
312
|
+
*
|
|
313
|
+
* // Playback
|
|
314
|
+
* const { status, play, videoRef } = usePlayer({ whepUrl: "..." });
|
|
315
|
+
*
|
|
316
|
+
* // Compositor with React
|
|
317
|
+
* <CompositorProvider width={1280} height={720}>
|
|
318
|
+
* <SourceComponent />
|
|
319
|
+
* </CompositorProvider>
|
|
320
|
+
* ```
|
|
321
|
+
*
|
|
322
|
+
* @packageDocumentation
|
|
323
|
+
*/
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* React hook for managing a WebRTC broadcast session.
|
|
327
|
+
*
|
|
328
|
+
* @param options - Broadcast configuration including WHIP URL
|
|
329
|
+
* @returns Broadcast status and control functions
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* ```tsx
|
|
333
|
+
* function BroadcastComponent() {
|
|
334
|
+
* const { status, start, stop } = useBroadcast({
|
|
335
|
+
* whipUrl: "https://livepeer.studio/webrtc/...",
|
|
336
|
+
* });
|
|
337
|
+
*
|
|
338
|
+
* const handleStart = async () => {
|
|
339
|
+
* const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
|
|
340
|
+
* await start(stream);
|
|
341
|
+
* };
|
|
342
|
+
*
|
|
343
|
+
* return (
|
|
344
|
+
* <div>
|
|
345
|
+
* <p>Status: {status.state}</p>
|
|
346
|
+
* {status.state === "live" && <p>Playback URL: {status.whepUrl}</p>}
|
|
347
|
+
* <button onClick={status.state === "idle" ? handleStart : stop}>
|
|
348
|
+
* {status.state === "idle" ? "Start" : "Stop"}
|
|
349
|
+
* </button>
|
|
350
|
+
* </div>
|
|
351
|
+
* );
|
|
352
|
+
* }
|
|
353
|
+
* ```
|
|
354
|
+
*/
|
|
135
355
|
declare function useBroadcast(options: UseBroadcastOptions): UseBroadcastReturn;
|
|
356
|
+
/**
|
|
357
|
+
* React hook for managing a WebRTC playback session.
|
|
358
|
+
*
|
|
359
|
+
* @param options - Player configuration including WHEP URL
|
|
360
|
+
* @returns Player status, control functions, and video element ref
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```tsx
|
|
364
|
+
* function PlayerComponent({ whepUrl }) {
|
|
365
|
+
* const { status, play, stop, videoRef } = usePlayer({
|
|
366
|
+
* whepUrl,
|
|
367
|
+
* autoPlay: true,
|
|
368
|
+
* });
|
|
369
|
+
*
|
|
370
|
+
* useEffect(() => {
|
|
371
|
+
* if (whepUrl) play();
|
|
372
|
+
* }, [whepUrl, play]);
|
|
373
|
+
*
|
|
374
|
+
* return (
|
|
375
|
+
* <div>
|
|
376
|
+
* <video ref={videoRef} autoPlay muted playsInline />
|
|
377
|
+
* <p>Status: {status.state}</p>
|
|
378
|
+
* </div>
|
|
379
|
+
* );
|
|
380
|
+
* }
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
136
383
|
declare function usePlayer(options: UsePlayerOptions): UsePlayerReturn;
|
|
137
384
|
|
|
138
385
|
export { type CompositorApi, CompositorProvider, type CompositorProviderProps, type UseBroadcastOptions, type UseBroadcastReturn, type UseBroadcastStatus, type UsePlayerOptions, type UsePlayerReturn, type UsePlayerStatus, type UseSourceOptions, type UseSourceReturn, useBroadcast, useCompositor, usePlayer, useSource };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { AudioConfig, BroadcastState, CanvasSource, Compositor, CompositorEvent, CompositorEventMap, CompositorOptions, ContentHint, Ctx2D, DaydreamError, DaydreamErrorCode, FitMode, PlayerState, ReconnectConfig, ReconnectInfo, Size, Source, VideoConfig, VideoSource } from '@daydreamlive/browser';
|
|
1
|
+
import { BroadcastOptions, ReconnectInfo, DaydreamError, PlayerOptions, CompositorOptions, Source, Size, Compositor, ContentHint, FitMode } from '@daydreamlive/browser';
|
|
2
|
+
export { AudioConfig, BaseDaydreamError, Broadcast, BroadcastConfig, BroadcastEventMap, BroadcastOptions, BroadcastState, CanvasSource, Compositor, CompositorEvent, CompositorEventMap, CompositorOptions, ConnectionError, ContentHint, Ctx2D, DEFAULT_AUDIO_BITRATE, DEFAULT_ICE_SERVERS, DEFAULT_VIDEO_BITRATE, DaydreamError, DaydreamErrorCode, FitMode, LivepeerBroadcastOptions, NetworkError, Player, PlayerConfig, PlayerEventMap, PlayerOptions, PlayerState, ReconnectConfig, ReconnectInfo, Size, Source, StreamNotFoundError, UnauthorizedError, VideoConfig, VideoSource, WHIPResponseResult, createCompositor, livepeerResponseHandler } from '@daydreamlive/browser';
|
|
3
3
|
import { RefObject, PropsWithChildren } from 'react';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Options for the useBroadcast hook.
|
|
8
|
+
* Same as BroadcastOptions but without `stream` (passed to `start()`) and `onResponse` (pre-configured).
|
|
9
|
+
*/
|
|
10
|
+
type UseBroadcastOptions = Omit<BroadcastOptions, "stream" | "onResponse">;
|
|
11
|
+
/**
|
|
12
|
+
* Status returned by the useBroadcast hook.
|
|
13
|
+
* Discriminated union based on the `state` property.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* const { status } = useBroadcast({ whipUrl });
|
|
18
|
+
*
|
|
19
|
+
* if (status.state === "live") {
|
|
20
|
+
* console.log("Playback URL:", status.whepUrl);
|
|
21
|
+
* } else if (status.state === "error") {
|
|
22
|
+
* console.error("Error:", status.error);
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
16
26
|
type UseBroadcastStatus = {
|
|
17
27
|
state: "idle";
|
|
18
28
|
} | {
|
|
@@ -30,23 +40,45 @@ type UseBroadcastStatus = {
|
|
|
30
40
|
state: "error";
|
|
31
41
|
error: DaydreamError;
|
|
32
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* Return value of the useBroadcast hook.
|
|
45
|
+
*/
|
|
33
46
|
interface UseBroadcastReturn {
|
|
47
|
+
/** Current broadcast status. */
|
|
34
48
|
status: UseBroadcastStatus;
|
|
49
|
+
/** Start broadcasting with the given MediaStream. */
|
|
35
50
|
start: (stream: MediaStream) => Promise<void>;
|
|
51
|
+
/** Stop broadcasting. */
|
|
36
52
|
stop: () => Promise<void>;
|
|
53
|
+
/** Set the maximum frame rate for the video track. */
|
|
37
54
|
setMaxFramerate: (fps?: number) => void;
|
|
38
55
|
}
|
|
39
56
|
|
|
40
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Options for the usePlayer hook.
|
|
59
|
+
* Extends PlayerOptions with WHEP URL and autoPlay settings.
|
|
60
|
+
*/
|
|
61
|
+
type UsePlayerOptions = PlayerOptions & {
|
|
62
|
+
/** WHEP endpoint URL. Set to null to disable playback. */
|
|
41
63
|
whepUrl: string | null;
|
|
42
|
-
|
|
43
|
-
iceServers?: RTCIceServer[];
|
|
44
|
-
connectionTimeout?: number;
|
|
45
|
-
skipIceGathering?: boolean;
|
|
64
|
+
/** Whether to automatically start playback when connected. Defaults to true. */
|
|
46
65
|
autoPlay?: boolean;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Status returned by the usePlayer hook.
|
|
69
|
+
* Discriminated union based on the `state` property.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```tsx
|
|
73
|
+
* const { status } = usePlayer({ whepUrl });
|
|
74
|
+
*
|
|
75
|
+
* if (status.state === "buffering") {
|
|
76
|
+
* console.log("Reconnecting:", status.reconnectInfo.attempt);
|
|
77
|
+
* } else if (status.state === "error") {
|
|
78
|
+
* console.error("Error:", status.error);
|
|
79
|
+
* }
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
50
82
|
type UsePlayerStatus = {
|
|
51
83
|
state: "idle";
|
|
52
84
|
} | {
|
|
@@ -62,18 +94,52 @@ type UsePlayerStatus = {
|
|
|
62
94
|
state: "error";
|
|
63
95
|
error: DaydreamError;
|
|
64
96
|
};
|
|
97
|
+
/**
|
|
98
|
+
* Return value of the usePlayer hook.
|
|
99
|
+
*/
|
|
65
100
|
interface UsePlayerReturn {
|
|
101
|
+
/** Current player status. */
|
|
66
102
|
status: UsePlayerStatus;
|
|
103
|
+
/** Start playback. */
|
|
67
104
|
play: () => Promise<void>;
|
|
105
|
+
/** Stop playback. */
|
|
68
106
|
stop: () => Promise<void>;
|
|
107
|
+
/** Ref to attach to a video element for displaying the stream. */
|
|
69
108
|
videoRef: RefObject<HTMLVideoElement | null>;
|
|
70
109
|
}
|
|
71
110
|
|
|
111
|
+
/**
|
|
112
|
+
* API provided by the CompositorProvider context.
|
|
113
|
+
* Combines compositor functionality with React state management.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```tsx
|
|
117
|
+
* function VideoSource() {
|
|
118
|
+
* const compositor = useCompositor();
|
|
119
|
+
* const videoRef = useRef<HTMLVideoElement>(null);
|
|
120
|
+
*
|
|
121
|
+
* useEffect(() => {
|
|
122
|
+
* if (videoRef.current) {
|
|
123
|
+
* compositor.register("camera", { kind: "video", element: videoRef.current });
|
|
124
|
+
* compositor.activate("camera");
|
|
125
|
+
* }
|
|
126
|
+
* return () => compositor.unregister("camera");
|
|
127
|
+
* }, [compositor]);
|
|
128
|
+
*
|
|
129
|
+
* return <video ref={videoRef} />;
|
|
130
|
+
* }
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
72
133
|
interface CompositorApi {
|
|
134
|
+
/** Register a source with a unique ID. */
|
|
73
135
|
register(id: string, source: Source): void;
|
|
136
|
+
/** Unregister a source by ID. */
|
|
74
137
|
unregister(id: string): void;
|
|
138
|
+
/** Get a registered source by ID. */
|
|
75
139
|
get(id: string): Source | undefined;
|
|
140
|
+
/** Check if a source is registered. */
|
|
76
141
|
has(id: string): boolean;
|
|
142
|
+
/** List all registered sources. */
|
|
77
143
|
list(): Array<{
|
|
78
144
|
id: string;
|
|
79
145
|
source: Source;
|
|
@@ -100,39 +166,220 @@ interface CompositorApi {
|
|
|
100
166
|
* @param id - The source ID to activate
|
|
101
167
|
*/
|
|
102
168
|
activate(id: string): void;
|
|
169
|
+
/** Deactivate the current source. */
|
|
103
170
|
deactivate(): void;
|
|
171
|
+
/** ID of the currently active source, or null if none. */
|
|
104
172
|
readonly activeId: string | null;
|
|
173
|
+
/** The composited output MediaStream. Reactive - updates when stream changes. */
|
|
105
174
|
readonly stream: MediaStream | null;
|
|
175
|
+
/** Current output size. Reactive - updates when size changes. */
|
|
106
176
|
readonly size: Size;
|
|
177
|
+
/** Resize the output canvas. */
|
|
107
178
|
setSize(width: number, height: number, dpr?: number): void;
|
|
179
|
+
/** Current rendering frame rate. Reactive. */
|
|
108
180
|
readonly fps: number;
|
|
181
|
+
/** Set the rendering frame rate. */
|
|
109
182
|
setFps(fps: number): void;
|
|
183
|
+
/** Current send frame rate. Reactive. */
|
|
110
184
|
readonly sendFps: number;
|
|
185
|
+
/** Set the send frame rate. */
|
|
111
186
|
setSendFps(fps: number): void;
|
|
187
|
+
/** Add an audio track to the output stream. */
|
|
112
188
|
addAudioTrack(track: MediaStreamTrack): void;
|
|
189
|
+
/** Remove an audio track by track ID. */
|
|
113
190
|
removeAudioTrack(trackId: string): void;
|
|
191
|
+
/** Manually unlock the audio context. */
|
|
114
192
|
unlockAudio(): Promise<boolean>;
|
|
193
|
+
/** Subscribe to compositor events. */
|
|
115
194
|
on: Compositor["on"];
|
|
116
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Props for the CompositorProvider component.
|
|
198
|
+
* Inherits all CompositorOptions except onSendFpsChange (managed internally).
|
|
199
|
+
*/
|
|
117
200
|
interface CompositorProviderProps extends PropsWithChildren, Partial<Omit<CompositorOptions, "onSendFpsChange">> {
|
|
118
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* React context provider for the Compositor.
|
|
204
|
+
* Creates and manages a Compositor instance, providing it to child components via context.
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```tsx
|
|
208
|
+
* function App() {
|
|
209
|
+
* return (
|
|
210
|
+
* <CompositorProvider width={1280} height={720} fps={30}>
|
|
211
|
+
* <VideoSource />
|
|
212
|
+
* <BroadcastButton />
|
|
213
|
+
* </CompositorProvider>
|
|
214
|
+
* );
|
|
215
|
+
* }
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
119
218
|
declare function CompositorProvider({ children, width, height, fps: initialFps, sendFps: initialSendFps, dpr, keepalive, autoUnlockAudio, unlockEvents, disableSilentAudio, }: CompositorProviderProps): react_jsx_runtime.JSX.Element;
|
|
219
|
+
/**
|
|
220
|
+
* Hook to access the Compositor API from context.
|
|
221
|
+
* Must be used within a CompositorProvider.
|
|
222
|
+
*
|
|
223
|
+
* @returns The CompositorApi for managing sources and output
|
|
224
|
+
* @throws {Error} If used outside of CompositorProvider
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```tsx
|
|
228
|
+
* function BroadcastButton() {
|
|
229
|
+
* const compositor = useCompositor();
|
|
230
|
+
* const { start } = useBroadcast({ whipUrl: "..." });
|
|
231
|
+
*
|
|
232
|
+
* const handleClick = async () => {
|
|
233
|
+
* if (compositor.stream) {
|
|
234
|
+
* await start(compositor.stream);
|
|
235
|
+
* }
|
|
236
|
+
* };
|
|
237
|
+
*
|
|
238
|
+
* return <button onClick={handleClick}>Start Broadcast</button>;
|
|
239
|
+
* }
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
120
242
|
declare function useCompositor(): CompositorApi;
|
|
121
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Options for the useSource hook.
|
|
246
|
+
*/
|
|
122
247
|
interface UseSourceOptions {
|
|
248
|
+
/** Type of source element: "video" for HTMLVideoElement, "canvas" for HTMLCanvasElement. */
|
|
123
249
|
kind: "video" | "canvas";
|
|
250
|
+
/** Content hint for encoding optimization. */
|
|
124
251
|
contentHint?: ContentHint;
|
|
252
|
+
/** How to fit the source content within the output canvas. Only applies to video sources. */
|
|
125
253
|
fit?: FitMode;
|
|
126
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* Return value of the useSource hook.
|
|
257
|
+
*/
|
|
127
258
|
interface UseSourceReturn<T extends HTMLVideoElement | HTMLCanvasElement> {
|
|
259
|
+
/** Ref to attach to the source element. */
|
|
128
260
|
ref: React.RefObject<T>;
|
|
261
|
+
/** Whether this source is currently active. Reactive. */
|
|
129
262
|
isActive: boolean;
|
|
263
|
+
/** Activate this source for rendering. */
|
|
130
264
|
activate: () => void;
|
|
265
|
+
/** Deactivate this source (if it's currently active). */
|
|
131
266
|
deactivate: () => void;
|
|
132
267
|
}
|
|
268
|
+
/**
|
|
269
|
+
* React hook for managing a compositor source.
|
|
270
|
+
*
|
|
271
|
+
* Automatically registers the source element with the compositor and provides
|
|
272
|
+
* methods for activation/deactivation. Cleans up on unmount.
|
|
273
|
+
*
|
|
274
|
+
* @typeParam T - The element type (HTMLVideoElement or HTMLCanvasElement)
|
|
275
|
+
* @param id - Unique identifier for this source
|
|
276
|
+
* @param options - Source configuration
|
|
277
|
+
* @returns Source state and control functions
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```tsx
|
|
281
|
+
* function CameraSource() {
|
|
282
|
+
* const { ref, isActive, activate } = useSource<HTMLVideoElement>("camera", {
|
|
283
|
+
* kind: "video",
|
|
284
|
+
* fit: "cover",
|
|
285
|
+
* });
|
|
286
|
+
*
|
|
287
|
+
* useEffect(() => {
|
|
288
|
+
* navigator.mediaDevices.getUserMedia({ video: true })
|
|
289
|
+
* .then(stream => {
|
|
290
|
+
* if (ref.current) {
|
|
291
|
+
* ref.current.srcObject = stream;
|
|
292
|
+
* activate();
|
|
293
|
+
* }
|
|
294
|
+
* });
|
|
295
|
+
* }, [activate]);
|
|
296
|
+
*
|
|
297
|
+
* return <video ref={ref} autoPlay muted />;
|
|
298
|
+
* }
|
|
299
|
+
* ```
|
|
300
|
+
*/
|
|
133
301
|
declare function useSource<T extends HTMLVideoElement | HTMLCanvasElement = HTMLVideoElement | HTMLCanvasElement>(id: string, options: UseSourceOptions): UseSourceReturn<T>;
|
|
134
302
|
|
|
303
|
+
/**
|
|
304
|
+
* @daydreamlive/react - React hooks and components for WebRTC broadcasting and playback.
|
|
305
|
+
*
|
|
306
|
+
* @example
|
|
307
|
+
* ```tsx
|
|
308
|
+
* import { useBroadcast, usePlayer, CompositorProvider, useCompositor, useSource } from "@daydreamlive/react";
|
|
309
|
+
*
|
|
310
|
+
* // Broadcasting
|
|
311
|
+
* const { status, start, stop } = useBroadcast({ whipUrl: "..." });
|
|
312
|
+
*
|
|
313
|
+
* // Playback
|
|
314
|
+
* const { status, play, videoRef } = usePlayer({ whepUrl: "..." });
|
|
315
|
+
*
|
|
316
|
+
* // Compositor with React
|
|
317
|
+
* <CompositorProvider width={1280} height={720}>
|
|
318
|
+
* <SourceComponent />
|
|
319
|
+
* </CompositorProvider>
|
|
320
|
+
* ```
|
|
321
|
+
*
|
|
322
|
+
* @packageDocumentation
|
|
323
|
+
*/
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* React hook for managing a WebRTC broadcast session.
|
|
327
|
+
*
|
|
328
|
+
* @param options - Broadcast configuration including WHIP URL
|
|
329
|
+
* @returns Broadcast status and control functions
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* ```tsx
|
|
333
|
+
* function BroadcastComponent() {
|
|
334
|
+
* const { status, start, stop } = useBroadcast({
|
|
335
|
+
* whipUrl: "https://livepeer.studio/webrtc/...",
|
|
336
|
+
* });
|
|
337
|
+
*
|
|
338
|
+
* const handleStart = async () => {
|
|
339
|
+
* const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
|
|
340
|
+
* await start(stream);
|
|
341
|
+
* };
|
|
342
|
+
*
|
|
343
|
+
* return (
|
|
344
|
+
* <div>
|
|
345
|
+
* <p>Status: {status.state}</p>
|
|
346
|
+
* {status.state === "live" && <p>Playback URL: {status.whepUrl}</p>}
|
|
347
|
+
* <button onClick={status.state === "idle" ? handleStart : stop}>
|
|
348
|
+
* {status.state === "idle" ? "Start" : "Stop"}
|
|
349
|
+
* </button>
|
|
350
|
+
* </div>
|
|
351
|
+
* );
|
|
352
|
+
* }
|
|
353
|
+
* ```
|
|
354
|
+
*/
|
|
135
355
|
declare function useBroadcast(options: UseBroadcastOptions): UseBroadcastReturn;
|
|
356
|
+
/**
|
|
357
|
+
* React hook for managing a WebRTC playback session.
|
|
358
|
+
*
|
|
359
|
+
* @param options - Player configuration including WHEP URL
|
|
360
|
+
* @returns Player status, control functions, and video element ref
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```tsx
|
|
364
|
+
* function PlayerComponent({ whepUrl }) {
|
|
365
|
+
* const { status, play, stop, videoRef } = usePlayer({
|
|
366
|
+
* whepUrl,
|
|
367
|
+
* autoPlay: true,
|
|
368
|
+
* });
|
|
369
|
+
*
|
|
370
|
+
* useEffect(() => {
|
|
371
|
+
* if (whepUrl) play();
|
|
372
|
+
* }, [whepUrl, play]);
|
|
373
|
+
*
|
|
374
|
+
* return (
|
|
375
|
+
* <div>
|
|
376
|
+
* <video ref={videoRef} autoPlay muted playsInline />
|
|
377
|
+
* <p>Status: {status.state}</p>
|
|
378
|
+
* </div>
|
|
379
|
+
* );
|
|
380
|
+
* }
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
136
383
|
declare function usePlayer(options: UsePlayerOptions): UsePlayerReturn;
|
|
137
384
|
|
|
138
385
|
export { type CompositorApi, CompositorProvider, type CompositorProviderProps, type UseBroadcastOptions, type UseBroadcastReturn, type UseBroadcastStatus, type UsePlayerOptions, type UsePlayerReturn, type UsePlayerStatus, type UseSourceOptions, type UseSourceReturn, useBroadcast, useCompositor, usePlayer, useSource };
|
package/dist/index.js
CHANGED
|
@@ -210,6 +210,26 @@ function usePlayer(options, factory) {
|
|
|
210
210
|
};
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
+
// src/index.ts
|
|
214
|
+
import {
|
|
215
|
+
BaseDaydreamError,
|
|
216
|
+
NetworkError,
|
|
217
|
+
ConnectionError,
|
|
218
|
+
StreamNotFoundError,
|
|
219
|
+
UnauthorizedError
|
|
220
|
+
} from "@daydreamlive/browser";
|
|
221
|
+
import {
|
|
222
|
+
DEFAULT_ICE_SERVERS,
|
|
223
|
+
DEFAULT_VIDEO_BITRATE,
|
|
224
|
+
DEFAULT_AUDIO_BITRATE
|
|
225
|
+
} from "@daydreamlive/browser";
|
|
226
|
+
import {
|
|
227
|
+
createCompositor as createCompositor2,
|
|
228
|
+
livepeerResponseHandler,
|
|
229
|
+
Broadcast,
|
|
230
|
+
Player
|
|
231
|
+
} from "@daydreamlive/browser";
|
|
232
|
+
|
|
213
233
|
// src/useCompositor.tsx
|
|
214
234
|
import {
|
|
215
235
|
createContext,
|
|
@@ -416,7 +436,19 @@ function usePlayer2(options) {
|
|
|
416
436
|
return usePlayer(options, createPlayer);
|
|
417
437
|
}
|
|
418
438
|
export {
|
|
439
|
+
BaseDaydreamError,
|
|
440
|
+
Broadcast,
|
|
419
441
|
CompositorProvider,
|
|
442
|
+
ConnectionError,
|
|
443
|
+
DEFAULT_AUDIO_BITRATE,
|
|
444
|
+
DEFAULT_ICE_SERVERS,
|
|
445
|
+
DEFAULT_VIDEO_BITRATE,
|
|
446
|
+
NetworkError,
|
|
447
|
+
Player,
|
|
448
|
+
StreamNotFoundError,
|
|
449
|
+
UnauthorizedError,
|
|
450
|
+
createCompositor2 as createCompositor,
|
|
451
|
+
livepeerResponseHandler,
|
|
420
452
|
useBroadcast2 as useBroadcast,
|
|
421
453
|
useCompositor,
|
|
422
454
|
usePlayer2 as usePlayer,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/useBroadcast.ts","../src/usePlayer.ts","../src/useCompositor.tsx","../src/useSource.ts"],"sourcesContent":["import { createBroadcast, createPlayer } from \"@daydreamlive/browser\";\nimport {\n useBroadcast as baseUseBroadcast,\n type UseBroadcastOptions,\n type UseBroadcastReturn,\n type UseBroadcastStatus,\n} from \"./useBroadcast\";\nimport {\n usePlayer as baseUsePlayer,\n type UsePlayerOptions,\n type UsePlayerReturn,\n type UsePlayerStatus,\n} from \"./usePlayer\";\n\nexport function useBroadcast(options: UseBroadcastOptions): UseBroadcastReturn {\n return baseUseBroadcast(options, createBroadcast);\n}\n\nexport function usePlayer(options: UsePlayerOptions): UsePlayerReturn {\n return baseUsePlayer(options, createPlayer);\n}\n\nexport type {\n UseBroadcastOptions,\n UseBroadcastReturn,\n UseBroadcastStatus,\n UsePlayerOptions,\n UsePlayerReturn,\n UsePlayerStatus,\n};\n\nexport type {\n AudioConfig,\n BroadcastState,\n PlayerState,\n ReconnectConfig,\n ReconnectInfo,\n VideoConfig,\n DaydreamError,\n DaydreamErrorCode,\n // Compositor types\n Compositor,\n CompositorOptions,\n CompositorEvent,\n CompositorEventMap,\n Source,\n VideoSource,\n CanvasSource,\n Size,\n FitMode,\n ContentHint,\n Ctx2D,\n} from \"@daydreamlive/browser\";\n\nexport {\n CompositorProvider,\n useCompositor,\n type CompositorApi,\n type CompositorProviderProps,\n} from \"./useCompositor\";\n\nexport {\n useSource,\n type UseSourceOptions,\n type UseSourceReturn,\n} from \"./useSource\";\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type {\n AudioConfig,\n Broadcast,\n BroadcastOptions,\n BroadcastState,\n DaydreamError,\n ReconnectConfig,\n ReconnectInfo,\n VideoConfig,\n} from \"@daydreamlive/browser\";\n\nexport interface UseBroadcastOptions {\n whipUrl: string;\n reconnect?: ReconnectConfig;\n video?: VideoConfig;\n audio?: AudioConfig;\n iceServers?: RTCIceServer[];\n connectionTimeout?: number;\n onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n}\n\nexport type BroadcastFactory = (options: BroadcastOptions) => Broadcast;\n\nexport type UseBroadcastStatus =\n | { state: \"idle\" }\n | { state: \"connecting\" }\n | { state: \"live\"; whepUrl: string }\n | { state: \"reconnecting\"; whepUrl: string; reconnectInfo: ReconnectInfo }\n | { state: \"ended\" }\n | { state: \"error\"; error: DaydreamError };\n\nexport interface UseBroadcastReturn {\n status: UseBroadcastStatus;\n start: (stream: MediaStream) => Promise<void>;\n stop: () => Promise<void>;\n setMaxFramerate: (fps?: number) => void;\n}\n\nexport function useBroadcast(\n options: UseBroadcastOptions,\n factory: BroadcastFactory,\n): UseBroadcastReturn {\n const [status, setStatus] = useState<UseBroadcastStatus>({ state: \"idle\" });\n const broadcastRef = useRef<Broadcast | null>(null);\n const whepUrlRef = useRef<string | null>(null);\n const optionsRef = useRef(options);\n const factoryRef = useRef(factory);\n\n useEffect(() => {\n optionsRef.current = options;\n }, [options]);\n\n useEffect(() => {\n factoryRef.current = factory;\n }, [factory]);\n\n useEffect(() => {\n return () => {\n broadcastRef.current?.stop();\n };\n }, []);\n\n const updateStatus = useCallback((newState: BroadcastState, error?: DaydreamError) => {\n const whepUrl = whepUrlRef.current;\n switch (newState) {\n case \"connecting\":\n setStatus({ state: \"connecting\" });\n break;\n case \"live\":\n setStatus({ state: \"live\", whepUrl: whepUrl! });\n break;\n case \"reconnecting\":\n // reconnectInfo will be set by the reconnect event\n break;\n case \"ended\":\n setStatus({ state: \"ended\" });\n break;\n case \"error\":\n setStatus({ state: \"error\", error: error! });\n break;\n }\n }, []);\n\n const start = useCallback(async (stream: MediaStream) => {\n if (broadcastRef.current) {\n await broadcastRef.current.stop();\n broadcastRef.current = null;\n }\n\n setStatus({ state: \"connecting\" });\n\n const broadcast = factoryRef.current({\n stream,\n ...optionsRef.current,\n });\n\n broadcastRef.current = broadcast;\n\n broadcast.on(\"stateChange\", (newState) => {\n // Guard against events from stopped broadcast\n if (broadcastRef.current !== broadcast) return;\n if (newState === \"live\" || newState === \"reconnecting\") {\n whepUrlRef.current = broadcast.whepUrl;\n }\n updateStatus(newState);\n });\n\n broadcast.on(\"error\", (err) => {\n if (broadcastRef.current !== broadcast) return;\n updateStatus(\"error\", err);\n });\n\n broadcast.on(\"reconnect\", (info) => {\n if (broadcastRef.current !== broadcast) return;\n setStatus({\n state: \"reconnecting\",\n whepUrl: whepUrlRef.current!,\n reconnectInfo: info,\n });\n });\n\n try {\n await broadcast.connect();\n if (broadcastRef.current !== broadcast) return;\n whepUrlRef.current = broadcast.whepUrl;\n updateStatus(broadcast.state);\n } catch (err) {\n if (broadcastRef.current !== broadcast) return;\n setStatus({ state: \"error\", error: err as DaydreamError });\n throw err;\n }\n }, [updateStatus]);\n\n const stop = useCallback(async () => {\n await broadcastRef.current?.stop();\n broadcastRef.current = null;\n whepUrlRef.current = null;\n setStatus({ state: \"idle\" });\n }, []);\n\n const setMaxFramerate = useCallback((fps?: number) => {\n broadcastRef.current?.setMaxFramerate(fps);\n }, []);\n\n return {\n status,\n start,\n stop,\n setMaxFramerate,\n };\n}\n","import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type RefObject,\n} from \"react\";\nimport type {\n Player,\n PlayerOptions,\n PlayerState,\n DaydreamError,\n ReconnectConfig,\n ReconnectInfo,\n} from \"@daydreamlive/browser\";\n\nexport interface UsePlayerOptions {\n whepUrl: string | null;\n reconnect?: ReconnectConfig;\n iceServers?: RTCIceServer[];\n connectionTimeout?: number;\n skipIceGathering?: boolean;\n autoPlay?: boolean;\n onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n}\n\nexport type PlayerFactory = (\n whepUrl: string,\n options?: PlayerOptions,\n) => Player;\n\nexport type UsePlayerStatus =\n | { state: \"idle\" }\n | { state: \"connecting\" }\n | { state: \"playing\" }\n | { state: \"buffering\"; reconnectInfo: ReconnectInfo }\n | { state: \"ended\" }\n | { state: \"error\"; error: DaydreamError };\n\nexport interface UsePlayerReturn {\n status: UsePlayerStatus;\n play: () => Promise<void>;\n stop: () => Promise<void>;\n videoRef: RefObject<HTMLVideoElement | null>;\n}\n\nexport function usePlayer(\n options: UsePlayerOptions,\n factory: PlayerFactory,\n): UsePlayerReturn {\n const [status, setStatus] = useState<UsePlayerStatus>({ state: \"idle\" });\n const playerRef = useRef<Player | null>(null);\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const optionsRef = useRef(options);\n const factoryRef = useRef(factory);\n\n useEffect(() => {\n optionsRef.current = options;\n }, [options]);\n\n useEffect(() => {\n factoryRef.current = factory;\n }, [factory]);\n\n useEffect(() => {\n return () => {\n playerRef.current?.stop();\n };\n }, []);\n\n const updateStatus = useCallback(\n (newState: PlayerState, error?: DaydreamError) => {\n switch (newState) {\n case \"connecting\":\n setStatus({ state: \"connecting\" });\n break;\n case \"playing\":\n setStatus({ state: \"playing\" });\n break;\n case \"buffering\":\n // reconnectInfo will be set by the reconnect event\n break;\n case \"ended\":\n setStatus({ state: \"ended\" });\n break;\n case \"error\":\n setStatus({ state: \"error\", error: error! });\n break;\n }\n },\n [],\n );\n\n const play = useCallback(async () => {\n const currentWhepUrl = optionsRef.current.whepUrl;\n if (!currentWhepUrl) {\n return;\n }\n\n if (playerRef.current) {\n await playerRef.current.stop();\n playerRef.current = null;\n }\n\n setStatus({ state: \"connecting\" });\n\n const player = factoryRef.current(currentWhepUrl, {\n reconnect: optionsRef.current?.reconnect,\n iceServers: optionsRef.current?.iceServers,\n connectionTimeout: optionsRef.current?.connectionTimeout,\n skipIceGathering: optionsRef.current?.skipIceGathering,\n onStats: optionsRef.current?.onStats,\n statsIntervalMs: optionsRef.current?.statsIntervalMs,\n });\n\n playerRef.current = player;\n\n player.on(\"stateChange\", (newState) => {\n // Guard against events from stopped player\n if (playerRef.current !== player) return;\n updateStatus(newState);\n // Re-attach stream after reconnect\n if (newState === \"playing\" && videoRef.current && player.stream) {\n if (videoRef.current.srcObject !== player.stream) {\n player.attachTo(videoRef.current);\n }\n }\n });\n\n player.on(\"error\", (err) => {\n if (playerRef.current !== player) return;\n updateStatus(\"error\", err);\n });\n\n player.on(\"reconnect\", (info) => {\n if (playerRef.current !== player) return;\n setStatus({ state: \"buffering\", reconnectInfo: info });\n });\n\n try {\n await player.connect();\n if (playerRef.current !== player) return;\n updateStatus(player.state);\n\n if (videoRef.current) {\n player.attachTo(videoRef.current);\n if (optionsRef.current?.autoPlay !== false) {\n try {\n await videoRef.current.play();\n } catch {\n // Autoplay blocked\n }\n }\n }\n } catch (err) {\n if (playerRef.current !== player) return;\n setStatus({ state: \"error\", error: err as DaydreamError });\n throw err;\n }\n }, [updateStatus]);\n\n const stop = useCallback(async () => {\n await playerRef.current?.stop();\n playerRef.current = null;\n setStatus({ state: \"idle\" });\n }, []);\n\n return {\n status,\n play,\n stop,\n videoRef,\n };\n}\n","\"use client\";\n\nimport {\n createContext,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type PropsWithChildren,\n} from \"react\";\nimport {\n createCompositor,\n type Compositor,\n type CompositorOptions,\n type Size,\n type Source,\n} from \"@daydreamlive/browser\";\n\nexport interface CompositorApi {\n // Registry\n register(id: string, source: Source): void;\n unregister(id: string): void;\n get(id: string): Source | undefined;\n has(id: string): boolean;\n list(): Array<{ id: string; source: Source }>;\n\n /**\n * Register a source, activate it, and return an unregister function.\n * Convenience method that combines register + activate with automatic cleanup.\n *\n * @example\n * ```tsx\n * useEffect(() => {\n * const unregister = compositor.use(\"camera\", {\n * kind: \"video\",\n * element: videoRef.current,\n * fit: \"cover\",\n * });\n * return unregister;\n * }, [compositor]);\n * ```\n */\n use(id: string, source: Source): () => void;\n\n // Active source\n /**\n * Activate a registered source.\n * @param id - The source ID to activate\n */\n activate(id: string): void;\n deactivate(): void;\n readonly activeId: string | null;\n\n // Output (reactive)\n readonly stream: MediaStream | null;\n readonly size: Size;\n setSize(width: number, height: number, dpr?: number): void;\n\n // FPS (reactive)\n readonly fps: number;\n setFps(fps: number): void;\n readonly sendFps: number;\n setSendFps(fps: number): void;\n\n // Audio\n addAudioTrack(track: MediaStreamTrack): void;\n removeAudioTrack(trackId: string): void;\n unlockAudio(): Promise<boolean>;\n\n // Events\n on: Compositor[\"on\"];\n}\n\nconst CompositorContext = createContext<CompositorApi | null>(null);\n\nexport interface CompositorProviderProps\n extends PropsWithChildren,\n Partial<Omit<CompositorOptions, \"onSendFpsChange\">> {}\n\nexport function CompositorProvider({\n children,\n width = 512,\n height = 512,\n fps: initialFps = 30,\n sendFps: initialSendFps,\n dpr,\n keepalive,\n autoUnlockAudio,\n unlockEvents,\n disableSilentAudio = true,\n}: CompositorProviderProps) {\n const compositorRef = useRef<Compositor | null>(null);\n const [stream, setStream] = useState<MediaStream | null>(null);\n const [size, setSize] = useState<Size>({\n width,\n height,\n dpr: Math.min(\n 2,\n dpr ?? (typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1),\n ),\n });\n const [fps, setFpsState] = useState(initialFps);\n const [sendFps, setSendFpsState] = useState(initialSendFps ?? initialFps);\n\n // Create compositor once\n useLayoutEffect(() => {\n const compositor = createCompositor({\n width,\n height,\n fps: initialFps,\n sendFps: initialSendFps,\n dpr,\n keepalive,\n autoUnlockAudio,\n unlockEvents,\n disableSilentAudio,\n onSendFpsChange: (newFps) => setSendFpsState(newFps),\n });\n\n compositorRef.current = compositor;\n setStream(compositor.stream);\n setSize(compositor.size);\n\n return () => {\n compositor.destroy();\n compositorRef.current = null;\n };\n }, []);\n\n // Sync size changes\n useEffect(() => {\n const compositor = compositorRef.current;\n if (!compositor) return;\n\n compositor.resize(size.width, size.height, size.dpr);\n setStream(compositor.stream);\n }, [size.width, size.height, size.dpr]);\n\n // Sync fps changes\n useEffect(() => {\n const compositor = compositorRef.current;\n if (!compositor) return;\n\n compositor.setFps(fps);\n setStream(compositor.stream);\n }, [fps]);\n\n // Sync sendFps changes\n useEffect(() => {\n const compositor = compositorRef.current;\n if (!compositor) return;\n\n compositor.setSendFps(sendFps);\n }, [sendFps]);\n\n // Memoized API\n const api = useMemo<CompositorApi>(\n () => ({\n // Registry\n register: (id, source) => compositorRef.current?.register(id, source),\n unregister: (id) => compositorRef.current?.unregister(id),\n get: (id) => compositorRef.current?.get(id),\n has: (id) => compositorRef.current?.has(id) ?? false,\n list: () => compositorRef.current?.list() ?? [],\n use: (id, source) => {\n compositorRef.current?.register(id, source);\n compositorRef.current?.activate(id);\n return () => compositorRef.current?.unregister(id);\n },\n\n // Active source\n activate: (id) => compositorRef.current?.activate(id),\n deactivate: () => compositorRef.current?.deactivate(),\n get activeId() {\n return compositorRef.current?.activeId ?? null;\n },\n\n // Stream & size\n stream,\n size,\n setSize: (w, h, d) =>\n setSize({ width: w, height: h, dpr: d ?? size.dpr }),\n\n // FPS\n fps,\n setFps: setFpsState,\n sendFps,\n setSendFps: setSendFpsState,\n\n // Audio\n addAudioTrack: (t) => compositorRef.current?.addAudioTrack(t),\n removeAudioTrack: (id) => compositorRef.current?.removeAudioTrack(id),\n unlockAudio: () =>\n compositorRef.current?.unlockAudio() ?? Promise.resolve(false),\n\n // Events\n on: (event, cb) => compositorRef.current?.on(event, cb) ?? (() => {}),\n }),\n [stream, size, fps, sendFps],\n );\n\n return (\n <CompositorContext.Provider value={api}>\n {children}\n </CompositorContext.Provider>\n );\n}\n\nexport function useCompositor(): CompositorApi {\n const ctx = useContext(CompositorContext);\n if (!ctx) {\n throw new Error(\"useCompositor must be used within <CompositorProvider>\");\n }\n return ctx;\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState, useCallback, useMemo } from \"react\";\nimport type { Source, FitMode, ContentHint } from \"@daydreamlive/browser\";\nimport { useCompositor } from \"./useCompositor\";\n\nexport interface UseSourceOptions {\n kind: \"video\" | \"canvas\";\n contentHint?: ContentHint;\n fit?: FitMode;\n}\n\nexport interface UseSourceReturn<\n T extends HTMLVideoElement | HTMLCanvasElement,\n> {\n ref: React.RefObject<T>;\n isActive: boolean;\n activate: () => void;\n deactivate: () => void;\n}\n\nexport function useSource<\n T extends HTMLVideoElement | HTMLCanvasElement =\n | HTMLVideoElement\n | HTMLCanvasElement,\n>(id: string, options: UseSourceOptions): UseSourceReturn<T> {\n const compositor = useCompositor();\n const compositorRef = useRef(compositor);\n compositorRef.current = compositor;\n\n const ref = useRef<T>(null);\n const [isActive, setIsActive] = useState(false);\n const registeredRef = useRef(false);\n const idRef = useRef(id);\n idRef.current = id;\n\n const { kind, contentHint, fit } = options;\n\n const optionsRef = useRef({ kind, contentHint, fit });\n optionsRef.current = { kind, contentHint, fit };\n\n const registerSource = useCallback((element: T) => {\n const { kind, contentHint, fit } = optionsRef.current;\n const source =\n kind === \"video\"\n ? {\n kind: \"video\" as const,\n element: element as HTMLVideoElement,\n contentHint,\n fit,\n }\n : {\n kind: \"canvas\" as const,\n element: element as HTMLCanvasElement,\n contentHint,\n };\n\n compositorRef.current.register(idRef.current, source);\n registeredRef.current = true;\n }, []);\n\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n registerSource(element);\n }, [id, kind, contentHint, fit, registerSource]);\n\n useEffect(() => {\n const currentId = id;\n return () => {\n if (registeredRef.current) {\n registeredRef.current = false;\n setIsActive(false);\n compositorRef.current.unregister(currentId);\n }\n };\n }, [id]);\n\n useEffect(() => {\n setIsActive(compositor.activeId === id);\n }, [compositor.activeId, id]);\n\n const activate = useCallback(() => {\n const element = ref.current;\n if (!element) return;\n\n if (!registeredRef.current) {\n registerSource(element);\n }\n\n compositorRef.current.activate(idRef.current);\n setIsActive(true);\n }, [registerSource]);\n\n const deactivate = useCallback(() => {\n if (compositorRef.current.activeId === idRef.current) {\n compositorRef.current.deactivate();\n setIsActive(false);\n }\n }, []);\n\n return useMemo(\n () => ({\n ref,\n isActive,\n activate,\n deactivate,\n }),\n [isActive, activate, deactivate],\n );\n}\n"],"mappings":";AAAA,SAAS,iBAAiB,oBAAoB;;;ACA9C,SAAS,aAAa,WAAW,QAAQ,gBAAgB;AAwClD,SAAS,aACd,SACA,SACoB;AACpB,QAAM,CAAC,QAAQ,SAAS,IAAI,SAA6B,EAAE,OAAO,OAAO,CAAC;AAC1E,QAAM,eAAe,OAAyB,IAAI;AAClD,QAAM,aAAa,OAAsB,IAAI;AAC7C,QAAM,aAAa,OAAO,OAAO;AACjC,QAAM,aAAa,OAAO,OAAO;AAEjC,YAAU,MAAM;AACd,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,OAAO,CAAC;AAEZ,YAAU,MAAM;AACd,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,OAAO,CAAC;AAEZ,YAAU,MAAM;AACd,WAAO,MAAM;AACX,mBAAa,SAAS,KAAK;AAAA,IAC7B;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,eAAe,YAAY,CAAC,UAA0B,UAA0B;AACpF,UAAM,UAAU,WAAW;AAC3B,YAAQ,UAAU;AAAA,MAChB,KAAK;AACH,kBAAU,EAAE,OAAO,aAAa,CAAC;AACjC;AAAA,MACF,KAAK;AACH,kBAAU,EAAE,OAAO,QAAQ,QAAkB,CAAC;AAC9C;AAAA,MACF,KAAK;AAEH;AAAA,MACF,KAAK;AACH,kBAAU,EAAE,OAAO,QAAQ,CAAC;AAC5B;AAAA,MACF,KAAK;AACH,kBAAU,EAAE,OAAO,SAAS,MAAc,CAAC;AAC3C;AAAA,IACJ;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,QAAQ,YAAY,OAAO,WAAwB;AACvD,QAAI,aAAa,SAAS;AACxB,YAAM,aAAa,QAAQ,KAAK;AAChC,mBAAa,UAAU;AAAA,IACzB;AAEA,cAAU,EAAE,OAAO,aAAa,CAAC;AAEjC,UAAM,YAAY,WAAW,QAAQ;AAAA,MACnC;AAAA,MACA,GAAG,WAAW;AAAA,IAChB,CAAC;AAED,iBAAa,UAAU;AAEvB,cAAU,GAAG,eAAe,CAAC,aAAa;AAExC,UAAI,aAAa,YAAY,UAAW;AACxC,UAAI,aAAa,UAAU,aAAa,gBAAgB;AACtD,mBAAW,UAAU,UAAU;AAAA,MACjC;AACA,mBAAa,QAAQ;AAAA,IACvB,CAAC;AAED,cAAU,GAAG,SAAS,CAAC,QAAQ;AAC7B,UAAI,aAAa,YAAY,UAAW;AACxC,mBAAa,SAAS,GAAG;AAAA,IAC3B,CAAC;AAED,cAAU,GAAG,aAAa,CAAC,SAAS;AAClC,UAAI,aAAa,YAAY,UAAW;AACxC,gBAAU;AAAA,QACR,OAAO;AAAA,QACP,SAAS,WAAW;AAAA,QACpB,eAAe;AAAA,MACjB,CAAC;AAAA,IACH,CAAC;AAED,QAAI;AACF,YAAM,UAAU,QAAQ;AACxB,UAAI,aAAa,YAAY,UAAW;AACxC,iBAAW,UAAU,UAAU;AAC/B,mBAAa,UAAU,KAAK;AAAA,IAC9B,SAAS,KAAK;AACZ,UAAI,aAAa,YAAY,UAAW;AACxC,gBAAU,EAAE,OAAO,SAAS,OAAO,IAAqB,CAAC;AACzD,YAAM;AAAA,IACR;AAAA,EACF,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,OAAO,YAAY,YAAY;AACnC,UAAM,aAAa,SAAS,KAAK;AACjC,iBAAa,UAAU;AACvB,eAAW,UAAU;AACrB,cAAU,EAAE,OAAO,OAAO,CAAC;AAAA,EAC7B,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAkB,YAAY,CAAC,QAAiB;AACpD,iBAAa,SAAS,gBAAgB,GAAG;AAAA,EAC3C,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACxJA;AAAA,EACE,eAAAA;AAAA,EACA,aAAAC;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,OAEK;AAyCA,SAAS,UACd,SACA,SACiB;AACjB,QAAM,CAAC,QAAQ,SAAS,IAAIA,UAA0B,EAAE,OAAO,OAAO,CAAC;AACvE,QAAM,YAAYD,QAAsB,IAAI;AAC5C,QAAM,WAAWA,QAAgC,IAAI;AACrD,QAAM,aAAaA,QAAO,OAAO;AACjC,QAAM,aAAaA,QAAO,OAAO;AAEjC,EAAAD,WAAU,MAAM;AACd,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,OAAO,CAAC;AAEZ,EAAAA,WAAU,MAAM;AACd,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,OAAO,CAAC;AAEZ,EAAAA,WAAU,MAAM;AACd,WAAO,MAAM;AACX,gBAAU,SAAS,KAAK;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,eAAeD;AAAA,IACnB,CAAC,UAAuB,UAA0B;AAChD,cAAQ,UAAU;AAAA,QAChB,KAAK;AACH,oBAAU,EAAE,OAAO,aAAa,CAAC;AACjC;AAAA,QACF,KAAK;AACH,oBAAU,EAAE,OAAO,UAAU,CAAC;AAC9B;AAAA,QACF,KAAK;AAEH;AAAA,QACF,KAAK;AACH,oBAAU,EAAE,OAAO,QAAQ,CAAC;AAC5B;AAAA,QACF,KAAK;AACH,oBAAU,EAAE,OAAO,SAAS,MAAc,CAAC;AAC3C;AAAA,MACJ;AAAA,IACF;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,OAAOA,aAAY,YAAY;AACnC,UAAM,iBAAiB,WAAW,QAAQ;AAC1C,QAAI,CAAC,gBAAgB;AACnB;AAAA,IACF;AAEA,QAAI,UAAU,SAAS;AACrB,YAAM,UAAU,QAAQ,KAAK;AAC7B,gBAAU,UAAU;AAAA,IACtB;AAEA,cAAU,EAAE,OAAO,aAAa,CAAC;AAEjC,UAAM,SAAS,WAAW,QAAQ,gBAAgB;AAAA,MAChD,WAAW,WAAW,SAAS;AAAA,MAC/B,YAAY,WAAW,SAAS;AAAA,MAChC,mBAAmB,WAAW,SAAS;AAAA,MACvC,kBAAkB,WAAW,SAAS;AAAA,MACtC,SAAS,WAAW,SAAS;AAAA,MAC7B,iBAAiB,WAAW,SAAS;AAAA,IACvC,CAAC;AAED,cAAU,UAAU;AAEpB,WAAO,GAAG,eAAe,CAAC,aAAa;AAErC,UAAI,UAAU,YAAY,OAAQ;AAClC,mBAAa,QAAQ;AAErB,UAAI,aAAa,aAAa,SAAS,WAAW,OAAO,QAAQ;AAC/D,YAAI,SAAS,QAAQ,cAAc,OAAO,QAAQ;AAChD,iBAAO,SAAS,SAAS,OAAO;AAAA,QAClC;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO,GAAG,SAAS,CAAC,QAAQ;AAC1B,UAAI,UAAU,YAAY,OAAQ;AAClC,mBAAa,SAAS,GAAG;AAAA,IAC3B,CAAC;AAED,WAAO,GAAG,aAAa,CAAC,SAAS;AAC/B,UAAI,UAAU,YAAY,OAAQ;AAClC,gBAAU,EAAE,OAAO,aAAa,eAAe,KAAK,CAAC;AAAA,IACvD,CAAC;AAED,QAAI;AACF,YAAM,OAAO,QAAQ;AACrB,UAAI,UAAU,YAAY,OAAQ;AAClC,mBAAa,OAAO,KAAK;AAEzB,UAAI,SAAS,SAAS;AACpB,eAAO,SAAS,SAAS,OAAO;AAChC,YAAI,WAAW,SAAS,aAAa,OAAO;AAC1C,cAAI;AACF,kBAAM,SAAS,QAAQ,KAAK;AAAA,UAC9B,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,UAAU,YAAY,OAAQ;AAClC,gBAAU,EAAE,OAAO,SAAS,OAAO,IAAqB,CAAC;AACzD,YAAM;AAAA,IACR;AAAA,EACF,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,OAAOA,aAAY,YAAY;AACnC,UAAM,UAAU,SAAS,KAAK;AAC9B,cAAU,UAAU;AACpB,cAAU,EAAE,OAAO,OAAO,CAAC;AAAA,EAC7B,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AC5KA;AAAA,EACE;AAAA,EACA;AAAA,EACA,aAAAI;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,OAEK;AACP;AAAA,EACE;AAAA,OAKK;AA0LH;AAjIJ,IAAM,oBAAoB,cAAoC,IAAI;AAM3D,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,KAAK,aAAa;AAAA,EAClB,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAqB;AACvB,GAA4B;AAC1B,QAAM,gBAAgBD,QAA0B,IAAI;AACpD,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAA6B,IAAI;AAC7D,QAAM,CAAC,MAAM,OAAO,IAAIA,UAAe;AAAA,IACrC;AAAA,IACA;AAAA,IACA,KAAK,KAAK;AAAA,MACR;AAAA,MACA,QAAQ,OAAO,WAAW,cAAc,OAAO,oBAAoB,IAAI;AAAA,IACzE;AAAA,EACF,CAAC;AACD,QAAM,CAAC,KAAK,WAAW,IAAIA,UAAS,UAAU;AAC9C,QAAM,CAAC,SAAS,eAAe,IAAIA,UAAS,kBAAkB,UAAU;AAGxE,kBAAgB,MAAM;AACpB,UAAM,aAAa,iBAAiB;AAAA,MAClC;AAAA,MACA;AAAA,MACA,KAAK;AAAA,MACL,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,iBAAiB,CAAC,WAAW,gBAAgB,MAAM;AAAA,IACrD,CAAC;AAED,kBAAc,UAAU;AACxB,cAAU,WAAW,MAAM;AAC3B,YAAQ,WAAW,IAAI;AAEvB,WAAO,MAAM;AACX,iBAAW,QAAQ;AACnB,oBAAc,UAAU;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,EAAAF,WAAU,MAAM;AACd,UAAM,aAAa,cAAc;AACjC,QAAI,CAAC,WAAY;AAEjB,eAAW,OAAO,KAAK,OAAO,KAAK,QAAQ,KAAK,GAAG;AACnD,cAAU,WAAW,MAAM;AAAA,EAC7B,GAAG,CAAC,KAAK,OAAO,KAAK,QAAQ,KAAK,GAAG,CAAC;AAGtC,EAAAA,WAAU,MAAM;AACd,UAAM,aAAa,cAAc;AACjC,QAAI,CAAC,WAAY;AAEjB,eAAW,OAAO,GAAG;AACrB,cAAU,WAAW,MAAM;AAAA,EAC7B,GAAG,CAAC,GAAG,CAAC;AAGR,EAAAA,WAAU,MAAM;AACd,UAAM,aAAa,cAAc;AACjC,QAAI,CAAC,WAAY;AAEjB,eAAW,WAAW,OAAO;AAAA,EAC/B,GAAG,CAAC,OAAO,CAAC;AAGZ,QAAM,MAAM;AAAA,IACV,OAAO;AAAA;AAAA,MAEL,UAAU,CAAC,IAAI,WAAW,cAAc,SAAS,SAAS,IAAI,MAAM;AAAA,MACpE,YAAY,CAAC,OAAO,cAAc,SAAS,WAAW,EAAE;AAAA,MACxD,KAAK,CAAC,OAAO,cAAc,SAAS,IAAI,EAAE;AAAA,MAC1C,KAAK,CAAC,OAAO,cAAc,SAAS,IAAI,EAAE,KAAK;AAAA,MAC/C,MAAM,MAAM,cAAc,SAAS,KAAK,KAAK,CAAC;AAAA,MAC9C,KAAK,CAAC,IAAI,WAAW;AACnB,sBAAc,SAAS,SAAS,IAAI,MAAM;AAC1C,sBAAc,SAAS,SAAS,EAAE;AAClC,eAAO,MAAM,cAAc,SAAS,WAAW,EAAE;AAAA,MACnD;AAAA;AAAA,MAGA,UAAU,CAAC,OAAO,cAAc,SAAS,SAAS,EAAE;AAAA,MACpD,YAAY,MAAM,cAAc,SAAS,WAAW;AAAA,MACpD,IAAI,WAAW;AACb,eAAO,cAAc,SAAS,YAAY;AAAA,MAC5C;AAAA;AAAA,MAGA;AAAA,MACA;AAAA,MACA,SAAS,CAAC,GAAG,GAAG,MACd,QAAQ,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,KAAK,KAAK,IAAI,CAAC;AAAA;AAAA,MAGrD;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA,YAAY;AAAA;AAAA,MAGZ,eAAe,CAAC,MAAM,cAAc,SAAS,cAAc,CAAC;AAAA,MAC5D,kBAAkB,CAAC,OAAO,cAAc,SAAS,iBAAiB,EAAE;AAAA,MACpE,aAAa,MACX,cAAc,SAAS,YAAY,KAAK,QAAQ,QAAQ,KAAK;AAAA;AAAA,MAG/D,IAAI,CAAC,OAAO,OAAO,cAAc,SAAS,GAAG,OAAO,EAAE,MAAM,MAAM;AAAA,MAAC;AAAA,IACrE;AAAA,IACA,CAAC,QAAQ,MAAM,KAAK,OAAO;AAAA,EAC7B;AAEA,SACE,oBAAC,kBAAkB,UAAlB,EAA2B,OAAO,KAChC,UACH;AAEJ;AAEO,SAAS,gBAA+B;AAC7C,QAAM,MAAM,WAAW,iBAAiB;AACxC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,SAAO;AACT;;;ACtNA,SAAS,aAAAG,YAAW,UAAAC,SAAQ,YAAAC,WAAU,eAAAC,cAAa,WAAAC,gBAAe;AAmB3D,SAAS,UAId,IAAY,SAA+C;AAC3D,QAAM,aAAa,cAAc;AACjC,QAAM,gBAAgBC,QAAO,UAAU;AACvC,gBAAc,UAAU;AAExB,QAAM,MAAMA,QAAU,IAAI;AAC1B,QAAM,CAAC,UAAU,WAAW,IAAIC,UAAS,KAAK;AAC9C,QAAM,gBAAgBD,QAAO,KAAK;AAClC,QAAM,QAAQA,QAAO,EAAE;AACvB,QAAM,UAAU;AAEhB,QAAM,EAAE,MAAM,aAAa,IAAI,IAAI;AAEnC,QAAM,aAAaA,QAAO,EAAE,MAAM,aAAa,IAAI,CAAC;AACpD,aAAW,UAAU,EAAE,MAAM,aAAa,IAAI;AAE9C,QAAM,iBAAiBE,aAAY,CAAC,YAAe;AACjD,UAAM,EAAE,MAAAC,OAAM,aAAAC,cAAa,KAAAC,KAAI,IAAI,WAAW;AAC9C,UAAM,SACJF,UAAS,UACL;AAAA,MACE,MAAM;AAAA,MACN;AAAA,MACA,aAAAC;AAAA,MACA,KAAAC;AAAA,IACF,IACA;AAAA,MACE,MAAM;AAAA,MACN;AAAA,MACA,aAAAD;AAAA,IACF;AAEN,kBAAc,QAAQ,SAAS,MAAM,SAAS,MAAM;AACpD,kBAAc,UAAU;AAAA,EAC1B,GAAG,CAAC,CAAC;AAEL,EAAAE,WAAU,MAAM;AACd,UAAM,UAAU,IAAI;AACpB,QAAI,CAAC,QAAS;AAEd,mBAAe,OAAO;AAAA,EACxB,GAAG,CAAC,IAAI,MAAM,aAAa,KAAK,cAAc,CAAC;AAE/C,EAAAA,WAAU,MAAM;AACd,UAAM,YAAY;AAClB,WAAO,MAAM;AACX,UAAI,cAAc,SAAS;AACzB,sBAAc,UAAU;AACxB,oBAAY,KAAK;AACjB,sBAAc,QAAQ,WAAW,SAAS;AAAA,MAC5C;AAAA,IACF;AAAA,EACF,GAAG,CAAC,EAAE,CAAC;AAEP,EAAAA,WAAU,MAAM;AACd,gBAAY,WAAW,aAAa,EAAE;AAAA,EACxC,GAAG,CAAC,WAAW,UAAU,EAAE,CAAC;AAE5B,QAAM,WAAWJ,aAAY,MAAM;AACjC,UAAM,UAAU,IAAI;AACpB,QAAI,CAAC,QAAS;AAEd,QAAI,CAAC,cAAc,SAAS;AAC1B,qBAAe,OAAO;AAAA,IACxB;AAEA,kBAAc,QAAQ,SAAS,MAAM,OAAO;AAC5C,gBAAY,IAAI;AAAA,EAClB,GAAG,CAAC,cAAc,CAAC;AAEnB,QAAM,aAAaA,aAAY,MAAM;AACnC,QAAI,cAAc,QAAQ,aAAa,MAAM,SAAS;AACpD,oBAAc,QAAQ,WAAW;AACjC,kBAAY,KAAK;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAOK;AAAA,IACL,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,UAAU,UAAU,UAAU;AAAA,EACjC;AACF;;;AJjGO,SAASC,cAAa,SAAkD;AAC7E,SAAO,aAAiB,SAAS,eAAe;AAClD;AAEO,SAASC,WAAU,SAA4C;AACpE,SAAO,UAAc,SAAS,YAAY;AAC5C;","names":["useCallback","useEffect","useRef","useState","useEffect","useRef","useState","useEffect","useRef","useState","useCallback","useMemo","useRef","useState","useCallback","kind","contentHint","fit","useEffect","useMemo","useBroadcast","usePlayer"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/useBroadcast.ts","../src/usePlayer.ts","../src/useCompositor.tsx","../src/useSource.ts"],"sourcesContent":["/**\n * @daydreamlive/react - React hooks and components for WebRTC broadcasting and playback.\n *\n * @example\n * ```tsx\n * import { useBroadcast, usePlayer, CompositorProvider, useCompositor, useSource } from \"@daydreamlive/react\";\n *\n * // Broadcasting\n * const { status, start, stop } = useBroadcast({ whipUrl: \"...\" });\n *\n * // Playback\n * const { status, play, videoRef } = usePlayer({ whepUrl: \"...\" });\n *\n * // Compositor with React\n * <CompositorProvider width={1280} height={720}>\n * <SourceComponent />\n * </CompositorProvider>\n * ```\n *\n * @packageDocumentation\n */\n\nimport { createBroadcast, createPlayer } from \"@daydreamlive/browser\";\nimport {\n useBroadcast as baseUseBroadcast,\n type UseBroadcastOptions,\n type UseBroadcastReturn,\n type UseBroadcastStatus,\n} from \"./useBroadcast\";\nimport {\n usePlayer as baseUsePlayer,\n type UsePlayerOptions,\n type UsePlayerReturn,\n type UsePlayerStatus,\n} from \"./usePlayer\";\n\n/**\n * React hook for managing a WebRTC broadcast session.\n *\n * @param options - Broadcast configuration including WHIP URL\n * @returns Broadcast status and control functions\n *\n * @example\n * ```tsx\n * function BroadcastComponent() {\n * const { status, start, stop } = useBroadcast({\n * whipUrl: \"https://livepeer.studio/webrtc/...\",\n * });\n *\n * const handleStart = async () => {\n * const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });\n * await start(stream);\n * };\n *\n * return (\n * <div>\n * <p>Status: {status.state}</p>\n * {status.state === \"live\" && <p>Playback URL: {status.whepUrl}</p>}\n * <button onClick={status.state === \"idle\" ? handleStart : stop}>\n * {status.state === \"idle\" ? \"Start\" : \"Stop\"}\n * </button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useBroadcast(options: UseBroadcastOptions): UseBroadcastReturn {\n return baseUseBroadcast(options, createBroadcast);\n}\n\n/**\n * React hook for managing a WebRTC playback session.\n *\n * @param options - Player configuration including WHEP URL\n * @returns Player status, control functions, and video element ref\n *\n * @example\n * ```tsx\n * function PlayerComponent({ whepUrl }) {\n * const { status, play, stop, videoRef } = usePlayer({\n * whepUrl,\n * autoPlay: true,\n * });\n *\n * useEffect(() => {\n * if (whepUrl) play();\n * }, [whepUrl, play]);\n *\n * return (\n * <div>\n * <video ref={videoRef} autoPlay muted playsInline />\n * <p>Status: {status.state}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function usePlayer(options: UsePlayerOptions): UsePlayerReturn {\n return baseUsePlayer(options, createPlayer);\n}\n\nexport type {\n UseBroadcastOptions,\n UseBroadcastReturn,\n UseBroadcastStatus,\n UsePlayerOptions,\n UsePlayerReturn,\n UsePlayerStatus,\n};\n\nexport {\n BaseDaydreamError,\n NetworkError,\n ConnectionError,\n StreamNotFoundError,\n UnauthorizedError,\n} from \"@daydreamlive/browser\";\n\nexport {\n DEFAULT_ICE_SERVERS,\n DEFAULT_VIDEO_BITRATE,\n DEFAULT_AUDIO_BITRATE,\n} from \"@daydreamlive/browser\";\n\nexport {\n createCompositor,\n livepeerResponseHandler,\n Broadcast,\n Player,\n} from \"@daydreamlive/browser\";\n\nexport type {\n AudioConfig,\n BroadcastState,\n BroadcastOptions,\n BroadcastConfig,\n BroadcastEventMap,\n LivepeerBroadcastOptions,\n VideoConfig,\n WHIPResponseResult,\n PlayerState,\n PlayerOptions,\n PlayerConfig,\n PlayerEventMap,\n ReconnectConfig,\n ReconnectInfo,\n DaydreamError,\n DaydreamErrorCode,\n // Compositor types\n Compositor,\n CompositorOptions,\n CompositorEvent,\n CompositorEventMap,\n Source,\n VideoSource,\n CanvasSource,\n Size,\n FitMode,\n ContentHint,\n Ctx2D,\n} from \"@daydreamlive/browser\";\n\nexport {\n CompositorProvider,\n useCompositor,\n type CompositorApi,\n type CompositorProviderProps,\n} from \"./useCompositor\";\n\nexport {\n useSource,\n type UseSourceOptions,\n type UseSourceReturn,\n} from \"./useSource\";\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type {\n Broadcast,\n BroadcastOptions,\n BroadcastState,\n DaydreamError,\n ReconnectInfo,\n} from \"@daydreamlive/browser\";\n\n/**\n * Options for the useBroadcast hook.\n * Same as BroadcastOptions but without `stream` (passed to `start()`) and `onResponse` (pre-configured).\n */\nexport type UseBroadcastOptions = Omit<BroadcastOptions, \"stream\" | \"onResponse\">;\n\n/**\n * Factory function type for creating Broadcast instances.\n * @internal\n */\nexport type BroadcastFactory = (options: BroadcastOptions) => Broadcast;\n\n/**\n * Status returned by the useBroadcast hook.\n * Discriminated union based on the `state` property.\n *\n * @example\n * ```tsx\n * const { status } = useBroadcast({ whipUrl });\n *\n * if (status.state === \"live\") {\n * console.log(\"Playback URL:\", status.whepUrl);\n * } else if (status.state === \"error\") {\n * console.error(\"Error:\", status.error);\n * }\n * ```\n */\nexport type UseBroadcastStatus =\n | { state: \"idle\" }\n | { state: \"connecting\" }\n | { state: \"live\"; whepUrl: string }\n | { state: \"reconnecting\"; whepUrl: string; reconnectInfo: ReconnectInfo }\n | { state: \"ended\" }\n | { state: \"error\"; error: DaydreamError };\n\n/**\n * Return value of the useBroadcast hook.\n */\nexport interface UseBroadcastReturn {\n /** Current broadcast status. */\n status: UseBroadcastStatus;\n /** Start broadcasting with the given MediaStream. */\n start: (stream: MediaStream) => Promise<void>;\n /** Stop broadcasting. */\n stop: () => Promise<void>;\n /** Set the maximum frame rate for the video track. */\n setMaxFramerate: (fps?: number) => void;\n}\n\n/**\n * React hook for managing a WebRTC broadcast session.\n *\n * Provides reactive state management, automatic cleanup, and a simple API\n * for starting and stopping broadcasts.\n *\n * @param options - Broadcast configuration options\n * @param factory - Factory function for creating Broadcast instances\n * @returns Broadcast status and control functions\n *\n * @example\n * ```tsx\n * function BroadcastComponent() {\n * const { status, start, stop } = useBroadcast({ whipUrl: \"...\" });\n *\n * const handleStart = async () => {\n * const stream = await navigator.mediaDevices.getUserMedia({ video: true });\n * await start(stream);\n * };\n *\n * return (\n * <div>\n * <p>Status: {status.state}</p>\n * {status.state === \"idle\" && <button onClick={handleStart}>Start</button>}\n * {status.state === \"live\" && <button onClick={stop}>Stop</button>}\n * </div>\n * );\n * }\n * ```\n *\n * @internal Use the re-exported `useBroadcast` from the package root instead.\n */\nexport function useBroadcast(\n options: UseBroadcastOptions,\n factory: BroadcastFactory,\n): UseBroadcastReturn {\n const [status, setStatus] = useState<UseBroadcastStatus>({ state: \"idle\" });\n const broadcastRef = useRef<Broadcast | null>(null);\n const whepUrlRef = useRef<string | null>(null);\n const optionsRef = useRef(options);\n const factoryRef = useRef(factory);\n\n useEffect(() => {\n optionsRef.current = options;\n }, [options]);\n\n useEffect(() => {\n factoryRef.current = factory;\n }, [factory]);\n\n useEffect(() => {\n return () => {\n broadcastRef.current?.stop();\n };\n }, []);\n\n const updateStatus = useCallback((newState: BroadcastState, error?: DaydreamError) => {\n const whepUrl = whepUrlRef.current;\n switch (newState) {\n case \"connecting\":\n setStatus({ state: \"connecting\" });\n break;\n case \"live\":\n setStatus({ state: \"live\", whepUrl: whepUrl! });\n break;\n case \"reconnecting\":\n // reconnectInfo will be set by the reconnect event\n break;\n case \"ended\":\n setStatus({ state: \"ended\" });\n break;\n case \"error\":\n setStatus({ state: \"error\", error: error! });\n break;\n }\n }, []);\n\n const start = useCallback(async (stream: MediaStream) => {\n if (broadcastRef.current) {\n await broadcastRef.current.stop();\n broadcastRef.current = null;\n }\n\n setStatus({ state: \"connecting\" });\n\n const broadcast = factoryRef.current({\n stream,\n ...optionsRef.current,\n });\n\n broadcastRef.current = broadcast;\n\n broadcast.on(\"stateChange\", (newState) => {\n // Guard against events from stopped broadcast\n if (broadcastRef.current !== broadcast) return;\n if (newState === \"live\" || newState === \"reconnecting\") {\n whepUrlRef.current = broadcast.whepUrl;\n }\n updateStatus(newState);\n });\n\n broadcast.on(\"error\", (err) => {\n if (broadcastRef.current !== broadcast) return;\n updateStatus(\"error\", err);\n });\n\n broadcast.on(\"reconnect\", (info) => {\n if (broadcastRef.current !== broadcast) return;\n setStatus({\n state: \"reconnecting\",\n whepUrl: whepUrlRef.current!,\n reconnectInfo: info,\n });\n });\n\n try {\n await broadcast.connect();\n if (broadcastRef.current !== broadcast) return;\n whepUrlRef.current = broadcast.whepUrl;\n updateStatus(broadcast.state);\n } catch (err) {\n if (broadcastRef.current !== broadcast) return;\n setStatus({ state: \"error\", error: err as DaydreamError });\n throw err;\n }\n }, [updateStatus]);\n\n const stop = useCallback(async () => {\n await broadcastRef.current?.stop();\n broadcastRef.current = null;\n whepUrlRef.current = null;\n setStatus({ state: \"idle\" });\n }, []);\n\n const setMaxFramerate = useCallback((fps?: number) => {\n broadcastRef.current?.setMaxFramerate(fps);\n }, []);\n\n return {\n status,\n start,\n stop,\n setMaxFramerate,\n };\n}\n","import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type RefObject,\n} from \"react\";\nimport type {\n Player,\n PlayerOptions,\n PlayerState,\n DaydreamError,\n ReconnectInfo,\n} from \"@daydreamlive/browser\";\n\n/**\n * Options for the usePlayer hook.\n * Extends PlayerOptions with WHEP URL and autoPlay settings.\n */\nexport type UsePlayerOptions = PlayerOptions & {\n /** WHEP endpoint URL. Set to null to disable playback. */\n whepUrl: string | null;\n /** Whether to automatically start playback when connected. Defaults to true. */\n autoPlay?: boolean;\n};\n\n/**\n * Factory function type for creating Player instances.\n * @internal\n */\nexport type PlayerFactory = (\n whepUrl: string,\n options?: PlayerOptions,\n) => Player;\n\n/**\n * Status returned by the usePlayer hook.\n * Discriminated union based on the `state` property.\n *\n * @example\n * ```tsx\n * const { status } = usePlayer({ whepUrl });\n *\n * if (status.state === \"buffering\") {\n * console.log(\"Reconnecting:\", status.reconnectInfo.attempt);\n * } else if (status.state === \"error\") {\n * console.error(\"Error:\", status.error);\n * }\n * ```\n */\nexport type UsePlayerStatus =\n | { state: \"idle\" }\n | { state: \"connecting\" }\n | { state: \"playing\" }\n | { state: \"buffering\"; reconnectInfo: ReconnectInfo }\n | { state: \"ended\" }\n | { state: \"error\"; error: DaydreamError };\n\n/**\n * Return value of the usePlayer hook.\n */\nexport interface UsePlayerReturn {\n /** Current player status. */\n status: UsePlayerStatus;\n /** Start playback. */\n play: () => Promise<void>;\n /** Stop playback. */\n stop: () => Promise<void>;\n /** Ref to attach to a video element for displaying the stream. */\n videoRef: RefObject<HTMLVideoElement | null>;\n}\n\n/**\n * React hook for managing a WebRTC playback session.\n *\n * Provides reactive state management, automatic cleanup, and a video element ref\n * for displaying the received stream.\n *\n * @param options - Player configuration options including WHEP URL\n * @param factory - Factory function for creating Player instances\n * @returns Player status, control functions, and video element ref\n *\n * @example\n * ```tsx\n * function PlayerComponent({ whepUrl }) {\n * const { status, play, stop, videoRef } = usePlayer({ whepUrl });\n *\n * useEffect(() => {\n * if (whepUrl) play();\n * }, [whepUrl, play]);\n *\n * return (\n * <div>\n * <video ref={videoRef} autoPlay muted />\n * <p>Status: {status.state}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @internal Use the re-exported `usePlayer` from the package root instead.\n */\nexport function usePlayer(\n options: UsePlayerOptions,\n factory: PlayerFactory,\n): UsePlayerReturn {\n const [status, setStatus] = useState<UsePlayerStatus>({ state: \"idle\" });\n const playerRef = useRef<Player | null>(null);\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const optionsRef = useRef(options);\n const factoryRef = useRef(factory);\n\n useEffect(() => {\n optionsRef.current = options;\n }, [options]);\n\n useEffect(() => {\n factoryRef.current = factory;\n }, [factory]);\n\n useEffect(() => {\n return () => {\n playerRef.current?.stop();\n };\n }, []);\n\n const updateStatus = useCallback(\n (newState: PlayerState, error?: DaydreamError) => {\n switch (newState) {\n case \"connecting\":\n setStatus({ state: \"connecting\" });\n break;\n case \"playing\":\n setStatus({ state: \"playing\" });\n break;\n case \"buffering\":\n // reconnectInfo will be set by the reconnect event\n break;\n case \"ended\":\n setStatus({ state: \"ended\" });\n break;\n case \"error\":\n setStatus({ state: \"error\", error: error! });\n break;\n }\n },\n [],\n );\n\n const play = useCallback(async () => {\n const currentWhepUrl = optionsRef.current.whepUrl;\n if (!currentWhepUrl) {\n return;\n }\n\n if (playerRef.current) {\n await playerRef.current.stop();\n playerRef.current = null;\n }\n\n setStatus({ state: \"connecting\" });\n\n const player = factoryRef.current(currentWhepUrl, {\n reconnect: optionsRef.current?.reconnect,\n iceServers: optionsRef.current?.iceServers,\n connectionTimeout: optionsRef.current?.connectionTimeout,\n skipIceGathering: optionsRef.current?.skipIceGathering,\n onStats: optionsRef.current?.onStats,\n statsIntervalMs: optionsRef.current?.statsIntervalMs,\n });\n\n playerRef.current = player;\n\n player.on(\"stateChange\", (newState) => {\n // Guard against events from stopped player\n if (playerRef.current !== player) return;\n updateStatus(newState);\n // Re-attach stream after reconnect\n if (newState === \"playing\" && videoRef.current && player.stream) {\n if (videoRef.current.srcObject !== player.stream) {\n player.attachTo(videoRef.current);\n }\n }\n });\n\n player.on(\"error\", (err) => {\n if (playerRef.current !== player) return;\n updateStatus(\"error\", err);\n });\n\n player.on(\"reconnect\", (info) => {\n if (playerRef.current !== player) return;\n setStatus({ state: \"buffering\", reconnectInfo: info });\n });\n\n try {\n await player.connect();\n if (playerRef.current !== player) return;\n updateStatus(player.state);\n\n if (videoRef.current) {\n player.attachTo(videoRef.current);\n if (optionsRef.current?.autoPlay !== false) {\n try {\n await videoRef.current.play();\n } catch {\n // Autoplay blocked\n }\n }\n }\n } catch (err) {\n if (playerRef.current !== player) return;\n setStatus({ state: \"error\", error: err as DaydreamError });\n throw err;\n }\n }, [updateStatus]);\n\n const stop = useCallback(async () => {\n await playerRef.current?.stop();\n playerRef.current = null;\n setStatus({ state: \"idle\" });\n }, []);\n\n return {\n status,\n play,\n stop,\n videoRef,\n };\n}\n","\"use client\";\n\nimport {\n createContext,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type PropsWithChildren,\n} from \"react\";\nimport {\n createCompositor,\n type Compositor,\n type CompositorOptions,\n type Size,\n type Source,\n} from \"@daydreamlive/browser\";\n\n/**\n * API provided by the CompositorProvider context.\n * Combines compositor functionality with React state management.\n *\n * @example\n * ```tsx\n * function VideoSource() {\n * const compositor = useCompositor();\n * const videoRef = useRef<HTMLVideoElement>(null);\n *\n * useEffect(() => {\n * if (videoRef.current) {\n * compositor.register(\"camera\", { kind: \"video\", element: videoRef.current });\n * compositor.activate(\"camera\");\n * }\n * return () => compositor.unregister(\"camera\");\n * }, [compositor]);\n *\n * return <video ref={videoRef} />;\n * }\n * ```\n */\nexport interface CompositorApi {\n // Registry\n /** Register a source with a unique ID. */\n register(id: string, source: Source): void;\n /** Unregister a source by ID. */\n unregister(id: string): void;\n /** Get a registered source by ID. */\n get(id: string): Source | undefined;\n /** Check if a source is registered. */\n has(id: string): boolean;\n /** List all registered sources. */\n list(): Array<{ id: string; source: Source }>;\n\n /**\n * Register a source, activate it, and return an unregister function.\n * Convenience method that combines register + activate with automatic cleanup.\n *\n * @example\n * ```tsx\n * useEffect(() => {\n * const unregister = compositor.use(\"camera\", {\n * kind: \"video\",\n * element: videoRef.current,\n * fit: \"cover\",\n * });\n * return unregister;\n * }, [compositor]);\n * ```\n */\n use(id: string, source: Source): () => void;\n\n // Active source\n /**\n * Activate a registered source.\n * @param id - The source ID to activate\n */\n activate(id: string): void;\n /** Deactivate the current source. */\n deactivate(): void;\n /** ID of the currently active source, or null if none. */\n readonly activeId: string | null;\n\n // Output (reactive)\n /** The composited output MediaStream. Reactive - updates when stream changes. */\n readonly stream: MediaStream | null;\n /** Current output size. Reactive - updates when size changes. */\n readonly size: Size;\n /** Resize the output canvas. */\n setSize(width: number, height: number, dpr?: number): void;\n\n // FPS (reactive)\n /** Current rendering frame rate. Reactive. */\n readonly fps: number;\n /** Set the rendering frame rate. */\n setFps(fps: number): void;\n /** Current send frame rate. Reactive. */\n readonly sendFps: number;\n /** Set the send frame rate. */\n setSendFps(fps: number): void;\n\n // Audio\n /** Add an audio track to the output stream. */\n addAudioTrack(track: MediaStreamTrack): void;\n /** Remove an audio track by track ID. */\n removeAudioTrack(trackId: string): void;\n /** Manually unlock the audio context. */\n unlockAudio(): Promise<boolean>;\n\n // Events\n /** Subscribe to compositor events. */\n on: Compositor[\"on\"];\n}\n\nconst CompositorContext = createContext<CompositorApi | null>(null);\n\n/**\n * Props for the CompositorProvider component.\n * Inherits all CompositorOptions except onSendFpsChange (managed internally).\n */\nexport interface CompositorProviderProps\n extends PropsWithChildren,\n Partial<Omit<CompositorOptions, \"onSendFpsChange\">> {}\n\n/**\n * React context provider for the Compositor.\n * Creates and manages a Compositor instance, providing it to child components via context.\n *\n * @example\n * ```tsx\n * function App() {\n * return (\n * <CompositorProvider width={1280} height={720} fps={30}>\n * <VideoSource />\n * <BroadcastButton />\n * </CompositorProvider>\n * );\n * }\n * ```\n */\nexport function CompositorProvider({\n children,\n width = 512,\n height = 512,\n fps: initialFps = 30,\n sendFps: initialSendFps,\n dpr,\n keepalive,\n autoUnlockAudio,\n unlockEvents,\n disableSilentAudio = true,\n}: CompositorProviderProps) {\n const compositorRef = useRef<Compositor | null>(null);\n const [stream, setStream] = useState<MediaStream | null>(null);\n const [size, setSize] = useState<Size>({\n width,\n height,\n dpr: Math.min(\n 2,\n dpr ?? (typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1),\n ),\n });\n const [fps, setFpsState] = useState(initialFps);\n const [sendFps, setSendFpsState] = useState(initialSendFps ?? initialFps);\n\n // Create compositor once\n useLayoutEffect(() => {\n const compositor = createCompositor({\n width,\n height,\n fps: initialFps,\n sendFps: initialSendFps,\n dpr,\n keepalive,\n autoUnlockAudio,\n unlockEvents,\n disableSilentAudio,\n onSendFpsChange: (newFps) => setSendFpsState(newFps),\n });\n\n compositorRef.current = compositor;\n setStream(compositor.stream);\n setSize(compositor.size);\n\n return () => {\n compositor.destroy();\n compositorRef.current = null;\n };\n }, []);\n\n // Sync size changes\n useEffect(() => {\n const compositor = compositorRef.current;\n if (!compositor) return;\n\n compositor.resize(size.width, size.height, size.dpr);\n setStream(compositor.stream);\n }, [size.width, size.height, size.dpr]);\n\n // Sync fps changes\n useEffect(() => {\n const compositor = compositorRef.current;\n if (!compositor) return;\n\n compositor.setFps(fps);\n setStream(compositor.stream);\n }, [fps]);\n\n // Sync sendFps changes\n useEffect(() => {\n const compositor = compositorRef.current;\n if (!compositor) return;\n\n compositor.setSendFps(sendFps);\n }, [sendFps]);\n\n // Memoized API\n const api = useMemo<CompositorApi>(\n () => ({\n // Registry\n register: (id, source) => compositorRef.current?.register(id, source),\n unregister: (id) => compositorRef.current?.unregister(id),\n get: (id) => compositorRef.current?.get(id),\n has: (id) => compositorRef.current?.has(id) ?? false,\n list: () => compositorRef.current?.list() ?? [],\n use: (id, source) => {\n compositorRef.current?.register(id, source);\n compositorRef.current?.activate(id);\n return () => compositorRef.current?.unregister(id);\n },\n\n // Active source\n activate: (id) => compositorRef.current?.activate(id),\n deactivate: () => compositorRef.current?.deactivate(),\n get activeId() {\n return compositorRef.current?.activeId ?? null;\n },\n\n // Stream & size\n stream,\n size,\n setSize: (w, h, d) =>\n setSize({ width: w, height: h, dpr: d ?? size.dpr }),\n\n // FPS\n fps,\n setFps: setFpsState,\n sendFps,\n setSendFps: setSendFpsState,\n\n // Audio\n addAudioTrack: (t) => compositorRef.current?.addAudioTrack(t),\n removeAudioTrack: (id) => compositorRef.current?.removeAudioTrack(id),\n unlockAudio: () =>\n compositorRef.current?.unlockAudio() ?? Promise.resolve(false),\n\n // Events\n on: (event, cb) => compositorRef.current?.on(event, cb) ?? (() => {}),\n }),\n [stream, size, fps, sendFps],\n );\n\n return (\n <CompositorContext.Provider value={api}>\n {children}\n </CompositorContext.Provider>\n );\n}\n\n/**\n * Hook to access the Compositor API from context.\n * Must be used within a CompositorProvider.\n *\n * @returns The CompositorApi for managing sources and output\n * @throws {Error} If used outside of CompositorProvider\n *\n * @example\n * ```tsx\n * function BroadcastButton() {\n * const compositor = useCompositor();\n * const { start } = useBroadcast({ whipUrl: \"...\" });\n *\n * const handleClick = async () => {\n * if (compositor.stream) {\n * await start(compositor.stream);\n * }\n * };\n *\n * return <button onClick={handleClick}>Start Broadcast</button>;\n * }\n * ```\n */\nexport function useCompositor(): CompositorApi {\n const ctx = useContext(CompositorContext);\n if (!ctx) {\n throw new Error(\"useCompositor must be used within <CompositorProvider>\");\n }\n return ctx;\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState, useCallback, useMemo } from \"react\";\nimport type { Source, FitMode, ContentHint } from \"@daydreamlive/browser\";\nimport { useCompositor } from \"./useCompositor\";\n\n/**\n * Options for the useSource hook.\n */\nexport interface UseSourceOptions {\n /** Type of source element: \"video\" for HTMLVideoElement, \"canvas\" for HTMLCanvasElement. */\n kind: \"video\" | \"canvas\";\n /** Content hint for encoding optimization. */\n contentHint?: ContentHint;\n /** How to fit the source content within the output canvas. Only applies to video sources. */\n fit?: FitMode;\n}\n\n/**\n * Return value of the useSource hook.\n */\nexport interface UseSourceReturn<\n T extends HTMLVideoElement | HTMLCanvasElement,\n> {\n /** Ref to attach to the source element. */\n ref: React.RefObject<T>;\n /** Whether this source is currently active. Reactive. */\n isActive: boolean;\n /** Activate this source for rendering. */\n activate: () => void;\n /** Deactivate this source (if it's currently active). */\n deactivate: () => void;\n}\n\n/**\n * React hook for managing a compositor source.\n *\n * Automatically registers the source element with the compositor and provides\n * methods for activation/deactivation. Cleans up on unmount.\n *\n * @typeParam T - The element type (HTMLVideoElement or HTMLCanvasElement)\n * @param id - Unique identifier for this source\n * @param options - Source configuration\n * @returns Source state and control functions\n *\n * @example\n * ```tsx\n * function CameraSource() {\n * const { ref, isActive, activate } = useSource<HTMLVideoElement>(\"camera\", {\n * kind: \"video\",\n * fit: \"cover\",\n * });\n *\n * useEffect(() => {\n * navigator.mediaDevices.getUserMedia({ video: true })\n * .then(stream => {\n * if (ref.current) {\n * ref.current.srcObject = stream;\n * activate();\n * }\n * });\n * }, [activate]);\n *\n * return <video ref={ref} autoPlay muted />;\n * }\n * ```\n */\nexport function useSource<\n T extends HTMLVideoElement | HTMLCanvasElement =\n | HTMLVideoElement\n | HTMLCanvasElement,\n>(id: string, options: UseSourceOptions): UseSourceReturn<T> {\n const compositor = useCompositor();\n const compositorRef = useRef(compositor);\n compositorRef.current = compositor;\n\n const ref = useRef<T>(null);\n const [isActive, setIsActive] = useState(false);\n const registeredRef = useRef(false);\n const idRef = useRef(id);\n idRef.current = id;\n\n const { kind, contentHint, fit } = options;\n\n const optionsRef = useRef({ kind, contentHint, fit });\n optionsRef.current = { kind, contentHint, fit };\n\n const registerSource = useCallback((element: T) => {\n const { kind, contentHint, fit } = optionsRef.current;\n const source =\n kind === \"video\"\n ? {\n kind: \"video\" as const,\n element: element as HTMLVideoElement,\n contentHint,\n fit,\n }\n : {\n kind: \"canvas\" as const,\n element: element as HTMLCanvasElement,\n contentHint,\n };\n\n compositorRef.current.register(idRef.current, source);\n registeredRef.current = true;\n }, []);\n\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n registerSource(element);\n }, [id, kind, contentHint, fit, registerSource]);\n\n useEffect(() => {\n const currentId = id;\n return () => {\n if (registeredRef.current) {\n registeredRef.current = false;\n setIsActive(false);\n compositorRef.current.unregister(currentId);\n }\n };\n }, [id]);\n\n useEffect(() => {\n setIsActive(compositor.activeId === id);\n }, [compositor.activeId, id]);\n\n const activate = useCallback(() => {\n const element = ref.current;\n if (!element) return;\n\n if (!registeredRef.current) {\n registerSource(element);\n }\n\n compositorRef.current.activate(idRef.current);\n setIsActive(true);\n }, [registerSource]);\n\n const deactivate = useCallback(() => {\n if (compositorRef.current.activeId === idRef.current) {\n compositorRef.current.deactivate();\n setIsActive(false);\n }\n }, []);\n\n return useMemo(\n () => ({\n ref,\n isActive,\n activate,\n deactivate,\n }),\n [isActive, activate, deactivate],\n );\n}\n"],"mappings":"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","names":["useCallback","useEffect","useRef","useState","createCompositor","useEffect","useRef","useState","useEffect","useRef","useState","useCallback","useMemo","useRef","useState","useCallback","kind","contentHint","fit","useEffect","useMemo","useBroadcast","usePlayer"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@daydreamlive/react",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -27,18 +27,24 @@
|
|
|
27
27
|
"build": "tsup",
|
|
28
28
|
"dev": "tsup --watch",
|
|
29
29
|
"clean": "rm -rf dist",
|
|
30
|
-
"typecheck": "tsc --noEmit"
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"test": "vitest run",
|
|
32
|
+
"test:watch": "vitest"
|
|
31
33
|
},
|
|
32
34
|
"dependencies": {
|
|
33
|
-
"@daydreamlive/browser": "
|
|
35
|
+
"@daydreamlive/browser": "^0.3.2"
|
|
34
36
|
},
|
|
35
37
|
"peerDependencies": {
|
|
36
38
|
"react": ">=18.0.0"
|
|
37
39
|
},
|
|
38
40
|
"devDependencies": {
|
|
41
|
+
"@testing-library/react": "^16.0.0",
|
|
39
42
|
"@types/react": "^18.2.45",
|
|
43
|
+
"jsdom": "^24.0.0",
|
|
40
44
|
"react": "^18.2.0",
|
|
45
|
+
"react-dom": "^18.2.0",
|
|
41
46
|
"typescript": "^5.3.3",
|
|
42
|
-
"tsup": "^8.0.1"
|
|
47
|
+
"tsup": "^8.0.1",
|
|
48
|
+
"vitest": "^1.1.3"
|
|
43
49
|
}
|
|
44
50
|
}
|