@fishjam-cloud/react-client 0.7.1 → 0.8.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 (64) hide show
  1. package/dist/DeviceManager.d.ts +25 -15
  2. package/dist/DeviceManager.d.ts.map +1 -1
  3. package/dist/DeviceManager.js +125 -79
  4. package/dist/devices/MiddlewareManager.d.ts +9 -0
  5. package/dist/devices/MiddlewareManager.d.ts.map +1 -0
  6. package/dist/devices/MiddlewareManager.js +26 -0
  7. package/dist/fishjamProvider.d.ts +5 -2
  8. package/dist/fishjamProvider.d.ts.map +1 -1
  9. package/dist/fishjamProvider.js +12 -4
  10. package/dist/hooks/deviceManagers/useDeviceManager.d.ts.map +1 -1
  11. package/dist/hooks/deviceManagers/useDeviceManager.js +2 -2
  12. package/dist/hooks/devices/useCamera.d.ts +7 -0
  13. package/dist/hooks/devices/useCamera.d.ts.map +1 -0
  14. package/dist/hooks/devices/useCamera.js +35 -0
  15. package/dist/hooks/devices/useInitializeDevices.d.ts +8 -0
  16. package/dist/hooks/devices/useInitializeDevices.d.ts.map +1 -0
  17. package/dist/hooks/devices/useInitializeDevices.js +41 -0
  18. package/dist/hooks/devices/useMicrophone.d.ts +7 -0
  19. package/dist/hooks/devices/useMicrophone.d.ts.map +1 -0
  20. package/dist/hooks/devices/useMicrophone.js +37 -0
  21. package/dist/hooks/public.d.ts +3 -1
  22. package/dist/hooks/public.d.ts.map +1 -1
  23. package/dist/hooks/public.js +3 -1
  24. package/dist/hooks/useFishjamContext.d.ts +4 -3
  25. package/dist/hooks/useFishjamContext.d.ts.map +1 -1
  26. package/dist/hooks/useScreenShare.d.ts +10 -1
  27. package/dist/hooks/useScreenShare.d.ts.map +1 -1
  28. package/dist/hooks/useScreenShare.js +34 -33
  29. package/dist/hooks/useTrackManager.d.ts +4 -2
  30. package/dist/hooks/useTrackManager.d.ts.map +1 -1
  31. package/dist/hooks/useTrackManager.js +55 -71
  32. package/dist/index.d.ts +1 -1
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/mediaInitializer.d.ts.map +1 -1
  35. package/dist/mediaInitializer.js +30 -1
  36. package/dist/types/internal.d.ts +20 -31
  37. package/dist/types/internal.d.ts.map +1 -1
  38. package/dist/types/public.d.ts +16 -5
  39. package/dist/types/public.d.ts.map +1 -1
  40. package/dist/utils/bandwidth.d.ts +3 -0
  41. package/dist/utils/bandwidth.d.ts.map +1 -0
  42. package/dist/utils/bandwidth.js +4 -0
  43. package/dist/utils/localStorage.d.ts +3 -4
  44. package/dist/utils/localStorage.d.ts.map +1 -1
  45. package/dist/utils/localStorage.js +18 -4
  46. package/dist/utils/track.d.ts +8 -2
  47. package/dist/utils/track.d.ts.map +1 -1
  48. package/dist/utils/track.js +23 -0
  49. package/package.json +5 -5
  50. package/dist/hooks/deviceManagers/useAudioDeviceManager.d.ts +0 -6
  51. package/dist/hooks/deviceManagers/useAudioDeviceManager.d.ts.map +0 -1
  52. package/dist/hooks/deviceManagers/useAudioDeviceManager.js +0 -11
  53. package/dist/hooks/deviceManagers/useVideoDeviceManager.d.ts +0 -6
  54. package/dist/hooks/deviceManagers/useVideoDeviceManager.d.ts.map +0 -1
  55. package/dist/hooks/deviceManagers/useVideoDeviceManager.js +0 -11
  56. package/dist/hooks/useDevices.d.ts +0 -19
  57. package/dist/hooks/useDevices.d.ts.map +0 -1
  58. package/dist/hooks/useDevices.js +0 -98
  59. package/dist/hooks/useProcessedPreviewStream.d.ts +0 -3
  60. package/dist/hooks/useProcessedPreviewStream.d.ts.map +0 -1
  61. package/dist/hooks/useProcessedPreviewStream.js +0 -17
  62. package/dist/utils/media.d.ts +0 -13
  63. package/dist/utils/media.d.ts.map +0 -1
  64. package/dist/utils/media.js +0 -64
