@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.
- package/dist/FishjamProvider.d.ts.map +1 -1
- package/dist/FishjamProvider.js +6 -2
- package/dist/devices/DeviceManager.d.ts +1 -0
- package/dist/devices/DeviceManager.d.ts.map +1 -1
- package/dist/devices/DeviceManager.js +7 -19
- package/dist/devices/mediaInitializer.d.ts +1 -1
- package/dist/devices/mediaInitializer.d.ts.map +1 -1
- package/dist/devices/mediaInitializer.js +39 -20
- package/dist/hooks/devices/useInitializeDevices.d.ts +6 -1
- package/dist/hooks/devices/useInitializeDevices.d.ts.map +1 -1
- package/dist/hooks/devices/useInitializeDevices.js +40 -29
- package/dist/hooks/devices/useMicrophone.d.ts +2 -1
- package/dist/hooks/devices/useMicrophone.d.ts.map +1 -1
- package/dist/hooks/devices/useMicrophone.js +2 -1
- package/dist/hooks/internal/device/useDeviceManager.d.ts.map +1 -1
- package/dist/hooks/internal/device/useDeviceManager.js +1 -0
- package/dist/hooks/internal/useFishjamContext.d.ts +5 -5
- package/dist/hooks/internal/useFishjamContext.d.ts.map +1 -1
- package/dist/hooks/internal/useTrackManager.d.ts +3 -1
- package/dist/hooks/internal/useTrackManager.d.ts.map +1 -1
- package/dist/hooks/internal/useTrackManager.js +33 -26
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/types/internal.d.ts +1 -2
- package/dist/types/internal.d.ts.map +1 -1
- package/dist/utils/deferred.d.ts +9 -0
- package/dist/utils/deferred.d.ts.map +1 -0
- package/dist/utils/deferred.js +17 -0
- package/package.json +12 -8
|
@@ -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,
|
|
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"}
|
package/dist/FishjamProvider.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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":"AACA,OAAO,KAAK,YAAY,MAAM,eAAe,CAAC;AAE9C,OAAO,KAAK,EACV,mBAAmB,EAEnB,WAAW,EACX,KAAK,EACL,YAAY,EAEb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAO3G,MAAM,MAAM,mBAAmB,GAAG;IAChC,cAAc,EAAE,CACd,KAAK,EAAE,WAAW,GAAG;QACnB,WAAW,EAAE,qBAAqB,GAAG,SAAS,CAAC;KAChD,EACD,KAAK,EAAE,WAAW,KACf,IAAI,CAAC;IACV,kBAAkB,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACjD,cAAc,EAAE,CACd,KAAK,EAAE;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAA;KAAE,EAC7E,KAAK,EAAE,WAAW,KACf,IAAI,CAAC;IACV,WAAW,EAAE,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,WAAW,CAAA;KAAE,EAAE,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IAC1E,YAAY,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,EAAE,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACxF,aAAa,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IAC5C,aAAa,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IAC5C,cAAc,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IAC7C,aAAa,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IAE5C,KAAK,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;
|
|
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
|
-
|
|
95
|
-
|
|
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
|
-
|
|
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
|
|
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;
|
|
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
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
|
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
|
|
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<
|
|
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":"
|
|
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 {
|
|
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,
|
|
11
|
+
const { videoDeviceManagerRef, audioDeviceManagerRef, devicesInitializationRef } = useFishjamContext();
|
|
11
12
|
const initializeDevices = useCallback(async ({ enableVideo = true, enableAudio = true } = {}) => {
|
|
12
|
-
if (
|
|
13
|
-
return;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
*/
|
|
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
|
|
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
|
-
*/
|
|
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;
|
|
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"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import type { FishjamClient } from "@fishjam-cloud/ts-client";
|
|
2
|
-
import { type
|
|
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:
|
|
10
|
-
videoDeviceManagerRef:
|
|
11
|
-
audioDeviceManagerRef:
|
|
12
|
-
|
|
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,
|
|
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;
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
45
|
+
currentTrackIdRef.current = remoteTrackId;
|
|
44
46
|
setPaused(false);
|
|
45
47
|
return remoteTrackId;
|
|
46
|
-
}, [
|
|
48
|
+
}, [mediaManager, tsClient, bandwidthLimits]);
|
|
47
49
|
const refreshStreamedTrack = useCallback(async () => {
|
|
48
|
-
|
|
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(
|
|
54
|
-
}, [
|
|
56
|
+
return tsClient.replaceTrack(trackId, newTrack);
|
|
57
|
+
}, [getCurrentTrackId, mediaManager, tsClient]);
|
|
55
58
|
const pauseStreaming = useCallback(async () => {
|
|
56
|
-
|
|
59
|
+
const trackId = getCurrentTrackId();
|
|
60
|
+
if (!trackId)
|
|
57
61
|
return;
|
|
58
62
|
setPaused(true);
|
|
59
|
-
await tsClient.replaceTrack(
|
|
63
|
+
await tsClient.replaceTrack(trackId, null);
|
|
60
64
|
const deviceType = getDeviceType(mediaManager);
|
|
61
65
|
const trackMetadata = { type: deviceType, paused: true };
|
|
62
|
-
return tsClient.updateTrackMetadata(
|
|
63
|
-
}, [
|
|
66
|
+
return tsClient.updateTrackMetadata(trackId, trackMetadata);
|
|
67
|
+
}, [mediaManager, getCurrentTrackId, tsClient]);
|
|
64
68
|
const resumeStreaming = useCallback(async () => {
|
|
65
|
-
|
|
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(
|
|
77
|
+
await tsClient.replaceTrack(trackId, media.track);
|
|
73
78
|
const trackMetadata = { type: deviceType, paused: false };
|
|
74
|
-
return tsClient.updateTrackMetadata(
|
|
75
|
-
}, [
|
|
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
|
-
|
|
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
|
-
}, [
|
|
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 (
|
|
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
|
-
}, [
|
|
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
|
-
|
|
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
|
|
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";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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";
|
package/dist/types/internal.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Peer } from "@fishjam-cloud/ts-client";
|
|
2
|
-
import type { DeviceError, DeviceType, PeerId,
|
|
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":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAErD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/types/internal.ts"],"names":[],"mappings":"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"}
|
|
@@ -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.
|
|
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":
|
|
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.
|
|
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.
|
|
45
|
-
"@types/react": "^19.0.
|
|
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.
|
|
49
|
-
"typedoc-plugin-mdn-links": "^4.0.
|
|
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.
|
|
57
|
+
"@fishjam-cloud/ts-client": "0.14.0",
|
|
54
58
|
"events": "3.3.0",
|
|
55
59
|
"lodash.isequal": "4.5.0"
|
|
56
60
|
},
|