@fishjam-cloud/react-client 0.6.0 → 0.7.1

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 (111) hide show
  1. package/dist/DeviceManager.d.ts +15 -10
  2. package/dist/DeviceManager.d.ts.map +1 -1
  3. package/dist/DeviceManager.js +29 -35
  4. package/dist/constraints.d.ts +2 -22
  5. package/dist/constraints.d.ts.map +1 -1
  6. package/dist/constraints.js +11 -16
  7. package/dist/fishjamProvider.d.ts +10 -8
  8. package/dist/fishjamProvider.d.ts.map +1 -1
  9. package/dist/fishjamProvider.js +47 -23
  10. package/dist/hooks/deviceManagers/useAudioDeviceManager.d.ts +6 -0
  11. package/dist/hooks/deviceManagers/useAudioDeviceManager.d.ts.map +1 -0
  12. package/dist/hooks/deviceManagers/useAudioDeviceManager.js +11 -0
  13. package/dist/hooks/deviceManagers/useDeviceManager.d.ts +4 -0
  14. package/dist/hooks/deviceManagers/useDeviceManager.d.ts.map +1 -0
  15. package/dist/hooks/deviceManagers/useDeviceManager.js +39 -0
  16. package/dist/hooks/deviceManagers/useVideoDeviceManager.d.ts +6 -0
  17. package/dist/hooks/deviceManagers/useVideoDeviceManager.d.ts.map +1 -0
  18. package/dist/hooks/deviceManagers/useVideoDeviceManager.js +11 -0
  19. package/dist/hooks/internal.d.ts +2 -0
  20. package/dist/hooks/internal.d.ts.map +1 -0
  21. package/dist/hooks/internal.js +1 -0
  22. package/dist/hooks/public.d.ts +6 -6
  23. package/dist/hooks/public.d.ts.map +1 -1
  24. package/dist/hooks/public.js +6 -6
  25. package/dist/hooks/useConnection.d.ts +12 -0
  26. package/dist/hooks/useConnection.d.ts.map +1 -0
  27. package/dist/hooks/useConnection.js +20 -0
  28. package/dist/hooks/useDevices.d.ts +19 -0
  29. package/dist/hooks/useDevices.d.ts.map +1 -0
  30. package/dist/hooks/useDevices.js +98 -0
  31. package/dist/hooks/useFishjamClientState.d.ts +10 -0
  32. package/dist/hooks/useFishjamClientState.d.ts.map +1 -0
  33. package/dist/hooks/{clientState.js → useFishjamClientState.js} +49 -34
  34. package/dist/hooks/useFishjamClient_DO_NOT_USE.d.ts +7 -0
  35. package/dist/hooks/useFishjamClient_DO_NOT_USE.d.ts.map +1 -0
  36. package/dist/hooks/useFishjamClient_DO_NOT_USE.js +11 -0
  37. package/dist/hooks/useFishjamContext.d.ts +20 -0
  38. package/dist/hooks/useFishjamContext.d.ts.map +1 -0
  39. package/dist/hooks/usePeerStatus.d.ts +8 -0
  40. package/dist/hooks/usePeerStatus.d.ts.map +1 -0
  41. package/dist/hooks/usePeerStatus.js +39 -0
  42. package/dist/hooks/usePeers.d.ts +10 -0
  43. package/dist/hooks/usePeers.d.ts.map +1 -0
  44. package/dist/hooks/usePeers.js +19 -0
  45. package/dist/hooks/useProcessedPreviewStream.d.ts +3 -0
  46. package/dist/hooks/useProcessedPreviewStream.d.ts.map +1 -0
  47. package/dist/hooks/useProcessedPreviewStream.js +17 -0
  48. package/dist/hooks/useReconnection.d.ts +7 -0
  49. package/dist/hooks/useReconnection.d.ts.map +1 -0
  50. package/dist/hooks/useReconnection.js +31 -0
  51. package/dist/hooks/useScreenShare.d.ts +7 -0
  52. package/dist/hooks/useScreenShare.d.ts.map +1 -0
  53. package/dist/hooks/{screenShare.js → useScreenShare.js} +53 -24
  54. package/dist/hooks/useStatus.d.ts +6 -0
  55. package/dist/hooks/useStatus.d.ts.map +1 -0
  56. package/dist/hooks/useStatus.js +8 -0
  57. package/dist/hooks/useTrackManager.d.ts +11 -0
  58. package/dist/hooks/useTrackManager.d.ts.map +1 -0
  59. package/dist/hooks/useTrackManager.js +176 -0
  60. package/dist/index.d.ts +3 -8
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +2 -4
  63. package/dist/mediaInitializer.d.ts +2 -2
  64. package/dist/mediaInitializer.d.ts.map +1 -1
  65. package/dist/types/internal.d.ts +129 -0
  66. package/dist/types/internal.d.ts.map +1 -0
  67. package/dist/types/public.d.ts +65 -0
  68. package/dist/types/public.d.ts.map +1 -0
  69. package/dist/utils/errors.d.ts +1 -1
  70. package/dist/utils/errors.d.ts.map +1 -1
  71. package/dist/utils/media.d.ts +3 -2
  72. package/dist/utils/media.d.ts.map +1 -1
  73. package/dist/utils/track.d.ts +2 -2
  74. package/dist/utils/track.d.ts.map +1 -1
  75. package/dist/utils/track.js +0 -2
  76. package/package.json +12 -15
  77. package/readme.md +20 -118
  78. package/dist/Client.d.ts +0 -198
  79. package/dist/Client.d.ts.map +0 -1
  80. package/dist/Client.js +0 -461
  81. package/dist/hooks/clientState.d.ts +0 -4
  82. package/dist/hooks/clientState.d.ts.map +0 -1
  83. package/dist/hooks/connection.d.ts +0 -6
  84. package/dist/hooks/connection.d.ts.map +0 -1
  85. package/dist/hooks/connection.js +0 -28
  86. package/dist/hooks/devices.d.ts +0 -4
  87. package/dist/hooks/devices.d.ts.map +0 -1
  88. package/dist/hooks/devices.js +0 -9
  89. package/dist/hooks/fishjamContext.d.ts +0 -4
  90. package/dist/hooks/fishjamContext.d.ts.map +0 -1
  91. package/dist/hooks/participants.d.ts +0 -6
  92. package/dist/hooks/participants.d.ts.map +0 -1
  93. package/dist/hooks/participants.js +0 -13
  94. package/dist/hooks/screenShare.d.ts +0 -3
  95. package/dist/hooks/screenShare.d.ts.map +0 -1
  96. package/dist/hooks/setupMedia.d.ts +0 -3
  97. package/dist/hooks/setupMedia.d.ts.map +0 -1
  98. package/dist/hooks/setupMedia.js +0 -200
  99. package/dist/hooks/state.d.ts +0 -6
  100. package/dist/hooks/state.d.ts.map +0 -1
  101. package/dist/hooks/state.js +0 -15
  102. package/dist/state.types.d.ts +0 -55
  103. package/dist/state.types.d.ts.map +0 -1
  104. package/dist/trackManager.d.ts +0 -9
  105. package/dist/trackManager.d.ts.map +0 -1
  106. package/dist/trackManager.js +0 -116
  107. package/dist/types.d.ts +0 -235
  108. package/dist/types.d.ts.map +0 -1
  109. /package/dist/hooks/{fishjamContext.js → useFishjamContext.js} +0 -0
  110. /package/dist/{state.types.js → types/internal.js} +0 -0
  111. /package/dist/{types.js → types/public.js} +0 -0