@@ -0,0 +1,37 @@
1
+ import { useDeviceManager } from "../deviceManagers/useDeviceManager";
2
+ import { useFishjamContext } from "../useFishjamContext";
3
+ /**
4
+ *
5
+ * @category Devices
6
+ */
7
+ export function useMicrophone() {
8
+ const { audioTrackManager, audioDeviceManagerRef } = useFishjamContext();
9
+ const { deviceState, status } = useDeviceManager(audioDeviceManagerRef.current);
10
+ const { currentTrack, ...trackManager } = audioTrackManager;
11
+ const stream = deviceState.media?.stream ?? null;
12
+ const currentMiddleware = deviceState.currentMiddleware ?? null;
13
+ const isStreaming = Boolean(currentTrack?.stream);
14
+ const track = stream?.getAudioTracks()[0] ?? null;
15
+ const trackId = currentTrack?.trackId ?? null;
16
+ const devices = deviceState.devices ?? [];
17
+ const activeDevice = deviceState.media?.deviceInfo ?? null;
18
+ const isAudioPlaying = currentTrack?.vadStatus === "speech";
19
+ const isMuted = !deviceState.media?.enabled;
20
+ const deviceError = deviceState.error ?? null;
21
+ const isDeviceEnabled = Boolean(deviceState.media);
22
+ return {
23
+ ...trackManager,
24
+ currentMiddleware,
25
+ isDeviceEnabled,
26
+ status,
27
+ stream,
28
+ track,
29
+ isStreaming,
30
+ trackId,
31
+ devices,
32
+ activeDevice,
33
+ isMuted,
34
+ deviceError,
35
+ isAudioPlaying,
36
+ };
37
+ }
@@ -1,6 +1,8 @@
1
1
  export { useConnect, useDisconnect } from "./useConnection";
2
2
  export { useReconnection } from "./useReconnection";
3
- export { useCamera, useMicrophone, useInitializeDevices } from "./useDevices";
3
+ export { useCamera } from "./devices/useCamera";
4
+ export { useMicrophone } from "./devices/useMicrophone";
5
+ export { useInitializeDevices } from "./devices/useInitializeDevices";
4
6
  export { usePeers } from "./usePeers";
5
7
  export { useScreenShare } from "./useScreenShare";
6
8
  export { useStatus } from "./useStatus";
