@fishjam-cloud/react-client 0.12.0 → 0.14.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.
@@ -1 +1 @@
1
- {"version":3,"file":"FishjamProvider.d.ts","sourceRoot":"","sources":["../src/FishjamProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,KAAK,iBAAiB,EAAU,MAAM,OAAO,CAAC;AAUvD,OAAO,KAAK,EAAE,eAAe,EAAE,yBAAyB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG/F;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,iBAAiB;IAC7D;;;OAGG;IACH,SAAS,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC;IACtC;;;;OAIG;IACH,WAAW,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC;IAC9D;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,GAAG,yBAAyB,CAAC;IACxD;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAC3C;;OAEG;IACH,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B;;OAEG;IACH,WAAW,CAAC,EAAE,YAAY,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,2CA8D1D"}
1
+ {"version":3,"file":"FishjamProvider.d.ts","sourceRoot":"","sources":["../src/FishjamProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,KAAK,iBAAiB,EAAU,MAAM,OAAO,CAAC;AAUvD,OAAO,KAAK,EAAE,eAAe,EAAE,yBAAyB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG/F;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,iBAAiB;IAC7D;;;OAGG;IACH,SAAS,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC;IACtC;;;;OAIG;IACH,WAAW,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC;IAC9D;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,GAAG,yBAAyB,CAAC;IACxD;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAC3C;;OAEG;IACH,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B;;OAEG;IACH,WAAW,CAAC,EAAE,YAAY,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,2CAmE1D"}
@@ -15,7 +15,9 @@ import { mergeWithDefaultBandwitdthLimits } from "./utils/bandwidth";
15
15
  */
16
16
  export function FishjamProvider(props) {
17
17
  const fishjamClientRef = useRef(new FishjamClient({ reconnect: props.reconnect }));
18
- const hasDevicesBeenInitializedRef = useRef(false);
18
+ // HACK: This is a workaround to prevent multiple device initialization calls.
19
+ // TODO to be removed in FCE-1278
20
+ const devicesInitializationRef = useRef(null);
19
21
  const storage = props.persistLastDevice;
20
22
  const videoDeviceManagerRef = useRef(new DeviceManager({
21
23
  deviceType: "video",
@@ -37,6 +39,7 @@ export function FishjamProvider(props) {
37
39
  getCurrentPeerStatus,
38
40
  bandwidthLimits: mergedBandwidthLimits,
39
41
  streamConfig: props.videoConfig,
42
+ devicesInitializationRef,
40
43
  });
41
44
  const audioTrackManager = useTrackManager({
42
45
  mediaManager: audioDeviceManagerRef.current,
@@ -44,6 +47,7 @@ export function FishjamProvider(props) {
44
47
  getCurrentPeerStatus,
45
48
  bandwidthLimits: mergedBandwidthLimits,
46
49
  streamConfig: props.audioConfig,
50
+ devicesInitializationRef,
47
51
  });
48
52
  const screenShareManager = useScreenShareManager({ fishjamClient: fishjamClientRef.current, getCurrentPeerStatus });
49
53
  const clientState = useFishjamClientState(fishjamClientRef.current);
@@ -55,7 +59,7 @@ export function FishjamProvider(props) {
55
59
  audioTrackManager,
56
60
  videoDeviceManagerRef,
57
61
  audioDeviceManagerRef,
58
- hasDevicesBeenInitializedRef,
62
+ devicesInitializationRef,
59
63
  clientState,
60
64
  bandwidthLimits: mergedBandwidthLimits,
61
65
  };
@@ -21,6 +21,7 @@ export type DeviceManagerEvents = {
21
21
  deviceDisabled: (state: DeviceState) => void;
22
22
  middlewareSet: (state: DeviceState) => void;
23
23
  error: (event: any, state: DeviceState) => void;
24
+ initializedWithError: (state: DeviceState) => void;
24
25
  };
25
26
  export type DeviceManagerConfig = {
26
27
  deviceType: DeviceType;
@@ -1 +1 @@
1
- {"version":3,"file":"DeviceManager.d.ts","sourceRoot":"","sources":["../../src/devices/DeviceManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DeviceManager.d.ts","sourceRoot":"","sources":["../../src/devices/DeviceManager.ts"],"names":[],"mappings":"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"}
@@ -58,6 +58,9 @@ export class DeviceManager extends EventEmitter {
58
58
  this.devicesStatus = devicesStatus;
59
59
  this.mediaStatus = devicesStatus;
60
60
  this.error = newError ?? error;
61
+ if (this.error) {
62
+ this.emit("initializedWithError", this.getState());
63
+ }
61
64
  this.updateMedia({
62
65
  stream: track ? stream : null,
63
66
  track,
@@ -91,22 +94,8 @@ export class DeviceManager extends EventEmitter {
91
94
  if (deviceInfo) {
92
95
  this.saveLastDevice?.(deviceInfo);
93
96
  }
94
- // The device manager assumes that there is only one audio and video track.
95
- // All previous tracks are deactivated even if the browser is able to handle multiple active sessions. (Chrome, Firefox)
96
- //
97
- // Safari always deactivates the track and emits the `ended` event.
98
- // Its handling is asynchronous and can be executed even before returning a value from the re-execution of `getUserMedia`.
99
- // In such a case, the tracks are already deactivated at this point (logic in `onTrackEnded` method).
100
- // The track is null, so the stop method will not execute.
101
- //
102
- // However, if Safari has not yet handled this event, the tracks are manually stopped at this point.
103
- // Manually stopping tracks on its own does not generate the `ended` event.
104
- // The ended event in Safari has already been emitted and will be handled in the future.
105
- // Therefore, in the `onTrackEnded` method, events for already stopped tracks are filtered out to prevent the state from being damaged.
106
- if (shouldReplaceDevice) {
107
- this.rawMedia?.track?.stop();
108
- this.processedMediaTrack?.stop();
109
- }
97
+ this.rawMedia?.track?.stop();
98
+ this.processedMediaTrack?.stop();
110
99
  this.updateMedia({
111
100
  stream,
112
101
  track,
@@ -125,9 +114,7 @@ export class DeviceManager extends EventEmitter {
125
114
  parsedError,
126
115
  constraints: exactConstraints,
127
116
  };
128
- if (exactConstraints) {
129
- this.error = parsedError;
130
- }
117
+ this.error = parsedError;
131
118
  this.emit("error", event, this.getState());
132
119
  }
133
120
  }
@@ -144,6 +131,7 @@ export class DeviceManager extends EventEmitter {
144
131
  this.middlewareManager.clearMiddleware();
145
132
  this.processedMediaTrack?.stop();
146
133
  this.rawMedia?.track?.stop();
134
+ this.media?.track?.stop();
147
135
  this.updateMedia(null);
148
136
  this.emit("deviceStopped", this.getState());
149
137
  }
@@ -6,6 +6,6 @@ type AudioVideo<T> = {
6
6
  type MediaConstraints = AudioVideo<MediaTrackConstraints | undefined | boolean>;
7
7
  type PreviousDevices = AudioVideo<MediaDeviceInfo | null>;
8
8
  export declare const getAvailableMedia: (constraints: MediaStreamConstraints, deviceErrors?: AudioVideo<DeviceError | null>) => Promise<[MediaStream | null, AudioVideo<DeviceError | null>]>;
9
- export declare const getCorrectedResult: (stream: MediaStream, deviceErrors: AudioVideo<DeviceError | null>, devices: MediaDeviceInfo[], constraints: MediaConstraints, previousDevices: PreviousDevices) => Promise<[MediaStream | null, AudioVideo<DeviceError | null>]>;
9
+ export declare const correctDevicesOnSafari: (stream: MediaStream, deviceErrors: AudioVideo<DeviceError | null>, devices: MediaDeviceInfo[], constraints: MediaConstraints, previousDevices: PreviousDevices) => Promise<[MediaStream | null, AudioVideo<DeviceError | null>]>;
10
10
  export {};
11
11
  //# sourceMappingURL=mediaInitializer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mediaInitializer.d.ts","sourceRoot":"","sources":["../../src/devices/mediaInitializer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAInD,KAAK,UAAU,CAAC,CAAC,IAAI;IAAE,KAAK,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC;AAE5C,KAAK,gBAAgB,GAAG,UAAU,CAAC,qBAAqB,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC;AAEhF,KAAK,eAAe,GAAG,UAAU,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;AAsB1D,eAAO,MAAM,iBAAiB,gBACf,sBAAsB,iBACrB,UAAU,CAAC,WAAW,GAAG,IAAI,CAAC,KAC3C,OAAO,CAAC,CAAC,WAAW,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,CAuB9D,CAAC;AAIF,eAAO,MAAM,kBAAkB,WACrB,WAAW,gBACL,UAAU,CAAC,WAAW,GAAG,IAAI,CAAC,WACnC,eAAe,EAAE,eACb,gBAAgB,mBACZ,eAAe,KAC/B,OAAO,CAAC,CAAC,WAAW,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,CAsB9D,CAAC"}
1
+ {"version":3,"file":"mediaInitializer.d.ts","sourceRoot":"","sources":["../../src/devices/mediaInitializer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAInD,KAAK,UAAU,CAAC,CAAC,IAAI;IAAE,KAAK,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC;AAE5C,KAAK,gBAAgB,GAAG,UAAU,CAAC,qBAAqB,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC;AAChF,KAAK,eAAe,GAAG,UAAU,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;AAqC1D,eAAO,MAAM,iBAAiB,gBACf,sBAAsB,iBACrB,UAAU,CAAC,WAAW,GAAG,IAAI,CAAC,KAC3C,OAAO,CAAC,CAAC,WAAW,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,CAwB9D,CAAC;AAIF,eAAO,MAAM,sBAAsB,WACzB,WAAW,gBACL,UAAU,CAAC,WAAW,GAAG,IAAI,CAAC,WACnC,eAAe,EAAE,eACb,gBAAgB,mBACZ,eAAe,KAC/B,OAAO,CAAC,CAAC,WAAW,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,CAsB9D,CAAC"}
@@ -1,36 +1,55 @@
1
1
  import { NOT_FOUND_ERROR, OVERCONSTRAINED_ERROR, PERMISSION_DENIED, UNHANDLED_ERROR } from "../utils/errors";
2
2
  import { prepareConstraints } from "./constraints";
3
3
  const defaultErrors = { audio: null, video: null };
4
- const tryToGetAudioOnlyThenVideoOnly = async (constraints, deviceErrors = defaultErrors, transformConstraint = () => false) => {
5
- const audioOnly = await getAvailableMedia({ ...constraints, video: transformConstraint(constraints.video) }, { ...deviceErrors, audio: null });
6
- if (audioOnly[0])
7
- return audioOnly;
8
- return getAvailableMedia({ ...constraints, audio: transformConstraint(constraints.audio) }, { ...deviceErrors, video: null });
4
+ const errorMap = {
5
+ NotFoundError: NOT_FOUND_ERROR,
6
+ OverconstrainedError: OVERCONSTRAINED_ERROR,
7
+ NotAllowedError: PERMISSION_DENIED,
8
+ };
9
+ const getSingleMedia = async (type, constraints) => {
10
+ const baseConstraints = { audio: undefined, video: undefined };
11
+ try {
12
+ const stream = await navigator.mediaDevices.getUserMedia({ ...baseConstraints, [type]: constraints });
13
+ return [stream, null];
14
+ }
15
+ catch (err) {
16
+ if (!(err instanceof DOMException))
17
+ return [null, UNHANDLED_ERROR];
18
+ return [null, errorMap[err.name] ?? UNHANDLED_ERROR];
19
+ }
20
+ };
21
+ const tryToGetAudioOnlyThenVideoOnly = async (constraints, initialError) => {
22
+ const [audioStream, audioErr] = await getSingleMedia("audio", constraints.audio);
23
+ if (audioStream)
24
+ return [audioStream, { video: initialError, audio: null }];
25
+ const [videoStream, videoErr] = await getSingleMedia("video", constraints.video);
26
+ return [videoStream, { audio: audioErr, video: videoErr }];
9
27
  };
10
28
  export const getAvailableMedia = async (constraints, deviceErrors = defaultErrors) => {
11
29
  try {
12
30
  return [await navigator.mediaDevices.getUserMedia(constraints), deviceErrors];
13
31
  }
14
32
  catch (err) {
15
- if (!(err instanceof DOMException))
16
- return [null, { audio: UNHANDLED_ERROR, video: UNHANDLED_ERROR }];
17
- if (err.name === deviceErrors.audio?.name || err.name === deviceErrors.video?.name)
18
- return [null, deviceErrors];
19
- switch (err.name) {
20
- case "NotFoundError":
21
- return tryToGetAudioOnlyThenVideoOnly(constraints, { audio: NOT_FOUND_ERROR, video: NOT_FOUND_ERROR });
22
- case "OverconstrainedError":
23
- return tryToGetAudioOnlyThenVideoOnly(constraints, { audio: OVERCONSTRAINED_ERROR, video: OVERCONSTRAINED_ERROR }, removeSpecifiedDeviceFromConstraints);
24
- case "NotAllowedError":
25
- return tryToGetAudioOnlyThenVideoOnly(constraints, { audio: PERMISSION_DENIED, video: PERMISSION_DENIED });
26
- default:
27
- return [null, { audio: UNHANDLED_ERROR, video: UNHANDLED_ERROR }];
33
+ const unhandledErr = { audio: UNHANDLED_ERROR, video: UNHANDLED_ERROR };
34
+ if (err instanceof DOMException) {
35
+ switch (err.name) {
36
+ case deviceErrors.audio?.name:
37
+ case deviceErrors.video?.name:
38
+ return [null, deviceErrors];
39
+ case "NotFoundError":
40
+ return tryToGetAudioOnlyThenVideoOnly(constraints, PERMISSION_DENIED);
41
+ case "OverconstrainedError":
42
+ return getAvailableMedia({ audio: unspecifyDevice(constraints.audio), video: unspecifyDevice(constraints.video) }, { audio: OVERCONSTRAINED_ERROR, video: OVERCONSTRAINED_ERROR });
43
+ case "NotAllowedError":
44
+ return tryToGetAudioOnlyThenVideoOnly(constraints, PERMISSION_DENIED);
45
+ }
28
46
  }
47
+ return [null, unhandledErr];
29
48
  }
30
49
  };
31
50
  // Safari changes deviceId between sessions, therefore we cannot rely on deviceId for identification purposes.
32
51
  // We can switch a random device that comes from safari to one that has the same label as the one used in the previous session.
33
- export const getCorrectedResult = async (stream, deviceErrors, devices, constraints, previousDevices) => {
52
+ export const correctDevicesOnSafari = async (stream, deviceErrors, devices, constraints, previousDevices) => {
34
53
  const shouldCorrectDevices = isAnyDeviceDifferentFromLastSession(previousDevices.video, previousDevices.audio, getCurrentDevicesSettings(stream, devices));
35
54
  if (!shouldCorrectDevices)
36
55
  return [stream, deviceErrors];
@@ -69,7 +88,7 @@ const stopTracks = (requestedDevices) => {
69
88
  track.stop();
70
89
  }
71
90
  };
72
- const removeSpecifiedDeviceFromConstraints = (trackConstraints) => {
91
+ const unspecifyDevice = (trackConstraints) => {
73
92
  if (typeof trackConstraints === "object") {
74
93
  return { ...trackConstraints, deviceId: undefined };
75
94
  }
@@ -1,7 +1,12 @@
1
+ import { type DeviceError } from "../../types/public";
1
2
  export type UseInitializeDevicesParams = {
2
3
  enableVideo?: boolean;
3
4
  enableAudio?: boolean;
4
5
  };
6
+ export type InitializeDevicesErrors = {
7
+ audio: DeviceError | null;
8
+ video: DeviceError | null;
9
+ };
5
10
  /**
6
11
  * Hook allows you to initialize access to the devices before joining the room.
7
12
  * @category Devices
@@ -10,6 +15,6 @@ export declare const useInitializeDevices: () => {
10
15
  /**
11
16
  * Initialize access to the devices before joining the room
12
17
  */
13
- initializeDevices: (params?: UseInitializeDevicesParams) => Promise<void>;
18
+ initializeDevices: (params?: UseInitializeDevicesParams) => Promise<null | InitializeDevicesErrors>;
14
19
  };
15
20
  //# sourceMappingURL=useInitializeDevices.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useInitializeDevices.d.ts","sourceRoot":"","sources":["../../../src/hooks/devices/useInitializeDevices.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,0BAA0B,GAAG;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,oBAAoB;IAwD7B;;OAEG;iCAvD8B,0BAA0B,KAAK,OAAO,CAAC,IAAI,CAAC;CA0DhF,CAAC"}
1
+ {"version":3,"file":"useInitializeDevices.d.ts","sourceRoot":"","sources":["../../../src/hooks/devices/useInitializeDevices.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAItD,MAAM,MAAM,0BAA0B,GAAG;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;CAAE,CAAC;AAE/F;;;GAGG;AACH,eAAO,MAAM,oBAAoB;IA4E7B;;OAEG;iCA3E8B,0BAA0B,KAAK,OAAO,CAAC,IAAI,GAAG,uBAAuB,CAAC;CA8E1G,CAAC"}
@@ -1,42 +1,53 @@
1
1
  import { useCallback } from "react";
2
2
  import { prepareConstraints } from "../../devices/constraints";
3
- import { getAvailableMedia, getCorrectedResult } from "../../devices/mediaInitializer";
3
+ import { correctDevicesOnSafari, getAvailableMedia } from "../../devices/mediaInitializer";
4
+ import { Deferred } from "../../utils/deferred";
4
5
  import { useFishjamContext } from "../internal/useFishjamContext";
5
6
  /**
6
7
  * Hook allows you to initialize access to the devices before joining the room.
7
8
  * @category Devices
8
9
  */
9
10
  export const useInitializeDevices = () => {
10
- const { videoDeviceManagerRef, audioDeviceManagerRef, hasDevicesBeenInitializedRef } = useFishjamContext();
11
+ const { videoDeviceManagerRef, audioDeviceManagerRef, devicesInitializationRef } = useFishjamContext();
11
12
  const initializeDevices = useCallback(async ({ enableVideo = true, enableAudio = true } = {}) => {
12
- if (hasDevicesBeenInitializedRef.current)
13
- return;
14
- hasDevicesBeenInitializedRef.current = true;
15
- const videoManager = videoDeviceManagerRef.current;
16
- const audioManager = audioDeviceManagerRef.current;
17
- const constraints = {
18
- video: enableVideo && videoManager.getConstraints(),
19
- audio: enableAudio && audioManager.getConstraints(),
20
- };
21
- const previousDevices = {
22
- video: videoManager.getLastDevice(),
23
- audio: audioManager.getLastDevice(),
24
- };
25
- // Attempt to start the last selected device to avoid an unnecessary restart.
26
- // Without this, the first device will start, and `getCorrectedResult` will attempt to fix it.
27
- let [stream, deviceErrors] = await getAvailableMedia({
28
- video: enableVideo && prepareConstraints(previousDevices.video?.deviceId, constraints.video),
29
- audio: enableAudio && prepareConstraints(previousDevices.audio?.deviceId, constraints.audio),
30
- });
31
- const devices = await navigator.mediaDevices.enumerateDevices();
32
- const videoDevices = devices.filter(({ kind }) => kind === "videoinput");
33
- const audioDevices = devices.filter(({ kind }) => kind === "audioinput");
34
- if (stream) {
35
- [stream, deviceErrors] = await getCorrectedResult(stream, deviceErrors, devices, constraints, previousDevices);
13
+ if (devicesInitializationRef.current)
14
+ return null;
15
+ const deferred = new Deferred();
16
+ devicesInitializationRef.current = deferred.promise;
17
+ try {
18
+ const videoManager = videoDeviceManagerRef.current;
19
+ const audioManager = audioDeviceManagerRef.current;
20
+ const constraints = {
21
+ video: enableVideo && videoManager.getConstraints(),
22
+ audio: enableAudio && audioManager.getConstraints(),
23
+ };
24
+ const previousDevices = {
25
+ video: videoManager.getLastDevice(),
26
+ audio: audioManager.getLastDevice(),
27
+ };
28
+ // Attempt to start the last selected device to avoid an unnecessary restart.
29
+ // Without this, the first device will start, and `correctDevicesOnSafari` will attempt to fix it.
30
+ let [stream, deviceErrors] = await getAvailableMedia({
31
+ video: enableVideo && prepareConstraints(previousDevices.video?.deviceId, constraints.video),
32
+ audio: enableAudio && prepareConstraints(previousDevices.audio?.deviceId, constraints.audio),
33
+ });
34
+ const devices = await navigator.mediaDevices.enumerateDevices();
35
+ const videoDevices = devices.filter(({ kind }) => kind === "videoinput");
36
+ const audioDevices = devices.filter(({ kind }) => kind === "audioinput");
37
+ if (stream) {
38
+ [stream, deviceErrors] = await correctDevicesOnSafari(stream, deviceErrors, devices, constraints, previousDevices);
39
+ }
40
+ videoManager.initialize(stream, stream?.getVideoTracks()?.[0] ?? null, videoDevices, !!constraints.video, deviceErrors.video);
41
+ audioManager.initialize(stream, stream?.getAudioTracks()?.[0] ?? null, audioDevices, !!constraints.audio, deviceErrors.audio);
42
+ deferred.resolve();
43
+ if (deviceErrors.video || deviceErrors.audio)
44
+ return deviceErrors;
36
45
  }
37
- videoManager.initialize(stream, stream?.getVideoTracks()?.[0] ?? null, videoDevices, !!constraints.video, deviceErrors.video);
38
- audioManager.initialize(stream, stream?.getAudioTracks()?.[0] ?? null, audioDevices, !!constraints.audio, deviceErrors.audio);
39
- }, [videoDeviceManagerRef, audioDeviceManagerRef, hasDevicesBeenInitializedRef]);
46
+ catch {
47
+ deferred.reject();
48
+ }
49
+ return null;
50
+ }, [videoDeviceManagerRef, audioDeviceManagerRef, devicesInitializationRef]);
40
51
  return {
41
52
  /**
42
53
  * Initialize access to the devices before joining the room
@@ -19,7 +19,8 @@ export declare function useMicrophone(): {
19
19
  isMicrophoneOn: boolean;
20
20
  /**
21
21
  * Indicates whether the microphone is muted
22
- */ isMicrophoneMuted: boolean;
22
+ */
23
+ isMicrophoneMuted: boolean;
23
24
  /**
24
25
  * The MediaStream object containing the current audio stream
25
26
  */
@@ -1 +1 @@
1
- {"version":3,"file":"useMicrophone.d.ts","sourceRoot":"","sources":["../../../src/hooks/devices/useMicrophone.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,aAAa;IAKzB,wCAAwC;;IAExC,mCAAmC;;IAEnC,oCAAoC;;IAEpC;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;IACH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;EAGN"}
1
+ {"version":3,"file":"useMicrophone.d.ts","sourceRoot":"","sources":["../../../src/hooks/devices/useMicrophone.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,aAAa;IAKzB,wCAAwC;;IAExC,mCAAmC;;IAEnC,oCAAoC;;IAEpC;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;EAGN"}
@@ -24,7 +24,8 @@ export function useMicrophone() {
24
24
  isMicrophoneOn: !!deviceApi.mediaStream,
25
25
  /**
26
26
  * Indicates whether the microphone is muted
27
- */ isMicrophoneMuted: audioTrackManager.paused,
27
+ */
28
+ isMicrophoneMuted: audioTrackManager.paused,
28
29
  /**
29
30
  * The MediaStream object containing the current audio stream
30
31
  */
@@ -1 +1 @@
1
- {"version":3,"file":"useDeviceManager.d.ts","sourceRoot":"","sources":["../../../../src/hooks/internal/device/useDeviceManager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAuB,MAAM,gCAAgC,CAAC;AACzF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAelE,eAAO,MAAM,gBAAgB,kBAAmB,aAAa,uBAoC5D,CAAC"}
1
+ {"version":3,"file":"useDeviceManager.d.ts","sourceRoot":"","sources":["../../../../src/hooks/internal/device/useDeviceManager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAuB,MAAM,gCAAgC,CAAC;AACzF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAgBlE,eAAO,MAAM,gBAAgB,kBAAmB,aAAa,uBAoC5D,CAAC"}
@@ -10,6 +10,7 @@ const eventNames = [
10
10
  "managerInitialized",
11
11
  "error",
12
12
  "middlewareSet",
13
+ "initializedWithError",
13
14
  ];
14
15
  export const useDeviceManager = (deviceManager) => {
15
16
  const mutationRef = useRef(false);
@@ -1,15 +1,15 @@
1
1
  import type { FishjamClient } from "@fishjam-cloud/ts-client";
2
- import { type MutableRefObject } from "react";
2
+ import { type RefObject } from "react";
3
3
  import type { DeviceManager } from "../../devices/DeviceManager";
4
4
  import type { TrackManager } from "../../types/internal";
5
5
  import type { BandwidthLimits, PeerStatus } from "../../types/public";
6
6
  import type { FishjamClientState } from "./useFishjamClientState";
7
7
  import type { UseScreenshareResult } from "./useScreenshareManager";
8
8
  export type FishjamContextType = {
9
- fishjamClientRef: MutableRefObject<FishjamClient>;
10
- videoDeviceManagerRef: MutableRefObject<DeviceManager>;
11
- audioDeviceManagerRef: MutableRefObject<DeviceManager>;
12
- hasDevicesBeenInitializedRef: MutableRefObject<boolean>;
9
+ fishjamClientRef: RefObject<FishjamClient>;
10
+ videoDeviceManagerRef: RefObject<DeviceManager>;
11
+ audioDeviceManagerRef: RefObject<DeviceManager>;
12
+ devicesInitializationRef: RefObject<Promise<void> | null>;
13
13
  screenShareManager: UseScreenshareResult;
14
14
  peerStatus: PeerStatus;
15
15
  videoTrackManager: TrackManager;
@@ -1 +1 @@
1
- {"version":3,"file":"useFishjamContext.d.ts","sourceRoot":"","sources":["../../../src/hooks/internal/useFishjamContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAiB,KAAK,gBAAgB,EAAc,MAAM,OAAO,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAEpE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,gBAAgB,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAC;IAClD,qBAAqB,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAC;IACvD,qBAAqB,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAC;IACvD,4BAA4B,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACxD,kBAAkB,EAAE,oBAAoB,CAAC;IACzC,UAAU,EAAE,UAAU,CAAC;IACvB,iBAAiB,EAAE,YAAY,CAAC;IAChC,iBAAiB,EAAE,YAAY,CAAC;IAChC,WAAW,EAAE,kBAAkB,CAAC;IAChC,eAAe,EAAE,eAAe,CAAC;CAClC,CAAC;AAEF,eAAO,MAAM,cAAc,oDAAiD,CAAC;AAE7E,wBAAgB,iBAAiB,IAGb,kBAAkB,CACrC"}
1
+ {"version":3,"file":"useFishjamContext.d.ts","sourceRoot":"","sources":["../../../src/hooks/internal/useFishjamContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAiB,KAAK,SAAS,EAAc,MAAM,OAAO,CAAC;AAElE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAEpE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,gBAAgB,EAAE,SAAS,CAAC,aAAa,CAAC,CAAC;IAC3C,qBAAqB,EAAE,SAAS,CAAC,aAAa,CAAC,CAAC;IAChD,qBAAqB,EAAE,SAAS,CAAC,aAAa,CAAC,CAAC;IAChD,wBAAwB,EAAE,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;IAC1D,kBAAkB,EAAE,oBAAoB,CAAC;IACzC,UAAU,EAAE,UAAU,CAAC;IACvB,iBAAiB,EAAE,YAAY,CAAC;IAChC,iBAAiB,EAAE,YAAY,CAAC;IAChC,WAAW,EAAE,kBAAkB,CAAC;IAChC,eAAe,EAAE,eAAe,CAAC;CAClC,CAAC;AAEF,eAAO,MAAM,cAAc,oDAAiD,CAAC;AAE7E,wBAAgB,iBAAiB,IAGb,kBAAkB,CACrC"}
@@ -1,4 +1,5 @@
1
1
  import { type FishjamClient } from "@fishjam-cloud/ts-client";
2
+ import { type RefObject } from "react";
2
3
  import type { MediaManager, TrackManager } from "../../types/internal";
3
4
  import type { BandwidthLimits, PeerStatus, StreamConfig } from "../../types/public";
4
5
  interface TrackManagerConfig {
@@ -7,7 +8,8 @@ interface TrackManagerConfig {
7
8
  getCurrentPeerStatus: () => PeerStatus;
8
9
  bandwidthLimits: BandwidthLimits;
9
10
  streamConfig?: StreamConfig;
11
+ devicesInitializationRef: RefObject<Promise<void> | null>;
10
12
  }
11
- export declare const useTrackManager: ({ mediaManager, tsClient, getCurrentPeerStatus, bandwidthLimits, streamConfig, }: TrackManagerConfig) => TrackManager;
13
+ export declare const useTrackManager: ({ mediaManager, tsClient, getCurrentPeerStatus, bandwidthLimits, streamConfig, devicesInitializationRef, }: TrackManagerConfig) => TrackManager;
12
14
  export {};
13
15
  //# sourceMappingURL=useTrackManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useTrackManager.d.ts","sourceRoot":"","sources":["../../../src/hooks/internal/useTrackManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAA+B,MAAM,0BAA0B,CAAC;AAG3F,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAmB,MAAM,oBAAoB,CAAC;AAGrG,UAAU,kBAAkB;IAC1B,YAAY,EAAE,YAAY,CAAC;IAC3B,QAAQ,EAAE,aAAa,CAAC;IACxB,oBAAoB,EAAE,MAAM,UAAU,CAAC;IACvC,eAAe,EAAE,eAAe,CAAC;IACjC,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAWD,eAAO,MAAM,eAAe,qFAMzB,kBAAkB,KAAG,YAsKvB,CAAC"}
1
+ {"version":3,"file":"useTrackManager.d.ts","sourceRoot":"","sources":["../../../src/hooks/internal/useTrackManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAA+B,MAAM,0BAA0B,CAAC;AAC3F,OAAO,EAAE,KAAK,SAAS,EAA4C,MAAM,OAAO,CAAC;AAEjF,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAmB,MAAM,oBAAoB,CAAC;AAGrG,UAAU,kBAAkB;IAC1B,YAAY,EAAE,YAAY,CAAC;IAC3B,QAAQ,EAAE,aAAa,CAAC;IACxB,oBAAoB,EAAE,MAAM,UAAU,CAAC;IACvC,eAAe,EAAE,eAAe,CAAC;IACjC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,wBAAwB,EAAE,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;CAC3D;AAWD,eAAO,MAAM,eAAe,+GAOzB,kBAAkB,KAAG,YAiLvB,CAAC"}
@@ -1,27 +1,29 @@
1
1
  import { Variant } from "@fishjam-cloud/ts-client";
2
- import { useCallback, useEffect, useMemo, useState } from "react";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
3
  import { getConfigAndBandwidthFromProps, getRemoteOrLocalTrack } from "../../utils/track";
4
4
  const TRACK_TYPE_TO_DEVICE = {
5
5
  video: "camera",
6
6
  audio: "microphone",
7
7
  };
8
8
  const getDeviceType = (mediaManager) => TRACK_TYPE_TO_DEVICE[mediaManager.getDeviceType()];
9
- export const useTrackManager = ({ mediaManager, tsClient, getCurrentPeerStatus, bandwidthLimits, streamConfig, }) => {
10
- const [currentTrackId, setCurrentTrackId] = useState(null);
9
+ export const useTrackManager = ({ mediaManager, tsClient, getCurrentPeerStatus, bandwidthLimits, streamConfig, devicesInitializationRef, }) => {
10
+ const currentTrackIdRef = useRef(null);
11
11
  const [paused, setPaused] = useState(false);
12
- const currentTrack = useMemo(() => getRemoteOrLocalTrack(tsClient, currentTrackId), [tsClient, currentTrackId]);
13
12
  async function setTrackMiddleware(middleware) {
14
13
  mediaManager.setTrackMiddleware(middleware);
15
14
  await refreshStreamedTrack();
16
15
  }
17
16
  async function selectDevice(deviceId) {
18
17
  await mediaManager?.start(deviceId);
18
+ const currentTrackId = currentTrackIdRef.current;
19
19
  if (!currentTrackId)
20
20
  return;
21
21
  const newTrack = mediaManager.getMedia()?.track ?? null;
22
22
  await tsClient.replaceTrack(currentTrackId, newTrack);
23
23
  }
24
+ const getCurrentTrackId = useCallback(() => getRemoteOrLocalTrack(tsClient, currentTrackIdRef.current)?.trackId, [tsClient]);
24
25
  const startStreaming = useCallback(async (props = { simulcast: [Variant.VARIANT_LOW, Variant.VARIANT_MEDIUM, Variant.VARIANT_HIGH] }) => {
26
+ const currentTrackId = currentTrackIdRef.current;
25
27
  if (currentTrackId)
26
28
  throw Error("Track already added");
27
29
  const media = mediaManager.getMedia();
@@ -31,7 +33,7 @@ export const useTrackManager = ({ mediaManager, tsClient, getCurrentPeerStatus,
31
33
  if (track)
32
34
  return track.trackId;
33
35
  // see `getRemoteOrLocalTrackContext()` explanation
34
- setCurrentTrackId(media.track.id);
36
+ currentTrackIdRef.current = media.track.id;
35
37
  const deviceType = getDeviceType(mediaManager);
36
38
  const trackMetadata = { type: deviceType, paused: false };
37
39
  const displayName = tsClient.getLocalPeer()?.metadata?.peer?.displayName;
@@ -40,56 +42,62 @@ export const useTrackManager = ({ mediaManager, tsClient, getCurrentPeerStatus,
40
42
  }
41
43
  const [maxBandwidth, simulcastConfig] = getConfigAndBandwidthFromProps(props.simulcast, bandwidthLimits);
42
44
  const remoteTrackId = await tsClient.addTrack(media.track, trackMetadata, simulcastConfig, maxBandwidth);
43
- setCurrentTrackId(remoteTrackId);
45
+ currentTrackIdRef.current = remoteTrackId;
44
46
  setPaused(false);
45
47
  return remoteTrackId;
46
- }, [currentTrackId, mediaManager, tsClient, bandwidthLimits]);
48
+ }, [mediaManager, tsClient, bandwidthLimits]);
47
49
  const refreshStreamedTrack = useCallback(async () => {
48
- if (!currentTrack)
50
+ const trackId = getCurrentTrackId();
51
+ if (!trackId)
49
52
  return;
50
53
  const newTrack = mediaManager.getMedia()?.track ?? null;
51
54
  if (!newTrack)
52
55
  throw Error("New track is empty");
53
- return tsClient.replaceTrack(currentTrack.trackId, newTrack);
54
- }, [currentTrack, mediaManager, tsClient]);
56
+ return tsClient.replaceTrack(trackId, newTrack);
57
+ }, [getCurrentTrackId, mediaManager, tsClient]);
55
58
  const pauseStreaming = useCallback(async () => {
56
- if (!currentTrack)
59
+ const trackId = getCurrentTrackId();
60
+ if (!trackId)
57
61
  return;
58
62
  setPaused(true);
59
- await tsClient.replaceTrack(currentTrack.trackId, null);
63
+ await tsClient.replaceTrack(trackId, null);
60
64
  const deviceType = getDeviceType(mediaManager);
61
65
  const trackMetadata = { type: deviceType, paused: true };
62
- return tsClient.updateTrackMetadata(currentTrack.trackId, trackMetadata);
63
- }, [currentTrack, mediaManager, tsClient]);
66
+ return tsClient.updateTrackMetadata(trackId, trackMetadata);
67
+ }, [mediaManager, getCurrentTrackId, tsClient]);
64
68
  const resumeStreaming = useCallback(async () => {
65
- if (!currentTrack)
69
+ const trackId = getCurrentTrackId();
70
+ if (!trackId)
66
71
  return;
67
72
  const media = mediaManager.getMedia();
68
73
  const deviceType = getDeviceType(mediaManager);
69
74
  if (!media)
70
75
  throw Error("Device is unavailable");
71
76
  setPaused(false);
72
- await tsClient.replaceTrack(currentTrack.trackId, media.track);
77
+ await tsClient.replaceTrack(trackId, media.track);
73
78
  const trackMetadata = { type: deviceType, paused: false };
74
- return tsClient.updateTrackMetadata(currentTrack.trackId, trackMetadata);
75
- }, [currentTrack, mediaManager, tsClient]);
79
+ return tsClient.updateTrackMetadata(trackId, trackMetadata);
80
+ }, [mediaManager, tsClient, getCurrentTrackId]);
76
81
  const stream = useCallback(async () => {
77
82
  if (getCurrentPeerStatus() !== "connected")
78
83
  return;
79
- if (currentTrack?.trackId) {
84
+ const trackId = getRemoteOrLocalTrack(tsClient, currentTrackIdRef.current)?.trackId;
85
+ if (trackId) {
80
86
  await resumeStreaming();
81
87
  }
82
88
  else {
83
89
  await startStreaming();
84
90
  }
85
- }, [currentTrack?.trackId, getCurrentPeerStatus, resumeStreaming, startStreaming]);
91
+ }, [tsClient, getCurrentPeerStatus, resumeStreaming, startStreaming]);
86
92
  const toggle = useCallback(async (mode) => {
93
+ await devicesInitializationRef.current;
87
94
  const mediaStream = mediaManager.getMedia()?.stream;
88
95
  const track = mediaManager.getMedia()?.track ?? null;
89
96
  const enabled = Boolean(track?.enabled);
97
+ const trackId = getRemoteOrLocalTrack(tsClient, currentTrackIdRef.current)?.trackId;
90
98
  if (mediaStream && enabled) {
91
99
  mediaManager.disable();
92
- if (currentTrack?.trackId) {
100
+ if (trackId) {
93
101
  await pauseStreaming();
94
102
  }
95
103
  if (mode === "hard") {
@@ -104,7 +112,7 @@ export const useTrackManager = ({ mediaManager, tsClient, getCurrentPeerStatus,
104
112
  await mediaManager.start();
105
113
  await stream();
106
114
  }
107
- }, [currentTrack, mediaManager, pauseStreaming, stream]);
115
+ }, [devicesInitializationRef, mediaManager, tsClient, pauseStreaming, stream]);
108
116
  /**
109
117
  * @see {@link TrackManager#toggleMute} for more details.
110
118
  */
@@ -121,7 +129,7 @@ export const useTrackManager = ({ mediaManager, tsClient, getCurrentPeerStatus,
121
129
  };
122
130
  const onLeftRoom = () => {
123
131
  setPaused(true);
124
- setCurrentTrackId(null);
132
+ currentTrackIdRef.current = null;
125
133
  };
126
134
  tsClient.on("joined", onJoinedRoom);
127
135
  tsClient.on("disconnected", onLeftRoom);
@@ -129,11 +137,10 @@ export const useTrackManager = ({ mediaManager, tsClient, getCurrentPeerStatus,
129
137
  tsClient.off("joined", onJoinedRoom);
130
138
  tsClient.off("disconnected", onLeftRoom);
131
139
  };
132
- }, [mediaManager, startStreaming, tsClient, streamConfig, currentTrackId]);
140
+ }, [mediaManager, startStreaming, tsClient, streamConfig]);
133
141
  return {
134
- currentTrack,
135
- setTrackMiddleware,
136
142
  paused,
143
+ setTrackMiddleware,
137
144
  selectDevice,
138
145
  toggleMute,
139
146
  toggleDevice,
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { FishjamProvider, type FishjamProviderProps } from "./FishjamProvider";
2
2
  export { useCamera } from "./hooks/devices/useCamera";
3
- export { useInitializeDevices, UseInitializeDevicesParams } from "./hooks/devices/useInitializeDevices";
3
+ export { InitializeDevicesErrors, useInitializeDevices, UseInitializeDevicesParams, } from "./hooks/devices/useInitializeDevices";
4
4
  export { useMicrophone } from "./hooks/devices/useMicrophone";
5
5
  export { type JoinRoomConfig, useConnection } from "./hooks/useConnection";
6
6
  export { type PeerWithTracks, usePeers } from "./hooks/usePeers";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AACxG,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,KAAK,cAAc,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,KAAK,cAAc,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,YAAY,EACV,eAAe,EACf,KAAK,EACL,WAAW,EACX,UAAU,EACV,MAAM,EACN,UAAU,EACV,yBAAyB,EACzB,wBAAwB,EACxB,YAAY,EACZ,KAAK,EACL,OAAO,EACP,eAAe,EACf,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,eAAe,EACf,eAAe,EACf,QAAQ,EACR,eAAe,EACf,kBAAkB,EAClB,uBAAuB,EACvB,eAAe,EACf,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,KAAK,cAAc,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,KAAK,cAAc,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,YAAY,EACV,eAAe,EACf,KAAK,EACL,WAAW,EACX,UAAU,EACV,MAAM,EACN,UAAU,EACV,yBAAyB,EACzB,wBAAwB,EACxB,YAAY,EACZ,KAAK,EACL,OAAO,EACP,eAAe,EACf,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,eAAe,EACf,eAAe,EACf,QAAQ,EACR,eAAe,EACf,kBAAkB,EAClB,uBAAuB,EACvB,eAAe,EACf,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { FishjamProvider } from "./FishjamProvider";
2
2
  export { useCamera } from "./hooks/devices/useCamera";
3
- export { useInitializeDevices } from "./hooks/devices/useInitializeDevices";
3
+ export { useInitializeDevices, } from "./hooks/devices/useInitializeDevices";
4
4
  export { useMicrophone } from "./hooks/devices/useMicrophone";
5
5
  export { useConnection } from "./hooks/useConnection";
6
6
  export { usePeers } from "./hooks/usePeers";
@@ -1,5 +1,5 @@
1
1
  import type { Peer } from "@fishjam-cloud/ts-client";
2
- import type { DeviceError, DeviceType, PeerId, Track, TrackMiddleware, TracksMiddleware } from "./public";
2
+ import type { DeviceError, DeviceType, PeerId, TrackMiddleware, TracksMiddleware } from "./public";
3
3
  export type DevicesStatus = "OK" | "Error" | "Not requested" | "Requesting";
4
4
  export type MediaStatus = "OK" | "Error" | "Not requested" | "Requesting";
5
5
  export type DeviceManagerStatus = "uninitialized" | "initializing" | "initialized" | "error";
@@ -56,7 +56,6 @@ export interface TrackManager {
56
56
  selectDevice: (deviceId?: string) => Promise<void>;
57
57
  paused: boolean;
58
58
  setTrackMiddleware: (middleware: TrackMiddleware | null) => Promise<void>;
59
- currentTrack: Track | null;
60
59
  /**
61
60
  * Either enables or disables the stream.
62
61
  *
@@ -1 +1 @@
1
- {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/types/internal.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/types/internal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export declare class Deferred<T, E = unknown> {
2
+ readonly promise: Promise<T>;
3
+ private resolveFn;
4
+ private rejectFn;
5
+ constructor();
6
+ resolve(value: T): void;
7
+ reject(reason?: E): void;
8
+ }
9
+ //# sourceMappingURL=deferred.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deferred.d.ts","sourceRoot":"","sources":["../../src/utils/deferred.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO;IAClC,SAAgB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAEpC,OAAO,CAAC,SAAS,CAAmD;IACpE,OAAO,CAAC,QAAQ,CAAoC;;IAS7C,OAAO,CAAC,KAAK,EAAE,CAAC;IAIhB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;CAGzB"}
@@ -0,0 +1,17 @@
1
+ export class Deferred {
2
+ promise;
3
+ resolveFn = () => null;
4
+ rejectFn = () => null;
5
+ constructor() {
6
+ this.promise = new Promise((resolve, reject) => {
7
+ this.resolveFn = resolve;
8
+ this.rejectFn = reject;
9
+ });
10
+ }
11
+ resolve(value) {
12
+ this.resolveFn(value);
13
+ }
14
+ reject(reason) {
15
+ this.rejectFn(reason);
16
+ }
17
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fishjam-cloud/react-client",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "React client library for Fishjam",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Fishjam Team",
@@ -10,7 +10,11 @@
10
10
  "files": [
11
11
  "dist/**"
12
12
  ],
13
- "repository": "github:fishjam-cloud/web-client-sdk",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/fishjam-cloud/web-client-sdk.git",
16
+ "directory": "packages/react-client"
17
+ },
14
18
  "homepage": "https://github.com/fishjam-cloud/web-client-sdk#readme",
15
19
  "bugs": "https://github.com/fishjam-cloud/web-client-sdk/issues",
16
20
  "keywords": [
@@ -38,19 +42,19 @@
38
42
  "prepack": "yarn workspace @fishjam-cloud/ts-client build && yarn build"
39
43
  },
40
44
  "devDependencies": {
41
- "@playwright/test": "^1.50.0",
45
+ "@playwright/test": "^1.50.1",
42
46
  "@types/events": "^3.0.3",
43
47
  "@types/lodash.isequal": "^4.5.8",
44
- "@types/node": "^22.12.0",
45
- "@types/react": "^19.0.8",
48
+ "@types/node": "^22.13.4",
49
+ "@types/react": "^19.0.10",
46
50
  "react": "^19.0.0",
47
51
  "typed-emitter": "^2.1.0",
48
- "typedoc": "^0.27.6",
49
- "typedoc-plugin-mdn-links": "^4.0.10",
52
+ "typedoc": "^0.27.7",
53
+ "typedoc-plugin-mdn-links": "^4.0.13",
50
54
  "typescript": "^5.7.3"
51
55
  },
52
56
  "dependencies": {
53
- "@fishjam-cloud/ts-client": "0.12.0",
57
+ "@fishjam-cloud/ts-client": "0.14.0",
54
58
  "events": "3.3.0",
55
59
  "lodash.isequal": "4.5.0"
56
60
  },