@daydreamlive/react 0.1.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 ADDED
@@ -0,0 +1,68 @@
1
+ # @daydreamlive/react
2
+
3
+ React hooks for Daydream WebRTC streaming.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @daydreamlive/react
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### useBroadcast
14
+
15
+ ```tsx
16
+ import { useBroadcast } from "@daydreamlive/react";
17
+
18
+ function Broadcaster({ whipUrl }: { whipUrl: string }) {
19
+ const { state, whepUrl, error, start, stop } = useBroadcast({
20
+ whipUrl,
21
+ reconnect: { enabled: true },
22
+ });
23
+
24
+ const handleStart = async () => {
25
+ const stream = await navigator.mediaDevices.getUserMedia({ video: true });
26
+ await start(stream);
27
+ };
28
+
29
+ return (
30
+ <div>
31
+ <p>State: {state}</p>
32
+ <button onClick={handleStart} disabled={state === "live"}>
33
+ Start
34
+ </button>
35
+ <button onClick={stop}>Stop</button>
36
+ </div>
37
+ );
38
+ }
39
+ ```
40
+
41
+ ### usePlayer
42
+
43
+ ```tsx
44
+ import { usePlayer } from "@daydreamlive/react";
45
+
46
+ function Player({ whepUrl }: { whepUrl: string }) {
47
+ const { state, error, videoRef } = usePlayer(whepUrl, {
48
+ autoPlay: true,
49
+ reconnect: { enabled: true },
50
+ });
51
+
52
+ return <video ref={videoRef} autoPlay playsInline muted />;
53
+ }
54
+ ```
55
+
56
+ ## API
57
+
58
+ ### `useBroadcast(options)`
59
+
60
+ Returns: `{ state, whepUrl, error, start, stop }`
61
+
62
+ ### `usePlayer(whepUrl, options?)`
63
+
64
+ Returns: `{ state, error, play, stop, videoRef }`
65
+
66
+ ## License
67
+
68
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ useBroadcast: () => useBroadcast2,
24
+ usePlayer: () => usePlayer2
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+ var import_browser = require("@daydreamlive/browser");
28
+
29
+ // src/useBroadcast.ts
30
+ var import_react = require("react");
31
+ function useBroadcast(options, factory) {
32
+ const [state, setState] = (0, import_react.useState)("idle");
33
+ const [whepUrl, setWhepUrl] = (0, import_react.useState)(null);
34
+ const [error, setError] = (0, import_react.useState)(null);
35
+ const broadcastRef = (0, import_react.useRef)(null);
36
+ const optionsRef = (0, import_react.useRef)(options);
37
+ const factoryRef = (0, import_react.useRef)(factory);
38
+ (0, import_react.useEffect)(() => {
39
+ optionsRef.current = options;
40
+ }, [options]);
41
+ (0, import_react.useEffect)(() => {
42
+ factoryRef.current = factory;
43
+ }, [factory]);
44
+ (0, import_react.useEffect)(() => {
45
+ return () => {
46
+ broadcastRef.current?.stop();
47
+ };
48
+ }, []);
49
+ const start = (0, import_react.useCallback)(async (stream) => {
50
+ setError(null);
51
+ if (broadcastRef.current) {
52
+ await broadcastRef.current.stop();
53
+ }
54
+ try {
55
+ const broadcast = factoryRef.current({
56
+ stream,
57
+ ...optionsRef.current
58
+ });
59
+ broadcastRef.current = broadcast;
60
+ broadcast.on("stateChange", (newState) => {
61
+ setState(newState);
62
+ if (newState === "live") {
63
+ setWhepUrl(broadcast.whepUrl);
64
+ }
65
+ });
66
+ broadcast.on("error", (err) => {
67
+ setError(err);
68
+ });
69
+ await broadcast.connect();
70
+ setState(broadcast.state);
71
+ setWhepUrl(broadcast.whepUrl);
72
+ } catch (err) {
73
+ setError(err);
74
+ setState("error");
75
+ throw err;
76
+ }
77
+ }, []);
78
+ const stop = (0, import_react.useCallback)(async () => {
79
+ await broadcastRef.current?.stop();
80
+ broadcastRef.current = null;
81
+ setWhepUrl(null);
82
+ setState("idle");
83
+ }, []);
84
+ return {
85
+ state,
86
+ whepUrl,
87
+ error,
88
+ start,
89
+ stop
90
+ };
91
+ }
92
+
93
+ // src/usePlayer.ts
94
+ var import_react2 = require("react");
95
+ function usePlayer(whepUrl, options, factory) {
96
+ const [state, setState] = (0, import_react2.useState)("idle");
97
+ const [error, setError] = (0, import_react2.useState)(null);
98
+ const playerRef = (0, import_react2.useRef)(null);
99
+ const videoRef = (0, import_react2.useRef)(null);
100
+ const optionsRef = (0, import_react2.useRef)(options);
101
+ const whepUrlRef = (0, import_react2.useRef)(whepUrl);
102
+ const factoryRef = (0, import_react2.useRef)(factory);
103
+ (0, import_react2.useEffect)(() => {
104
+ optionsRef.current = options;
105
+ }, [options]);
106
+ (0, import_react2.useEffect)(() => {
107
+ factoryRef.current = factory;
108
+ }, [factory]);
109
+ (0, import_react2.useEffect)(() => {
110
+ whepUrlRef.current = whepUrl;
111
+ }, [whepUrl]);
112
+ (0, import_react2.useEffect)(() => {
113
+ return () => {
114
+ playerRef.current?.stop();
115
+ };
116
+ }, []);
117
+ const play = (0, import_react2.useCallback)(async () => {
118
+ const currentWhepUrl = whepUrlRef.current;
119
+ if (!currentWhepUrl) {
120
+ return;
121
+ }
122
+ setError(null);
123
+ if (playerRef.current) {
124
+ await playerRef.current.stop();
125
+ }
126
+ 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
+ await player.connect();
140
+ setState(player.state);
141
+ if (videoRef.current) {
142
+ player.attachTo(videoRef.current);
143
+ if (optionsRef.current?.autoPlay !== false) {
144
+ try {
145
+ await videoRef.current.play();
146
+ } catch {
147
+ }
148
+ }
149
+ }
150
+ } catch (err) {
151
+ setError(err);
152
+ setState("error");
153
+ throw err;
154
+ }
155
+ }, []);
156
+ const stop = (0, import_react2.useCallback)(async () => {
157
+ await playerRef.current?.stop();
158
+ playerRef.current = null;
159
+ setState("idle");
160
+ }, []);
161
+ return {
162
+ state,
163
+ error,
164
+ play,
165
+ stop,
166
+ videoRef
167
+ };
168
+ }
169
+
170
+ // src/index.ts
171
+ function useBroadcast2(options) {
172
+ return useBroadcast(options, import_browser.createBroadcast);
173
+ }
174
+ function usePlayer2(whepUrl, options) {
175
+ return usePlayer(whepUrl, options, import_browser.createPlayer);
176
+ }
177
+ // Annotate the CommonJS export names for ESM import in node:
178
+ 0 && (module.exports = {
179
+ useBroadcast,
180
+ usePlayer
181
+ });
182
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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"]}
@@ -0,0 +1,36 @@
1
+ import { ReconnectConfig, VideoConfig, BroadcastState, DaydreamError, PlayerState } from '@daydreamlive/browser';
2
+ import { RefObject } from 'react';
3
+
4
+ interface UseBroadcastOptions {
5
+ whipUrl: string;
6
+ reconnect?: ReconnectConfig;
7
+ video?: VideoConfig;
8
+ onStats?: (report: RTCStatsReport) => void;
9
+ statsIntervalMs?: number;
10
+ }
11
+ interface UseBroadcastReturn {
12
+ state: BroadcastState | "idle";
13
+ whepUrl: string | null;
14
+ error: DaydreamError | null;
15
+ start: (stream: MediaStream) => Promise<void>;
16
+ stop: () => Promise<void>;
17
+ }
18
+
19
+ interface UsePlayerOptions {
20
+ reconnect?: ReconnectConfig;
21
+ autoPlay?: boolean;
22
+ onStats?: (report: RTCStatsReport) => void;
23
+ statsIntervalMs?: number;
24
+ }
25
+ interface UsePlayerReturn {
26
+ state: PlayerState | "idle";
27
+ error: DaydreamError | null;
28
+ play: () => Promise<void>;
29
+ stop: () => Promise<void>;
30
+ videoRef: RefObject<HTMLVideoElement | null>;
31
+ }
32
+
33
+ declare function useBroadcast(options: UseBroadcastOptions): UseBroadcastReturn;
34
+ declare function usePlayer(whepUrl: string | null, options?: UsePlayerOptions): UsePlayerReturn;
35
+
36
+ export { type UseBroadcastOptions, type UseBroadcastReturn, type UsePlayerOptions, type UsePlayerReturn, useBroadcast, usePlayer };
@@ -0,0 +1,36 @@
1
+ import { ReconnectConfig, VideoConfig, BroadcastState, DaydreamError, PlayerState } from '@daydreamlive/browser';
2
+ import { RefObject } from 'react';
3
+
4
+ interface UseBroadcastOptions {
5
+ whipUrl: string;
6
+ reconnect?: ReconnectConfig;
7
+ video?: VideoConfig;
8
+ onStats?: (report: RTCStatsReport) => void;
9
+ statsIntervalMs?: number;
10
+ }
11
+ interface UseBroadcastReturn {
12
+ state: BroadcastState | "idle";
13
+ whepUrl: string | null;
14
+ error: DaydreamError | null;
15
+ start: (stream: MediaStream) => Promise<void>;
16
+ stop: () => Promise<void>;
17
+ }
18
+
19
+ interface UsePlayerOptions {
20
+ reconnect?: ReconnectConfig;
21
+ autoPlay?: boolean;
22
+ onStats?: (report: RTCStatsReport) => void;
23
+ statsIntervalMs?: number;
24
+ }
25
+ interface UsePlayerReturn {
26
+ state: PlayerState | "idle";
27
+ error: DaydreamError | null;
28
+ play: () => Promise<void>;
29
+ stop: () => Promise<void>;
30
+ videoRef: RefObject<HTMLVideoElement | null>;
31
+ }
32
+
33
+ declare function useBroadcast(options: UseBroadcastOptions): UseBroadcastReturn;
34
+ declare function usePlayer(whepUrl: string | null, options?: UsePlayerOptions): UsePlayerReturn;
35
+
36
+ export { type UseBroadcastOptions, type UseBroadcastReturn, type UsePlayerOptions, type UsePlayerReturn, useBroadcast, usePlayer };
package/dist/index.js ADDED
@@ -0,0 +1,161 @@
1
+ // src/index.ts
2
+ import { createBroadcast, createPlayer } from "@daydreamlive/browser";
3
+
4
+ // src/useBroadcast.ts
5
+ import { useCallback, useEffect, useRef, useState } from "react";
6
+ function useBroadcast(options, factory) {
7
+ const [state, setState] = useState("idle");
8
+ const [whepUrl, setWhepUrl] = useState(null);
9
+ const [error, setError] = useState(null);
10
+ const broadcastRef = useRef(null);
11
+ const optionsRef = useRef(options);
12
+ const factoryRef = useRef(factory);
13
+ useEffect(() => {
14
+ optionsRef.current = options;
15
+ }, [options]);
16
+ useEffect(() => {
17
+ factoryRef.current = factory;
18
+ }, [factory]);
19
+ useEffect(() => {
20
+ return () => {
21
+ broadcastRef.current?.stop();
22
+ };
23
+ }, []);
24
+ const start = useCallback(async (stream) => {
25
+ setError(null);
26
+ if (broadcastRef.current) {
27
+ await broadcastRef.current.stop();
28
+ }
29
+ try {
30
+ const broadcast = factoryRef.current({
31
+ stream,
32
+ ...optionsRef.current
33
+ });
34
+ broadcastRef.current = broadcast;
35
+ broadcast.on("stateChange", (newState) => {
36
+ setState(newState);
37
+ if (newState === "live") {
38
+ setWhepUrl(broadcast.whepUrl);
39
+ }
40
+ });
41
+ broadcast.on("error", (err) => {
42
+ setError(err);
43
+ });
44
+ await broadcast.connect();
45
+ setState(broadcast.state);
46
+ setWhepUrl(broadcast.whepUrl);
47
+ } catch (err) {
48
+ setError(err);
49
+ setState("error");
50
+ throw err;
51
+ }
52
+ }, []);
53
+ const stop = useCallback(async () => {
54
+ await broadcastRef.current?.stop();
55
+ broadcastRef.current = null;
56
+ setWhepUrl(null);
57
+ setState("idle");
58
+ }, []);
59
+ return {
60
+ state,
61
+ whepUrl,
62
+ error,
63
+ start,
64
+ stop
65
+ };
66
+ }
67
+
68
+ // src/usePlayer.ts
69
+ import {
70
+ useCallback as useCallback2,
71
+ useEffect as useEffect2,
72
+ useRef as useRef2,
73
+ useState as useState2
74
+ } from "react";
75
+ function usePlayer(whepUrl, options, factory) {
76
+ const [state, setState] = useState2("idle");
77
+ const [error, setError] = useState2(null);
78
+ const playerRef = useRef2(null);
79
+ const videoRef = useRef2(null);
80
+ const optionsRef = useRef2(options);
81
+ const whepUrlRef = useRef2(whepUrl);
82
+ const factoryRef = useRef2(factory);
83
+ useEffect2(() => {
84
+ optionsRef.current = options;
85
+ }, [options]);
86
+ useEffect2(() => {
87
+ factoryRef.current = factory;
88
+ }, [factory]);
89
+ useEffect2(() => {
90
+ whepUrlRef.current = whepUrl;
91
+ }, [whepUrl]);
92
+ useEffect2(() => {
93
+ return () => {
94
+ playerRef.current?.stop();
95
+ };
96
+ }, []);
97
+ const play = useCallback2(async () => {
98
+ const currentWhepUrl = whepUrlRef.current;
99
+ if (!currentWhepUrl) {
100
+ return;
101
+ }
102
+ setError(null);
103
+ if (playerRef.current) {
104
+ await playerRef.current.stop();
105
+ }
106
+ 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
+ await player.connect();
120
+ setState(player.state);
121
+ if (videoRef.current) {
122
+ player.attachTo(videoRef.current);
123
+ if (optionsRef.current?.autoPlay !== false) {
124
+ try {
125
+ await videoRef.current.play();
126
+ } catch {
127
+ }
128
+ }
129
+ }
130
+ } catch (err) {
131
+ setError(err);
132
+ setState("error");
133
+ throw err;
134
+ }
135
+ }, []);
136
+ const stop = useCallback2(async () => {
137
+ await playerRef.current?.stop();
138
+ playerRef.current = null;
139
+ setState("idle");
140
+ }, []);
141
+ return {
142
+ state,
143
+ error,
144
+ play,
145
+ stop,
146
+ videoRef
147
+ };
148
+ }
149
+
150
+ // src/index.ts
151
+ function useBroadcast2(options) {
152
+ return useBroadcast(options, createBroadcast);
153
+ }
154
+ function usePlayer2(whepUrl, options) {
155
+ return usePlayer(whepUrl, options, createPlayer);
156
+ }
157
+ export {
158
+ useBroadcast2 as useBroadcast,
159
+ usePlayer2 as usePlayer
160
+ };
161
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"]}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@daydreamlive/react",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.cjs",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.cts",
16
+ "default": "./dist/index.cjs"
17
+ }
18
+ }
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "scripts": {
27
+ "build": "tsup",
28
+ "dev": "tsup --watch",
29
+ "clean": "rm -rf dist",
30
+ "typecheck": "tsc --noEmit"
31
+ },
32
+ "dependencies": {
33
+ "@daydreamlive/browser": "^0.1.0"
34
+ },
35
+ "peerDependencies": {
36
+ "react": ">=18.0.0"
37
+ },
38
+ "devDependencies": {
39
+ "@types/react": "^18.2.45",
40
+ "react": "^18.2.0",
41
+ "typescript": "^5.3.3",
42
+ "tsup": "^8.0.1"
43
+ }
44
+ }