@@ -0,0 +1,98 @@
1
+ import { useFishjamContext } from "./useFishjamContext";
2
+ import { useVideoDeviceManager } from "./deviceManagers/useVideoDeviceManager";
3
+ import { useAudioDeviceManager } from "./deviceManagers/useAudioDeviceManager";
4
+ import { useCallback } from "react";
5
+ import { getAvailableMedia, getCorrectedResult } from "../mediaInitializer";
6
+ import { useProcessedPreviewStream } from "./useProcessedPreviewStream";
7
+ import { prepareConstraints } from "../constraints";
8
+ /**
9
+ *
10
+ * @category Devices
11
+ */
12
+ export function useCamera() {
13
+ const { videoTrackManager } = useFishjamContext();
14
+ const { deviceState, status } = useVideoDeviceManager();
15
+ const { currentTrack, ...trackManager } = videoTrackManager;
16
+ const processedPreviewStream = useProcessedPreviewStream(videoTrackManager, deviceState.media?.track);
17
+ const stream = currentTrack?.stream ?? processedPreviewStream ?? deviceState.media?.stream ?? null;
18
+ const isStreaming = Boolean(currentTrack?.stream);
19
+ const track = stream?.getAudioTracks()[0] ?? null;
20
+ const trackId = currentTrack?.trackId ?? null;
21
+ const devices = deviceState.devices ?? [];
22
+ const activeDevice = deviceState.media?.deviceInfo ?? null;
23
+ return {
24
+ ...trackManager,
25
+ status,
26
+ stream,
27
+ devices,
28
+ activeDevice,
29
+ isStreaming,
30
+ track,
31
+ trackId,
32
+ };
33
+ }
34
+ /**
35
+ *
36
+ * @category Devices
37
+ */
38
+ export function useMicrophone() {
39
+ const { audioTrackManager } = useFishjamContext();
40
+ const { deviceState, status } = useAudioDeviceManager();
41
+ const { currentTrack, ...trackManager } = audioTrackManager;
42
+ const processedPreviewStream = useProcessedPreviewStream(audioTrackManager, deviceState.media?.track);
43
+ const stream = currentTrack?.stream ?? processedPreviewStream ?? deviceState.media?.stream ?? null;
44
+ const isStreaming = Boolean(currentTrack?.stream);
45
+ const track = stream?.getAudioTracks()[0] ?? null;
46
+ const trackId = currentTrack?.trackId ?? null;
47
+ const devices = deviceState.devices ?? [];
48
+ const activeDevice = deviceState.media?.deviceInfo ?? null;
49
+ const isAudioPlaying = currentTrack?.vadStatus === "speech";
50
+ return {
51
+ ...trackManager,
52
+ status,
53
+ stream,
54
+ isStreaming,
55
+ track,
56
+ trackId,
57
+ devices,
58
+ activeDevice,
59
+ isAudioPlaying,
60
+ };
61
+ }
62
+ /**
63
+ *
64
+ * @category Devices
65
+ */
66
+ export const useInitializeDevices = () => {
67
+ const { videoDeviceManagerRef, audioDeviceManagerRef, hasDevicesBeenInitializedRef } = useFishjamContext();
68
+ const initializeDevices = useCallback(async () => {
69
+ if (hasDevicesBeenInitializedRef.current)
70
+ return;
71
+ hasDevicesBeenInitializedRef.current = true;
72
+ const videoManager = videoDeviceManagerRef.current;
73
+ const audioManager = audioDeviceManagerRef.current;
74
+ const constraints = {
75
+ video: videoManager.getConstraints(),
76
+ audio: audioManager.getConstraints(),
77
+ };
78
+ const previousDevices = {
79
+ video: videoManager.getLastDevice(),
80
+ audio: audioManager.getLastDevice(),
81
+ };
82
+ // Attempt to start the last selected device to avoid an unnecessary restart.
83
+ // Without this, the first device will start, and `getCorrectedResult` will attempt to fix it.
84
+ let [stream, deviceErrors] = await getAvailableMedia({
85
+ video: prepareConstraints(previousDevices.video?.deviceId, constraints.video),
86
+ audio: prepareConstraints(previousDevices.audio?.deviceId, constraints.audio),
87
+ });
88
+ const devices = await navigator.mediaDevices.enumerateDevices();
89
+ const videoDevices = devices.filter(({ kind }) => kind === "videoinput");
90
+ const audioDevices = devices.filter(({ kind }) => kind === "audioinput");
91
+ if (stream) {
92
+ [stream, deviceErrors] = await getCorrectedResult(stream, deviceErrors, devices, constraints, previousDevices);
93
+ }
94
+ videoManager.initialize(stream, stream?.getVideoTracks()?.[0] ?? null, videoDevices, !!constraints.video, deviceErrors.video);
95
+ audioManager.initialize(stream, stream?.getAudioTracks()?.[0] ?? null, audioDevices, !!constraints.audio, deviceErrors.audio);
96
+ }, [videoDeviceManagerRef, audioDeviceManagerRef, hasDevicesBeenInitializedRef]);
97
+ return { initializeDevices };
98
+ };
@@ -0,0 +1,10 @@
1
+ import type { FishjamClient } from "@fishjam-cloud/ts-client";
2
+ import type { PeerMetadata, PeerState, TrackMetadata } from "../types/internal";
3
+ export interface FishjamClientState {
4
+ peers: PeerState[];
5
+ components: PeerState[];
6
+ localPeer: PeerState | null;
7
+ isReconnecting: boolean;
8
+ }
9
+ export declare function useFishjamClientState(fishjamClient: FishjamClient<PeerMetadata, TrackMetadata>): FishjamClientState;
10
+ //# sourceMappingURL=useFishjamClientState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFishjamClientState.d.ts","sourceRoot":"","sources":["../../src/hooks/useFishjamClientState.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA0D,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACtH,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAW,aAAa,EAAE,MAAM,mBAAmB,CAAC;AA2CzF,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;CACzB;AAmCD,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,aAAa,CAAC,YAAY,EAAE,aAAa,CAAC,GAAG,kBAAkB,CAyCnH"}
@@ -1,38 +1,29 @@
1
- import { useCallback, useRef, useSyncExternalStore } from "react";
1
+ import { useCallback, useMemo, useRef, useSyncExternalStore } from "react";
2
2
  const eventNames = [
3
- "socketOpen",
4
- "socketError",
5
3
  "socketClose",
4
+ "socketError",
5
+ "socketOpen",
6
6
  "authSuccess",
7
7
  "authError",
8
8
  "disconnected",
9
- "joined",
10
- "joinError",
11
- "peerJoined",
12
- "peerUpdated",
13
- "peerLeft",
9
+ "reconnectionStarted",
14
10
  "reconnected",
15
11
  "reconnectionRetriesLimitReached",
16
- "reconnectionStarted",
17
- "componentAdded",
18
- "componentUpdated",
19
- "componentRemoved",
12
+ "joined",
13
+ "joinError",
20
14
  "trackReady",
21
15
  "trackAdded",
22
16
  "trackRemoved",
23
17
  "trackUpdated",
18
+ "peerJoined",
19
+ "peerLeft",
20
+ "peerUpdated",
21
+ "componentAdded",
22
+ "componentRemoved",
23
+ "componentUpdated",
24
+ "connectionError",
25
+ "tracksPriorityChanged",
24
26
  "bandwidthEstimationChanged",
25
- "encodingChanged",
26
- "voiceActivityChanged",
27
- "deviceDisabled",
28
- "deviceEnabled",
29
- "managerInitialized",
30
- "managerStarted",
31
- "deviceStopped",
32
- "deviceReady",
33
- "devicesStarted",
34
- "devicesReady",
35
- "error",
36
27
  "targetTrackEncodingRequested",
37
28
  "localTrackAdded",
38
29
  "localTrackRemoved",
@@ -47,7 +38,31 @@ const eventNames = [
47
38
  "localTrackMetadataChanged",
48
39
  "disconnectRequested",
49
40
  ];
50
- export const useClientState = (client) => {
41
+ function trackContextToTrack(track) {
42
+ return {
43
+ metadata: track.metadata,
44
+ trackId: track.trackId,
45
+ stream: track.stream,
46
+ simulcastConfig: track.simulcastConfig ?? null,
47
+ encoding: track.encoding ?? null,
48
+ vadStatus: track.vadStatus,
49
+ track: track.track,
50
+ };
51
+ }
52
+ function endpointToPeerState(peer) {
53
+ const tracks = [...peer.tracks].reduce((acc, [, track]) => ({ ...acc, [track.trackId]: trackContextToTrack(track) }), {});
54
+ return {
55
+ metadata: peer.metadata,
56
+ id: peer.id,
57
+ tracks,
58
+ };
59
+ }
60
+ /*
61
+ This is an internally used hook.
62
+ It is not meant to be used by the end user.
63
+ */
64
+ export function useFishjamClientState(fishjamClient) {
65
+ const client = useMemo(() => fishjamClient, [fishjamClient]);
51
66
  const mutationRef = useRef(false);
52
67
  const subscribe = useCallback((subscribeCallback) => {
53
68
  const callback = () => {
@@ -62,20 +77,20 @@ export const useClientState = (client) => {
62
77
  const lastSnapshotRef = useRef(null);
63
78
  const getSnapshot = useCallback(() => {
64
79
  if (mutationRef.current || lastSnapshotRef.current === null) {
80
+ const peers = Object.values(client.getRemotePeers()).map(endpointToPeerState);
81
+ const components = Object.values(client.getRemoteComponents()).map(endpointToPeerState);
82
+ const localEndpoint = client.getLocalPeer();
83
+ const localPeer = localEndpoint ? endpointToPeerState(localEndpoint) : null;
84
+ const isReconnecting = client.isReconnecting();
65
85
  lastSnapshotRef.current = {
66
- remote: client.peers,
67
- media: client.media,
68
- bandwidthEstimation: client.bandwidthEstimation,
69
- tracks: client.peersTracks,
70
- local: client.local,
71
- status: client.status,
72
- devices: client.devices,
73
- client: client,
74
- reconnectionStatus: client.reconnectionStatus,
86
+ peers,
87
+ components,
88
+ localPeer,
89
+ isReconnecting,
75
90
  };
76
91
  mutationRef.current = false;
77
92
  }
78
93
  return lastSnapshotRef.current;
79
94
  }, [client]);
80
95
  return useSyncExternalStore(subscribe, getSnapshot);
81
- };
96
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ *
3
+ * @category Connection
4
+ * @deprecated
5
+ */
6
+ export declare function useFishjamClient_DO_NOT_USE(): import("@fishjam-cloud/ts-client").FishjamClient<import("../types/internal").PeerMetadata, import("../types/internal").TrackMetadata>;
7
+ //# sourceMappingURL=useFishjamClient_DO_NOT_USE.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFishjamClient_DO_NOT_USE.d.ts","sourceRoot":"","sources":["../../src/hooks/useFishjamClient_DO_NOT_USE.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,2BAA2B,0IAI1C"}
@@ -0,0 +1,11 @@
1
+ import { useFishjamContext } from "./useFishjamContext";
2
+ import { useMemo } from "react";
3
+ /**
4
+ *
5
+ * @category Connection
6
+ * @deprecated
7
+ */
8
+ export function useFishjamClient_DO_NOT_USE() {
9
+ const client = useFishjamContext().fishjamClientRef.current;
10
+ return useMemo(() => client, [client]);
11
+ }
@@ -0,0 +1,20 @@
1
+ import type { FishjamClient } from "@fishjam-cloud/ts-client";
2
+ import { type MutableRefObject } from "react";
3
+ import type { PeerMetadata, TrackMetadata, ScreenShareState, TrackManager } from "../types/internal";
4
+ import type { DeviceManager } from "../DeviceManager";
5
+ import type { FishjamClientState } from "./useFishjamClientState";
6
+ import type { PeerStatus } from "../types/public";
7
+ export type FishjamContextType = {
8
+ fishjamClientRef: MutableRefObject<FishjamClient<PeerMetadata, TrackMetadata>>;
9
+ videoDeviceManagerRef: MutableRefObject<DeviceManager>;
10
+ audioDeviceManagerRef: MutableRefObject<DeviceManager>;
11
+ hasDevicesBeenInitializedRef: MutableRefObject<boolean>;
12
+ screenShareState: [ScreenShareState, React.Dispatch<React.SetStateAction<ScreenShareState>>];
13
+ peerStatus: PeerStatus;
14
+ videoTrackManager: TrackManager;
15
+ audioTrackManager: TrackManager;
16
+ clientState: FishjamClientState;
17
+ };
18
+ export declare const FishjamContext: import("react").Context<FishjamContextType | null>;
19
+ export declare function useFishjamContext(): FishjamContextType;
20
+ //# sourceMappingURL=useFishjamContext.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,8 @@
1
+ import type { FishjamClient } from "@fishjam-cloud/ts-client";
2
+ import type { PeerMetadata, TrackMetadata } from "../types/internal";
3
+ import type { PeerStatus } from "../types/public";
4
+ export declare const usePeerStatus: (client: FishjamClient<PeerMetadata, TrackMetadata>) => {
5
+ readonly peerStatus: PeerStatus;
6
+ readonly getCurrentPeerStatus: () => PeerStatus;
7
+ };
8
+ //# sourceMappingURL=usePeerStatus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePeerStatus.d.ts","sourceRoot":"","sources":["../../src/hooks/usePeerStatus.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,eAAO,MAAM,aAAa,WAAY,aAAa,CAAC,YAAY,EAAE,aAAa,CAAC;;;CA8C/E,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ export const usePeerStatus = (client) => {
3
+ const [peerStatus, setPeerStatusState] = useState("idle");
4
+ const peerStatusRef = useRef("idle");
5
+ const setPeerStatus = useCallback((status) => {
6
+ peerStatusRef.current = status;
7
+ setPeerStatusState(status);
8
+ }, [setPeerStatusState]);
9
+ const getCurrentPeerStatus = useCallback(() => peerStatusRef.current, []);
10
+ useEffect(() => {
11
+ const setConnecting = () => {
12
+ setPeerStatus("connecting");
13
+ };
14
+ const setError = () => {
15
+ setPeerStatus("error");
16
+ };
17
+ const setJoined = () => {
18
+ setPeerStatus("connected");
19
+ };
20
+ const setDisconnected = () => {
21
+ setPeerStatus("idle");
22
+ };
23
+ client.on("connectionStarted", setConnecting);
24
+ client.on("joined", setJoined);
25
+ client.on("authError", setError);
26
+ client.on("joinError", setError);
27
+ client.on("connectionError", setError);
28
+ client.on("disconnected", setDisconnected);
29
+ return () => {
30
+ client.off("connectionStarted", setConnecting);
31
+ client.off("joined", setJoined);
32
+ client.off("authError", setError);
33
+ client.off("joinError", setError);
34
+ client.off("connectionError", setError);
35
+ client.off("disconnected", setDisconnected);
36
+ };
37
+ }, [client, setPeerStatus]);
38
+ return { peerStatus, getCurrentPeerStatus };
39
+ };
@@ -0,0 +1,10 @@
1
+ import type { PeerWithTracks } from "../types/public";
2
+ /**
3
+ *
4
+ * @category Connection
5
+ */
6
+ export declare function usePeers(): {
7
+ localPeer: PeerWithTracks | null;
8
+ peers: PeerWithTracks[];
9
+ };
10
+ //# sourceMappingURL=usePeers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePeers.d.ts","sourceRoot":"","sources":["../../src/hooks/usePeers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AActD;;;GAGG;AACH,wBAAgB,QAAQ;;;EAOvB"}
@@ -0,0 +1,19 @@
1
+ import { useFishjamContext } from "./useFishjamContext";
2
+ function getPeerWithDistinguishedTracks(peerState) {
3
+ const peerTracks = Object.values(peerState.tracks ?? {});
4
+ const cameraTrack = peerTracks.find(({ metadata }) => metadata?.type === "camera");
5
+ const microphoneTrack = peerTracks.find(({ metadata }) => metadata?.type === "microphone");
6
+ const screenShareVideoTrack = peerTracks.find(({ metadata }) => metadata?.type === "screenShareVideo");
7
+ const screenShareAudioTrack = peerTracks.find(({ metadata }) => metadata?.type === "screenShareAudio");
8
+ return { ...peerState, cameraTrack, microphoneTrack, screenShareVideoTrack, screenShareAudioTrack };
9
+ }
10
+ /**
11
+ *
12
+ * @category Connection
13
+ */
14
+ export function usePeers() {
15
+ const { clientState } = useFishjamContext();
16
+ const localPeer = clientState.localPeer ? getPeerWithDistinguishedTracks(clientState.localPeer) : null;
17
+ const peers = Object.values(clientState.peers).map(getPeerWithDistinguishedTracks);
18
+ return { localPeer, peers };
19
+ }
@@ -0,0 +1,3 @@
1
+ import type { TrackManager } from "../types/internal";
2
+ export declare function useProcessedPreviewStream(trackManager: TrackManager, deviceTrack: MediaStreamTrack | null | undefined): MediaStream | null;
3
+ //# sourceMappingURL=useProcessedPreviewStream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useProcessedPreviewStream.d.ts","sourceRoot":"","sources":["../../src/hooks/useProcessedPreviewStream.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,YAAY,EAC1B,WAAW,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,sBAiBjD"}
@@ -0,0 +1,17 @@
1
+ import { useEffect, useState } from "react";
2
+ export function useProcessedPreviewStream(trackManager, deviceTrack) {
3
+ const [previewStream, setPreviewStream] = useState(null);
4
+ const { currentTrack, currentTrackMiddleware } = trackManager;
5
+ useEffect(() => {
6
+ if (currentTrack || !deviceTrack)
7
+ return;
8
+ const result = currentTrackMiddleware?.(deviceTrack);
9
+ if (result?.track)
10
+ setPreviewStream(new MediaStream([result.track]));
11
+ return () => {
12
+ result?.onClear?.();
13
+ setPreviewStream(null);
14
+ };
15
+ }, [currentTrack, deviceTrack, currentTrackMiddleware]);
16
+ return previewStream;
17
+ }
@@ -0,0 +1,7 @@
1
+ import type { ReconnectionStatus } from "@fishjam-cloud/ts-client";
2
+ /**
3
+ *
4
+ * @category Connection
5
+ */
6
+ export declare const useReconnection: () => ReconnectionStatus;
7
+ //# sourceMappingURL=useReconnection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useReconnection.d.ts","sourceRoot":"","sources":["../../src/hooks/useReconnection.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE;;;GAGG;AACH,eAAO,MAAM,eAAe,QAAO,kBA6BlC,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { useEffect, useState } from "react";
2
+ import { useFishjamContext } from "./useFishjamContext";
3
+ /**
4
+ *
5
+ * @category Connection
6
+ */
7
+ export const useReconnection = () => {
8
+ const { fishjamClientRef } = useFishjamContext();
9
+ const [reconnectionStatus, setReconnectionStatus] = useState("idle");
10
+ useEffect(() => {
11
+ const client = fishjamClientRef.current;
12
+ const setReconnecting = () => {
13
+ setReconnectionStatus("reconnecting");
14
+ };
15
+ const setIdle = () => {
16
+ setReconnectionStatus("idle");
17
+ };
18
+ const setError = () => {
19
+ setReconnectionStatus("error");
20
+ };
21
+ client.on("reconnectionStarted", setReconnecting);
22
+ client.on("reconnected", setIdle);
23
+ client.on("reconnectionRetriesLimitReached", setError);
24
+ return () => {
25
+ client.off("reconnectionStarted", setReconnecting);
26
+ client.off("reconnected", setIdle);
27
+ client.off("reconnectionRetriesLimitReached", setError);
28
+ };
29
+ }, [fishjamClientRef]);
30
+ return reconnectionStatus;
31
+ };
@@ -0,0 +1,7 @@
1
+ import type { ScreenshareApi } from "../types/public";
2
+ /**
3
+ *
4
+ * @category Screenshare
5
+ */
6
+ export declare const useScreenShare: () => ScreenshareApi;
7
+ //# sourceMappingURL=useScreenShare.d.ts.map
@@ -0,0 +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,24 +1,40 @@
1
- import { useCallback, useEffect } from "react";
1
+ import { useCallback, useEffect, useRef } from "react";
2
2
  import { getRemoteOrLocalTrack } from "../utils/track";
3
- import { useFishjamContext } from "./fishjamContext";
3
+ import { useFishjamContext } from "./useFishjamContext";
4
4
  const getTracks = (stream) => {
5
5
  const video = stream.getVideoTracks()[0];
6
6
  const audio = stream.getAudioTracks()[0] ?? null;
7
7
  return [video, audio];
8
8
  };
9
+ /**
10
+ *
11
+ * @category Screenshare
12
+ */
9
13
  export const useScreenShare = () => {
10
14
  const ctx = useFishjamContext();
11
- const [state, setState] = ctx.screenshareState;
12
- const tsClient = ctx.state.client.getTsClient();
15
+ const [state, setState] = ctx.screenShareState;
16
+ const cleanMiddlewareFnRef = useRef(null);
17
+ const { fishjamClientRef } = useFishjamContext();
18
+ const tsClient = fishjamClientRef.current;
19
+ const stream = state.stream ?? null;
20
+ const [videoTrack, audioTrack] = stream ? getTracks(stream) : [null, null];
21
+ const getDisplayName = () => tsClient.getLocalPeer()?.metadata?.peer?.displayName;
13
22
  const startStreaming = async (props) => {
14
23
  const stream = await navigator.mediaDevices.getDisplayMedia({
15
24
  video: props?.videoConstraints ?? true,
16
25
  audio: props?.audioConstraints ?? true,
17
26
  });
18
- const [video, audio] = getTracks(stream);
19
- const addTrackPromises = [tsClient.addTrack(video)];
27
+ const displayName = getDisplayName();
28
+ let [video, audio] = getTracks(stream);
29
+ if (state.tracksMiddleware) {
30
+ const { videoTrack, audioTrack, onClear } = state.tracksMiddleware(video, audio);
31
+ video = videoTrack;
32
+ audio = audioTrack;
33
+ cleanMiddlewareFnRef.current = onClear;
34
+ }
35
+ const addTrackPromises = [tsClient.addTrack(video, { displayName, type: "screenShareVideo", paused: false })];
20
36
  if (audio)
21
- addTrackPromises.push(tsClient.addTrack(audio));
37
+ addTrackPromises.push(tsClient.addTrack(audio, { displayName, type: "screenShareAudio", paused: false }));
22
38
  const [videoId, audioId] = await Promise.all(addTrackPromises);
23
39
  setState({ stream, trackIds: { videoId, audioId } });
24
40
  };
@@ -31,15 +47,25 @@ export const useScreenShare = () => {
31
47
  }
32
48
  await Promise.all(addTrackPromises);
33
49
  };
50
+ const cleanMiddleware = useCallback(() => {
51
+ cleanMiddlewareFnRef.current?.();
52
+ cleanMiddlewareFnRef.current = null;
53
+ }, []);
34
54
  const setTracksMiddleware = async (middleware) => {
35
55
  if (!state?.stream)
36
56
  return;
37
- const [videoTrack, audioTrack] = getTracks(state.stream);
38
- const [newVideoTrack, newAudioTrack] = middleware?.(videoTrack, audioTrack) ?? [videoTrack, audioTrack];
39
- await replaceTracks(newVideoTrack, newAudioTrack);
57
+ const [video, audio] = getTracks(state.stream);
58
+ cleanMiddleware();
59
+ const { videoTrack, audioTrack, onClear } = middleware?.(video, audio) ?? {
60
+ videoTrack: video,
61
+ audioTrack: audio,
62
+ onClear: null,
63
+ };
64
+ cleanMiddlewareFnRef.current = onClear;
65
+ await replaceTracks(videoTrack, audioTrack);
40
66
  };
41
67
  const stopStreaming = useCallback(async () => {
42
- if (!state) {
68
+ if (!state.stream) {
43
69
  console.warn("No stream to stop");
44
70
  return;
45
71
  }
@@ -47,14 +73,16 @@ export const useScreenShare = () => {
47
73
  video.stop();
48
74
  if (audio)
49
75
  audio.stop();
50
- const removeTrackPromises = [tsClient.removeTrack(state.trackIds.videoId)];
76
+ const client = fishjamClientRef.current;
77
+ const removeTrackPromises = [client.removeTrack(state.trackIds.videoId)];
51
78
  if (state.trackIds.audioId)
52
- removeTrackPromises.push(tsClient.removeTrack(state.trackIds.audioId));
79
+ removeTrackPromises.push(client.removeTrack(state.trackIds.audioId));
53
80
  await Promise.all(removeTrackPromises);
54
- setState(null);
55
- }, [state, tsClient, setState]);
81
+ cleanMiddleware();
82
+ setState(({ tracksMiddleware }) => ({ stream: null, trackIds: null, tracksMiddleware }));
83
+ }, [state, fishjamClientRef, setState, cleanMiddleware]);
56
84
  useEffect(() => {
57
- if (!state)
85
+ if (!state.stream)
58
86
  return;
59
87
  const [video, audio] = getTracks(state.stream);
60
88
  const trackEndedHandler = () => {
@@ -68,18 +96,19 @@ export const useScreenShare = () => {
68
96
  };
69
97
  }, [state, stopStreaming]);
70
98
  useEffect(() => {
99
+ const client = fishjamClientRef.current;
71
100
  const onDisconnected = () => {
72
- stopStreaming();
101
+ if (stream) {
102
+ stopStreaming();
103
+ }
73
104
  };
74
- tsClient.on("disconnected", onDisconnected);
105
+ client.on("disconnected", onDisconnected);
75
106
  return () => {
76
- tsClient.removeListener("disconnected", onDisconnected);
107
+ client.removeListener("disconnected", onDisconnected);
77
108
  };
78
- }, [stopStreaming, tsClient]);
79
- const stream = state?.stream ?? null;
80
- const [videoTrack, audioTrack] = stream ? getTracks(stream) : [null, null];
81
- const videoBroadcast = state ? getRemoteOrLocalTrack(tsClient, state.trackIds.videoId) : null;
82
- const audioBroadcast = state?.trackIds.audioId ? getRemoteOrLocalTrack(tsClient, state.trackIds.audioId) : null;
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;
83
112
  return {
84
113
  startStreaming,
85
114
  stopStreaming,
@@ -0,0 +1,6 @@
1
+ /**
2
+ *
3
+ * @category Connection
4
+ */
5
+ export declare function useStatus(): import("..").PeerStatus;
6
+ //# sourceMappingURL=useStatus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStatus.d.ts","sourceRoot":"","sources":["../../src/hooks/useStatus.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,SAAS,4BAExB"}
@@ -0,0 +1,8 @@
1
+ import { useFishjamContext } from "./useFishjamContext";
2
+ /**
3
+ *
4
+ * @category Connection
5
+ */
6
+ export function useStatus() {
7
+ return useFishjamContext().peerStatus;
8
+ }
@@ -0,0 +1,11 @@
1
+ import type { FishjamClient } from "@fishjam-cloud/ts-client";
2
+ import type { MediaManager, PeerMetadata, TrackManager, TrackMetadata } from "../types/internal";
3
+ import type { PeerStatus } from "../types/public";
4
+ interface TrackManagerConfig {
5
+ mediaManager: MediaManager;
6
+ tsClient: FishjamClient<PeerMetadata, TrackMetadata>;
7
+ getCurrentPeerStatus: () => PeerStatus;
8
+ }
9
+ export declare const useTrackManager: ({ mediaManager, tsClient, getCurrentPeerStatus }: TrackManagerConfig) => TrackManager;
10
+ export {};
11
+ //# sourceMappingURL=useTrackManager.d.ts.map
@@ -0,0 +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"}