@fishjam-cloud/react-client 0.15.0 → 0.16.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.
Files changed (33) hide show
  1. package/dist/contexts/initDevices.d.ts +2 -1
  2. package/dist/contexts/initDevices.d.ts.map +1 -1
  3. package/dist/hooks/devices/useCamera.d.ts +7 -2
  4. package/dist/hooks/devices/useCamera.d.ts.map +1 -1
  5. package/dist/hooks/devices/useCamera.js +6 -1
  6. package/dist/hooks/devices/useInitializeDevices.d.ts +1 -1
  7. package/dist/hooks/devices/useMicrophone.d.ts +6 -1
  8. package/dist/hooks/devices/useMicrophone.d.ts.map +1 -1
  9. package/dist/hooks/devices/useMicrophone.js +5 -0
  10. package/dist/hooks/internal/devices/useDeviceManager.d.ts +6 -3
  11. package/dist/hooks/internal/devices/useDeviceManager.d.ts.map +1 -1
  12. package/dist/hooks/internal/devices/useDeviceManager.js +40 -7
  13. package/dist/hooks/internal/devices/useHandleTrackEnd.d.ts +2 -0
  14. package/dist/hooks/internal/devices/useHandleTrackEnd.d.ts.map +1 -0
  15. package/dist/hooks/internal/devices/useHandleTrackEnd.js +11 -0
  16. package/dist/hooks/internal/devices/useMediaDevices.d.ts +5 -4
  17. package/dist/hooks/internal/devices/useMediaDevices.d.ts.map +1 -1
  18. package/dist/hooks/internal/devices/useMediaDevices.js +17 -18
  19. package/dist/hooks/internal/useTrackManager.d.ts.map +1 -1
  20. package/dist/hooks/internal/useTrackManager.js +6 -3
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/tests/useHandleTrackEnd.spec.d.ts +2 -0
  24. package/dist/tests/useHandleTrackEnd.spec.d.ts.map +1 -0
  25. package/dist/tests/useHandleTrackEnd.spec.js +14 -0
  26. package/dist/types/internal.d.ts +1 -1
  27. package/dist/types/internal.d.ts.map +1 -1
  28. package/dist/utils/track.d.ts.map +1 -1
  29. package/dist/utils/track.js +1 -1
  30. package/package.json +12 -6
  31. package/dist/hooks/internal/devices/useHandleStreamEnd.d.ts +0 -9
  32. package/dist/hooks/internal/devices/useHandleStreamEnd.d.ts.map +0 -1
  33. package/dist/hooks/internal/devices/useHandleStreamEnd.js +0 -13
@@ -1,3 +1,4 @@
1
+ import type { InitializeDevicesSettings } from "../hooks/internal/devices/useMediaDevices";
1
2
  import type { InitializeDevicesResult } from "../types/public";
2
- export declare const InitDevicesContext: import("react").Context<(() => Promise<InitializeDevicesResult>) | null>;
3
+ export declare const InitDevicesContext: import("react").Context<((settings?: InitializeDevicesSettings) => Promise<InitializeDevicesResult>) | null>;
3
4
  //# sourceMappingURL=initDevices.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"initDevices.d.ts","sourceRoot":"","sources":["../../src/contexts/initDevices.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE/D,eAAO,MAAM,kBAAkB,iCAAwB,OAAO,CAAC,uBAAuB,CAAC,SAAe,CAAC"}
