@daydreamlive/react 0.1.0 → 0.2.0

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/README.md CHANGED
@@ -16,7 +16,7 @@ npm install @daydreamlive/react
16
16
  import { useBroadcast } from "@daydreamlive/react";
17
17
 
18
18
  function Broadcaster({ whipUrl }: { whipUrl: string }) {
19
- const { state, whepUrl, error, start, stop } = useBroadcast({
19
+ const { status, start, stop } = useBroadcast({
20
20
  whipUrl,
21
21
  reconnect: { enabled: true },
22
22
  });
@@ -28,8 +28,10 @@ function Broadcaster({ whipUrl }: { whipUrl: string }) {
28
28
 
29
29
  return (
30
30
  <div>
31
- <p>State: {state}</p>
32
- <button onClick={handleStart} disabled={state === "live"}>
31
+ <p>State: {status.state}</p>
32
+ {status.state === "live" && <p>WHEP URL: {status.whepUrl}</p>}
33
+ {status.state === "error" && <p>Error: {status.error.message}</p>}
34
+ <button onClick={handleStart} disabled={status.state === "live"}>
33
35
  Start
34
36
  </button>
35
37
  <button onClick={stop}>Stop</button>
@@ -44,12 +46,22 @@ function Broadcaster({ whipUrl }: { whipUrl: string }) {
44
46
  import { usePlayer } from "@daydreamlive/react";
45
47
 
46
48
  function Player({ whepUrl }: { whepUrl: string }) {
47
- const { state, error, videoRef } = usePlayer(whepUrl, {
49
+ const { status, play, stop, videoRef } = usePlayer(whepUrl, {
48
50
  autoPlay: true,
49
51
  reconnect: { enabled: true },
50
52
  });
51
53
 
52
- return <video ref={videoRef} autoPlay playsInline muted />;
54
+ return (
55
+ <div>
56
+ <p>State: {status.state}</p>
57
+ {status.state === "error" && <p>Error: {status.error.message}</p>}
58
+ <video ref={videoRef} autoPlay playsInline muted />
59
+ <button onClick={play} disabled={status.state === "playing"}>
60
+ Play
61
+ </button>
62
+ <button onClick={stop}>Stop</button>
63
+ </div>
64
+ );
53
65
  }
54
66
  ```
55
67
 
@@ -57,11 +69,33 @@ function Player({ whepUrl }: { whepUrl: string }) {
57
69
 
58
70
  ### `useBroadcast(options)`
59
71
 
60
- Returns: `{ state, whepUrl, error, start, stop }`
72
+ Returns: `{ status, start, stop, setMaxFramerate }`
73
+
74
+ - `status`: `UseBroadcastStatus` - Discriminated union with `state` property
75
+ - `{ state: "idle" }`
76
+ - `{ state: "connecting" }`
77
+ - `{ state: "live", whepUrl: string }`
78
+ - `{ state: "reconnecting", whepUrl: string, reconnectInfo: ReconnectInfo }`
79
+ - `{ state: "ended" }`
80
+ - `{ state: "error", error: DaydreamError }`
81
+ - `start(stream: MediaStream)`: Start broadcasting
82
+ - `stop()`: Stop broadcasting
83
+ - `setMaxFramerate(fps?: number)`: Set max framerate
61
84
 
62
85
  ### `usePlayer(whepUrl, options?)`
63
86
 
64
- Returns: `{ state, error, play, stop, videoRef }`
87
+ Returns: `{ status, play, stop, videoRef }`
88
+
89
+ - `status`: `UsePlayerStatus` - Discriminated union with `state` property
90
+ - `{ state: "idle" }`
91
+ - `{ state: "connecting" }`
92
+ - `{ state: "playing" }`
93
+ - `{ state: "buffering", reconnectInfo: ReconnectInfo }`
94
+ - `{ state: "ended" }`
95
+ - `{ state: "error", error: DaydreamError }`
96
+ - `play()`: Start playing
97
+ - `stop()`: Stop playing
98
+ - `videoRef`: Ref to attach to `<video>` element
65
99
 
66
100
  ## License
67
101
 
package/dist/index.cjs CHANGED
@@ -20,19 +20,20 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ CompositorProvider: () => CompositorProvider,
23
24
  useBroadcast: () => useBroadcast2,
25
+ useCompositor: () => useCompositor,
24
26
  usePlayer: () => usePlayer2
25
27
  });
26
28
  module.exports = __toCommonJS(index_exports);
27
- var import_browser = require("@daydreamlive/browser");
29
+ var import_browser2 = require("@daydreamlive/browser");
28
30
 
29
31
  // src/useBroadcast.ts
30
32
  var import_react = require("react");
31
33
  function useBroadcast(options, factory) {
32
- const [state, setState] = (0, import_react.useState)("idle");
33
- const [whepUrl, setWhepUrl] = (0, import_react.useState)(null);
34
- const [error, setError] = (0, import_react.useState)(null);
34
+ const [status, setStatus] = (0, import_react.useState)({ state: "idle" });
35
35
  const broadcastRef = (0, import_react.useRef)(null);
36
+ const whepUrlRef = (0, import_react.useRef)(null);
36
37
  const optionsRef = (0, import_react.useRef)(options);
37
38
  const factoryRef = (0, import_react.useRef)(factory);
38
39
  (0, import_react.useEffect)(() => {
@@ -46,55 +47,87 @@ function useBroadcast(options, factory) {
46
47
  broadcastRef.current?.stop();
47
48
  };
48
49
  }, []);
50
+ const updateStatus = (0, import_react.useCallback)((newState, error) => {
51
+ const whepUrl = whepUrlRef.current;
52
+ switch (newState) {
53
+ case "connecting":
54
+ setStatus({ state: "connecting" });
55
+ break;
56
+ case "live":
57
+ setStatus({ state: "live", whepUrl });
58
+ break;
59
+ case "reconnecting":
60
+ break;
61
+ case "ended":
62
+ setStatus({ state: "ended" });
63
+ break;
64
+ case "error":
65
+ setStatus({ state: "error", error });
66
+ break;
67
+ }
68
+ }, []);
49
69
  const start = (0, import_react.useCallback)(async (stream) => {
50
- setError(null);
51
70
  if (broadcastRef.current) {
52
71
  await broadcastRef.current.stop();
72
+ broadcastRef.current = null;
53
73
  }
54
- try {
55
- const broadcast = factoryRef.current({
56
- stream,
57
- ...optionsRef.current
58
- });
59
- broadcastRef.current = broadcast;
60
- broadcast.on("stateChange", (newState) => {
61
- setState(newState);
62
- if (newState === "live") {
63
- setWhepUrl(broadcast.whepUrl);
64
- }
65
- });
66
- broadcast.on("error", (err) => {
67
- setError(err);
74
+ setStatus({ state: "connecting" });
75
+ const broadcast = factoryRef.current({
76
+ stream,
77
+ ...optionsRef.current
78
+ });
79
+ broadcastRef.current = broadcast;
80
+ broadcast.on("stateChange", (newState) => {
81
+ if (broadcastRef.current !== broadcast) return;
82
+ if (newState === "live" || newState === "reconnecting") {
83
+ whepUrlRef.current = broadcast.whepUrl;
84
+ }
85
+ updateStatus(newState);
86
+ });
87
+ broadcast.on("error", (err) => {
88
+ if (broadcastRef.current !== broadcast) return;
89
+ updateStatus("error", err);
90
+ });
91
+ broadcast.on("reconnect", (info) => {
92
+ if (broadcastRef.current !== broadcast) return;
93
+ setStatus({
94
+ state: "reconnecting",
95
+ whepUrl: whepUrlRef.current,
96
+ reconnectInfo: info
68
97
  });
98
+ });
99
+ try {
69
100
  await broadcast.connect();
70
- setState(broadcast.state);
71
- setWhepUrl(broadcast.whepUrl);
101
+ if (broadcastRef.current !== broadcast) return;
102
+ whepUrlRef.current = broadcast.whepUrl;
103
+ updateStatus(broadcast.state);
72
104
  } catch (err) {
73
- setError(err);
74
- setState("error");
105
+ if (broadcastRef.current !== broadcast) return;
106
+ setStatus({ state: "error", error: err });
75
107
  throw err;
76
108
  }
77
- }, []);
109
+ }, [updateStatus]);
78
110
  const stop = (0, import_react.useCallback)(async () => {
79
111
  await broadcastRef.current?.stop();
80
112
  broadcastRef.current = null;
81
- setWhepUrl(null);
82
- setState("idle");
113
+ whepUrlRef.current = null;
114
+ setStatus({ state: "idle" });
115
+ }, []);
116
+ const setMaxFramerate = (0, import_react.useCallback)((fps) => {
117
+ broadcastRef.current?.setMaxFramerate(fps);
83
118
  }, []);
84
119
  return {
85
- state,
86
- whepUrl,
87
- error,
120
+ status,
88
121
  start,
89
- stop
122
+ stop,
123
+ setMaxFramerate
90
124
  };
91
125
  }
92
126
 
93
127
  // src/usePlayer.ts
94
128
  var import_react2 = require("react");
95
129
  function usePlayer(whepUrl, options, factory) {
96
- const [state, setState] = (0, import_react2.useState)("idle");
97
- const [error, setError] = (0, import_react2.useState)(null);
130
+ const [status, setStatus] = (0, import_react2.useState)({ state: "idle" });
98
131
  const playerRef = (0, import_react2.useRef)(null);
99
132
  const videoRef = (0, import_react2.useRef)(null);
100
133
  const optionsRef = (0, import_react2.useRef)(options);
@@ -114,30 +147,63 @@ function usePlayer(whepUrl, options, factory) {
114
147
  playerRef.current?.stop();
115
148
  };
116
149
  }, []);
150
+ const updateStatus = (0, import_react2.useCallback)((newState, error) => {
151
+ switch (newState) {
152
+ case "connecting":
153
+ setStatus({ state: "connecting" });
154
+ break;
155
+ case "playing":
156
+ setStatus({ state: "playing" });
157
+ break;
158
+ case "buffering":
159
+ break;
160
+ case "ended":
161
+ setStatus({ state: "ended" });
162
+ break;
163
+ case "error":
164
+ setStatus({ state: "error", error });
165
+ break;
166
+ }
167
+ }, []);
117
168
  const play = (0, import_react2.useCallback)(async () => {
118
169
  const currentWhepUrl = whepUrlRef.current;
119
170
  if (!currentWhepUrl) {
120
171
  return;
121
172
  }
122
- setError(null);
123
173
  if (playerRef.current) {
124
174
  await playerRef.current.stop();
175
+ playerRef.current = null;
125
176
  }
177
+ setStatus({ state: "connecting" });
178
+ const player = factoryRef.current(currentWhepUrl, {
179
+ reconnect: optionsRef.current?.reconnect,
180
+ iceServers: optionsRef.current?.iceServers,
181
+ connectionTimeout: optionsRef.current?.connectionTimeout,
182
+ onStats: optionsRef.current?.onStats,
183
+ statsIntervalMs: optionsRef.current?.statsIntervalMs
184
+ });
185
+ playerRef.current = player;
186
+ player.on("stateChange", (newState) => {
187
+ if (playerRef.current !== player) return;
188
+ updateStatus(newState);
189
+ if (newState === "playing" && videoRef.current && player.stream) {
190
+ if (videoRef.current.srcObject !== player.stream) {
191
+ player.attachTo(videoRef.current);
192
+ }
193
+ }
194
+ });
195
+ player.on("error", (err) => {
196
+ if (playerRef.current !== player) return;
197
+ updateStatus("error", err);
198
+ });
199
+ player.on("reconnect", (info) => {
200
+ if (playerRef.current !== player) return;
201
+ setStatus({ state: "buffering", reconnectInfo: info });
202
+ });
126
203
  try {
127
- const player = factoryRef.current(currentWhepUrl, {
128
- reconnect: optionsRef.current?.reconnect,
129
- onStats: optionsRef.current?.onStats,
130
- statsIntervalMs: optionsRef.current?.statsIntervalMs
131
- });
132
- playerRef.current = player;
133
- player.on("stateChange", (newState) => {
134
- setState(newState);
135
- });
136
- player.on("error", (err) => {
137
- setError(err);
138
- });
139
204
  await player.connect();
140
- setState(player.state);
205
+ if (playerRef.current !== player) return;
206
+ updateStatus(player.state);
141
207
  if (videoRef.current) {
142
208
  player.attachTo(videoRef.current);
143
209
  if (optionsRef.current?.autoPlay !== false) {
@@ -148,35 +214,148 @@ function usePlayer(whepUrl, options, factory) {
148
214
  }
149
215
  }
150
216
  } catch (err) {
151
- setError(err);
152
- setState("error");
217
+ if (playerRef.current !== player) return;
218
+ setStatus({ state: "error", error: err });
153
219
  throw err;
154
220
  }
155
- }, []);
221
+ }, [updateStatus]);
156
222
  const stop = (0, import_react2.useCallback)(async () => {
157
223
  await playerRef.current?.stop();
158
224
  playerRef.current = null;
159
- setState("idle");
225
+ setStatus({ state: "idle" });
160
226
  }, []);
161
227
  return {
162
- state,
163
- error,
228
+ status,
164
229
  play,
165
230
  stop,
166
231
  videoRef
167
232
  };
168
233
  }
169
234
 
235
+ // src/useCompositor.tsx
236
+ var import_react3 = require("react");
237
+ var import_browser = require("@daydreamlive/browser");
238
+ var import_jsx_runtime = require("react/jsx-runtime");
239
+ var CompositorContext = (0, import_react3.createContext)(null);
240
+ function CompositorProvider({
241
+ children,
242
+ width = 512,
243
+ height = 512,
244
+ fps: initialFps = 30,
245
+ sendFps: initialSendFps,
246
+ dpr,
247
+ crossfadeMs = 500,
248
+ keepalive,
249
+ autoUnlockAudio,
250
+ unlockEvents,
251
+ disableSilentAudio = true
252
+ }) {
253
+ const compositorRef = (0, import_react3.useRef)(null);
254
+ const [stream, setStream] = (0, import_react3.useState)(null);
255
+ const [size, setSize] = (0, import_react3.useState)({
256
+ width,
257
+ height,
258
+ dpr: Math.min(
259
+ 2,
260
+ dpr ?? (typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1)
261
+ )
262
+ });
263
+ const [fps, setFpsState] = (0, import_react3.useState)(initialFps);
264
+ const [sendFps, setSendFpsState] = (0, import_react3.useState)(initialSendFps ?? initialFps);
265
+ (0, import_react3.useLayoutEffect)(() => {
266
+ const compositor = (0, import_browser.createCompositor)({
267
+ width,
268
+ height,
269
+ fps: initialFps,
270
+ sendFps: initialSendFps,
271
+ dpr,
272
+ crossfadeMs,
273
+ keepalive,
274
+ autoUnlockAudio,
275
+ unlockEvents,
276
+ disableSilentAudio,
277
+ onSendFpsChange: (newFps) => setSendFpsState(newFps)
278
+ });
279
+ compositorRef.current = compositor;
280
+ setStream(compositor.stream);
281
+ setSize(compositor.size);
282
+ return () => {
283
+ compositor.destroy();
284
+ compositorRef.current = null;
285
+ };
286
+ }, []);
287
+ (0, import_react3.useEffect)(() => {
288
+ const compositor = compositorRef.current;
289
+ if (!compositor) return;
290
+ compositor.resize(size.width, size.height, size.dpr);
291
+ setStream(compositor.stream);
292
+ }, [size.width, size.height, size.dpr]);
293
+ (0, import_react3.useEffect)(() => {
294
+ const compositor = compositorRef.current;
295
+ if (!compositor) return;
296
+ compositor.setFps(fps);
297
+ setStream(compositor.stream);
298
+ }, [fps]);
299
+ (0, import_react3.useEffect)(() => {
300
+ const compositor = compositorRef.current;
301
+ if (!compositor) return;
302
+ compositor.setSendFps(sendFps);
303
+ }, [sendFps]);
304
+ const api = (0, import_react3.useMemo)(
305
+ () => ({
306
+ // Registry
307
+ register: (id, source) => compositorRef.current?.register(id, source),
308
+ unregister: (id) => compositorRef.current?.unregister(id),
309
+ get: (id) => compositorRef.current?.get(id),
310
+ has: (id) => compositorRef.current?.has(id) ?? false,
311
+ list: () => compositorRef.current?.list() ?? [],
312
+ // Active source
313
+ activate: (id) => compositorRef.current?.activate(id),
314
+ deactivate: () => compositorRef.current?.deactivate(),
315
+ get activeId() {
316
+ return compositorRef.current?.activeId ?? null;
317
+ },
318
+ // Stream & size
319
+ stream,
320
+ size,
321
+ setSize: (w, h, d) => setSize({ width: w, height: h, dpr: d ?? size.dpr }),
322
+ // FPS
323
+ fps,
324
+ setFps: setFpsState,
325
+ sendFps,
326
+ setSendFps: setSendFpsState,
327
+ // Audio
328
+ addAudioTrack: (t) => compositorRef.current?.addAudioTrack(t),
329
+ removeAudioTrack: (id) => compositorRef.current?.removeAudioTrack(id),
330
+ unlockAudio: () => compositorRef.current?.unlockAudio() ?? Promise.resolve(false),
331
+ // Events
332
+ on: (event, cb) => compositorRef.current?.on(event, cb) ?? (() => {
333
+ })
334
+ }),
335
+ [stream, size, fps, sendFps]
336
+ );
337
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CompositorContext.Provider, { value: api, children });
338
+ }
339
+ function useCompositor() {
340
+ const ctx = (0, import_react3.useContext)(CompositorContext);
341
+ if (!ctx) {
342
+ throw new Error("useCompositor must be used within <CompositorProvider>");
343
+ }
344
+ return ctx;
345
+ }
346
+
170
347
  // src/index.ts
171
348
  function useBroadcast2(options) {
172
- return useBroadcast(options, import_browser.createBroadcast);
349
+ return useBroadcast(options, import_browser2.createBroadcast);
173
350
  }
174
351
  function usePlayer2(whepUrl, options) {
175
- return usePlayer(whepUrl, options, import_browser.createPlayer);
352
+ return usePlayer(whepUrl, options, import_browser2.createPlayer);
176
353
  }
177
354
  // Annotate the CommonJS export names for ESM import in node:
178
355
  0 && (module.exports = {
356
+ CompositorProvider,
179
357
  useBroadcast,
358
+ useCompositor,
180
359
  usePlayer
181
360
  });
182
361
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/useBroadcast.ts","../src/usePlayer.ts"],"sourcesContent":["import { createBroadcast, createPlayer } from \"@daydreamlive/browser\";\nimport {\n useBroadcast as baseUseBroadcast,\n type UseBroadcastOptions,\n type UseBroadcastReturn,\n} from \"./useBroadcast\";\nimport {\n usePlayer as baseUsePlayer,\n type UsePlayerOptions,\n type UsePlayerReturn,\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 UsePlayerOptions,\n UsePlayerReturn,\n};\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type {\n Broadcast,\n BroadcastOptions,\n BroadcastState,\n DaydreamError,\n ReconnectConfig,\n VideoConfig,\n} from \"@daydreamlive/browser\";\n\nexport interface UseBroadcastOptions {\n whipUrl: string;\n reconnect?: ReconnectConfig;\n video?: VideoConfig;\n onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n}\n\nexport type BroadcastFactory = (options: BroadcastOptions) => Broadcast;\n\nexport interface UseBroadcastReturn {\n state: BroadcastState | \"idle\";\n whepUrl: string | null;\n error: DaydreamError | null;\n start: (stream: MediaStream) => Promise<void>;\n stop: () => Promise<void>;\n}\n\nexport function useBroadcast(\n options: UseBroadcastOptions,\n factory: BroadcastFactory,\n): UseBroadcastReturn {\n const [state, setState] = useState<BroadcastState | \"idle\">(\"idle\");\n const [whepUrl, setWhepUrl] = useState<string | null>(null);\n const [error, setError] = useState<DaydreamError | null>(null);\n const broadcastRef = useRef<Broadcast | 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 start = useCallback(async (stream: MediaStream) => {\n setError(null);\n\n if (broadcastRef.current) {\n await broadcastRef.current.stop();\n }\n\n try {\n const broadcast = factoryRef.current({\n stream,\n ...optionsRef.current,\n });\n\n broadcastRef.current = broadcast;\n\n broadcast.on(\"stateChange\", (newState) => {\n setState(newState);\n if (newState === \"live\") {\n setWhepUrl(broadcast.whepUrl);\n }\n });\n\n broadcast.on(\"error\", (err) => {\n setError(err);\n });\n\n await broadcast.connect();\n setState(broadcast.state);\n setWhepUrl(broadcast.whepUrl);\n } catch (err) {\n setError(err as DaydreamError);\n setState(\"error\");\n throw err;\n }\n }, []);\n\n const stop = useCallback(async () => {\n await broadcastRef.current?.stop();\n broadcastRef.current = null;\n setWhepUrl(null);\n setState(\"idle\");\n }, []);\n\n return {\n state,\n whepUrl,\n error,\n start,\n stop,\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} from \"@daydreamlive/browser\";\n\nexport interface UsePlayerOptions {\n reconnect?: ReconnectConfig;\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 interface UsePlayerReturn {\n state: PlayerState | \"idle\";\n error: DaydreamError | null;\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 [state, setState] = useState<PlayerState | \"idle\">(\"idle\");\n const [error, setError] = useState<DaydreamError | null>(null);\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 play = useCallback(async () => {\n const currentWhepUrl = whepUrlRef.current;\n if (!currentWhepUrl) {\n return;\n }\n\n setError(null);\n\n if (playerRef.current) {\n await playerRef.current.stop();\n }\n\n try {\n const player = factoryRef.current(currentWhepUrl, {\n reconnect: optionsRef.current?.reconnect,\n onStats: optionsRef.current?.onStats,\n statsIntervalMs: optionsRef.current?.statsIntervalMs,\n });\n\n playerRef.current = player;\n\n player.on(\"stateChange\", (newState) => {\n setState(newState);\n });\n\n player.on(\"error\", (err) => {\n setError(err);\n });\n\n await player.connect();\n setState(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 setError(err as DaydreamError);\n setState(\"error\");\n throw err;\n }\n }, []);\n\n const stop = useCallback(async () => {\n await playerRef.current?.stop();\n playerRef.current = null;\n setState(\"idle\");\n }, []);\n\n return {\n state,\n error,\n play,\n stop,\n videoRef,\n };\n}\n"],"mappings":"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","names":["useBroadcast","usePlayer","import_react","useBroadcast","usePlayer"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/useBroadcast.ts","../src/usePlayer.ts","../src/useCompositor.tsx"],"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 CustomSource,\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","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 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 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 // Active source\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 crossfadeMs = 500,\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 crossfadeMs,\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\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"],"mappings":"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","names":["useBroadcast","usePlayer","import_browser","import_react","import_react","useBroadcast","usePlayer"]}
package/dist/index.d.cts CHANGED
@@ -1,36 +1,102 @@
1
- import { ReconnectConfig, VideoConfig, BroadcastState, DaydreamError, PlayerState } from '@daydreamlive/browser';
2
- import { RefObject } from 'react';
1
+ import { ReconnectConfig, VideoConfig, AudioConfig, ReconnectInfo, DaydreamError, CompositorOptions, Source, Size, Compositor } from '@daydreamlive/browser';
2
+ export { AudioConfig, BroadcastState, CanvasSource, Compositor, CompositorEvent, CompositorEventMap, CompositorOptions, ContentHint, Ctx2D, CustomSource, DaydreamError, DaydreamErrorCode, FitMode, PlayerState, ReconnectConfig, ReconnectInfo, Size, Source, VideoConfig, VideoSource } from '@daydreamlive/browser';
3
+ import { RefObject, PropsWithChildren } from 'react';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
5
 
4
6
  interface UseBroadcastOptions {
5
7
  whipUrl: string;
6
8
  reconnect?: ReconnectConfig;
7
9
  video?: VideoConfig;
10
+ audio?: AudioConfig;
11
+ iceServers?: RTCIceServer[];
12
+ connectionTimeout?: number;
8
13
  onStats?: (report: RTCStatsReport) => void;
9
14
  statsIntervalMs?: number;
10
15
  }
16
+ type UseBroadcastStatus = {
17
+ state: "idle";
18
+ } | {
19
+ state: "connecting";
20
+ } | {
21
+ state: "live";
22
+ whepUrl: string;
23
+ } | {
24
+ state: "reconnecting";
25
+ whepUrl: string;
26
+ reconnectInfo: ReconnectInfo;
27
+ } | {
28
+ state: "ended";
29
+ } | {
30
+ state: "error";
31
+ error: DaydreamError;
32
+ };
11
33
  interface UseBroadcastReturn {
12
- state: BroadcastState | "idle";
13
- whepUrl: string | null;
14
- error: DaydreamError | null;
34
+ status: UseBroadcastStatus;
15
35
  start: (stream: MediaStream) => Promise<void>;
16
36
  stop: () => Promise<void>;
37
+ setMaxFramerate: (fps?: number) => void;
17
38
  }
18
39
 
19
40
  interface UsePlayerOptions {
20
41
  reconnect?: ReconnectConfig;
42
+ iceServers?: RTCIceServer[];
43
+ connectionTimeout?: number;
21
44
  autoPlay?: boolean;
22
45
  onStats?: (report: RTCStatsReport) => void;
23
46
  statsIntervalMs?: number;
24
47
  }
48
+ type UsePlayerStatus = {
49
+ state: "idle";
50
+ } | {
51
+ state: "connecting";
52
+ } | {
53
+ state: "playing";
54
+ } | {
55
+ state: "buffering";
56
+ reconnectInfo: ReconnectInfo;
57
+ } | {
58
+ state: "ended";
59
+ } | {
60
+ state: "error";
61
+ error: DaydreamError;
62
+ };
25
63
  interface UsePlayerReturn {
26
- state: PlayerState | "idle";
27
- error: DaydreamError | null;
64
+ status: UsePlayerStatus;
28
65
  play: () => Promise<void>;
29
66
  stop: () => Promise<void>;
30
67
  videoRef: RefObject<HTMLVideoElement | null>;
31
68
  }
32
69
 
70
+ interface CompositorApi {
71
+ register(id: string, source: Source): void;
72
+ unregister(id: string): void;
73
+ get(id: string): Source | undefined;
74
+ has(id: string): boolean;
75
+ list(): Array<{
76
+ id: string;
77
+ source: Source;
78
+ }>;
79
+ activate(id: string): void;
80
+ deactivate(): void;
81
+ readonly activeId: string | null;
82
+ readonly stream: MediaStream | null;
83
+ readonly size: Size;
84
+ setSize(width: number, height: number, dpr?: number): void;
85
+ readonly fps: number;
86
+ setFps(fps: number): void;
87
+ readonly sendFps: number;
88
+ setSendFps(fps: number): void;
89
+ addAudioTrack(track: MediaStreamTrack): void;
90
+ removeAudioTrack(trackId: string): void;
91
+ unlockAudio(): Promise<boolean>;
92
+ on: Compositor["on"];
93
+ }
94
+ interface CompositorProviderProps extends PropsWithChildren, Partial<Omit<CompositorOptions, "onSendFpsChange">> {
95
+ }
96
+ declare function CompositorProvider({ children, width, height, fps: initialFps, sendFps: initialSendFps, dpr, crossfadeMs, keepalive, autoUnlockAudio, unlockEvents, disableSilentAudio, }: CompositorProviderProps): react_jsx_runtime.JSX.Element;
97
+ declare function useCompositor(): CompositorApi;
98
+
33
99
  declare function useBroadcast(options: UseBroadcastOptions): UseBroadcastReturn;
34
100
  declare function usePlayer(whepUrl: string | null, options?: UsePlayerOptions): UsePlayerReturn;
35
101
 
36
- export { type UseBroadcastOptions, type UseBroadcastReturn, type UsePlayerOptions, type UsePlayerReturn, useBroadcast, usePlayer };
102
+ export { type CompositorApi, CompositorProvider, type CompositorProviderProps, type UseBroadcastOptions, type UseBroadcastReturn, type UseBroadcastStatus, type UsePlayerOptions, type UsePlayerReturn, type UsePlayerStatus, useBroadcast, useCompositor, usePlayer };
package/dist/index.d.ts CHANGED
@@ -1,36 +1,102 @@
1
- import { ReconnectConfig, VideoConfig, BroadcastState, DaydreamError, PlayerState } from '@daydreamlive/browser';
2
- import { RefObject } from 'react';
1
+ import { ReconnectConfig, VideoConfig, AudioConfig, ReconnectInfo, DaydreamError, CompositorOptions, Source, Size, Compositor } from '@daydreamlive/browser';
2
+ export { AudioConfig, BroadcastState, CanvasSource, Compositor, CompositorEvent, CompositorEventMap, CompositorOptions, ContentHint, Ctx2D, CustomSource, DaydreamError, DaydreamErrorCode, FitMode, PlayerState, ReconnectConfig, ReconnectInfo, Size, Source, VideoConfig, VideoSource } from '@daydreamlive/browser';
3
+ import { RefObject, PropsWithChildren } from 'react';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
5
 
4
6
  interface UseBroadcastOptions {
5
7
  whipUrl: string;
6
8
  reconnect?: ReconnectConfig;
7
9
  video?: VideoConfig;
10
+ audio?: AudioConfig;
11
+ iceServers?: RTCIceServer[];
12
+ connectionTimeout?: number;
8
13
  onStats?: (report: RTCStatsReport) => void;
9
14
  statsIntervalMs?: number;
10
15
  }
16
+ type UseBroadcastStatus = {
17
+ state: "idle";
18
+ } | {
19
+ state: "connecting";
20
+ } | {
21
+ state: "live";
22
+ whepUrl: string;
23
+ } | {
24
+ state: "reconnecting";
25
+ whepUrl: string;
26
+ reconnectInfo: ReconnectInfo;
27
+ } | {
28
+ state: "ended";
29
+ } | {
30
+ state: "error";
31
+ error: DaydreamError;
32
+ };
11
33
  interface UseBroadcastReturn {
12
- state: BroadcastState | "idle";
13
- whepUrl: string | null;
14
- error: DaydreamError | null;
34
+ status: UseBroadcastStatus;
15
35
  start: (stream: MediaStream) => Promise<void>;
16
36
  stop: () => Promise<void>;
37
+ setMaxFramerate: (fps?: number) => void;
17
38
  }
18
39
 
19
40
  interface UsePlayerOptions {
20
41
  reconnect?: ReconnectConfig;
42
+ iceServers?: RTCIceServer[];
43
+ connectionTimeout?: number;
21
44
  autoPlay?: boolean;
22
45
  onStats?: (report: RTCStatsReport) => void;
23
46
  statsIntervalMs?: number;
24
47
  }
48
+ type UsePlayerStatus = {
49
+ state: "idle";
50
+ } | {
51
+ state: "connecting";
52
+ } | {
53
+ state: "playing";
54
+ } | {
55
+ state: "buffering";
56
+ reconnectInfo: ReconnectInfo;
57
+ } | {
58
+ state: "ended";
59
+ } | {
60
+ state: "error";
61
+ error: DaydreamError;
62
+ };
25
63
  interface UsePlayerReturn {
26
- state: PlayerState | "idle";
27
- error: DaydreamError | null;
64
+ status: UsePlayerStatus;
28
65
  play: () => Promise<void>;
29
66
  stop: () => Promise<void>;
30
67
  videoRef: RefObject<HTMLVideoElement | null>;
31
68
  }
32
69
 
70
+ interface CompositorApi {
71
+ register(id: string, source: Source): void;
72
+ unregister(id: string): void;
73
+ get(id: string): Source | undefined;
74
+ has(id: string): boolean;
75
+ list(): Array<{
76
+ id: string;
77
+ source: Source;
78
+ }>;
79
+ activate(id: string): void;
80
+ deactivate(): void;
81
+ readonly activeId: string | null;
82
+ readonly stream: MediaStream | null;
83
+ readonly size: Size;
84
+ setSize(width: number, height: number, dpr?: number): void;
85
+ readonly fps: number;
86
+ setFps(fps: number): void;
87
+ readonly sendFps: number;
88
+ setSendFps(fps: number): void;
89
+ addAudioTrack(track: MediaStreamTrack): void;
90
+ removeAudioTrack(trackId: string): void;
91
+ unlockAudio(): Promise<boolean>;
92
+ on: Compositor["on"];
93
+ }
94
+ interface CompositorProviderProps extends PropsWithChildren, Partial<Omit<CompositorOptions, "onSendFpsChange">> {
95
+ }
96
+ declare function CompositorProvider({ children, width, height, fps: initialFps, sendFps: initialSendFps, dpr, crossfadeMs, keepalive, autoUnlockAudio, unlockEvents, disableSilentAudio, }: CompositorProviderProps): react_jsx_runtime.JSX.Element;
97
+ declare function useCompositor(): CompositorApi;
98
+
33
99
  declare function useBroadcast(options: UseBroadcastOptions): UseBroadcastReturn;
34
100
  declare function usePlayer(whepUrl: string | null, options?: UsePlayerOptions): UsePlayerReturn;
35
101
 
36
- export { type UseBroadcastOptions, type UseBroadcastReturn, type UsePlayerOptions, type UsePlayerReturn, useBroadcast, usePlayer };
102
+ export { type CompositorApi, CompositorProvider, type CompositorProviderProps, type UseBroadcastOptions, type UseBroadcastReturn, type UseBroadcastStatus, type UsePlayerOptions, type UsePlayerReturn, type UsePlayerStatus, useBroadcast, useCompositor, usePlayer };
package/dist/index.js CHANGED
@@ -4,10 +4,9 @@ import { createBroadcast, createPlayer } from "@daydreamlive/browser";
4
4
  // src/useBroadcast.ts
5
5
  import { useCallback, useEffect, useRef, useState } from "react";
6
6
  function useBroadcast(options, factory) {
7
- const [state, setState] = useState("idle");
8
- const [whepUrl, setWhepUrl] = useState(null);
9
- const [error, setError] = useState(null);
7
+ const [status, setStatus] = useState({ state: "idle" });
10
8
  const broadcastRef = useRef(null);
9
+ const whepUrlRef = useRef(null);
11
10
  const optionsRef = useRef(options);
12
11
  const factoryRef = useRef(factory);
13
12
  useEffect(() => {
@@ -21,47 +20,80 @@ function useBroadcast(options, factory) {
21
20
  broadcastRef.current?.stop();
22
21
  };
23
22
  }, []);
23
+ const updateStatus = useCallback((newState, error) => {
24
+ const whepUrl = whepUrlRef.current;
25
+ switch (newState) {
26
+ case "connecting":
27
+ setStatus({ state: "connecting" });
28
+ break;
29
+ case "live":
30
+ setStatus({ state: "live", whepUrl });
31
+ break;
32
+ case "reconnecting":
33
+ break;
34
+ case "ended":
35
+ setStatus({ state: "ended" });
36
+ break;
37
+ case "error":
38
+ setStatus({ state: "error", error });
39
+ break;
40
+ }
41
+ }, []);
24
42
  const start = useCallback(async (stream) => {
25
- setError(null);
26
43
  if (broadcastRef.current) {
27
44
  await broadcastRef.current.stop();
45
+ broadcastRef.current = null;
28
46
  }
29
- try {
30
- const broadcast = factoryRef.current({
31
- stream,
32
- ...optionsRef.current
33
- });
34
- broadcastRef.current = broadcast;
35
- broadcast.on("stateChange", (newState) => {
36
- setState(newState);
37
- if (newState === "live") {
38
- setWhepUrl(broadcast.whepUrl);
39
- }
40
- });
41
- broadcast.on("error", (err) => {
42
- setError(err);
47
+ setStatus({ state: "connecting" });
48
+ const broadcast = factoryRef.current({
49
+ stream,
50
+ ...optionsRef.current
51
+ });
52
+ broadcastRef.current = broadcast;
53
+ broadcast.on("stateChange", (newState) => {
54
+ if (broadcastRef.current !== broadcast) return;
55
+ if (newState === "live" || newState === "reconnecting") {
56
+ whepUrlRef.current = broadcast.whepUrl;
57
+ }
58
+ updateStatus(newState);
59
+ });
60
+ broadcast.on("error", (err) => {
61
+ if (broadcastRef.current !== broadcast) return;
62
+ updateStatus("error", err);
63
+ });
64
+ broadcast.on("reconnect", (info) => {
65
+ if (broadcastRef.current !== broadcast) return;
66
+ setStatus({
67
+ state: "reconnecting",
68
+ whepUrl: whepUrlRef.current,
69
+ reconnectInfo: info
43
70
  });
71
+ });
72
+ try {
44
73
  await broadcast.connect();
45
- setState(broadcast.state);
46
- setWhepUrl(broadcast.whepUrl);
74
+ if (broadcastRef.current !== broadcast) return;
75
+ whepUrlRef.current = broadcast.whepUrl;
76
+ updateStatus(broadcast.state);
47
77
  } catch (err) {
48
- setError(err);
49
- setState("error");
78
+ if (broadcastRef.current !== broadcast) return;
79
+ setStatus({ state: "error", error: err });
50
80
  throw err;
51
81
  }
52
- }, []);
82
+ }, [updateStatus]);
53
83
  const stop = useCallback(async () => {
54
84
  await broadcastRef.current?.stop();
55
85
  broadcastRef.current = null;
56
- setWhepUrl(null);
57
- setState("idle");
86
+ whepUrlRef.current = null;
87
+ setStatus({ state: "idle" });
88
+ }, []);
89
+ const setMaxFramerate = useCallback((fps) => {
90
+ broadcastRef.current?.setMaxFramerate(fps);
58
91
  }, []);
59
92
  return {
60
- state,
61
- whepUrl,
62
- error,
93
+ status,
63
94
  start,
64
- stop
95
+ stop,
96
+ setMaxFramerate
65
97
  };
66
98
  }
67
99
 
@@ -73,8 +105,7 @@ import {
73
105
  useState as useState2
74
106
  } from "react";
75
107
  function usePlayer(whepUrl, options, factory) {
76
- const [state, setState] = useState2("idle");
77
- const [error, setError] = useState2(null);
108
+ const [status, setStatus] = useState2({ state: "idle" });
78
109
  const playerRef = useRef2(null);
79
110
  const videoRef = useRef2(null);
80
111
  const optionsRef = useRef2(options);
@@ -94,30 +125,63 @@ function usePlayer(whepUrl, options, factory) {
94
125
  playerRef.current?.stop();
95
126
  };
96
127
  }, []);
128
+ const updateStatus = useCallback2((newState, error) => {
129
+ switch (newState) {
130
+ case "connecting":
131
+ setStatus({ state: "connecting" });
132
+ break;
133
+ case "playing":
134
+ setStatus({ state: "playing" });
135
+ break;
136
+ case "buffering":
137
+ break;
138
+ case "ended":
139
+ setStatus({ state: "ended" });
140
+ break;
141
+ case "error":
142
+ setStatus({ state: "error", error });
143
+ break;
144
+ }
145
+ }, []);
97
146
  const play = useCallback2(async () => {
98
147
  const currentWhepUrl = whepUrlRef.current;
99
148
  if (!currentWhepUrl) {
100
149
  return;
101
150
  }
102
- setError(null);
103
151
  if (playerRef.current) {
104
152
  await playerRef.current.stop();
153
+ playerRef.current = null;
105
154
  }
155
+ setStatus({ state: "connecting" });
156
+ const player = factoryRef.current(currentWhepUrl, {
157
+ reconnect: optionsRef.current?.reconnect,
158
+ iceServers: optionsRef.current?.iceServers,
159
+ connectionTimeout: optionsRef.current?.connectionTimeout,
160
+ onStats: optionsRef.current?.onStats,
161
+ statsIntervalMs: optionsRef.current?.statsIntervalMs
162
+ });
163
+ playerRef.current = player;
164
+ player.on("stateChange", (newState) => {
165
+ if (playerRef.current !== player) return;
166
+ updateStatus(newState);
167
+ if (newState === "playing" && videoRef.current && player.stream) {
168
+ if (videoRef.current.srcObject !== player.stream) {
169
+ player.attachTo(videoRef.current);
170
+ }
171
+ }
172
+ });
173
+ player.on("error", (err) => {
174
+ if (playerRef.current !== player) return;
175
+ updateStatus("error", err);
176
+ });
177
+ player.on("reconnect", (info) => {
178
+ if (playerRef.current !== player) return;
179
+ setStatus({ state: "buffering", reconnectInfo: info });
180
+ });
106
181
  try {
107
- const player = factoryRef.current(currentWhepUrl, {
108
- reconnect: optionsRef.current?.reconnect,
109
- onStats: optionsRef.current?.onStats,
110
- statsIntervalMs: optionsRef.current?.statsIntervalMs
111
- });
112
- playerRef.current = player;
113
- player.on("stateChange", (newState) => {
114
- setState(newState);
115
- });
116
- player.on("error", (err) => {
117
- setError(err);
118
- });
119
182
  await player.connect();
120
- setState(player.state);
183
+ if (playerRef.current !== player) return;
184
+ updateStatus(player.state);
121
185
  if (videoRef.current) {
122
186
  player.attachTo(videoRef.current);
123
187
  if (optionsRef.current?.autoPlay !== false) {
@@ -128,25 +192,146 @@ function usePlayer(whepUrl, options, factory) {
128
192
  }
129
193
  }
130
194
  } catch (err) {
131
- setError(err);
132
- setState("error");
195
+ if (playerRef.current !== player) return;
196
+ setStatus({ state: "error", error: err });
133
197
  throw err;
134
198
  }
135
- }, []);
199
+ }, [updateStatus]);
136
200
  const stop = useCallback2(async () => {
137
201
  await playerRef.current?.stop();
138
202
  playerRef.current = null;
139
- setState("idle");
203
+ setStatus({ state: "idle" });
140
204
  }, []);
141
205
  return {
142
- state,
143
- error,
206
+ status,
144
207
  play,
145
208
  stop,
146
209
  videoRef
147
210
  };
148
211
  }
149
212
 
213
+ // src/useCompositor.tsx
214
+ import {
215
+ createContext,
216
+ useContext,
217
+ useEffect as useEffect3,
218
+ useLayoutEffect,
219
+ useMemo,
220
+ useRef as useRef3,
221
+ useState as useState3
222
+ } from "react";
223
+ import {
224
+ createCompositor
225
+ } from "@daydreamlive/browser";
226
+ import { jsx } from "react/jsx-runtime";
227
+ var CompositorContext = createContext(null);
228
+ function CompositorProvider({
229
+ children,
230
+ width = 512,
231
+ height = 512,
232
+ fps: initialFps = 30,
233
+ sendFps: initialSendFps,
234
+ dpr,
235
+ crossfadeMs = 500,
236
+ keepalive,
237
+ autoUnlockAudio,
238
+ unlockEvents,
239
+ disableSilentAudio = true
240
+ }) {
241
+ const compositorRef = useRef3(null);
242
+ const [stream, setStream] = useState3(null);
243
+ const [size, setSize] = useState3({
244
+ width,
245
+ height,
246
+ dpr: Math.min(
247
+ 2,
248
+ dpr ?? (typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1)
249
+ )
250
+ });
251
+ const [fps, setFpsState] = useState3(initialFps);
252
+ const [sendFps, setSendFpsState] = useState3(initialSendFps ?? initialFps);
253
+ useLayoutEffect(() => {
254
+ const compositor = createCompositor({
255
+ width,
256
+ height,
257
+ fps: initialFps,
258
+ sendFps: initialSendFps,
259
+ dpr,
260
+ crossfadeMs,
261
+ keepalive,
262
+ autoUnlockAudio,
263
+ unlockEvents,
264
+ disableSilentAudio,
265
+ onSendFpsChange: (newFps) => setSendFpsState(newFps)
266
+ });
267
+ compositorRef.current = compositor;
268
+ setStream(compositor.stream);
269
+ setSize(compositor.size);
270
+ return () => {
271
+ compositor.destroy();
272
+ compositorRef.current = null;
273
+ };
274
+ }, []);
275
+ useEffect3(() => {
276
+ const compositor = compositorRef.current;
277
+ if (!compositor) return;
278
+ compositor.resize(size.width, size.height, size.dpr);
279
+ setStream(compositor.stream);
280
+ }, [size.width, size.height, size.dpr]);
281
+ useEffect3(() => {
282
+ const compositor = compositorRef.current;
283
+ if (!compositor) return;
284
+ compositor.setFps(fps);
285
+ setStream(compositor.stream);
286
+ }, [fps]);
287
+ useEffect3(() => {
288
+ const compositor = compositorRef.current;
289
+ if (!compositor) return;
290
+ compositor.setSendFps(sendFps);
291
+ }, [sendFps]);
292
+ const api = useMemo(
293
+ () => ({
294
+ // Registry
295
+ register: (id, source) => compositorRef.current?.register(id, source),
296
+ unregister: (id) => compositorRef.current?.unregister(id),
297
+ get: (id) => compositorRef.current?.get(id),
298
+ has: (id) => compositorRef.current?.has(id) ?? false,
299
+ list: () => compositorRef.current?.list() ?? [],
300
+ // Active source
301
+ activate: (id) => compositorRef.current?.activate(id),
302
+ deactivate: () => compositorRef.current?.deactivate(),
303
+ get activeId() {
304
+ return compositorRef.current?.activeId ?? null;
305
+ },
306
+ // Stream & size
307
+ stream,
308
+ size,
309
+ setSize: (w, h, d) => setSize({ width: w, height: h, dpr: d ?? size.dpr }),
310
+ // FPS
311
+ fps,
312
+ setFps: setFpsState,
313
+ sendFps,
314
+ setSendFps: setSendFpsState,
315
+ // Audio
316
+ addAudioTrack: (t) => compositorRef.current?.addAudioTrack(t),
317
+ removeAudioTrack: (id) => compositorRef.current?.removeAudioTrack(id),
318
+ unlockAudio: () => compositorRef.current?.unlockAudio() ?? Promise.resolve(false),
319
+ // Events
320
+ on: (event, cb) => compositorRef.current?.on(event, cb) ?? (() => {
321
+ })
322
+ }),
323
+ [stream, size, fps, sendFps]
324
+ );
325
+ return /* @__PURE__ */ jsx(CompositorContext.Provider, { value: api, children });
326
+ }
327
+ function useCompositor() {
328
+ const ctx = useContext(CompositorContext);
329
+ if (!ctx) {
330
+ throw new Error("useCompositor must be used within <CompositorProvider>");
331
+ }
332
+ return ctx;
333
+ }
334
+
150
335
  // src/index.ts
151
336
  function useBroadcast2(options) {
152
337
  return useBroadcast(options, createBroadcast);
@@ -155,7 +340,9 @@ function usePlayer2(whepUrl, options) {
155
340
  return usePlayer(whepUrl, options, createPlayer);
156
341
  }
157
342
  export {
343
+ CompositorProvider,
158
344
  useBroadcast2 as useBroadcast,
345
+ useCompositor,
159
346
  usePlayer2 as usePlayer
160
347
  };
161
348
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/useBroadcast.ts","../src/usePlayer.ts"],"sourcesContent":["import { createBroadcast, createPlayer } from \"@daydreamlive/browser\";\nimport {\n useBroadcast as baseUseBroadcast,\n type UseBroadcastOptions,\n type UseBroadcastReturn,\n} from \"./useBroadcast\";\nimport {\n usePlayer as baseUsePlayer,\n type UsePlayerOptions,\n type UsePlayerReturn,\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 UsePlayerOptions,\n UsePlayerReturn,\n};\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type {\n Broadcast,\n BroadcastOptions,\n BroadcastState,\n DaydreamError,\n ReconnectConfig,\n VideoConfig,\n} from \"@daydreamlive/browser\";\n\nexport interface UseBroadcastOptions {\n whipUrl: string;\n reconnect?: ReconnectConfig;\n video?: VideoConfig;\n onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n}\n\nexport type BroadcastFactory = (options: BroadcastOptions) => Broadcast;\n\nexport interface UseBroadcastReturn {\n state: BroadcastState | \"idle\";\n whepUrl: string | null;\n error: DaydreamError | null;\n start: (stream: MediaStream) => Promise<void>;\n stop: () => Promise<void>;\n}\n\nexport function useBroadcast(\n options: UseBroadcastOptions,\n factory: BroadcastFactory,\n): UseBroadcastReturn {\n const [state, setState] = useState<BroadcastState | \"idle\">(\"idle\");\n const [whepUrl, setWhepUrl] = useState<string | null>(null);\n const [error, setError] = useState<DaydreamError | null>(null);\n const broadcastRef = useRef<Broadcast | 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 start = useCallback(async (stream: MediaStream) => {\n setError(null);\n\n if (broadcastRef.current) {\n await broadcastRef.current.stop();\n }\n\n try {\n const broadcast = factoryRef.current({\n stream,\n ...optionsRef.current,\n });\n\n broadcastRef.current = broadcast;\n\n broadcast.on(\"stateChange\", (newState) => {\n setState(newState);\n if (newState === \"live\") {\n setWhepUrl(broadcast.whepUrl);\n }\n });\n\n broadcast.on(\"error\", (err) => {\n setError(err);\n });\n\n await broadcast.connect();\n setState(broadcast.state);\n setWhepUrl(broadcast.whepUrl);\n } catch (err) {\n setError(err as DaydreamError);\n setState(\"error\");\n throw err;\n }\n }, []);\n\n const stop = useCallback(async () => {\n await broadcastRef.current?.stop();\n broadcastRef.current = null;\n setWhepUrl(null);\n setState(\"idle\");\n }, []);\n\n return {\n state,\n whepUrl,\n error,\n start,\n stop,\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} from \"@daydreamlive/browser\";\n\nexport interface UsePlayerOptions {\n reconnect?: ReconnectConfig;\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 interface UsePlayerReturn {\n state: PlayerState | \"idle\";\n error: DaydreamError | null;\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 [state, setState] = useState<PlayerState | \"idle\">(\"idle\");\n const [error, setError] = useState<DaydreamError | null>(null);\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 play = useCallback(async () => {\n const currentWhepUrl = whepUrlRef.current;\n if (!currentWhepUrl) {\n return;\n }\n\n setError(null);\n\n if (playerRef.current) {\n await playerRef.current.stop();\n }\n\n try {\n const player = factoryRef.current(currentWhepUrl, {\n reconnect: optionsRef.current?.reconnect,\n onStats: optionsRef.current?.onStats,\n statsIntervalMs: optionsRef.current?.statsIntervalMs,\n });\n\n playerRef.current = player;\n\n player.on(\"stateChange\", (newState) => {\n setState(newState);\n });\n\n player.on(\"error\", (err) => {\n setError(err);\n });\n\n await player.connect();\n setState(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 setError(err as DaydreamError);\n setState(\"error\");\n throw err;\n }\n }, []);\n\n const stop = useCallback(async () => {\n await playerRef.current?.stop();\n playerRef.current = null;\n setState(\"idle\");\n }, []);\n\n return {\n state,\n error,\n play,\n stop,\n videoRef,\n };\n}\n"],"mappings":"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","names":["useCallback","useEffect","useRef","useState","useBroadcast","usePlayer"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/useBroadcast.ts","../src/usePlayer.ts","../src/useCompositor.tsx"],"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 CustomSource,\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","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 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 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 // Active source\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 crossfadeMs = 500,\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 crossfadeMs,\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\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"],"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;AAuCA,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,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;AAiKH;AA9HJ,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,cAAc;AAAA,EACd;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;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;AAAA,MAG9C,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;;;AHjLO,SAASG,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","useBroadcast","usePlayer"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daydreamlive/react",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -30,7 +30,7 @@
30
30
  "typecheck": "tsc --noEmit"
31
31
  },
32
32
  "dependencies": {
33
- "@daydreamlive/browser": "^0.1.0"
33
+ "@daydreamlive/browser": "^0.2.0"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "react": ">=18.0.0"