@fishjam-cloud/react-client 0.5.1 → 0.5.5

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.
@@ -3,13 +3,10 @@ export const createUseSetupMediaHook = (useFishjamContext) => {
3
3
  const isBroadcastedTrackChanged = (client, pending) => client.status === "joined" && !pending && !client.isReconnecting();
4
4
  const isBroadcastedTrackStopped = (status, stream) => status === "joined" && stream;
5
5
  return (config) => {
6
- const { state } = useFishjamContext();
6
+ const { state, videoTrackManager, audioTrackManager } = useFishjamContext();
7
7
  const configRef = useRef(config);
8
8
  useEffect(() => {
9
9
  configRef.current = config;
10
- if (config.screenShare.streamConfig) {
11
- state.client.setScreenManagerConfig(config.screenShare.streamConfig);
12
- }
13
10
  state.client.setDeviceManagerConfig({
14
11
  storage: config.storage,
15
12
  });
@@ -17,28 +14,23 @@ export const createUseSetupMediaHook = (useFishjamContext) => {
17
14
  useEffect(() => {
18
15
  if (!configRef.current.startOnMount)
19
16
  return;
20
- if (state.client.audioDeviceManager.getStatus() === "uninitialized" ||
21
- state.client.videoDeviceManager.getStatus() === "uninitialized") {
22
- state.client.initializeDevices({
23
- audioTrackConstraints: configRef?.current.microphone.trackConstraints,
24
- videoTrackConstraints: configRef?.current.camera.trackConstraints,
25
- });
26
- }
17
+ state.client.initializeDevices({
18
+ audioTrackConstraints: configRef?.current.microphone.trackConstraints,
19
+ videoTrackConstraints: configRef?.current.camera.trackConstraints,
20
+ });
27
21
  // eslint-disable-next-line
28
22
  }, []);
29
23
  useEffect(() => {
30
24
  let pending = false;
31
25
  const broadcastOnCameraStart = async (client) => {
32
26
  const config = configRef.current.camera;
33
- const videoTrackManager = client.videoTrackManager;
34
27
  const onDeviceChange = config.onDeviceChange ?? "replace";
35
- const camera = client.devices.camera;
36
- const stream = camera.broadcast?.stream;
28
+ const stream = videoTrackManager.getCurrentTrack()?.stream;
37
29
  if (isBroadcastedTrackChanged(client, pending)) {
38
30
  if (!stream && config.broadcastOnDeviceStart) {
39
31
  pending = true;
40
32
  await videoTrackManager
41
- .startStreaming(config.defaultTrackMetadata, config.defaultSimulcastConfig, config.defaultMaxBandwidth)
33
+ .startStreaming(config.defaultSimulcastConfig, config.defaultMaxBandwidth)
42
34
  .finally(() => {
43
35
  pending = false;
44
36
  });
@@ -80,12 +72,10 @@ export const createUseSetupMediaHook = (useFishjamContext) => {
80
72
  state.client.removeListener("devicesReady", devicesReady);
81
73
  state.client.removeListener("deviceReady", deviceReady);
82
74
  };
83
- }, [state.client]);
75
+ }, [state.client, videoTrackManager]);
84
76
  useEffect(() => {
85
77
  const removeOnCameraStopped = async (event, client) => {
86
- const camera = client.devices.camera;
87
- const videoTrackManager = client.videoTrackManager;
88
- const stream = camera.broadcast?.stream;
78
+ const stream = videoTrackManager.getCurrentTrack()?.stream;
89
79
  const onDeviceStop = configRef.current.camera.onDeviceStop ?? "mute";
90
80
  if (event.mediaDeviceType === "userMedia" &&
91
81
  event.trackType === "video" &&
@@ -102,35 +92,31 @@ export const createUseSetupMediaHook = (useFishjamContext) => {
102
92
  return () => {
103
93
  state.client.removeListener("deviceStopped", removeOnCameraStopped);
104
94
  };
105
- }, [state.client]);
95
+ }, [state.client, videoTrackManager]);
106
96
  useEffect(() => {
107
97
  const broadcastCameraOnConnect = async (_, client) => {
108
98
  const camera = client.devices.camera;
109
99
  const stream = camera.stream;
110
100
  const config = configRef.current.camera;
111
101
  if (stream && config.broadcastOnConnect) {
112
- await client.videoTrackManager.startStreaming(config.defaultTrackMetadata, config.defaultSimulcastConfig, config.defaultMaxBandwidth);
102
+ await videoTrackManager.startStreaming(config.defaultSimulcastConfig, config.defaultMaxBandwidth);
113
103
  }
114
104
  };
115
105
  state.client.on("joined", broadcastCameraOnConnect);
116
106
  return () => {
117
107
  state.client.removeListener("joined", broadcastCameraOnConnect);
118
108
  };
119
- }, [state.client]);
109
+ }, [state.client, videoTrackManager]);
120
110
  useEffect(() => {
121
111
  let pending = false;
122
112
  const broadcastOnMicrophoneStart = async (client) => {
123
- const microphone = client.devices.microphone;
124
- const audioTrackManager = client.audioTrackManager;
125
- const stream = microphone.broadcast?.stream;
113
+ const stream = audioTrackManager.getCurrentTrack()?.stream;
126
114
  const config = configRef.current.microphone;
127
115
  const onDeviceChange = config.onDeviceChange ?? "replace";
128
116
  if (isBroadcastedTrackChanged(client, pending)) {
129
117
  if (!stream && config.broadcastOnDeviceStart) {
130
118
  pending = true;
131
- await audioTrackManager
132
- .startStreaming(config.defaultTrackMetadata, undefined, config.defaultMaxBandwidth)
133
- .finally(() => {
119
+ await audioTrackManager.startStreaming(undefined, config.defaultMaxBandwidth).finally(() => {
134
120
  pending = false;
135
121
  });
136
122
  }
@@ -171,11 +157,10 @@ export const createUseSetupMediaHook = (useFishjamContext) => {
171
157
  state.client.removeListener("deviceReady", deviceReady);
172
158
  state.client.removeListener("devicesReady", devicesReady);
173
159
  };
174
- }, [state.client]);
160
+ }, [state.client, audioTrackManager]);
175
161
  useEffect(() => {
176
162
  const onMicrophoneStopped = async (event, client) => {
177
- const audioTrackManager = client.audioTrackManager;
178
- const stream = client.devices.microphone.broadcast?.stream;
163
+ const stream = audioTrackManager.getCurrentTrack()?.stream;
179
164
  const onDeviceStop = configRef.current.microphone.onDeviceStop ?? "mute";
180
165
  const isRightDeviceType = event.mediaDeviceType === "userMedia";
181
166
  const isRightTrackType = event.trackType === "audio";
@@ -192,66 +177,20 @@ export const createUseSetupMediaHook = (useFishjamContext) => {
192
177
  return () => {
193
178
  state.client.removeListener("deviceStopped", onMicrophoneStopped);
194
179
  };
195
- }, [state.client]);
180
+ }, [state.client, audioTrackManager]);
196
181
  useEffect(() => {
197
182
  const broadcastMicrophoneOnConnect = async (_, client) => {
198
183
  const config = configRef.current.microphone;
199
184
  const microphone = client.devices.microphone;
200
185
  if (microphone.stream && config.broadcastOnConnect) {
201
- await client.audioTrackManager.startStreaming(config.defaultTrackMetadata, undefined, config.defaultMaxBandwidth);
186
+ await audioTrackManager.startStreaming(undefined, config.defaultMaxBandwidth);
202
187
  }
203
188
  };
204
189
  state.client.on("joined", broadcastMicrophoneOnConnect);
205
190
  return () => {
206
191
  state.client.removeListener("joined", broadcastMicrophoneOnConnect);
207
192
  };
208
- }, [state.client]);
209
- useEffect(() => {
210
- let pending = false;
211
- const broadcastOnScreenShareStart = async (event, client) => {
212
- const screenShare = client.devices.screenShare;
213
- const stream = screenShare.broadcast?.stream;
214
- const { broadcastOnDeviceStart, defaultTrackMetadata, defaultMaxBandwidth } = configRef.current.screenShare;
215
- if (event.mediaDeviceType === "displayMedia" &&
216
- isBroadcastedTrackChanged(client, pending) &&
217
- !stream &&
218
- broadcastOnDeviceStart) {
219
- pending = true;
220
- await screenShare.startStreaming(defaultTrackMetadata, defaultMaxBandwidth).finally(() => {
221
- pending = false;
222
- });
223
- }
224
- };
225
- state.client.on("deviceReady", broadcastOnScreenShareStart);
226
- return () => {
227
- state.client.removeListener("deviceReady", broadcastOnScreenShareStart);
228
- };
229
- }, [state.client]);
230
- useEffect(() => {
231
- const onScreenShareStop = async (event, client) => {
232
- const stream = client.devices.screenShare.broadcast?.stream;
233
- const isRightDeviceType = event.mediaDeviceType === "displayMedia";
234
- const isRightTrackType = event.trackType === "video";
235
- if (isRightDeviceType && isRightTrackType && isBroadcastedTrackStopped(client.status, stream)) {
236
- await client.devices.screenShare.stopStreaming();
237
- }
238
- };
239
- state.client.on("deviceStopped", onScreenShareStop);
240
- return () => {
241
- state.client.removeListener("deviceStopped", onScreenShareStop);
242
- };
243
- }, [state.client]);
244
- useEffect(() => {
245
- const broadcastScreenShareOnConnect = async (_, client) => {
246
- if (client.devices.screenShare.stream && configRef.current.screenShare.broadcastOnConnect) {
247
- await client.devices.screenShare.startStreaming(configRef.current.screenShare.defaultTrackMetadata, configRef.current.screenShare.defaultMaxBandwidth);
248
- }
249
- };
250
- state.client.on("joined", broadcastScreenShareOnConnect);
251
- return () => {
252
- state.client.removeListener("joined", broadcastScreenShareOnConnect);
253
- };
254
- }, [state.client]);
193
+ }, [state.client, audioTrackManager]);
255
194
  return useMemo(() => ({
256
195
  init: () => state.client.initializeDevices({
257
196
  audioTrackConstraints: configRef.current?.microphone?.trackConstraints,
@@ -0,0 +1,5 @@
1
+ import type { FishjamClient } from "@fishjam-cloud/ts-client";
2
+ import type { Track } from "../state.types";
3
+ import type { PeerMetadata, TrackMetadata } from "../types";
4
+ export declare const getRemoteOrLocalTrack: (tsClient: FishjamClient<PeerMetadata, TrackMetadata>, remoteOrLocalTrackId: string | null) => Track | null;
5
+ //# sourceMappingURL=track.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../../src/utils/track.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAgB,MAAM,0BAA0B,CAAC;AAC5E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAsC5D,eAAO,MAAM,qBAAqB,aACtB,aAAa,CAAC,YAAY,EAAE,aAAa,CAAC,wBAC9B,MAAM,GAAG,IAAI,iBAKpC,CAAC"}
@@ -0,0 +1,37 @@
1
+ // In most cases, the track is identified by its remote track ID.
2
+ // This ID comes from the ts-client `addTrack` method.
3
+ // However, we don't have that ID before the `addTrack` method returns it.
4
+ //
5
+ // The `addTrack` method emits the `localTrackAdded` event.
6
+ // This event will refresh the internal state of this object.
7
+ // However, in that event handler, we don't yet have the remote track ID.
8
+ // Therefore, for that brief moment, we will use the local track ID from the MediaStreamTrack object to identify the track.
9
+ const getRemoteOrLocalTrackContext = (tsClient, remoteOrLocalTrackId) => {
10
+ if (!remoteOrLocalTrackId)
11
+ return null;
12
+ const tracks = tsClient?.getLocalPeer()?.tracks;
13
+ if (!tracks)
14
+ return null;
15
+ const trackByRemoteId = tracks?.get(remoteOrLocalTrackId);
16
+ if (trackByRemoteId)
17
+ return trackByRemoteId;
18
+ const trackByLocalId = [...tracks.values()].find((track) => track.track?.id === remoteOrLocalTrackId);
19
+ return trackByLocalId ? trackByLocalId : null;
20
+ };
21
+ const getTrackFromContext = (context) => ({
22
+ rawMetadata: context.rawMetadata,
23
+ metadata: context.metadata,
24
+ trackId: context.trackId,
25
+ stream: context.stream,
26
+ simulcastConfig: context.simulcastConfig || null,
27
+ encoding: context.encoding || null,
28
+ vadStatus: context.vadStatus,
29
+ track: context.track,
30
+ metadataParsingError: context.metadataParsingError,
31
+ });
32
+ export const getRemoteOrLocalTrack = (tsClient, remoteOrLocalTrackId) => {
33
+ const context = getRemoteOrLocalTrackContext(tsClient, remoteOrLocalTrackId);
34
+ if (!context)
35
+ return null;
36
+ return getTrackFromContext(context);
37
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fishjam-cloud/react-client",
3
- "version": "0.5.1",
3
+ "version": "0.5.5",
4
4
  "description": "React client library for Fishjam Cloud",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Fishjam Cloud Team",
@@ -42,19 +42,19 @@
42
42
  "typecheck": "tsc"
43
43
  },
44
44
  "devDependencies": {
45
- "@playwright/test": "^1.45.3",
45
+ "@playwright/test": "^1.46.1",
46
46
  "@types/events": "^3.0.3",
47
47
  "@types/lodash.isequal": "^4.5.8",
48
- "@types/node": "^22.0.0",
48
+ "@types/node": "^22.4.1",
49
49
  "@types/react": "^18.2.55",
50
50
  "react": "^18.2.0",
51
51
  "typed-emitter": "^2.1.0",
52
- "typedoc": "^0.26.5",
53
- "typedoc-plugin-mdn-links": "^3.2.6",
52
+ "typedoc": "^0.26.6",
53
+ "typedoc-plugin-mdn-links": "^3.2.10",
54
54
  "typescript": "^5.5.4"
55
55
  },
56
56
  "dependencies": {
57
- "@fishjam-cloud/ts-client": "0.5.1",
57
+ "@fishjam-cloud/ts-client": "0.5.5",
58
58
  "events": "3.3.0",
59
59
  "lodash.isequal": "4.5.0"
60
60
  },
package/readme.md CHANGED
@@ -1,3 +1,7 @@
1
+ [![NPM Version](https://img.shields.io/npm/v/@fishjam-cloud/react-client)](https://www.npmjs.com/package/@fishjam-cloud/react-client)
2
+ [![TypeScript Strict](https://badgen.net/badge/TS/Strict)](https://www.typescriptlang.org)
3
+ [![TypeDoc](https://img.shields.io/badge/TypeDoc-8A2BE2)](https://fishjam-cloud.github.io/web-client-sdk/modules/_fishjam_dev_react_client.html)
4
+
1
5
  # Fishjam React Client
2
6
 
3
7
  React client library for [Fishjam Cloud](https://cloud.fishjam.stream).
@@ -6,7 +10,7 @@ the [TS client](../ts-client/README.md).
6
10
 
7
11
  ## Documentation
8
12
 
9
- Documentation is available [here](https://fishjam-cloud.github.io/web-client-sdk/modules/_fishjam_dev_react_client.html or you can generate it locally:
13
+ Documentation is available [here](https://fishjam-cloud.github.io/web-client-sdk/modules/_fishjam_dev_react_client.html) or you can generate it locally:
10
14
 
11
15
  ```bash
12
16
  yarn run docs
@@ -14,26 +18,23 @@ yarn run docs
14
18
 
15
19
  ## Installation
16
20
 
17
- You can install the library using `npm` or `yarn:
21
+ You can install this package using `npm`:
18
22
 
19
23
  ```bash
20
24
  npm install @fishjam-cloud/react-client
21
25
  ```
22
26
 
27
+ or `yarn`:
28
+
23
29
  ```bash
24
- yarn add @fishjam-cloud/react-client
30
+ yarn @fishjam-cloud/react-client
25
31
  ```
26
32
 
27
- It was tested with `nodejs` version mentioned in [`.tool-versions`](./.tool-versions) file.
28
-
29
33
  ## Usage
30
34
 
31
- For pure TypeScript usage,
32
- see [TS client](../ts-client/README.md).
33
-
34
35
  Prerequisites:
35
36
 
36
- - Account on Fishjam Cloud with App configured.
37
+ - Account on [Fishjam Cloud](https://cloud.fishjam.stream) with App configured.
37
38
  - Created room and token of peer in that room.
38
39
  You can use Room Manager to create room and peer token.
39
40
 
@@ -60,22 +61,9 @@ import { SCREEN_SHARING_MEDIA_CONSTRAINTS } from "@fishjam-cloud/react-client";
60
61
  import { create } from "@fishjam-cloud/react-client";
61
62
  import { useState } from "react";
62
63
 
63
- // Example metadata types for peer and track
64
- // You can define your own metadata types just make sure they are serializable
65
- export type PeerMetadata = {
66
- name: string;
67
- };
68
-
69
- export type TrackMetadata = {
70
- type: "camera" | "screen";
71
- };
72
-
73
64
  // Create a Fishjam client instance
74
65
  // remember to use FishjamContextProvider
75
- export const { useApi, useTracks, useStatus, useConnect, useDisconnect, FishjamContextProvider } = create<
76
- PeerMetadata,
77
- TrackMetadata
78
- >();
66
+ export const { useApi, useTracks, useStatus, useConnect, useDisconnect, FishjamContextProvider } = create();
79
67
 
80
68
  export const App = () => {
81
69
  const [token, setToken] = useState("");
@@ -95,7 +83,6 @@ export const App = () => {
95
83
  onClick={() => {
96
84
  if (!token || token === "") throw Error("Token is empty");
97
85
  connect({
98
- peerMetadata: { name: "John Doe" }, // example metadata
99
86
  token: token,
100
87
  });
101
88
  }}
@@ -133,11 +120,6 @@ export const App = () => {
133
120
  };
134
121
  ```
135
122
 
136
- ### Releasing new versions
137
-
138
- To release a new version of the package, go to `Actions` > `Release package` workflow and trigger it with the chosen release type.
139
- The workflow will bump the package version in `package.json`, release the package to NPM, create a new git tag and a GitHub release.
140
-
141
123
  ## Examples
142
124
 
143
125
  For examples, see [examples](../../examples/react-client/) folder.
@@ -1,57 +0,0 @@
1
- import type TypedEmitter from "typed-emitter";
2
- import type { DeviceError, DevicesStatus } from "./types";
3
- import type { TrackKind } from "@fishjam-cloud/ts-client";
4
- export type TrackType = TrackKind | "audiovideo";
5
- export type MediaDeviceType = "displayMedia" | "userMedia";
6
- export type DisplayMediaManagerEvents = {
7
- deviceReady: (event: {
8
- type: TrackType;
9
- }, state: ScreenShareDeviceState) => void;
10
- deviceStopped: (event: {
11
- type: TrackType;
12
- }, state: ScreenShareDeviceState) => void;
13
- deviceEnabled: (event: {
14
- type: TrackType;
15
- }, state: ScreenShareDeviceState) => void;
16
- deviceDisabled: (event: {
17
- type: TrackType;
18
- }, state: ScreenShareDeviceState) => void;
19
- error: (event: {
20
- type: TrackType;
21
- error: DeviceError | null;
22
- rawError: any;
23
- }, state: ScreenShareDeviceState) => void;
24
- };
25
- export interface ScreenShareManagerConfig {
26
- audioTrackConstraints?: boolean | MediaTrackConstraints;
27
- videoTrackConstraints?: boolean | MediaTrackConstraints;
28
- }
29
- export type ScreenShareMedia = {
30
- stream: MediaStream | null;
31
- track: MediaStreamTrack | null;
32
- enabled: boolean;
33
- };
34
- export type ScreenShareDeviceState = {
35
- status: DevicesStatus;
36
- audioMedia: ScreenShareMedia | null;
37
- videoMedia: ScreenShareMedia | null;
38
- error: DeviceError | null;
39
- };
40
- declare const ScreenShareManager_base: new () => TypedEmitter<DisplayMediaManagerEvents>;
41
- export declare class ScreenShareManager extends ScreenShareManager_base {
42
- private readonly defaultConfig?;
43
- private config?;
44
- private data;
45
- getSnapshot(): ScreenShareDeviceState;
46
- constructor(defaultConfig?: ScreenShareManagerConfig);
47
- setConfig(config: ScreenShareManagerConfig): void;
48
- private getType;
49
- getMedia: () => ScreenShareMedia | null;
50
- start(config?: ScreenShareManagerConfig): Promise<void>;
51
- private setupOnEndedCallback;
52
- private onTrackEnded;
53
- stop(type: TrackType): Promise<void>;
54
- setEnable(type: TrackType, value: boolean): void;
55
- }
56
- export {};
57
- //# sourceMappingURL=ScreenShareManager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ScreenShareManager.d.ts","sourceRoot":"","sources":["../src/ScreenShareManager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,YAAY,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAE1D,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC;AACjD,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,WAAW,CAAC;AAE3D,MAAM,MAAM,yBAAyB,GAAG;IACtC,WAAW,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,EAAE,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACjF,aAAa,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,EAAE,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACnF,aAAa,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,EAAE,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACnF,cAAc,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,EAAE,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACpF,KAAK,EAAE,CACL,KAAK,EAAE;QACL,IAAI,EAAE,SAAS,CAAC;QAChB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;QAC1B,QAAQ,EAAE,GAAG,CAAC;KACf,EACD,KAAK,EAAE,sBAAsB,KAC1B,IAAI,CAAC;CACX,CAAC;AAEF,MAAM,WAAW,wBAAwB;IACvC,qBAAqB,CAAC,EAAE,OAAO,GAAG,qBAAqB,CAAC;IACxD,qBAAqB,CAAC,EAAE,OAAO,GAAG,qBAAqB,CAAC;CACzD;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;CAC3B,CAAC;iDAEiE,YAAY,CAAC,yBAAyB,CAAC;AAA1G,qBAAa,kBAAmB,SAAQ,uBAAmE;IACzG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAA2B;IAC1D,OAAO,CAAC,MAAM,CAAC,CAA2B;IAE1C,OAAO,CAAC,IAAI,CAKV;IAGK,WAAW,IAAI,sBAAsB;gBAIhC,aAAa,CAAC,EAAE,wBAAwB;IAK7C,SAAS,CAAC,MAAM,EAAE,wBAAwB;IAIjD,OAAO,CAAC,OAAO;IAOR,QAAQ,gCAA8B;IAEhC,KAAK,CAAC,MAAM,CAAC,EAAE,wBAAwB;IA0CpD,OAAO,CAAC,oBAAoB;IAgB5B,OAAO,CAAC,YAAY,CAKlB;IAEW,IAAI,CAAC,IAAI,EAAE,SAAS;IA2B1B,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO;CAwBjD"}
@@ -1,135 +0,0 @@
1
- import EventEmitter from "events";
2
- import { parseUserMediaError } from "./utils/errors";
3
- export class ScreenShareManager extends EventEmitter {
4
- defaultConfig;
5
- config;
6
- data = {
7
- audioMedia: null,
8
- videoMedia: null,
9
- status: "Not requested",
10
- error: null,
11
- };
12
- // todo add nested read only
13
- getSnapshot() {
14
- return this.data;
15
- }
16
- constructor(defaultConfig) {
17
- super();
18
- this.defaultConfig = defaultConfig;
19
- }
20
- setConfig(config) {
21
- this.config = config;
22
- }
23
- getType(options) {
24
- if (options.audio && options.video)
25
- return "audiovideo";
26
- if (options.audio)
27
- return "audio";
28
- if (options.video)
29
- return "video";
30
- return null;
31
- }
32
- getMedia = () => this.data.videoMedia;
33
- async start(config) {
34
- const options = {
35
- video: config?.videoTrackConstraints ??
36
- this.config?.videoTrackConstraints ??
37
- this.defaultConfig?.videoTrackConstraints,
38
- audio: config?.audioTrackConstraints ??
39
- this.config?.audioTrackConstraints ??
40
- this.defaultConfig?.audioTrackConstraints,
41
- };
42
- const type = this.getType(options);
43
- if (!type)
44
- return;
45
- try {
46
- const newStream = await navigator.mediaDevices.getDisplayMedia(options);
47
- this.data = {
48
- error: null,
49
- videoMedia: {
50
- enabled: true,
51
- stream: newStream,
52
- track: newStream?.getVideoTracks()[0] ?? null,
53
- },
54
- audioMedia: {
55
- enabled: true,
56
- stream: newStream,
57
- track: newStream?.getAudioTracks()[0] ?? null,
58
- },
59
- status: "OK",
60
- };
61
- this.setupOnEndedCallback();
62
- this.emit("deviceReady", { type: type }, this.data);
63
- }
64
- catch (error) {
65
- const parsedError = parseUserMediaError(error);
66
- this.emit("error", { type, error: parsedError, rawError: error }, this.data);
67
- }
68
- }
69
- setupOnEndedCallback() {
70
- if (this.data.videoMedia?.track) {
71
- this.data.videoMedia.track.addEventListener("ended", async (event) => await this.onTrackEnded("video", event.target.id));
72
- }
73
- if (this.data.audioMedia?.track) {
74
- this.data.audioMedia.track.addEventListener("ended", async (event) => await this.onTrackEnded("audio", event.target.id));
75
- }
76
- }
77
- onTrackEnded = async (kind, trackId) => {
78
- const mediaType = kind === "video" ? "videoMedia" : "audioMedia";
79
- if (trackId === this?.data[mediaType]?.track?.id) {
80
- await this.stop("audiovideo");
81
- }
82
- };
83
- async stop(type) {
84
- if (type === "video") {
85
- for (const track of this.data?.videoMedia?.stream?.getTracks() ?? []) {
86
- track.stop();
87
- }
88
- this.data.videoMedia = null;
89
- }
90
- else if (type === "audio") {
91
- // todo test it
92
- for (const track of this.data?.audioMedia?.stream?.getTracks() ?? []) {
93
- track.stop();
94
- }
95
- this.data.audioMedia = null;
96
- }
97
- else {
98
- for (const track of this.data?.videoMedia?.stream?.getTracks() ?? []) {
99
- track.stop();
100
- }
101
- this.data.videoMedia = null;
102
- for (const track of this.data?.audioMedia?.stream?.getTracks() ?? []) {
103
- track.stop();
104
- }
105
- this.data.audioMedia = null;
106
- }
107
- this.emit("deviceStopped", { type }, this.data);
108
- }
109
- setEnable(type, value) {
110
- if (type === "video" && this.data.videoMedia?.track) {
111
- this.data.videoMedia.track.enabled = value;
112
- this.data.videoMedia.enabled = value;
113
- }
114
- else if (type === "audio" && this.data.audioMedia?.track) {
115
- this.data.audioMedia.track.enabled = value;
116
- this.data.audioMedia.enabled = value;
117
- }
118
- else {
119
- if (this.data.videoMedia?.track) {
120
- this.data.videoMedia.track.enabled = value;
121
- this.data.videoMedia.enabled = value;
122
- }
123
- if (this.data.audioMedia?.track) {
124
- this.data.audioMedia.track.enabled = value;
125
- this.data.audioMedia.enabled = value;
126
- }
127
- }
128
- if (value) {
129
- this.emit("deviceEnabled", { type }, this.data);
130
- }
131
- else {
132
- this.emit("deviceDisabled", { type }, this.data);
133
- }
134
- }
135
- }