@@ -1 +1 @@
1
- {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/hooks/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/hooks/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
@@ -1,6 +1,8 @@
1
1
  export { useConnect, useDisconnect } from "./useConnection";
2
2
  export { useReconnection } from "./useReconnection";
3
- export { useCamera, useMicrophone, useInitializeDevices } from "./useDevices";
3
+ export { useCamera } from "./devices/useCamera";
4
+ export { useMicrophone } from "./devices/useMicrophone";
5
+ export { useInitializeDevices } from "./devices/useInitializeDevices";
4
6
  export { usePeers } from "./usePeers";
5
7
  export { useScreenShare } from "./useScreenShare";
6
8
  export { useStatus } from "./useStatus";
@@ -1,19 +1,20 @@
1
1
  import type { FishjamClient } from "@fishjam-cloud/ts-client";
2
2
  import { type MutableRefObject } from "react";
3
- import type { PeerMetadata, TrackMetadata, ScreenShareState, TrackManager } from "../types/internal";
3
+ import type { PeerMetadata, TrackMetadata, TrackManager } from "../types/internal";
4
4
  import type { DeviceManager } from "../DeviceManager";
5
5
  import type { FishjamClientState } from "./useFishjamClientState";
6
- import type { PeerStatus } from "../types/public";
6
+ import type { BandwidthLimits, PeerStatus, ScreenshareApi } from "../types/public";
7
7
  export type FishjamContextType = {
8
8
  fishjamClientRef: MutableRefObject<FishjamClient<PeerMetadata, TrackMetadata>>;
9
9
  videoDeviceManagerRef: MutableRefObject<DeviceManager>;
10
10
  audioDeviceManagerRef: MutableRefObject<DeviceManager>;
11
11
  hasDevicesBeenInitializedRef: MutableRefObject<boolean>;
12
- screenShareState: [ScreenShareState, React.Dispatch<React.SetStateAction<ScreenShareState>>];
12
+ screenShareManager: ScreenshareApi;
13
13
  peerStatus: PeerStatus;
14
14
  videoTrackManager: TrackManager;
15
15
  audioTrackManager: TrackManager;
16
16
  clientState: FishjamClientState;
17
+ bandwidthLimits: BandwidthLimits;
17
18
  };
18
19
  export declare const FishjamContext: import("react").Context<FishjamContextType | null>;
19
20
  export declare function useFishjamContext(): FishjamContextType;
@@ -1 +1 @@
1
- {"version":3,"file":"useFishjamContext.d.ts","sourceRoot":"","sources":["../../src/hooks/useFishjamContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAiB,KAAK,gBAAgB,EAAc,MAAM,OAAO,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACrG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,gBAAgB,EAAE,gBAAgB,CAAC,aAAa,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC,CAAC;IAC/E,qBAAqB,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAC;IACvD,qBAAqB,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAC;IACvD,4BAA4B,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACxD,gBAAgB,EAAE,CAAC,gBAAgB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAC7F,UAAU,EAAE,UAAU,CAAC;IACvB,iBAAiB,EAAE,YAAY,CAAC;IAChC,iBAAiB,EAAE,YAAY,CAAC;IAChC,WAAW,EAAE,kBAAkB,CAAC;CACjC,CAAC;AAEF,eAAO,MAAM,cAAc,oDAAiD,CAAC;AAE7E,wBAAgB,iBAAiB,IAGb,kBAAkB,CACrC"}
1
+ {"version":3,"file":"useFishjamContext.d.ts","sourceRoot":"","sources":["../../src/hooks/useFishjamContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAiB,KAAK,gBAAgB,EAAc,MAAM,OAAO,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEnF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,gBAAgB,EAAE,gBAAgB,CAAC,aAAa,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC,CAAC;IAC/E,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,cAAc,CAAC;IACnC,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,7 +1,16 @@
1
- import type { ScreenshareApi } from "../types/public";
1
+ import type { FishjamClient } from "@fishjam-cloud/ts-client";
2
+ import type { ScreenshareApi, PeerStatus } from "../types/public";
3
+ import type { PeerMetadata, TrackMetadata } from "../types/internal";
4
+ interface ScreenShareManagerProps {
5
+ fishjamClient: FishjamClient<PeerMetadata, TrackMetadata>;
6
+ getCurrentPeerStatus: () => PeerStatus;
7
+ }
2
8
  /**
3
9
  *
4
10
  * @category Screenshare
5
11
  */
12
+ export declare const useScreenShareManager: ({ fishjamClient, getCurrentPeerStatus, }: ScreenShareManagerProps) => ScreenshareApi;
6
13
  export declare const useScreenShare: () => ScreenshareApi;
14
+ export declare const getTracksFromStream: (stream: MediaStream) => [MediaStreamTrack, MediaStreamTrack | null];
15
+ export {};
7
16
  //# sourceMappingURL=useScreenShare.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useScreenShare.d.ts","sourceRoot":"","sources":["../../src/hooks/useScreenShare.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAQxE;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,cA0IjC,CAAC"}
1
+ {"version":3,"file":"useScreenShare.d.ts","sourceRoot":"","sources":["../../src/hooks/useScreenShare.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,OAAO,KAAK,EAAoB,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACpF,OAAO,KAAK,EAAE,YAAY,EAAoB,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvF,UAAU,uBAAuB;IAC/B,aAAa,EAAE,aAAa,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;IAC1D,oBAAoB,EAAE,MAAM,UAAU,CAAC;CACxC;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,6CAG/B,uBAAuB,KAAG,cAqI5B,CAAC;AAEF,eAAO,MAAM,cAAc,sBAI1B,CAAC;AAEF,eAAO,MAAM,mBAAmB,WAAY,WAAW,KAAG,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAKnG,CAAC"}
@@ -1,49 +1,41 @@
1
- import { useCallback, useEffect, useRef } from "react";
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
2
  import { getRemoteOrLocalTrack } from "../utils/track";
3
3
  import { useFishjamContext } from "./useFishjamContext";
4
- const getTracks = (stream) => {
5
- const video = stream.getVideoTracks()[0];
6
- const audio = stream.getAudioTracks()[0] ?? null;
7
- return [video, audio];
8
- };
9
4
  /**
10
5
  *
11
6
  * @category Screenshare
12
7
  */
13
- export const useScreenShare = () => {
14
- const ctx = useFishjamContext();
15
- const [state, setState] = ctx.screenShareState;
8
+ export const useScreenShareManager = ({ fishjamClient, getCurrentPeerStatus, }) => {
9
+ const [state, setState] = useState({ stream: null, trackIds: null });
16
10
  const cleanMiddlewareFnRef = useRef(null);
17
- const { fishjamClientRef } = useFishjamContext();
18
- const tsClient = fishjamClientRef.current;
19
11
  const stream = state.stream ?? null;
20
- const [videoTrack, audioTrack] = stream ? getTracks(stream) : [null, null];
21
- const getDisplayName = () => tsClient.getLocalPeer()?.metadata?.peer?.displayName;
12
+ const [videoTrack, audioTrack] = stream ? getTracksFromStream(stream) : [null, null];
13
+ const getDisplayName = () => fishjamClient.getLocalPeer()?.metadata?.peer?.displayName;
22
14
  const startStreaming = async (props) => {
23
15
  const stream = await navigator.mediaDevices.getDisplayMedia({
24
16
  video: props?.videoConstraints ?? true,
25
17
  audio: props?.audioConstraints ?? true,
26
18
  });
27
19
  const displayName = getDisplayName();
28
- let [video, audio] = getTracks(stream);
20
+ let [video, audio] = getTracksFromStream(stream);
29
21
  if (state.tracksMiddleware) {
30
22
  const { videoTrack, audioTrack, onClear } = state.tracksMiddleware(video, audio);
31
23
  video = videoTrack;
32
24
  audio = audioTrack;
33
25
  cleanMiddlewareFnRef.current = onClear;
34
26
  }
35
- const addTrackPromises = [tsClient.addTrack(video, { displayName, type: "screenShareVideo", paused: false })];
27
+ const addTrackPromises = [fishjamClient.addTrack(video, { displayName, type: "screenShareVideo", paused: false })];
36
28
  if (audio)
37
- addTrackPromises.push(tsClient.addTrack(audio, { displayName, type: "screenShareAudio", paused: false }));
29
+ addTrackPromises.push(fishjamClient.addTrack(audio, { displayName, type: "screenShareAudio", paused: false }));
38
30
  const [videoId, audioId] = await Promise.all(addTrackPromises);
39
31
  setState({ stream, trackIds: { videoId, audioId } });
40
32
  };
41
33
  const replaceTracks = async (newVideoTrack, newAudioTrack) => {
42
34
  if (!state?.stream)
43
35
  return;
44
- const addTrackPromises = [tsClient.replaceTrack(state.trackIds.videoId, newVideoTrack)];
36
+ const addTrackPromises = [fishjamClient.replaceTrack(state.trackIds.videoId, newVideoTrack)];
45
37
  if (newAudioTrack && state.trackIds.audioId) {
46
- addTrackPromises.push(tsClient.replaceTrack(state.trackIds.audioId, newAudioTrack));
38
+ addTrackPromises.push(fishjamClient.replaceTrack(state.trackIds.audioId, newAudioTrack));
47
39
  }
48
40
  await Promise.all(addTrackPromises);
49
41
  };
@@ -54,7 +46,7 @@ export const useScreenShare = () => {
54
46
  const setTracksMiddleware = async (middleware) => {
55
47
  if (!state?.stream)
56
48
  return;
57
- const [video, audio] = getTracks(state.stream);
49
+ const [video, audio] = getTracksFromStream(state.stream);
58
50
  cleanMiddleware();
59
51
  const { videoTrack, audioTrack, onClear } = middleware?.(video, audio) ?? {
60
52
  videoTrack: video,
@@ -69,22 +61,23 @@ export const useScreenShare = () => {
69
61
  console.warn("No stream to stop");
70
62
  return;
71
63
  }
72
- const [video, audio] = getTracks(state.stream);
64
+ const [video, audio] = getTracksFromStream(state.stream);
73
65
  video.stop();
74
66
  if (audio)
75
67
  audio.stop();
76
- const client = fishjamClientRef.current;
77
- const removeTrackPromises = [client.removeTrack(state.trackIds.videoId)];
78
- if (state.trackIds.audioId)
79
- removeTrackPromises.push(client.removeTrack(state.trackIds.audioId));
80
- await Promise.all(removeTrackPromises);
68
+ if (getCurrentPeerStatus() === "connected") {
69
+ const removeTrackPromises = [fishjamClient.removeTrack(state.trackIds.videoId)];
70
+ if (state.trackIds.audioId)
71
+ removeTrackPromises.push(fishjamClient.removeTrack(state.trackIds.audioId));
72
+ await Promise.all(removeTrackPromises);
73
+ }
81
74
  cleanMiddleware();
82
75
  setState(({ tracksMiddleware }) => ({ stream: null, trackIds: null, tracksMiddleware }));
83
- }, [state, fishjamClientRef, setState, cleanMiddleware]);
76
+ }, [state, fishjamClient, setState, cleanMiddleware, getCurrentPeerStatus]);
84
77
  useEffect(() => {
85
78
  if (!state.stream)
86
79
  return;
87
- const [video, audio] = getTracks(state.stream);
80
+ const [video, audio] = getTracksFromStream(state.stream);
88
81
  const trackEndedHandler = () => {
89
82
  stopStreaming();
90
83
  };
@@ -96,19 +89,18 @@ export const useScreenShare = () => {
96
89
  };
97
90
  }, [state, stopStreaming]);
98
91
  useEffect(() => {
99
- const client = fishjamClientRef.current;
100
92
  const onDisconnected = () => {
101
93
  if (stream) {
102
94
  stopStreaming();
103
95
  }
104
96
  };
105
- client.on("disconnected", onDisconnected);
97
+ fishjamClient.on("disconnected", onDisconnected);
106
98
  return () => {
107
- client.removeListener("disconnected", onDisconnected);
99
+ fishjamClient.removeListener("disconnected", onDisconnected);
108
100
  };
109
- }, [stopStreaming, fishjamClientRef, stream]);
110
- const videoBroadcast = state.stream ? getRemoteOrLocalTrack(tsClient, state.trackIds.videoId) : null;
111
- const audioBroadcast = state.trackIds?.audioId ? getRemoteOrLocalTrack(tsClient, state.trackIds.audioId) : null;
101
+ }, [stopStreaming, fishjamClient, stream]);
102
+ const videoBroadcast = state.stream ? getRemoteOrLocalTrack(fishjamClient, state.trackIds.videoId) : null;
103
+ const audioBroadcast = state.trackIds?.audioId ? getRemoteOrLocalTrack(fishjamClient, state.trackIds.audioId) : null;
112
104
  return {
113
105
  startStreaming,
114
106
  stopStreaming,
@@ -121,3 +113,12 @@ export const useScreenShare = () => {
121
113
  currentTracksMiddleware: state?.tracksMiddleware ?? null,
122
114
  };
123
115
  };
116
+ export const useScreenShare = () => {
117
+ const { screenShareManager } = useFishjamContext();
118
+ return screenShareManager;
119
+ };
120
+ export const getTracksFromStream = (stream) => {
121
+ const video = stream.getVideoTracks()[0];
122
+ const audio = stream.getAudioTracks()[0] ?? null;
123
+ return [video, audio];
124
+ };
@@ -1,11 +1,13 @@
1
1
  import type { FishjamClient } from "@fishjam-cloud/ts-client";
2
2
  import type { MediaManager, PeerMetadata, TrackManager, TrackMetadata } from "../types/internal";
3
- import type { PeerStatus } from "../types/public";
3
+ import type { BandwidthLimits, PeerStatus, StartStreamingProps } from "../types/public";
4
4
  interface TrackManagerConfig {
5
5
  mediaManager: MediaManager;
6
6
  tsClient: FishjamClient<PeerMetadata, TrackMetadata>;
7
7
  getCurrentPeerStatus: () => PeerStatus;
8
+ bandwidthLimits: BandwidthLimits;
9
+ autoStreamProps?: StartStreamingProps | false;
8
10
  }
9
- export declare const useTrackManager: ({ mediaManager, tsClient, getCurrentPeerStatus }: TrackManagerConfig) => TrackManager;
11
+ export declare const useTrackManager: ({ mediaManager, tsClient, getCurrentPeerStatus, bandwidthLimits, autoStreamProps, }: TrackManagerConfig) => TrackManager;
10
12
  export {};
11
13
  //# sourceMappingURL=useTrackManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useTrackManager.d.ts","sourceRoot":"","sources":["../../src/hooks/useTrackManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAwC,MAAM,0BAA0B,CAAC;AACpG,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGjG,OAAO,KAAK,EAAE,UAAU,EAA+B,MAAM,iBAAiB,CAAC;AAE/E,UAAU,kBAAkB;IAC1B,YAAY,EAAE,YAAY,CAAC;IAC3B,QAAQ,EAAE,aAAa,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;IACrD,oBAAoB,EAAE,MAAM,UAAU,CAAC;CACxC;AAOD,eAAO,MAAM,eAAe,qDAAsD,kBAAkB,KAAG,YA2MtG,CAAC"}
1
+ {"version":3,"file":"useTrackManager.d.ts","sourceRoot":"","sources":["../../src/hooks/useTrackManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGjG,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,mBAAmB,EAAmB,MAAM,iBAAiB,CAAC;AAEzG,UAAU,kBAAkB;IAC1B,YAAY,EAAE,YAAY,CAAC;IAC3B,QAAQ,EAAE,aAAa,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;IACrD,oBAAoB,EAAE,MAAM,UAAU,CAAC;IACvC,eAAe,EAAE,eAAe,CAAC;IACjC,eAAe,CAAC,EAAE,mBAAmB,GAAG,KAAK,CAAC;CAC/C;AAWD,eAAO,MAAM,eAAe,wFAMzB,kBAAkB,KAAG,YA0LvB,CAAC"}
@@ -1,51 +1,27 @@
1
- import { getRemoteOrLocalTrack } from "../utils/track";
2
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
1
+ import { getConfigAndBandwidthFromProps, getRemoteOrLocalTrack } from "../utils/track";
2
+ import { useCallback, useEffect, useMemo, useState } from "react";
3
3
  const TRACK_TYPE_TO_DEVICE = {
4
4
  video: "camera",
5
5
  audio: "microphone",
6
6
  };
7
- export const useTrackManager = ({ mediaManager, tsClient, getCurrentPeerStatus }) => {
7
+ const getDeviceType = (mediaManager) => TRACK_TYPE_TO_DEVICE[mediaManager.getDeviceType()];
8
+ export const useTrackManager = ({ mediaManager, tsClient, getCurrentPeerStatus, bandwidthLimits, autoStreamProps, }) => {
8
9
  const [currentTrackId, setCurrentTrackId] = useState(null);
9
10
  const [paused, setPaused] = useState(false);
10
- const clearMiddlewareFnRef = useRef(null);
11
- const [currentTrackMiddleware, setCurrentTrackMiddleware] = useState(null);
12
- const type = TRACK_TYPE_TO_DEVICE[mediaManager.getDeviceType()];
13
- const metadata = useMemo(() => ({ type, paused }), [type, paused]);
14
11
  const currentTrack = useMemo(() => getRemoteOrLocalTrack(tsClient, currentTrackId), [tsClient, currentTrackId]);
15
- function clearMiddleware() {
16
- clearMiddlewareFnRef.current?.();
17
- clearMiddlewareFnRef.current = null;
18
- }
19
- const clearAndGetProcessedTrack = useCallback((inputTrack) => {
20
- clearMiddleware();
21
- const { onClear, track } = currentTrackMiddleware?.(inputTrack) ?? {};
22
- if (onClear)
23
- clearMiddlewareFnRef.current = onClear;
24
- return track ?? inputTrack;
25
- }, [currentTrackMiddleware]);
26
12
  async function setTrackMiddleware(middleware) {
27
- const mediaTrack = mediaManager.getTracks()[0];
28
- setCurrentTrackMiddleware(() => middleware);
29
- if (!currentTrack || !mediaTrack)
30
- return;
31
- clearMiddleware();
32
- const { onClear, track } = middleware?.(mediaTrack) ?? { track: mediaTrack };
33
- if (onClear)
34
- clearMiddlewareFnRef.current = onClear;
35
- await tsClient.replaceTrack(currentTrack.trackId, track);
13
+ mediaManager.setTrackMiddleware(middleware);
14
+ await refreshStreamedTrack();
36
15
  }
37
16
  async function initialize(deviceId) {
38
17
  await mediaManager?.start(deviceId);
39
18
  if (!currentTrackId)
40
19
  return;
41
- const newTrack = mediaManager.getTracks()[0];
42
- await tsClient.replaceTrack(currentTrackId, clearAndGetProcessedTrack(newTrack));
43
- }
44
- function stop() {
45
- clearMiddleware();
46
- return mediaManager?.stop();
20
+ const newTrack = mediaManager.getMedia()?.track ?? null;
21
+ await tsClient.replaceTrack(currentTrackId, newTrack);
47
22
  }
48
- const startStreaming = useCallback(async (simulcastConfig, maxBandwidth) => {
23
+ const stop = useCallback(() => mediaManager.stop(), [mediaManager]);
24
+ const startStreaming = useCallback(async (props = { simulcast: ["l", "m", "h"] }) => {
49
25
  if (currentTrackId)
50
26
  throw Error("Track already added");
51
27
  const media = mediaManager.getMedia();
@@ -57,56 +33,57 @@ export const useTrackManager = ({ mediaManager, tsClient, getCurrentPeerStatus }
57
33
  // see `getRemoteOrLocalTrackContext()` explanation
58
34
  setCurrentTrackId(media.track.id);
59
35
  const displayName = tsClient.getLocalPeer()?.metadata?.peer?.displayName;
60
- const trackMetadata = { ...metadata, displayName, paused: false };
61
- const processedTrack = clearAndGetProcessedTrack(media.track);
62
- const remoteTrackId = await tsClient.addTrack(processedTrack, trackMetadata, simulcastConfig, maxBandwidth);
36
+ const deviceType = getDeviceType(mediaManager);
37
+ const trackMetadata = { type: deviceType, displayName, paused: false };
38
+ const [maxBandwidth, simulcastConfig] = getConfigAndBandwidthFromProps(props.simulcast, bandwidthLimits);
39
+ const remoteTrackId = await tsClient.addTrack(media.track, trackMetadata, simulcastConfig, maxBandwidth);
63
40
  setCurrentTrackId(remoteTrackId);
64
41
  setPaused(false);
65
42
  return remoteTrackId;
66
- }, [clearAndGetProcessedTrack, currentTrackId, mediaManager, metadata, tsClient]);
67
- async function refreshStreamedTrack() {
43
+ }, [currentTrackId, mediaManager, tsClient, bandwidthLimits]);
44
+ const refreshStreamedTrack = useCallback(async () => {
68
45
  if (!currentTrack)
69
46
  return;
70
- const newTrack = mediaManager.getTracks()[0];
47
+ const newTrack = mediaManager.getMedia()?.track ?? null;
71
48
  if (!newTrack)
72
49
  throw Error("New track is empty");
73
- return tsClient.replaceTrack(currentTrack.trackId, clearAndGetProcessedTrack(newTrack));
74
- }
75
- async function stopStreaming() {
50
+ return tsClient.replaceTrack(currentTrack.trackId, newTrack);
51
+ }, [currentTrack, mediaManager, tsClient]);
52
+ const stopStreaming = useCallback(async () => {
76
53
  if (!currentTrack)
77
54
  return;
78
- clearMiddleware();
79
55
  setCurrentTrackId(null);
80
56
  setPaused(true);
81
57
  return tsClient.removeTrack(currentTrack.trackId);
82
- }
83
- async function pauseStreaming() {
58
+ }, [currentTrack, tsClient]);
59
+ const pauseStreaming = useCallback(async () => {
84
60
  if (!currentTrack)
85
61
  return;
86
62
  setPaused(true);
87
63
  await tsClient.replaceTrack(currentTrack.trackId, null);
88
- const trackMetadata = { ...metadata, paused: true };
64
+ const deviceType = getDeviceType(mediaManager);
65
+ const trackMetadata = { type: deviceType, paused: true };
89
66
  return tsClient.updateTrackMetadata(currentTrack.trackId, trackMetadata);
90
- }
91
- async function resumeStreaming() {
67
+ }, [currentTrack, mediaManager, tsClient]);
68
+ const resumeStreaming = useCallback(async () => {
92
69
  if (!currentTrack)
93
70
  return;
94
71
  const media = mediaManager.getMedia();
72
+ const deviceType = getDeviceType(mediaManager);
95
73
  if (!media)
96
74
  throw Error("Device is unavailable");
97
- const processedTrack = media.track ? clearAndGetProcessedTrack(media.track) : null;
98
75
  setPaused(false);
99
- await tsClient.replaceTrack(currentTrack.trackId, processedTrack);
100
- const trackMetadata = { ...metadata, paused: false };
76
+ await tsClient.replaceTrack(currentTrack.trackId, media.track);
77
+ const trackMetadata = { type: deviceType, paused: false };
101
78
  return tsClient.updateTrackMetadata(currentTrack.trackId, trackMetadata);
102
- }
103
- function disableTrack() {
79
+ }, [currentTrack, mediaManager, tsClient]);
80
+ const disableTrack = useCallback(() => {
104
81
  mediaManager.disable();
105
- }
106
- function enableTrack() {
82
+ }, [mediaManager]);
83
+ const enableTrack = useCallback(() => {
107
84
  mediaManager.enable();
108
- }
109
- const stream = async () => {
85
+ }, [mediaManager]);
86
+ const stream = useCallback(async () => {
110
87
  if (getCurrentPeerStatus() !== "connected")
111
88
  return;
112
89
  if (currentTrack?.trackId) {
@@ -115,13 +92,10 @@ export const useTrackManager = ({ mediaManager, tsClient, getCurrentPeerStatus }
115
92
  else {
116
93
  await startStreaming();
117
94
  }
118
- };
119
- /**
120
- * @see {@link TrackManager#toggle} for more details.
121
- */
122
- async function toggle(mode = "hard") {
95
+ }, [currentTrack?.trackId, getCurrentPeerStatus, resumeStreaming, startStreaming]);
96
+ const toggle = useCallback(async (mode) => {
123
97
  const mediaStream = mediaManager.getMedia()?.stream;
124
- const track = mediaManager.getTracks()?.[0];
98
+ const track = mediaManager.getMedia()?.track ?? null;
125
99
  const enabled = Boolean(track?.enabled);
126
100
  if (mediaStream && enabled) {
127
101
  mediaManager.disable();
@@ -129,7 +103,7 @@ export const useTrackManager = ({ mediaManager, tsClient, getCurrentPeerStatus }
129
103
  await pauseStreaming();
130
104
  }
131
105
  if (mode === "hard") {
132
- await mediaManager.stop();
106
+ mediaManager.stop();
133
107
  }
134
108
  }
135
109
  else if (mediaStream && !enabled) {
@@ -140,11 +114,21 @@ export const useTrackManager = ({ mediaManager, tsClient, getCurrentPeerStatus }
140
114
  await mediaManager.start();
141
115
  await stream();
142
116
  }
143
- }
117
+ }, [currentTrack, mediaManager, pauseStreaming, stream]);
118
+ /**
119
+ * @see {@link TrackManager#toggleMute} for more details.
120
+ */
121
+ const toggleMute = useCallback(() => toggle("soft"), [toggle]);
122
+ /**
123
+ * @see {@link TrackManager#toggleDevice} for more details.
124
+ */
125
+ const toggleDevice = useCallback(() => toggle("hard"), [toggle]);
144
126
  useEffect(() => {
127
+ if (autoStreamProps === false)
128
+ return;
145
129
  const joinedHandler = () => {
146
- if (mediaManager.getTracks().length > 0) {
147
- startStreaming();
130
+ if (mediaManager.getMedia()?.track) {
131
+ startStreaming(autoStreamProps);
148
132
  }
149
133
  };
150
134
  const disconnectedHandler = () => {
@@ -156,7 +140,7 @@ export const useTrackManager = ({ mediaManager, tsClient, getCurrentPeerStatus }
156
140
  tsClient.off("joined", joinedHandler);
157
141
  tsClient.off("disconnected", disconnectedHandler);
158
142
  };
159
- }, [mediaManager, startStreaming, tsClient]);
143
+ }, [mediaManager, startStreaming, tsClient, autoStreamProps]);
160
144
  return {
161
145
  currentTrack,
162
146
  setTrackMiddleware,
@@ -168,9 +152,9 @@ export const useTrackManager = ({ mediaManager, tsClient, getCurrentPeerStatus }
168
152
  resumeStreaming,
169
153
  disableTrack,
170
154
  enableTrack,
171
- currentTrackMiddleware,
172
155
  refreshStreamedTrack,
173
156
  paused,
174
- toggle,
157
+ toggleMute,
158
+ toggleDevice,
175
159
  };
176
160
  };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { useConnect, useDisconnect, useReconnection, useCamera, useMicrophone, useInitializeDevices, usePeers, useScreenShare, useStatus, } from "./hooks/public";
2
2
  export { FishjamProvider } from "./fishjamProvider";
3
- export { Track, TrackMiddleware, TracksMiddleware, PeerStatus, ToggleMode, Device, AudioDevice, PeerWithTracks, ConnectConfig, PersistLastDeviceHandlers, ScreenshareApi, } from "./types/public";
3
+ export { Track, TrackMiddleware, TracksMiddleware, PeerStatus, Device, AudioDevice, PeerWithTracks, ConnectConfig, PersistLastDeviceHandlers, ScreenshareApi, StartStreamingProps, } from "./types/public";
4
4
  export { AUDIO_TRACK_CONSTRAINTS, VIDEO_TRACK_CONSTRAINTS, SCREEN_SHARING_MEDIA_CONSTRAINTS } from "./constraints";
5
5
  export type { Peer, MessageEvents, CreateConfig, TrackBandwidthLimit, SimulcastBandwidthLimit, BandwidthLimit, WebRTCEndpointEvents, TrackContextEvents, Endpoint, SimulcastConfig, TrackContext, VadStatus, EncodingReason, MetadataParser, AuthErrorReason, Encoding, } from "@fishjam-cloud/ts-client";
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,aAAa,EACb,eAAe,EACf,SAAS,EACT,aAAa,EACb,oBAAoB,EACpB,QAAQ,EACR,cAAc,EACd,SAAS,GACV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EACL,KAAK,EACL,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,MAAM,EACN,WAAW,EACX,cAAc,EACd,aAAa,EACb,yBAAyB,EACzB,cAAc,GACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,gCAAgC,EAAE,MAAM,eAAe,CAAC;AAEnH,YAAY,EACV,IAAI,EACJ,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,uBAAuB,EACvB,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,SAAS,EACT,cAAc,EACd,cAAc,EACd,eAAe,EACf,QAAQ,GACT,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,aAAa,EACb,eAAe,EACf,SAAS,EACT,aAAa,EACb,oBAAoB,EACpB,QAAQ,EACR,cAAc,EACd,SAAS,GACV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EACL,KAAK,EACL,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,MAAM,EACN,WAAW,EACX,cAAc,EACd,aAAa,EACb,yBAAyB,EACzB,cAAc,EACd,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,gCAAgC,EAAE,MAAM,eAAe,CAAC;AAEnH,YAAY,EACV,IAAI,EACJ,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,uBAAuB,EACvB,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,SAAS,EACT,cAAc,EACd,cAAc,EACd,eAAe,EACf,QAAQ,GACT,MAAM,0BAA0B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"mediaInitializer.d.ts","sourceRoot":"","sources":["../src/mediaInitializer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AASpD,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/mediaInitializer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpE,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,6 +1,5 @@
1
1
  import { prepareConstraints } from "./constraints";
2
2
  import { NOT_FOUND_ERROR, OVERCONSTRAINED_ERROR, PERMISSION_DENIED, UNHANDLED_ERROR } from "./utils/errors";
3
- import { getCurrentDevicesSettings, stopTracks, isAnyDeviceDifferentFromLastSession, removeSpecifiedDeviceFromConstraints, } from "./utils/media";
4
3
  const defaultErrors = { audio: null, video: null };
5
4
  const tryToGetAudioOnlyThenVideoOnly = async (constraints, deviceErrors = defaultErrors, transformConstraint = () => false) => {
6
5
  const audioOnly = await getAvailableMedia({ ...constraints, video: transformConstraint(constraints.video) }, { ...deviceErrors, audio: null });
@@ -46,3 +45,33 @@ export const getCorrectedResult = async (stream, deviceErrors, devices, constrai
46
45
  };
47
46
  return await getAvailableMedia(exactConstraints, deviceErrors);
48
47
  };
48
+ const getCurrentDevicesSettings = (requestedDevices, mediaDeviceInfos) => {
49
+ const currentDevices = { videoinput: null, audioinput: null };
50
+ for (const track of requestedDevices.getTracks()) {
51
+ const settings = track.getSettings();
52
+ if (settings.deviceId) {
53
+ const currentDevice = mediaDeviceInfos.find((device) => device.deviceId == settings.deviceId);
54
+ const kind = currentDevice?.kind ?? null;
55
+ if ((currentDevice && kind === "videoinput") || kind === "audioinput") {
56
+ currentDevices[kind] = currentDevice ?? null;
57
+ }
58
+ }
59
+ }
60
+ return currentDevices;
61
+ };
62
+ const isDeviceDifferentFromLastSession = (lastDevice, currentDevice) => lastDevice && (currentDevice?.deviceId !== lastDevice.deviceId || currentDevice?.label !== lastDevice?.label);
63
+ const isAnyDeviceDifferentFromLastSession = (lastVideoDevice, lastAudioDevice, currentDevices) => !!((currentDevices?.videoinput &&
64
+ isDeviceDifferentFromLastSession(lastVideoDevice, currentDevices?.videoinput || null)) ||
65
+ (currentDevices?.audioinput &&
66
+ isDeviceDifferentFromLastSession(lastAudioDevice, currentDevices?.audioinput || null)));
67
+ const stopTracks = (requestedDevices) => {
68
+ for (const track of requestedDevices.getTracks()) {
69
+ track.stop();
70
+ }
71
+ };
72
+ const removeSpecifiedDeviceFromConstraints = (trackConstraints) => {
73
+ if (typeof trackConstraints === "object") {
74
+ return { ...trackConstraints, deviceId: undefined };
75
+ }
76
+ return trackConstraints;
77
+ };