@daydreamlive/react 0.1.1 → 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 +41 -7
- package/dist/index.cjs +233 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -8
- package/dist/index.d.ts +74 -8
- package/dist/index.js +238 -51
- 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,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
|
|
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 [
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
71
|
-
|
|
101
|
+
if (broadcastRef.current !== broadcast) return;
|
|
102
|
+
whepUrlRef.current = broadcast.whepUrl;
|
|
103
|
+
updateStatus(broadcast.state);
|
|
72
104
|
} catch (err) {
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
82
|
-
|
|
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
|
-
|
|
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 [
|
|
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
|
-
|
|
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
|
-
|
|
152
|
-
|
|
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
|
-
|
|
225
|
+
setStatus({ state: "idle" });
|
|
160
226
|
}, []);
|
|
161
227
|
return {
|
|
162
|
-
|
|
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,
|
|
349
|
+
return useBroadcast(options, import_browser2.createBroadcast);
|
|
173
350
|
}
|
|
174
351
|
function usePlayer2(whepUrl, options) {
|
|
175
|
-
return usePlayer(whepUrl, options,
|
|
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
|
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":"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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,
|
|
2
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
2
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 [
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
46
|
-
|
|
74
|
+
if (broadcastRef.current !== broadcast) return;
|
|
75
|
+
whepUrlRef.current = broadcast.whepUrl;
|
|
76
|
+
updateStatus(broadcast.state);
|
|
47
77
|
} catch (err) {
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
57
|
-
|
|
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
|
-
|
|
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 [
|
|
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
|
-
|
|
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
|
-
|
|
132
|
-
|
|
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
|
-
|
|
203
|
+
setStatus({ state: "idle" });
|
|
140
204
|
}, []);
|
|
141
205
|
return {
|
|
142
|
-
|
|
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":"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","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.
|
|
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.
|
|
33
|
+
"@daydreamlive/browser": "^0.2.0"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"react": ">=18.0.0"
|