@daydreamlive/react 0.3.0 → 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 +54 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +269 -21
- package/dist/index.d.ts +269 -21
- package/dist/index.js +57 -26
- package/dist/index.js.map +1 -1
- package/package.json +10 -4
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,22 +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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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. */
|
|
63
|
+
whepUrl: string | null;
|
|
64
|
+
/** Whether to automatically start playback when connected. Defaults to true. */
|
|
45
65
|
autoPlay?: boolean;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
+
*/
|
|
49
82
|
type UsePlayerStatus = {
|
|
50
83
|
state: "idle";
|
|
51
84
|
} | {
|
|
@@ -61,18 +94,52 @@ type UsePlayerStatus = {
|
|
|
61
94
|
state: "error";
|
|
62
95
|
error: DaydreamError;
|
|
63
96
|
};
|
|
97
|
+
/**
|
|
98
|
+
* Return value of the usePlayer hook.
|
|
99
|
+
*/
|
|
64
100
|
interface UsePlayerReturn {
|
|
101
|
+
/** Current player status. */
|
|
65
102
|
status: UsePlayerStatus;
|
|
103
|
+
/** Start playback. */
|
|
66
104
|
play: () => Promise<void>;
|
|
105
|
+
/** Stop playback. */
|
|
67
106
|
stop: () => Promise<void>;
|
|
107
|
+
/** Ref to attach to a video element for displaying the stream. */
|
|
68
108
|
videoRef: RefObject<HTMLVideoElement | null>;
|
|
69
109
|
}
|
|
70
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
|
+
*/
|
|
71
133
|
interface CompositorApi {
|
|
134
|
+
/** Register a source with a unique ID. */
|
|
72
135
|
register(id: string, source: Source): void;
|
|
136
|
+
/** Unregister a source by ID. */
|
|
73
137
|
unregister(id: string): void;
|
|
138
|
+
/** Get a registered source by ID. */
|
|
74
139
|
get(id: string): Source | undefined;
|
|
140
|
+
/** Check if a source is registered. */
|
|
75
141
|
has(id: string): boolean;
|
|
142
|
+
/** List all registered sources. */
|
|
76
143
|
list(): Array<{
|
|
77
144
|
id: string;
|
|
78
145
|
source: Source;
|
|
@@ -99,39 +166,220 @@ interface CompositorApi {
|
|
|
99
166
|
* @param id - The source ID to activate
|
|
100
167
|
*/
|
|
101
168
|
activate(id: string): void;
|
|
169
|
+
/** Deactivate the current source. */
|
|
102
170
|
deactivate(): void;
|
|
171
|
+
/** ID of the currently active source, or null if none. */
|
|
103
172
|
readonly activeId: string | null;
|
|
173
|
+
/** The composited output MediaStream. Reactive - updates when stream changes. */
|
|
104
174
|
readonly stream: MediaStream | null;
|
|
175
|
+
/** Current output size. Reactive - updates when size changes. */
|
|
105
176
|
readonly size: Size;
|
|
177
|
+
/** Resize the output canvas. */
|
|
106
178
|
setSize(width: number, height: number, dpr?: number): void;
|
|
179
|
+
/** Current rendering frame rate. Reactive. */
|
|
107
180
|
readonly fps: number;
|
|
181
|
+
/** Set the rendering frame rate. */
|
|
108
182
|
setFps(fps: number): void;
|
|
183
|
+
/** Current send frame rate. Reactive. */
|
|
109
184
|
readonly sendFps: number;
|
|
185
|
+
/** Set the send frame rate. */
|
|
110
186
|
setSendFps(fps: number): void;
|
|
187
|
+
/** Add an audio track to the output stream. */
|
|
111
188
|
addAudioTrack(track: MediaStreamTrack): void;
|
|
189
|
+
/** Remove an audio track by track ID. */
|
|
112
190
|
removeAudioTrack(trackId: string): void;
|
|
191
|
+
/** Manually unlock the audio context. */
|
|
113
192
|
unlockAudio(): Promise<boolean>;
|
|
193
|
+
/** Subscribe to compositor events. */
|
|
114
194
|
on: Compositor["on"];
|
|
115
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Props for the CompositorProvider component.
|
|
198
|
+
* Inherits all CompositorOptions except onSendFpsChange (managed internally).
|
|
199
|
+
*/
|
|
116
200
|
interface CompositorProviderProps extends PropsWithChildren, Partial<Omit<CompositorOptions, "onSendFpsChange">> {
|
|
117
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
|
+
*/
|
|
118
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
|
+
*/
|
|
119
242
|
declare function useCompositor(): CompositorApi;
|
|
120
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Options for the useSource hook.
|
|
246
|
+
*/
|
|
121
247
|
interface UseSourceOptions {
|
|
248
|
+
/** Type of source element: "video" for HTMLVideoElement, "canvas" for HTMLCanvasElement. */
|
|
122
249
|
kind: "video" | "canvas";
|
|
250
|
+
/** Content hint for encoding optimization. */
|
|
123
251
|
contentHint?: ContentHint;
|
|
252
|
+
/** How to fit the source content within the output canvas. Only applies to video sources. */
|
|
124
253
|
fit?: FitMode;
|
|
125
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* Return value of the useSource hook.
|
|
257
|
+
*/
|
|
126
258
|
interface UseSourceReturn<T extends HTMLVideoElement | HTMLCanvasElement> {
|
|
259
|
+
/** Ref to attach to the source element. */
|
|
127
260
|
ref: React.RefObject<T>;
|
|
261
|
+
/** Whether this source is currently active. Reactive. */
|
|
128
262
|
isActive: boolean;
|
|
263
|
+
/** Activate this source for rendering. */
|
|
129
264
|
activate: () => void;
|
|
265
|
+
/** Deactivate this source (if it's currently active). */
|
|
130
266
|
deactivate: () => void;
|
|
131
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
|
+
*/
|
|
132
301
|
declare function useSource<T extends HTMLVideoElement | HTMLCanvasElement = HTMLVideoElement | HTMLCanvasElement>(id: string, options: UseSourceOptions): UseSourceReturn<T>;
|
|
133
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
|
+
*/
|
|
134
355
|
declare function useBroadcast(options: UseBroadcastOptions): UseBroadcastReturn;
|
|
135
|
-
|
|
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
|
+
*/
|
|
383
|
+
declare function usePlayer(options: UsePlayerOptions): UsePlayerReturn;
|
|
136
384
|
|
|
137
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
|
@@ -104,12 +104,11 @@ import {
|
|
|
104
104
|
useRef as useRef2,
|
|
105
105
|
useState as useState2
|
|
106
106
|
} from "react";
|
|
107
|
-
function usePlayer(
|
|
107
|
+
function usePlayer(options, factory) {
|
|
108
108
|
const [status, setStatus] = useState2({ state: "idle" });
|
|
109
109
|
const playerRef = useRef2(null);
|
|
110
110
|
const videoRef = useRef2(null);
|
|
111
111
|
const optionsRef = useRef2(options);
|
|
112
|
-
const whepUrlRef = useRef2(whepUrl);
|
|
113
112
|
const factoryRef = useRef2(factory);
|
|
114
113
|
useEffect2(() => {
|
|
115
114
|
optionsRef.current = options;
|
|
@@ -117,34 +116,34 @@ function usePlayer(whepUrl, options, factory) {
|
|
|
117
116
|
useEffect2(() => {
|
|
118
117
|
factoryRef.current = factory;
|
|
119
118
|
}, [factory]);
|
|
120
|
-
useEffect2(() => {
|
|
121
|
-
whepUrlRef.current = whepUrl;
|
|
122
|
-
}, [whepUrl]);
|
|
123
119
|
useEffect2(() => {
|
|
124
120
|
return () => {
|
|
125
121
|
playerRef.current?.stop();
|
|
126
122
|
};
|
|
127
123
|
}, []);
|
|
128
|
-
const updateStatus = useCallback2(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
124
|
+
const updateStatus = useCallback2(
|
|
125
|
+
(newState, error) => {
|
|
126
|
+
switch (newState) {
|
|
127
|
+
case "connecting":
|
|
128
|
+
setStatus({ state: "connecting" });
|
|
129
|
+
break;
|
|
130
|
+
case "playing":
|
|
131
|
+
setStatus({ state: "playing" });
|
|
132
|
+
break;
|
|
133
|
+
case "buffering":
|
|
134
|
+
break;
|
|
135
|
+
case "ended":
|
|
136
|
+
setStatus({ state: "ended" });
|
|
137
|
+
break;
|
|
138
|
+
case "error":
|
|
139
|
+
setStatus({ state: "error", error });
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
[]
|
|
144
|
+
);
|
|
146
145
|
const play = useCallback2(async () => {
|
|
147
|
-
const currentWhepUrl =
|
|
146
|
+
const currentWhepUrl = optionsRef.current.whepUrl;
|
|
148
147
|
if (!currentWhepUrl) {
|
|
149
148
|
return;
|
|
150
149
|
}
|
|
@@ -211,6 +210,26 @@ function usePlayer(whepUrl, options, factory) {
|
|
|
211
210
|
};
|
|
212
211
|
}
|
|
213
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
|
+
|
|
214
233
|
// src/useCompositor.tsx
|
|
215
234
|
import {
|
|
216
235
|
createContext,
|
|
@@ -413,11 +432,23 @@ function useSource(id, options) {
|
|
|
413
432
|
function useBroadcast2(options) {
|
|
414
433
|
return useBroadcast(options, createBroadcast);
|
|
415
434
|
}
|
|
416
|
-
function usePlayer2(
|
|
417
|
-
return usePlayer(
|
|
435
|
+
function usePlayer2(options) {
|
|
436
|
+
return usePlayer(options, createPlayer);
|
|
418
437
|
}
|
|
419
438
|
export {
|
|
439
|
+
BaseDaydreamError,
|
|
440
|
+
Broadcast,
|
|
420
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,
|
|
421
452
|
useBroadcast2 as useBroadcast,
|
|
422
453
|
useCompositor,
|
|
423
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(\n whepUrl: string | null,\n options?: UsePlayerOptions,\n): UsePlayerReturn {\n return baseUsePlayer(whepUrl, 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 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 whepUrl: string | null,\n options: UsePlayerOptions | undefined,\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 whepUrlRef = useRef(whepUrl);\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 whepUrlRef.current = whepUrl;\n }, [whepUrl]);\n\n useEffect(() => {\n return () => {\n playerRef.current?.stop();\n };\n }, []);\n\n const updateStatus = useCallback((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 const play = useCallback(async () => {\n const currentWhepUrl = whepUrlRef.current;\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;AAwCA,SAAS,UACd,SACA,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;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,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,aAAY,CAAC,UAAuB,UAA0B;AACjF,YAAQ,UAAU;AAAA,MAChB,KAAK;AACH,kBAAU,EAAE,OAAO,aAAa,CAAC;AACjC;AAAA,MACF,KAAK;AACH,kBAAU,EAAE,OAAO,UAAU,CAAC;AAC9B;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,OAAOA,aAAY,YAAY;AACnC,UAAM,iBAAiB,WAAW;AAClC,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;;;AC9KA;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,WACd,SACA,SACiB;AACjB,SAAO,UAAc,SAAS,SAAS,YAAY;AACrD;","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"]}
|