1
+ {"version":3,"file":"initDevices.d.ts","sourceRoot":"","sources":["../../src/contexts/initDevices.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AAC3F,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE/D,eAAO,MAAM,kBAAkB,uCAChB,yBAAyB,KAAK,OAAO,CAAC,uBAAuB,CAAC,SACtE,CAAC"}
@@ -10,13 +10,18 @@ export declare function useCamera(): {
10
10
  /**
11
11
  * Selects the camera device
12
12
  */
13
- selectCamera: (deviceId?: string) => Promise<undefined | import("../..").DeviceError>;
13
+ selectCamera: (deviceId: string) => Promise<undefined | import("../..").DeviceError>;
14
14
  /**
15
+ * @deprecated Use `currentCamera` and `isCameraOn` instead
15
16
  * Indicates which camera is now turned on and streaming
16
17
  */
17
18
  activeCamera: import("../..").DeviceItem | null;
18
19
  /**
19
- * Indicates whether the microphone is streaming video
20
+ * Indicates which camera is now selected
21
+ */
22
+ currentCamera: MediaDeviceInfo | null;
23
+ /**
24
+ * Indicates whether the camera is streaming video
20
25
  */
21
26
  isCameraOn: boolean;
22
27
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"useCamera.d.ts","sourceRoot":"","sources":["../../../src/hooks/devices/useCamera.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,SAAS;IAarB;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;EAGN"}
1
+ {"version":3,"file":"useCamera.d.ts","sourceRoot":"","sources":["../../../src/hooks/devices/useCamera.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,SAAS;IAarB;;OAEG;;IAEH;;OAEG;;IAEH;;;OAGG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;EAGN"}
@@ -25,11 +25,16 @@ export function useCamera() {
25
25
  */
26
26
  selectCamera: videoTrackManager.selectDevice,
27
27
  /**
28
+ * @deprecated Use `currentCamera` and `isCameraOn` instead
28
29
  * Indicates which camera is now turned on and streaming
29
30
  */
30
31
  activeCamera: cameraManager.activeDevice,
31
32
  /**
32
- * Indicates whether the microphone is streaming video
33
+ * Indicates which camera is now selected
34
+ */
35
+ currentCamera: cameraManager.selectedDevice,
36
+ /**
37
+ * Indicates whether the camera is streaming video
33
38
  */
34
39
  isCameraOn: !!cameraStream,
35
40
  /**
@@ -10,6 +10,6 @@ export declare const useInitializeDevices: () => {
10
10
  /**
11
11
  * Initialize access to the devices before joining the room
12
12
  */
13
- initializeDevices: () => Promise<import("../..").InitializeDevicesResult>;
13
+ initializeDevices: (settings?: import("../..").InitializeDevicesSettings) => Promise<import("../..").InitializeDevicesResult>;
14
14
  };
15
15
  //# sourceMappingURL=useInitializeDevices.d.ts.map
@@ -8,11 +8,16 @@ export declare function useMicrophone(): {
8
8
  /** Mutes/unmutes the microphone */
9
9
  toggleMicrophoneMute: () => Promise<void>;
10
10
  /** Selects the microphone device */
11
- selectMicrophone: (deviceId?: string) => Promise<undefined | import("../..").DeviceError>;
11
+ selectMicrophone: (deviceId: string) => Promise<undefined | import("../..").DeviceError>;
12
12
  /**
13
+ * @deprecated Use `currentMicrophone` and `isMicrophoneOn` instead
13
14
  * Indicates which microphone is now turned on and streaming audio
14
15
  */
15
16
  activeMicrophone: import("../..").DeviceItem | null;
17
+ /**
18
+ * Indicates which microphone is now selected
19
+ */
20
+ currentMicrophone: MediaDeviceInfo | null;
16
21
  /**
17
22
  * Indicates whether the microphone is streaming audio
18
23
  */
@@ -1 +1 @@
1
- {"version":3,"file":"useMicrophone.d.ts","sourceRoot":"","sources":["../../../src/hooks/devices/useMicrophone.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,aAAa;IAazB,wCAAwC;;IAExC,mCAAmC;;IAEnC,oCAAoC;;IAEpC;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;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":"AAIA;;;GAGG;AACH,wBAAgB,aAAa;IAazB,wCAAwC;;IAExC,mCAAmC;;IAEnC,oCAAoC;;IAEpC;;;OAGG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;EAGN"}
@@ -23,9 +23,14 @@ export function useMicrophone() {
23
23
  /** Selects the microphone device */
24
24
  selectMicrophone: audioTrackManager.selectDevice,
25
25
  /**
26
+ * @deprecated Use `currentMicrophone` and `isMicrophoneOn` instead
26
27
  * Indicates which microphone is now turned on and streaming audio
27
28
  */
28
29
  activeMicrophone: microphoneManager.activeDevice,
30
+ /**
31
+ * Indicates which microphone is now selected
32
+ */
33
+ currentMicrophone: microphoneManager.selectedDevice,
29
34
  /**
30
35
  * Indicates whether the microphone is streaming audio
31
36
  */
@@ -9,11 +9,13 @@ type DeviceManagerProps = {
9
9
  deviceType: "audio" | "video";
10
10
  allDevicesList: MediaDeviceInfo[];
11
11
  constraints?: MediaTrackConstraints | boolean;
12
- saveUsedDevice: (device: MediaDeviceInfo) => void;
12
+ setSelectedDevice: (device: MediaDeviceInfo) => void;
13
+ selectedDevice: MediaDeviceInfo | null;
13
14
  };
14
15
  export type DeviceManager = {
15
- startDevice: (deviceId?: string) => Promise<[MediaStreamTrack, null] | [null, DeviceError]>;
16
+ startDevice: (deviceId?: string | null) => Promise<[MediaStreamTrack, null] | [null, DeviceError]>;
16
17
  stopDevice: () => void;
18
+ selectDevice: (deviceId: string) => Promise<[MediaStreamTrack, null] | [null, DeviceError]> | undefined;
17
19
  activeDevice: DeviceItem | null;
18
20
  deviceTrack: MediaStreamTrack | null;
19
21
  deviceList: DeviceItem[];
@@ -23,7 +25,8 @@ export type DeviceManager = {
23
25
  currentMiddleware: TrackMiddleware;
24
26
  applyMiddleware: (middleware: TrackMiddleware) => MediaStreamTrack | null;
25
27
  deviceError: DeviceError | null;
28
+ selectedDevice: MediaDeviceInfo | null;
26
29
  };
27
- export declare const useDeviceManager: ({ mediaStream, getInitialStream, deviceType, allDevicesList, setMediaStream, constraints, saveUsedDevice, deviceError, setDeviceError, }: DeviceManagerProps) => DeviceManager;
30
+ export declare const useDeviceManager: ({ mediaStream, setMediaStream, getInitialStream, deviceType, constraints, allDevicesList, setSelectedDevice, deviceError, setDeviceError, selectedDevice, }: DeviceManagerProps) => DeviceManager;
28
31
  export {};
29
32
  //# sourceMappingURL=useDeviceManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useDeviceManager.d.ts","sourceRoot":"","sources":["../../../../src/hooks/internal/devices/useDeviceManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAKtF,KAAK,kBAAkB,GAAG;IACxB,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC;IACrE,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC;IACrE,gBAAgB,EAAE,MAAM,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACpD,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC;IAC9B,cAAc,EAAE,eAAe,EAAE,CAAC;IAClC,WAAW,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC;IAC9C,cAAc,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,WAAW,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;IAC5F,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,YAAY,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACrC,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,iBAAiB,EAAE,eAAe,CAAC;IACnC,eAAe,EAAE,CAAC,UAAU,EAAE,eAAe,KAAK,gBAAgB,GAAG,IAAI,CAAC;IAC1E,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;CACjC,CAAC;AAsCF,eAAO,MAAM,gBAAgB,GAAI,0IAU9B,kBAAkB,KAAG,aAuFvB,CAAC"}
1
+ {"version":3,"file":"useDeviceManager.d.ts","sourceRoot":"","sources":["../../../../src/hooks/internal/devices/useDeviceManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAMtF,KAAK,kBAAkB,GAAG;IACxB,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC;IACrE,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC;IACrE,gBAAgB,EAAE,MAAM,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACpD,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC;IAC9B,cAAc,EAAE,eAAe,EAAE,CAAC;IAClC,WAAW,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC;IAC9C,iBAAiB,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;IACrD,cAAc,EAAE,eAAe,GAAG,IAAI,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,WAAW,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;IACnG,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,GAAG,SAAS,CAAC;IACxG,YAAY,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACrC,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,iBAAiB,EAAE,eAAe,CAAC;IACnC,eAAe,EAAE,CAAC,UAAU,EAAE,eAAe,KAAK,gBAAgB,GAAG,IAAI,CAAC;IAC1E,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,eAAe,GAAG,IAAI,CAAC;CACxC,CAAC;AAsCF,eAAO,MAAM,gBAAgB,GAAI,6JAW9B,kBAAkB,KAAG,aAgIvB,CAAC"}
@@ -2,6 +2,7 @@ import { useCallback, useMemo, useState } from "react";
2
2
  import { parseUserMediaError } from "../../../utils/errors";
3
3
  import { getTrackFromStream, stopStream } from "../../../utils/track";
4
4
  import { useTrackMiddleware } from "../useTrackMiddleware";
5
+ import { useHandleTrackEnd } from "./useHandleTrackEnd";
5
6
  function getReplaceStreamAction(newStream, deviceType) {
6
7
  return (oldStream) => {
7
8
  if (oldStream) {
@@ -28,8 +29,12 @@ async function getDeviceStream(type, constraints, deviceId) {
28
29
  });
29
30
  return stream;
30
31
  }
31
- export const useDeviceManager = ({ mediaStream, getInitialStream, deviceType, allDevicesList, setMediaStream, constraints, saveUsedDevice, deviceError, setDeviceError, }) => {
32
+ export const useDeviceManager = ({ mediaStream, setMediaStream, getInitialStream, deviceType, constraints, allDevicesList, setSelectedDevice, deviceError, setDeviceError, selectedDevice, }) => {
32
33
  const rawTrack = useMemo(() => mediaStream && getTrackFromStream(mediaStream, deviceType), [mediaStream, deviceType]);
34
+ const clearStream = useCallback(() => {
35
+ setMediaStream(null);
36
+ }, [setMediaStream]);
37
+ useHandleTrackEnd(rawTrack, clearStream);
33
38
  const { processedTrack, applyMiddleware, currentMiddleware } = useTrackMiddleware(rawTrack);
34
39
  const currentTrack = processedTrack ?? rawTrack;
35
40
  const deviceList = useMemo(() => allDevicesList.filter(({ kind }) => kind === `${deviceType}input`), [allDevicesList, deviceType]);
@@ -41,7 +46,13 @@ export const useDeviceManager = ({ mediaStream, getInitialStream, deviceType, al
41
46
  return { label: currentDevice.label, deviceId: currentDevice.deviceId };
42
47
  }, [mediaStream, deviceList, deviceType]);
43
48
  const [deviceEnabled, setDeviceEnabled] = useState(true);
44
- const startDevice = useCallback(async (deviceId) => {
49
+ const setSelectedDeviceId = useCallback((deviceId) => {
50
+ const device = deviceList.find((d) => d.deviceId === deviceId);
51
+ if (!device)
52
+ return;
53
+ setSelectedDevice(device);
54
+ }, [deviceList, setSelectedDevice]);
55
+ const startDevice = useCallback(async (deviceId = selectedDevice?.deviceId) => {
45
56
  const initialStream = await getInitialStream();
46
57
  const track = initialStream && getTrackFromStream(initialStream, deviceType);
47
58
  const isUsingDesiredDevice = !deviceId || deviceId === track?.getSettings().deviceId;
@@ -49,12 +60,15 @@ export const useDeviceManager = ({ mediaStream, getInitialStream, deviceType, al
49
60
  return [track, null];
50
61
  }
51
62
  try {
52
- const stream = await getDeviceStream(deviceType, constraints, deviceId);
63
+ const stream = await getDeviceStream(deviceType, constraints, deviceId ?? null);
53
64
  setMediaStream(getReplaceStreamAction(stream, deviceType));
54
65
  const retrievedTrack = stream && getTrackFromStream(stream, deviceType);
55
- const usedDevice = deviceList.find((device) => device.deviceId === retrievedTrack?.getSettings().deviceId);
56
- if (usedDevice) {
57
- saveUsedDevice(usedDevice);
66
+ const retrievedTrackDeviceId = retrievedTrack.getSettings().deviceId;
67
+ if (retrievedTrackDeviceId) {
68
+ setSelectedDeviceId(retrievedTrackDeviceId);
69
+ }
70
+ if (retrievedTrack && !deviceEnabled) {
71
+ retrievedTrack.enabled = false;
58
72
  }
59
73
  return [retrievedTrack, null];
60
74
  }
@@ -63,7 +77,24 @@ export const useDeviceManager = ({ mediaStream, getInitialStream, deviceType, al
63
77
  setDeviceError(parsedError);
64
78
  return [null, parsedError];
65
79
  }
66
- }, [getInitialStream, deviceType, constraints, setMediaStream, deviceList, saveUsedDevice, setDeviceError]);
80
+ }, [
81
+ selectedDevice?.deviceId,
82
+ getInitialStream,
83
+ deviceType,
84
+ constraints,
85
+ setMediaStream,
86
+ deviceEnabled,
87
+ setSelectedDeviceId,
88
+ setDeviceError,
89
+ ]);
90
+ const selectDevice = useCallback((deviceId) => {
91
+ if (currentTrack) {
92
+ return startDevice(deviceId);
93
+ }
94
+ else {
95
+ setSelectedDeviceId(deviceId);
96
+ }
97
+ }, [currentTrack, setSelectedDeviceId, startDevice]);
67
98
  const stopDevice = useCallback(() => {
68
99
  setMediaStream(getStopStreamAction(deviceType));
69
100
  }, [setMediaStream, deviceType]);
@@ -82,6 +113,7 @@ export const useDeviceManager = ({ mediaStream, getInitialStream, deviceType, al
82
113
  return {
83
114
  startDevice,
84
115
  stopDevice,
116
+ selectDevice,
85
117
  activeDevice,
86
118
  deviceTrack: processedTrack ?? rawTrack,
87
119
  deviceList,
@@ -91,5 +123,6 @@ export const useDeviceManager = ({ mediaStream, getInitialStream, deviceType, al
91
123
  currentMiddleware,
92
124
  applyMiddleware,
93
125
  deviceError,
126
+ selectedDevice,
94
127
  };
95
128
  };
@@ -0,0 +1,2 @@
1
+ export declare const useHandleTrackEnd: (track: MediaStreamTrack | null, clearStream: () => void) => void;
2
+ //# sourceMappingURL=useHandleTrackEnd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useHandleTrackEnd.d.ts","sourceRoot":"","sources":["../../../../src/hooks/internal/devices/useHandleTrackEnd.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,GAAI,OAAO,gBAAgB,GAAG,IAAI,EAAE,aAAa,MAAM,IAAI,SASxF,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { useEffect } from "react";
2
+ export const useHandleTrackEnd = (track, clearStream) => {
3
+ useEffect(() => {
4
+ if (!track)
5
+ return;
6
+ track.onended = () => {
7
+ track.stop();
8
+ clearStream();
9
+ };
10
+ }, [track, clearStream]);
11
+ };
@@ -4,11 +4,12 @@ interface UseDevicesProps {
4
4
  audioConstraints?: MediaTrackConstraints | boolean;
5
5
  persistHandlers?: PersistLastDeviceHandlers;
6
6
  }
7
+ export type InitializeDevicesSettings = {
8
+ enableVideo?: boolean;
9
+ enableAudio?: boolean;
10
+ };
7
11
  export declare const useMediaDevices: ({ videoConstraints, audioConstraints, persistHandlers }: UseDevicesProps) => {
8
- initializeDevices: (settings?: {
9
- enableVideo?: boolean;
10
- enableAudio?: boolean;
11
- }) => Promise<InitializeDevicesResult>;
12
+ initializeDevices: (settings?: InitializeDevicesSettings) => Promise<InitializeDevicesResult>;
12
13
  cameraManager: import("./useDeviceManager").DeviceManager;
13
14
  microphoneManager: import("./useDeviceManager").DeviceManager;
14
15
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useMediaDevices.d.ts","sourceRoot":"","sources":["../../../../src/hooks/internal/devices/useMediaDevices.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAe,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAI7G,UAAU,eAAe;IACvB,gBAAgB,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC;IACnD,gBAAgB,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC;IACnD,eAAe,CAAC,EAAE,yBAAyB,CAAC;CAC7C;AAED,eAAO,MAAM,eAAe,GAAI,yDAAyD,eAAe;mCA+BlF;QAAE,WAAW,CAAC,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE,KAAG,OAAO,CAAC,uBAAuB,CAAC;;;CA2GxG,CAAC"}
1
+ {"version":3,"file":"useMediaDevices.d.ts","sourceRoot":"","sources":["../../../../src/hooks/internal/devices/useMediaDevices.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAe,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAG7G,UAAU,eAAe;IACvB,gBAAgB,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC;IACnD,gBAAgB,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC;IACnD,eAAe,CAAC,EAAE,yBAAyB,CAAC;CAC7C;AAED,MAAM,MAAM,yBAAyB,GAAG;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEzF,eAAO,MAAM,eAAe,GAAI,yDAAyD,eAAe;mCAmClF,yBAAyB,KAAG,OAAO,CAAC,uBAAuB,CAAC;;;CA0GjF,CAAC"}
@@ -2,22 +2,21 @@ import { useCallback, useEffect, useRef, useState } from "react";
2
2
  import { prepareConstraints } from "../../../devices/constraints";
3
3
  import { correctDevicesOnSafari, getAvailableMedia } from "../../../devices/mediaInitializer";
4
4
  import { useDeviceManager } from "./useDeviceManager";
5
- import { useHandleTrackEnd } from "./useHandleStreamEnd";
6
5
  export const useMediaDevices = ({ videoConstraints, audioConstraints, persistHandlers }) => {
7
6
  const [deviceList, setDeviceList] = useState([]);
8
7
  const [videoStream, setVideoStream] = useState(null);
9
8
  const [audioStream, setAudioStream] = useState(null);
10
9
  const [videoError, setVideoError] = useState(null);
11
10
  const [audioError, setAudioError] = useState(null);
12
- const lastUsedCameraRef = useRef(persistHandlers?.getLastDevice("video") ?? null);
13
- const lastUsedMicRef = useRef(persistHandlers?.getLastDevice("audio") ?? null);
11
+ const [selectedCamera, setSelectedCamera] = useState(persistHandlers?.getLastDevice("video") ?? null);
12
+ const [selectedMic, setSelectedMic] = useState(persistHandlers?.getLastDevice("audio") ?? null);
14
13
  const initializationRef = useRef(null);
15
- const saveUsedCamera = useCallback((deviceInfo) => {
16
- lastUsedCameraRef.current = deviceInfo;
14
+ const selectCamera = useCallback((deviceInfo) => {
15
+ setSelectedCamera(deviceInfo);
17
16
  persistHandlers?.saveLastDevice(deviceInfo, "video");
18
17
  }, [persistHandlers]);
19
- const saveUsedMic = useCallback((deviceInfo) => {
20
- lastUsedMicRef.current = deviceInfo;
18
+ const selectMic = useCallback((deviceInfo) => {
19
+ setSelectedMic(deviceInfo);
21
20
  persistHandlers?.saveLastDevice(deviceInfo, "audio");
22
21
  }, [persistHandlers]);
23
22
  const initializeDevices = useCallback(async (settings) => {
@@ -25,8 +24,8 @@ export const useMediaDevices = ({ videoConstraints, audioConstraints, persistHan
25
24
  return { stream: null, errors: null, status: "already_initialized" };
26
25
  }
27
26
  const lastUsed = {
28
- audio: lastUsedMicRef.current,
29
- video: lastUsedCameraRef.current,
27
+ audio: selectedMic,
28
+ video: selectedCamera,
30
29
  };
31
30
  const constraints = {
32
31
  video: settings?.enableVideo !== false && prepareConstraints(lastUsed.video?.deviceId, videoConstraints),
@@ -43,29 +42,29 @@ export const useMediaDevices = ({ videoConstraints, audioConstraints, persistHan
43
42
  const videoDevice = deviceList.find((device) => device.deviceId === stream?.getVideoTracks()[0].getSettings().deviceId);
44
43
  const audioDevice = deviceList.find((device) => device.deviceId === stream?.getAudioTracks()[0].getSettings().deviceId);
45
44
  if (videoDevice) {
46
- saveUsedCamera(videoDevice);
45
+ selectCamera(videoDevice);
47
46
  }
48
47
  if (audioDevice) {
49
- saveUsedMic(audioDevice);
48
+ selectMic(audioDevice);
50
49
  }
51
50
  setVideoStream(stream);
52
51
  setAudioStream(stream);
53
52
  setVideoError(errors.video);
54
53
  setAudioError(errors.audio);
55
54
  if (!stream) {
56
- return { status: "failed", errors: errors, stream: null };
55
+ return { status: "failed", errors, stream: null };
57
56
  }
58
57
  else if (errors.video || errors.audio) {
59
58
  return { status: "initialized_with_errors", errors, stream: null };
60
59
  }
61
60
  else {
62
- return { status: "initialized", stream, errors: null };
61
+ return { status: "initialized", errors: null, stream };
63
62
  }
64
63
  };
65
64
  const initializePromise = intitialize();
66
65
  initializationRef.current = initializePromise;
67
66
  return await initializePromise;
68
- }, [deviceList, videoConstraints, audioConstraints, saveUsedCamera, saveUsedMic]);
67
+ }, [deviceList, selectedMic, selectedCamera, videoConstraints, audioConstraints, selectCamera, selectMic]);
69
68
  useEffect(() => {
70
69
  const isInitialStreamIrrelevant = videoStream !== audioStream;
71
70
  if (isInitialStreamIrrelevant) {
@@ -76,8 +75,6 @@ export const useMediaDevices = ({ videoConstraints, audioConstraints, persistHan
76
75
  const result = await initializationRef.current;
77
76
  return result?.stream ?? null;
78
77
  }, []);
79
- useHandleTrackEnd({ stream: videoStream, setStream: setVideoStream, type: "video" });
80
- useHandleTrackEnd({ stream: audioStream, setStream: setAudioStream, type: "audio" });
81
78
  const cameraManager = useDeviceManager({
82
79
  mediaStream: videoStream,
83
80
  setMediaStream: setVideoStream,
@@ -87,7 +84,8 @@ export const useMediaDevices = ({ videoConstraints, audioConstraints, persistHan
87
84
  deviceType: "video",
88
85
  allDevicesList: deviceList,
89
86
  constraints: videoConstraints,
90
- saveUsedDevice: saveUsedCamera,
87
+ setSelectedDevice: selectCamera,
88
+ selectedDevice: selectedCamera,
91
89
  });
92
90
  const microphoneManager = useDeviceManager({
93
91
  mediaStream: audioStream,
@@ -98,7 +96,8 @@ export const useMediaDevices = ({ videoConstraints, audioConstraints, persistHan
98
96
  deviceType: "audio",
99
97
  allDevicesList: deviceList,
100
98
  constraints: audioConstraints,
101
- saveUsedDevice: saveUsedMic,
99
+ setSelectedDevice: selectMic,
100
+ selectedDevice: selectedMic,
102
101
  });
103
102
  return {
104
103
  initializeDevices,
@@ -1 +1 @@
1
- {"version":3,"file":"useTrackManager.d.ts","sourceRoot":"","sources":["../../../src/hooks/internal/useTrackManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAA+C,MAAM,0BAA0B,CAAC;AAG3G,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAmB,MAAM,oBAAoB,CAAC;AAErG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE,UAAU,kBAAkB;IAC1B,aAAa,EAAE,aAAa,CAAC;IAC7B,QAAQ,EAAE,aAAa,CAAC;IACxB,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,EAAE,eAAe,CAAC;IACjC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,IAAI,EAAE,QAAQ,GAAG,YAAY,CAAC;CAC/B;AAED,eAAO,MAAM,eAAe,GAAI,+EAO7B,kBAAkB,KAAG,YAuKvB,CAAC"}
1
+ {"version":3,"file":"useTrackManager.d.ts","sourceRoot":"","sources":["../../../src/hooks/internal/useTrackManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAA+C,MAAM,0BAA0B,CAAC;AAG3G,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAmB,MAAM,oBAAoB,CAAC;AAErG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE,UAAU,kBAAkB;IAC1B,aAAa,EAAE,aAAa,CAAC;IAC7B,QAAQ,EAAE,aAAa,CAAC;IACxB,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,EAAE,eAAe,CAAC;IACjC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,IAAI,EAAE,QAAQ,GAAG,YAAY,CAAC;CAC/B;AAED,eAAO,MAAM,eAAe,GAAI,+EAO7B,kBAAkB,KAAG,YAkLvB,CAAC"}
@@ -3,7 +3,7 @@ import { useCallback, useEffect, useRef } from "react";
3
3
  import { getConfigAndBandwidthFromProps, getRemoteOrLocalTrack } from "../../utils/track";
4
4
  export const useTrackManager = ({ deviceManager, tsClient, peerStatus, bandwidthLimits, streamConfig, type, }) => {
5
5
  const currentTrackIdRef = useRef(null);
6
- const { startDevice, stopDevice, enableDevice, disableDevice, deviceTrack, applyMiddleware, currentMiddleware } = deviceManager;
6
+ const { startDevice, stopDevice, enableDevice, disableDevice, deviceTrack, applyMiddleware, currentMiddleware, selectDevice: _selectDevice, } = deviceManager;
7
7
  const getCurrentTrackId = useCallback(() => {
8
8
  const refTrackId = currentTrackIdRef.current;
9
9
  if (!refTrackId)
@@ -12,14 +12,17 @@ export const useTrackManager = ({ deviceManager, tsClient, peerStatus, bandwidth
12
12
  return currentTrack?.trackId ?? null;
13
13
  }, [tsClient]);
14
14
  const selectDevice = useCallback(async (deviceId) => {
15
- const [newTrack, error] = await startDevice(deviceId);
15
+ const result = await _selectDevice(deviceId);
16
+ if (!result)
17
+ return;
18
+ const [newTrack, error] = result;
16
19
  if (error)
17
20
  return error;
18
21
  const currentTrackId = getCurrentTrackId();
19
22
  if (!currentTrackId)
20
23
  return;
21
24
  await tsClient.replaceTrack(currentTrackId, newTrack);
22
- }, [getCurrentTrackId, startDevice, tsClient]);
25
+ }, [getCurrentTrackId, _selectDevice, tsClient]);
23
26
  const setTrackMiddleware = useCallback(async (middleware) => {
24
27
  const processedTrack = applyMiddleware(middleware);
25
28
  const currentTrackId = getCurrentTrackId();
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { FishjamProvider, type FishjamProviderProps } from "./FishjamProvider";
2
2
  export { useCamera } from "./hooks/devices/useCamera";
3
3
  export { useInitializeDevices, UseInitializeDevicesParams } from "./hooks/devices/useInitializeDevices";
4
4
  export { useMicrophone } from "./hooks/devices/useMicrophone";
5
+ export { InitializeDevicesSettings } from "./hooks/internal/devices/useMediaDevices";
5
6
  export { type JoinRoomConfig, useConnection } from "./hooks/useConnection";
6
7
  export { type PeerWithTracks, usePeers } from "./hooks/usePeers";
7
8
  export { useScreenShare } from "./hooks/useScreenShare";
@@ -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,uBAAuB,EACvB,uBAAuB,EACvB,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,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AACxG,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AACrF,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,uBAAuB,EACvB,uBAAuB,EACvB,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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=useHandleTrackEnd.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useHandleTrackEnd.spec.d.ts","sourceRoot":"","sources":["../../src/tests/useHandleTrackEnd.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,14 @@
1
+ import { renderHook } from "@testing-library/react";
2
+ import { FakeMediaStreamTrack } from "fake-mediastreamtrack";
3
+ import { describe, expect, it, vi } from "vitest";
4
+ import { useHandleTrackEnd } from "../hooks/internal/devices/useHandleTrackEnd";
5
+ describe("useHandleTrackEnd", () => {
6
+ it("should clear stream on track ended event", () => {
7
+ const clearStream = vi.fn();
8
+ const track = new FakeMediaStreamTrack({ kind: "it literally doesn't matter" });
9
+ renderHook(() => useHandleTrackEnd(track, clearStream));
10
+ expect(track.onended).toBeDefined();
11
+ track.remoteStop();
12
+ expect(clearStream).toHaveBeenCalled();
13
+ });
14
+ });
@@ -21,7 +21,7 @@ export type ScreenShareState = ({
21
21
  tracksMiddleware?: TracksMiddleware | null;
22
22
  };
23
23
  export interface TrackManager {
24
- selectDevice: (deviceId?: string) => Promise<undefined | DeviceError>;
24
+ selectDevice: (deviceId: string) => Promise<undefined | DeviceError>;
25
25
  deviceTrack: MediaStreamTrack | null;
26
26
  currentMiddleware: TrackMiddleware;
27
27
  setTrackMiddleware: (middleware: TrackMiddleware | null) => Promise<void>;
@@ -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,MAAM,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEvF,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI;IAAE,KAAK,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC;AAEnD,MAAM,MAAM,cAAc,GAAG;IAAE,UAAU,EAAE,eAAe,GAAG,IAAI,CAAC;IAAC,UAAU,EAAE,eAAe,GAAG,IAAI,CAAA;CAAE,CAAC;AAExG,MAAM,MAAM,gBAAgB,GAAG,CAC3B;IACE,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAClD,GACD;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,IAAI,CAAA;CAAE,CACnC,GAAG;IAAE,gBAAgB,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;CAAE,CAAC;AAEnD,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,GAAG,WAAW,CAAC,CAAC;IACtE,WAAW,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACrC,iBAAiB,EAAE,eAAe,CAAC;IACnC,kBAAkB,EAAE,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E;;;;;;;OAOG;IACH,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC;;;;;;OAMG;IACH,YAAY,EAAE,MAAM,OAAO,CAAC,SAAS,GAAG,WAAW,CAAC,CAAC;CACtD;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC"}
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,MAAM,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEvF,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI;IAAE,KAAK,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC;AAEnD,MAAM,MAAM,cAAc,GAAG;IAAE,UAAU,EAAE,eAAe,GAAG,IAAI,CAAC;IAAC,UAAU,EAAE,eAAe,GAAG,IAAI,CAAA;CAAE,CAAC;AAExG,MAAM,MAAM,gBAAgB,GAAG,CAC3B;IACE,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAClD,GACD;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,IAAI,CAAA;CAAE,CACnC,GAAG;IAAE,gBAAgB,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;CAAE,CAAC;AAEnD,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,GAAG,WAAW,CAAC,CAAC;IACrE,WAAW,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACrC,iBAAiB,EAAE,eAAe,CAAC;IACnC,kBAAkB,EAAE,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E;;;;;;;OAOG;IACH,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC;;;;;;OAMG;IACH,YAAY,EAAE,MAAM,OAAO,CAAC,SAAS,GAAG,WAAW,CAAC,CAAC;CACtD;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../../src/utils/track.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAA+B,MAAM,0BAA0B,CAAC;AAC5G,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAEnD,OAAO,KAAK,EAAE,eAAe,EAAE,KAAK,EAAW,MAAM,iBAAiB,CAAC;AAiCvE,eAAO,MAAM,qBAAqB,GAAI,UAAU,aAAa,EAAE,sBAAsB,MAAM,iBAI1F,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,gBAAgB,EACvB,iBAAiB,EAAE,MAAM,MAAM,GAAG,SAAS,EAC3C,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,QAQ9B;AAOD,eAAO,MAAM,8BAA8B,GACzC,WAAW,OAAO,EAAE,GAAG,KAAK,GAAG,SAAS,EACxC,iBAAiB,eAAe,oFAcjC,CAAC;AAOF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,oBAE9E;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,QAKtE"}
1
+ {"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../../src/utils/track.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAA+B,MAAM,0BAA0B,CAAC;AAC5G,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAEnD,OAAO,KAAK,EAAE,eAAe,EAAE,KAAK,EAAW,MAAM,iBAAiB,CAAC;AAiCvE,eAAO,MAAM,qBAAqB,GAAI,UAAU,aAAa,EAAE,sBAAsB,MAAM,iBAI1F,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,gBAAgB,EACvB,iBAAiB,EAAE,MAAM,MAAM,GAAG,SAAS,EAC3C,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,QAQ9B;AAOD,eAAO,MAAM,8BAA8B,GACzC,WAAW,OAAO,EAAE,GAAG,KAAK,GAAG,SAAS,EACxC,iBAAiB,eAAe,oFAgBjC,CAAC;AAOF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,oBAE9E;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,QAKtE"}
@@ -51,7 +51,7 @@ export const getConfigAndBandwidthFromProps = (encodings, bandwidthLimits) => {
51
51
  enabledVariants: encodings,
52
52
  disabledVariants: getDisabledEncodings(encodings),
53
53
  };
54
- const variantEntries = Object.entries(bandwidthLimits.simulcast);
54
+ const variantEntries = Object.entries(bandwidthLimits.simulcast).map(([key, value]) => [Number(key), value]);
55
55
  const bandwidth = new Map(variantEntries);
56
56
  return [bandwidth, config];
57
57
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fishjam-cloud/react-client",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "React client library for Fishjam",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Fishjam Team",
@@ -34,6 +34,7 @@
34
34
  "scripts": {
35
35
  "build": "tsc",
36
36
  "e2e": "NODE_OPTIONS=--dns-result-order=ipv4first playwright test",
37
+ "test": "vitest",
37
38
  "docs": "typedoc src src/experimental",
38
39
  "format": "prettier --write . --ignore-path ./.eslintignore",
39
40
  "format:check": "prettier --check . --ignore-path ./.eslintignore",
@@ -43,18 +44,23 @@
43
44
  },
44
45
  "devDependencies": {
45
46
  "@playwright/test": "^1.51.1",
47
+ "@testing-library/dom": "^10.4.0",
48
+ "@testing-library/react": "^16.3.0",
46
49
  "@types/events": "^3.0.3",
47
50
  "@types/lodash.isequal": "^4.5.8",
48
- "@types/node": "^22.13.10",
49
- "@types/react": "^19.0.11",
51
+ "@types/node": "^22.14.0",
52
+ "@types/react": "^19.0.12",
53
+ "fake-mediastreamtrack": "^2.0.0",
54
+ "jsdom": "^26.0.0",
50
55
  "react": "^19.0.0",
51
56
  "typed-emitter": "^2.1.0",
52
- "typedoc": "^0.28.0",
57
+ "typedoc": "^0.28.2",
53
58
  "typedoc-plugin-mdn-links": "^5.0.1",
54
- "typescript": "^5.8.2"
59
+ "typescript": "^5.8.3",
60
+ "vitest": "^3.1.1"
55
61
  },
56
62
  "dependencies": {
57
- "@fishjam-cloud/ts-client": "0.15.0",
63
+ "@fishjam-cloud/ts-client": "0.16.0",
58
64
  "events": "3.3.0",
59
65
  "lodash.isequal": "4.5.0"
60
66
  },
@@ -1,9 +0,0 @@
1
- import type { SetStateAction } from "react";
2
- interface HandleTrackEndProps {
3
- stream: MediaStream | null;
4
- setStream: (action: SetStateAction<MediaStream | null>) => void;
5
- type: "audio" | "video";
6
- }
7
- export declare const useHandleTrackEnd: ({ stream, setStream, type }: HandleTrackEndProps) => void;
8
- export {};
9
- //# sourceMappingURL=useHandleStreamEnd.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useHandleStreamEnd.d.ts","sourceRoot":"","sources":["../../../../src/hooks/internal/devices/useHandleStreamEnd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAK5C,UAAU,mBAAmB;IAC3B,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC;IAChE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;CACzB;AAED,eAAO,MAAM,iBAAiB,GAAI,6BAA6B,mBAAmB,SAUjF,CAAC"}
@@ -1,13 +0,0 @@
1
- import { useEffect } from "react";
2
- import { getTrackFromStream } from "../../../utils/track";
3
- export const useHandleTrackEnd = ({ stream, setStream, type }) => {
4
- useEffect(() => {
5
- const track = stream && getTrackFromStream(stream, type);
6
- if (!track)
7
- return;
8
- track.onended = () => {
9
- track.stop();
10
- setStream(null);
11
- };
12
- }, [type, stream, setStream]);
13
- };