@daydreamlive/react 0.1.1 → 0.3.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 +41 -7
- package/dist/index.cjs +314 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +109 -8
- package/dist/index.d.ts +109 -8
- package/dist/index.js +317 -52
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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 {
|
|
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
|
-
|
|
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 {
|
|
49
|
+
const { status, play, stop, videoRef } = usePlayer(whepUrl, {
|
|
48
50
|
autoPlay: true,
|
|
49
51
|
reconnect: { enabled: true },
|
|
50
52
|
});
|
|
51
53
|
|
|
52
|
-
return
|
|
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: `{
|
|
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: `{
|
|
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,21 @@ 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,
|
|
24
|
-
|
|
25
|
+
useCompositor: () => useCompositor,
|
|
26
|
+
usePlayer: () => usePlayer2,
|
|
27
|
+
useSource: () => useSource
|
|
25
28
|
});
|
|
26
29
|
module.exports = __toCommonJS(index_exports);
|
|
27
|
-
var
|
|
30
|
+
var import_browser2 = require("@daydreamlive/browser");
|
|
28
31
|
|
|
29
32
|
// src/useBroadcast.ts
|
|
30
33
|
var import_react = require("react");
|
|
31
34
|
function useBroadcast(options, factory) {
|
|
32
|
-
const [
|
|
33
|
-
const [whepUrl, setWhepUrl] = (0, import_react.useState)(null);
|
|
34
|
-
const [error, setError] = (0, import_react.useState)(null);
|
|
35
|
+
const [status, setStatus] = (0, import_react.useState)({ state: "idle" });
|
|
35
36
|
const broadcastRef = (0, import_react.useRef)(null);
|
|
37
|
+
const whepUrlRef = (0, import_react.useRef)(null);
|
|
36
38
|
const optionsRef = (0, import_react.useRef)(options);
|
|
37
39
|
const factoryRef = (0, import_react.useRef)(factory);
|
|
38
40
|
(0, import_react.useEffect)(() => {
|
|
@@ -46,55 +48,87 @@ function useBroadcast(options, factory) {
|
|
|
46
48
|
broadcastRef.current?.stop();
|
|
47
49
|
};
|
|
48
50
|
}, []);
|
|
51
|
+
const updateStatus = (0, import_react.useCallback)((newState, error) => {
|
|
52
|
+
const whepUrl = whepUrlRef.current;
|
|
53
|
+
switch (newState) {
|
|
54
|
+
case "connecting":
|
|
55
|
+
setStatus({ state: "connecting" });
|
|
56
|
+
break;
|
|
57
|
+
case "live":
|
|
58
|
+
setStatus({ state: "live", whepUrl });
|
|
59
|
+
break;
|
|
60
|
+
case "reconnecting":
|
|
61
|
+
break;
|
|
62
|
+
case "ended":
|
|
63
|
+
setStatus({ state: "ended" });
|
|
64
|
+
break;
|
|
65
|
+
case "error":
|
|
66
|
+
setStatus({ state: "error", error });
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}, []);
|
|
49
70
|
const start = (0, import_react.useCallback)(async (stream) => {
|
|
50
|
-
setError(null);
|
|
51
71
|
if (broadcastRef.current) {
|
|
52
72
|
await broadcastRef.current.stop();
|
|
73
|
+
broadcastRef.current = null;
|
|
53
74
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
75
|
+
setStatus({ state: "connecting" });
|
|
76
|
+
const broadcast = factoryRef.current({
|
|
77
|
+
stream,
|
|
78
|
+
...optionsRef.current
|
|
79
|
+
});
|
|
80
|
+
broadcastRef.current = broadcast;
|
|
81
|
+
broadcast.on("stateChange", (newState) => {
|
|
82
|
+
if (broadcastRef.current !== broadcast) return;
|
|
83
|
+
if (newState === "live" || newState === "reconnecting") {
|
|
84
|
+
whepUrlRef.current = broadcast.whepUrl;
|
|
85
|
+
}
|
|
86
|
+
updateStatus(newState);
|
|
87
|
+
});
|
|
88
|
+
broadcast.on("error", (err) => {
|
|
89
|
+
if (broadcastRef.current !== broadcast) return;
|
|
90
|
+
updateStatus("error", err);
|
|
91
|
+
});
|
|
92
|
+
broadcast.on("reconnect", (info) => {
|
|
93
|
+
if (broadcastRef.current !== broadcast) return;
|
|
94
|
+
setStatus({
|
|
95
|
+
state: "reconnecting",
|
|
96
|
+
whepUrl: whepUrlRef.current,
|
|
97
|
+
reconnectInfo: info
|
|
68
98
|
});
|
|
99
|
+
});
|
|
100
|
+
try {
|
|
69
101
|
await broadcast.connect();
|
|
70
|
-
|
|
71
|
-
|
|
102
|
+
if (broadcastRef.current !== broadcast) return;
|
|
103
|
+
whepUrlRef.current = broadcast.whepUrl;
|
|
104
|
+
updateStatus(broadcast.state);
|
|
72
105
|
} catch (err) {
|
|
73
|
-
|
|
74
|
-
|
|
106
|
+
if (broadcastRef.current !== broadcast) return;
|
|
107
|
+
setStatus({ state: "error", error: err });
|
|
75
108
|
throw err;
|
|
76
109
|
}
|
|
77
|
-
}, []);
|
|
110
|
+
}, [updateStatus]);
|
|
78
111
|
const stop = (0, import_react.useCallback)(async () => {
|
|
79
112
|
await broadcastRef.current?.stop();
|
|
80
113
|
broadcastRef.current = null;
|
|
81
|
-
|
|
82
|
-
|
|
114
|
+
whepUrlRef.current = null;
|
|
115
|
+
setStatus({ state: "idle" });
|
|
116
|
+
}, []);
|
|
117
|
+
const setMaxFramerate = (0, import_react.useCallback)((fps) => {
|
|
118
|
+
broadcastRef.current?.setMaxFramerate(fps);
|
|
83
119
|
}, []);
|
|
84
120
|
return {
|
|
85
|
-
|
|
86
|
-
whepUrl,
|
|
87
|
-
error,
|
|
121
|
+
status,
|
|
88
122
|
start,
|
|
89
|
-
stop
|
|
123
|
+
stop,
|
|
124
|
+
setMaxFramerate
|
|
90
125
|
};
|
|
91
126
|
}
|
|
92
127
|
|
|
93
128
|
// src/usePlayer.ts
|
|
94
129
|
var import_react2 = require("react");
|
|
95
130
|
function usePlayer(whepUrl, options, factory) {
|
|
96
|
-
const [
|
|
97
|
-
const [error, setError] = (0, import_react2.useState)(null);
|
|
131
|
+
const [status, setStatus] = (0, import_react2.useState)({ state: "idle" });
|
|
98
132
|
const playerRef = (0, import_react2.useRef)(null);
|
|
99
133
|
const videoRef = (0, import_react2.useRef)(null);
|
|
100
134
|
const optionsRef = (0, import_react2.useRef)(options);
|
|
@@ -114,30 +148,64 @@ function usePlayer(whepUrl, options, factory) {
|
|
|
114
148
|
playerRef.current?.stop();
|
|
115
149
|
};
|
|
116
150
|
}, []);
|
|
151
|
+
const updateStatus = (0, import_react2.useCallback)((newState, error) => {
|
|
152
|
+
switch (newState) {
|
|
153
|
+
case "connecting":
|
|
154
|
+
setStatus({ state: "connecting" });
|
|
155
|
+
break;
|
|
156
|
+
case "playing":
|
|
157
|
+
setStatus({ state: "playing" });
|
|
158
|
+
break;
|
|
159
|
+
case "buffering":
|
|
160
|
+
break;
|
|
161
|
+
case "ended":
|
|
162
|
+
setStatus({ state: "ended" });
|
|
163
|
+
break;
|
|
164
|
+
case "error":
|
|
165
|
+
setStatus({ state: "error", error });
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}, []);
|
|
117
169
|
const play = (0, import_react2.useCallback)(async () => {
|
|
118
170
|
const currentWhepUrl = whepUrlRef.current;
|
|
119
171
|
if (!currentWhepUrl) {
|
|
120
172
|
return;
|
|
121
173
|
}
|
|
122
|
-
setError(null);
|
|
123
174
|
if (playerRef.current) {
|
|
124
175
|
await playerRef.current.stop();
|
|
176
|
+
playerRef.current = null;
|
|
125
177
|
}
|
|
178
|
+
setStatus({ state: "connecting" });
|
|
179
|
+
const player = factoryRef.current(currentWhepUrl, {
|
|
180
|
+
reconnect: optionsRef.current?.reconnect,
|
|
181
|
+
iceServers: optionsRef.current?.iceServers,
|
|
182
|
+
connectionTimeout: optionsRef.current?.connectionTimeout,
|
|
183
|
+
skipIceGathering: optionsRef.current?.skipIceGathering,
|
|
184
|
+
onStats: optionsRef.current?.onStats,
|
|
185
|
+
statsIntervalMs: optionsRef.current?.statsIntervalMs
|
|
186
|
+
});
|
|
187
|
+
playerRef.current = player;
|
|
188
|
+
player.on("stateChange", (newState) => {
|
|
189
|
+
if (playerRef.current !== player) return;
|
|
190
|
+
updateStatus(newState);
|
|
191
|
+
if (newState === "playing" && videoRef.current && player.stream) {
|
|
192
|
+
if (videoRef.current.srcObject !== player.stream) {
|
|
193
|
+
player.attachTo(videoRef.current);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
player.on("error", (err) => {
|
|
198
|
+
if (playerRef.current !== player) return;
|
|
199
|
+
updateStatus("error", err);
|
|
200
|
+
});
|
|
201
|
+
player.on("reconnect", (info) => {
|
|
202
|
+
if (playerRef.current !== player) return;
|
|
203
|
+
setStatus({ state: "buffering", reconnectInfo: info });
|
|
204
|
+
});
|
|
126
205
|
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
206
|
await player.connect();
|
|
140
|
-
|
|
207
|
+
if (playerRef.current !== player) return;
|
|
208
|
+
updateStatus(player.state);
|
|
141
209
|
if (videoRef.current) {
|
|
142
210
|
player.attachTo(videoRef.current);
|
|
143
211
|
if (optionsRef.current?.autoPlay !== false) {
|
|
@@ -148,35 +216,225 @@ function usePlayer(whepUrl, options, factory) {
|
|
|
148
216
|
}
|
|
149
217
|
}
|
|
150
218
|
} catch (err) {
|
|
151
|
-
|
|
152
|
-
|
|
219
|
+
if (playerRef.current !== player) return;
|
|
220
|
+
setStatus({ state: "error", error: err });
|
|
153
221
|
throw err;
|
|
154
222
|
}
|
|
155
|
-
}, []);
|
|
223
|
+
}, [updateStatus]);
|
|
156
224
|
const stop = (0, import_react2.useCallback)(async () => {
|
|
157
225
|
await playerRef.current?.stop();
|
|
158
226
|
playerRef.current = null;
|
|
159
|
-
|
|
227
|
+
setStatus({ state: "idle" });
|
|
160
228
|
}, []);
|
|
161
229
|
return {
|
|
162
|
-
|
|
163
|
-
error,
|
|
230
|
+
status,
|
|
164
231
|
play,
|
|
165
232
|
stop,
|
|
166
233
|
videoRef
|
|
167
234
|
};
|
|
168
235
|
}
|
|
169
236
|
|
|
237
|
+
// src/useCompositor.tsx
|
|
238
|
+
var import_react3 = require("react");
|
|
239
|
+
var import_browser = require("@daydreamlive/browser");
|
|
240
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
241
|
+
var CompositorContext = (0, import_react3.createContext)(null);
|
|
242
|
+
function CompositorProvider({
|
|
243
|
+
children,
|
|
244
|
+
width = 512,
|
|
245
|
+
height = 512,
|
|
246
|
+
fps: initialFps = 30,
|
|
247
|
+
sendFps: initialSendFps,
|
|
248
|
+
dpr,
|
|
249
|
+
keepalive,
|
|
250
|
+
autoUnlockAudio,
|
|
251
|
+
unlockEvents,
|
|
252
|
+
disableSilentAudio = true
|
|
253
|
+
}) {
|
|
254
|
+
const compositorRef = (0, import_react3.useRef)(null);
|
|
255
|
+
const [stream, setStream] = (0, import_react3.useState)(null);
|
|
256
|
+
const [size, setSize] = (0, import_react3.useState)({
|
|
257
|
+
width,
|
|
258
|
+
height,
|
|
259
|
+
dpr: Math.min(
|
|
260
|
+
2,
|
|
261
|
+
dpr ?? (typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1)
|
|
262
|
+
)
|
|
263
|
+
});
|
|
264
|
+
const [fps, setFpsState] = (0, import_react3.useState)(initialFps);
|
|
265
|
+
const [sendFps, setSendFpsState] = (0, import_react3.useState)(initialSendFps ?? initialFps);
|
|
266
|
+
(0, import_react3.useLayoutEffect)(() => {
|
|
267
|
+
const compositor = (0, import_browser.createCompositor)({
|
|
268
|
+
width,
|
|
269
|
+
height,
|
|
270
|
+
fps: initialFps,
|
|
271
|
+
sendFps: initialSendFps,
|
|
272
|
+
dpr,
|
|
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
|
+
use: (id, source) => {
|
|
313
|
+
compositorRef.current?.register(id, source);
|
|
314
|
+
compositorRef.current?.activate(id);
|
|
315
|
+
return () => compositorRef.current?.unregister(id);
|
|
316
|
+
},
|
|
317
|
+
// Active source
|
|
318
|
+
activate: (id) => compositorRef.current?.activate(id),
|
|
319
|
+
deactivate: () => compositorRef.current?.deactivate(),
|
|
320
|
+
get activeId() {
|
|
321
|
+
return compositorRef.current?.activeId ?? null;
|
|
322
|
+
},
|
|
323
|
+
// Stream & size
|
|
324
|
+
stream,
|
|
325
|
+
size,
|
|
326
|
+
setSize: (w, h, d) => setSize({ width: w, height: h, dpr: d ?? size.dpr }),
|
|
327
|
+
// FPS
|
|
328
|
+
fps,
|
|
329
|
+
setFps: setFpsState,
|
|
330
|
+
sendFps,
|
|
331
|
+
setSendFps: setSendFpsState,
|
|
332
|
+
// Audio
|
|
333
|
+
addAudioTrack: (t) => compositorRef.current?.addAudioTrack(t),
|
|
334
|
+
removeAudioTrack: (id) => compositorRef.current?.removeAudioTrack(id),
|
|
335
|
+
unlockAudio: () => compositorRef.current?.unlockAudio() ?? Promise.resolve(false),
|
|
336
|
+
// Events
|
|
337
|
+
on: (event, cb) => compositorRef.current?.on(event, cb) ?? (() => {
|
|
338
|
+
})
|
|
339
|
+
}),
|
|
340
|
+
[stream, size, fps, sendFps]
|
|
341
|
+
);
|
|
342
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CompositorContext.Provider, { value: api, children });
|
|
343
|
+
}
|
|
344
|
+
function useCompositor() {
|
|
345
|
+
const ctx = (0, import_react3.useContext)(CompositorContext);
|
|
346
|
+
if (!ctx) {
|
|
347
|
+
throw new Error("useCompositor must be used within <CompositorProvider>");
|
|
348
|
+
}
|
|
349
|
+
return ctx;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// src/useSource.ts
|
|
353
|
+
var import_react4 = require("react");
|
|
354
|
+
function useSource(id, options) {
|
|
355
|
+
const compositor = useCompositor();
|
|
356
|
+
const compositorRef = (0, import_react4.useRef)(compositor);
|
|
357
|
+
compositorRef.current = compositor;
|
|
358
|
+
const ref = (0, import_react4.useRef)(null);
|
|
359
|
+
const [isActive, setIsActive] = (0, import_react4.useState)(false);
|
|
360
|
+
const registeredRef = (0, import_react4.useRef)(false);
|
|
361
|
+
const idRef = (0, import_react4.useRef)(id);
|
|
362
|
+
idRef.current = id;
|
|
363
|
+
const { kind, contentHint, fit } = options;
|
|
364
|
+
const optionsRef = (0, import_react4.useRef)({ kind, contentHint, fit });
|
|
365
|
+
optionsRef.current = { kind, contentHint, fit };
|
|
366
|
+
const registerSource = (0, import_react4.useCallback)((element) => {
|
|
367
|
+
const { kind: kind2, contentHint: contentHint2, fit: fit2 } = optionsRef.current;
|
|
368
|
+
const source = kind2 === "video" ? {
|
|
369
|
+
kind: "video",
|
|
370
|
+
element,
|
|
371
|
+
contentHint: contentHint2,
|
|
372
|
+
fit: fit2
|
|
373
|
+
} : {
|
|
374
|
+
kind: "canvas",
|
|
375
|
+
element,
|
|
376
|
+
contentHint: contentHint2
|
|
377
|
+
};
|
|
378
|
+
compositorRef.current.register(idRef.current, source);
|
|
379
|
+
registeredRef.current = true;
|
|
380
|
+
}, []);
|
|
381
|
+
(0, import_react4.useEffect)(() => {
|
|
382
|
+
const element = ref.current;
|
|
383
|
+
if (!element) return;
|
|
384
|
+
registerSource(element);
|
|
385
|
+
}, [id, kind, contentHint, fit, registerSource]);
|
|
386
|
+
(0, import_react4.useEffect)(() => {
|
|
387
|
+
const currentId = id;
|
|
388
|
+
return () => {
|
|
389
|
+
if (registeredRef.current) {
|
|
390
|
+
registeredRef.current = false;
|
|
391
|
+
setIsActive(false);
|
|
392
|
+
compositorRef.current.unregister(currentId);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
}, [id]);
|
|
396
|
+
(0, import_react4.useEffect)(() => {
|
|
397
|
+
setIsActive(compositor.activeId === id);
|
|
398
|
+
}, [compositor.activeId, id]);
|
|
399
|
+
const activate = (0, import_react4.useCallback)(() => {
|
|
400
|
+
const element = ref.current;
|
|
401
|
+
if (!element) return;
|
|
402
|
+
if (!registeredRef.current) {
|
|
403
|
+
registerSource(element);
|
|
404
|
+
}
|
|
405
|
+
compositorRef.current.activate(idRef.current);
|
|
406
|
+
setIsActive(true);
|
|
407
|
+
}, [registerSource]);
|
|
408
|
+
const deactivate = (0, import_react4.useCallback)(() => {
|
|
409
|
+
if (compositorRef.current.activeId === idRef.current) {
|
|
410
|
+
compositorRef.current.deactivate();
|
|
411
|
+
setIsActive(false);
|
|
412
|
+
}
|
|
413
|
+
}, []);
|
|
414
|
+
return (0, import_react4.useMemo)(
|
|
415
|
+
() => ({
|
|
416
|
+
ref,
|
|
417
|
+
isActive,
|
|
418
|
+
activate,
|
|
419
|
+
deactivate
|
|
420
|
+
}),
|
|
421
|
+
[isActive, activate, deactivate]
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
|
|
170
425
|
// src/index.ts
|
|
171
426
|
function useBroadcast2(options) {
|
|
172
|
-
return useBroadcast(options,
|
|
427
|
+
return useBroadcast(options, import_browser2.createBroadcast);
|
|
173
428
|
}
|
|
174
429
|
function usePlayer2(whepUrl, options) {
|
|
175
|
-
return usePlayer(whepUrl, options,
|
|
430
|
+
return usePlayer(whepUrl, options, import_browser2.createPlayer);
|
|
176
431
|
}
|
|
177
432
|
// Annotate the CommonJS export names for ESM import in node:
|
|
178
433
|
0 && (module.exports = {
|
|
434
|
+
CompositorProvider,
|
|
179
435
|
useBroadcast,
|
|
180
|
-
|
|
436
|
+
useCompositor,
|
|
437
|
+
usePlayer,
|
|
438
|
+
useSource
|
|
181
439
|
});
|
|
182
440
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,sBAAAA;AAAA,EAAA,iBAAAC;AAAA;AAAA;AAAA,qBAA8C;;;ACA9C,mBAAyD;AA4BlD,SAAS,aACd,SACA,SACoB;AACpB,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAkC,MAAM;AAClE,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAwB,IAAI;AAC1D,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAA+B,IAAI;AAC7D,QAAM,mBAAe,qBAAyB,IAAI;AAClD,QAAM,iBAAa,qBAAO,OAAO;AACjC,QAAM,iBAAa,qBAAO,OAAO;AAEjC,8BAAU,MAAM;AACd,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,OAAO,CAAC;AAEZ,8BAAU,MAAM;AACd,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,OAAO,CAAC;AAEZ,8BAAU,MAAM;AACd,WAAO,MAAM;AACX,mBAAa,SAAS,KAAK;AAAA,IAC7B;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,YAAQ,0BAAY,OAAO,WAAwB;AACvD,aAAS,IAAI;AAEb,QAAI,aAAa,SAAS;AACxB,YAAM,aAAa,QAAQ,KAAK;AAAA,IAClC;AAEA,QAAI;AACF,YAAM,YAAY,WAAW,QAAQ;AAAA,QACnC;AAAA,QACA,GAAG,WAAW;AAAA,MAChB,CAAC;AAED,mBAAa,UAAU;AAEvB,gBAAU,GAAG,eAAe,CAAC,aAAa;AACxC,iBAAS,QAAQ;AACjB,YAAI,aAAa,QAAQ;AACvB,qBAAW,UAAU,OAAO;AAAA,QAC9B;AAAA,MACF,CAAC;AAED,gBAAU,GAAG,SAAS,CAAC,QAAQ;AAC7B,iBAAS,GAAG;AAAA,MACd,CAAC;AAED,YAAM,UAAU,QAAQ;AACxB,eAAS,UAAU,KAAK;AACxB,iBAAW,UAAU,OAAO;AAAA,IAC9B,SAAS,KAAK;AACZ,eAAS,GAAoB;AAC7B,eAAS,OAAO;AAChB,YAAM;AAAA,IACR;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,WAAO,0BAAY,YAAY;AACnC,UAAM,aAAa,SAAS,KAAK;AACjC,iBAAa,UAAU;AACvB,eAAW,IAAI;AACf,aAAS,MAAM;AAAA,EACjB,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACvGA,IAAAC,gBAMO;AA6BA,SAAS,UACd,SACA,SACA,SACiB;AACjB,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAA+B,MAAM;AAC/D,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAA+B,IAAI;AAC7D,QAAM,gBAAY,sBAAsB,IAAI;AAC5C,QAAM,eAAW,sBAAgC,IAAI;AACrD,QAAM,iBAAa,sBAAO,OAAO;AACjC,QAAM,iBAAa,sBAAO,OAAO;AACjC,QAAM,iBAAa,sBAAO,OAAO;AAEjC,+BAAU,MAAM;AACd,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,OAAO,CAAC;AAEZ,+BAAU,MAAM;AACd,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,OAAO,CAAC;AAEZ,+BAAU,MAAM;AACd,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,OAAO,CAAC;AAEZ,+BAAU,MAAM;AACd,WAAO,MAAM;AACX,gBAAU,SAAS,KAAK;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,WAAO,2BAAY,YAAY;AACnC,UAAM,iBAAiB,WAAW;AAClC,QAAI,CAAC,gBAAgB;AACnB;AAAA,IACF;AAEA,aAAS,IAAI;AAEb,QAAI,UAAU,SAAS;AACrB,YAAM,UAAU,QAAQ,KAAK;AAAA,IAC/B;AAEA,QAAI;AACF,YAAM,SAAS,WAAW,QAAQ,gBAAgB;AAAA,QAChD,WAAW,WAAW,SAAS;AAAA,QAC/B,SAAS,WAAW,SAAS;AAAA,QAC7B,iBAAiB,WAAW,SAAS;AAAA,MACvC,CAAC;AAED,gBAAU,UAAU;AAEpB,aAAO,GAAG,eAAe,CAAC,aAAa;AACrC,iBAAS,QAAQ;AAAA,MACnB,CAAC;AAED,aAAO,GAAG,SAAS,CAAC,QAAQ;AAC1B,iBAAS,GAAG;AAAA,MACd,CAAC;AAED,YAAM,OAAO,QAAQ;AACrB,eAAS,OAAO,KAAK;AAErB,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,eAAS,GAAoB;AAC7B,eAAS,OAAO;AAChB,YAAM;AAAA,IACR;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,WAAO,2BAAY,YAAY;AACnC,UAAM,UAAU,SAAS,KAAK;AAC9B,cAAU,UAAU;AACpB,aAAS,MAAM;AAAA,EACjB,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AFpHO,SAASC,cAAa,SAAkD;AAC7E,SAAO,aAAiB,SAAS,8BAAe;AAClD;AAEO,SAASC,WACd,SACA,SACiB;AACjB,SAAO,UAAc,SAAS,SAAS,2BAAY;AACrD;","names":["useBroadcast","usePlayer","import_react","useBroadcast","usePlayer"]}
|
|
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":"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","names":["useBroadcast","usePlayer","import_browser","import_react","import_react","import_react","kind","contentHint","fit","useBroadcast","usePlayer"]}
|