Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Update react client #81

Merged
merged 7 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
nodejs 18.14.2
nodejs v20.13.1
protoc 24.2
554 changes: 300 additions & 254 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"lint:check": "eslint . --ext .ts,.tsx"
},
"dependencies": {
"@jellyfish-dev/react-client-sdk": "^0.2.0",
"@jellyfish-dev/react-client-sdk": "^0.3.1",
"@types/chartist": "^1.0.0",
"@types/ramda": "^0.29.10",
"axios": "^1.6.7",
Expand Down
6 changes: 3 additions & 3 deletions src/components/DeviceTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const DeviceTile = ({ selectedId, setSelectedId, streamInfo, id }: Props)
const isVideo = streamInfo.stream.getVideoTracks().length > 0;
const [enabled, setEnabled] = useState<boolean>(true);
const peer = state.rooms[state.selectedRoom || ""].peers[id];
const api = peer.client.useSelector((state) => state.connectivity.api);
const reactClient = peer.client.useSelector((state) => state.client);
const track = peer.tracks[streamInfo.id];
const setActiveLocalCameras = useSetAtom(activeLocalCamerasAtom);

Expand Down Expand Up @@ -69,9 +69,9 @@ export const DeviceTile = ({ selectedId, setSelectedId, streamInfo, id }: Props)
</button>
<CloseButton
descripiton="STOP STREAM AND REMOVE TRACKS"
onClick={() => {
onClick={async () => {
if (track.serverId) {
api?.removeTrack(track.serverId);
await reactClient?.removeTrack(track.serverId);
}
if (track.source === "navigator" && track.type === "video") {
setActiveLocalCameras((prev) => prev - 1);
Expand Down
8 changes: 4 additions & 4 deletions src/components/useConnectionToasts.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { JellyfishClient } from "@jellyfish-dev/react-client-sdk";
import { Client } from "@jellyfish-dev/react-client-sdk";

import { useEffect } from "react";
import { showToastError } from "./Toasts";

export const useConnectionToasts = <P, T>(client: JellyfishClient<P, T> | null) => {
export const useConnectionToasts = <P, T>(client: Client<P, T> | null) => {
useEffect(() => {
if (!client) return;

Expand All @@ -19,8 +19,8 @@ export const useConnectionToasts = <P, T>(client: JellyfishClient<P, T> | null)
showToastError("Failed to join the room");
};

const onAuthError = () => {
showToastError("Failed to authenticate");
const onAuthError = (error: string) => {
showToastError(`Failed to authenticate: ${error}`);
};

client.on("socketError", onSocketError);
Expand Down
16 changes: 2 additions & 14 deletions src/components/useLogging.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { JellyfishClient } from "@jellyfish-dev/react-client-sdk";
import { Client } from "@jellyfish-dev/react-client-sdk";
import { useEffect } from "react";
import { settingsSelectorAtom } from "./LogSelector";
import { useAtom } from "jotai";
Expand All @@ -18,7 +18,7 @@ const onEncodingChangedAtom = settingsSelectorAtom("onEncodingChanged");
const onVoiceActivityChangedAtom = settingsSelectorAtom("onVoiceActivityChanged");

// TODO: refactor this
export const useLogging = <P, T>(client: JellyfishClient<P, T> | null) => {
export const useLogging = <P, T>(client: Client<P, T> | null) => {
const [onJoinErrorLog] = useAtom(onJoinErrorAtom);
const [onJoinSuccessLog] = useAtom(onJoinSuccessAtom);
const [onPeerJoinedLog] = useAtom(onPeerJoinedAtom);
Expand Down Expand Up @@ -111,16 +111,6 @@ export const useLogging = <P, T>(client: JellyfishClient<P, T> | null) => {
}
};

const onTracksPriorityChanged = (enabledTracks: any, disabledTracks: any) => {
if (onTracksPriorityChangedLog) {
console.log({
name: "onTracksPriorityChanged",
enabledTracks,
disabledTracks,
});
}
};

const onAuthError = () => {
console.log("onAuthError");
};
Expand All @@ -146,7 +136,6 @@ export const useLogging = <P, T>(client: JellyfishClient<P, T> | null) => {
client.on("trackRemoved", onTrackRemoved);
client.on("trackUpdated", onTrackUpdated);
client.on("bandwidthEstimationChanged", onBandwidthEstimationChanged);
client.on("tracksPriorityChanged", onTracksPriorityChanged);

client.on("authError", onAuthError);
client.on("connectionError", onConnectionError);
Expand All @@ -164,7 +153,6 @@ export const useLogging = <P, T>(client: JellyfishClient<P, T> | null) => {
client.off("trackRemoved", onTrackRemoved);
client.off("trackUpdated", onTrackUpdated);
client.off("bandwidthEstimationChanged", onBandwidthEstimationChanged);
client.off("tracksPriorityChanged", onTracksPriorityChanged);

client.off("authError", onAuthError);
client.off("connectionError", onConnectionError);
Expand Down
10 changes: 10 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { CreateConfig } from "@jellyfish-dev/react-client-sdk";

export const NEW_CLIENT_CREATE_CONFIG: CreateConfig<unknown, unknown> = {
reconnect: {
delay: 5000,
initialDelay: 0,
maxAttempts: 1,
addTracksOnReconnect: true,
},
};
48 changes: 31 additions & 17 deletions src/containers/Client.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Fragment, useEffect, useRef, useState } from "react";
import { Fragment, ReactNode, useEffect, useRef, useState } from "react";
import { JsonComponent } from "../components/JsonComponent";
import { getArrayValue, getStringValue, useLocalStorageState } from "../components/LogSelector";
import { CloseButton } from "../components/CloseButton";
Expand Down Expand Up @@ -26,6 +26,7 @@ type ClientProps = {
peerId: string;
token: string | null;
id: string;
status?: "disconnected" | "connected";
refetchIfNeeded: () => void;
remove: (roomId: string) => void;
setToken: (token: string) => void;
Expand Down Expand Up @@ -71,11 +72,25 @@ const prepareHlsButtonMessage = (hlsComponent?: ComponentHLS): string | null =>
else return null;
};

type ClientContextProviderProps = {
roomId: string;
peerId: string;
children: ReactNode;
};

export const ClientContextProvider = ({ roomId, peerId, children }: ClientContextProviderProps) => {
const { state } = useStore();
const JellyfishContextProvider = state.rooms[roomId].peers[peerId].client.JellyfishContextProvider;

return <JellyfishContextProvider>{children}</JellyfishContextProvider>;
};

export const Client = ({
roomId,
peerId,
token,
id,
status,
refetchIfNeeded,
remove,
removeToken,
Expand All @@ -96,8 +111,7 @@ export const Client = ({
tracks: snapshot.tracks,
}));

const api = client.useSelector((snapshot) => snapshot.connectivity.api);
const jellyfishClient = client.useSelector((snapshot) => snapshot.connectivity.client);
const reactClient = client.useSelector((snapshot) => snapshot.client);
const { signalingHost, signalingPath, signalingURISchema, roomApi } = useServerSdk();
const [showClientState, setShowClientState] = useLocalStorageState(`show-client-state-json-${peerId}`);
const [attachClientMetadata, setAttachClientMetadata] = useLocalStorageState(`attach-client-metadata-${peerId}`);
Expand All @@ -110,8 +124,8 @@ export const Client = ({
statusRef.current = fullState?.status;
const isThereAnyTrack = Object.keys(fullState?.tracks || {}).length > 0;

useLogging(jellyfishClient);
useConnectionToasts(jellyfishClient);
useLogging(reactClient);
useConnectionToasts(reactClient);
const [maxBandwidth, setMaxBandwidth] = useState<string | null>(getStringValue("max-bandwidth"));
const [trackMetadata, setTrackMetadata] = useState<string | null>(getStringValue("track-metadata"));
const [attachMetadata, setAttachMetadata] = useState(getBooleanValue("attach-metadata", false));
Expand All @@ -124,7 +138,7 @@ export const Client = ({
const connectionErrorTimeoutId = useRef<NodeJS.Timeout | null>(null);

useEffect(() => {
if (!jellyfishClient) return;
if (!reactClient) return;

const cb = () => {
if (connectionErrorTimeoutId.current) {
Expand All @@ -133,24 +147,24 @@ export const Client = ({
connectionErrorTimeoutId.current = null;
};

jellyfishClient.on("joined", cb);
reactClient.on("joined", cb);

return () => {
jellyfishClient?.removeListener("joined", cb);
reactClient?.removeListener("joined", cb);
};
}, [jellyfishClient]);
}, [reactClient]);

const changeEncodingReceived = (trackId: string, encoding: TrackEncoding) => {
if (!fullState) return;
api?.setTargetTrackEncoding(trackId, encoding);
reactClient?.setTargetTrackEncoding(trackId, encoding);
};

const changeEncoding = (trackId: string, encoding: TrackEncoding, desiredState: boolean) => {
if (!trackId) return;
if (desiredState) {
api?.enableTrackEncoding(trackId, encoding);
reactClient?.enableTrackEncoding(trackId, encoding);
} else {
api?.disableTrackEncoding(trackId, encoding);
reactClient?.disableTrackEncoding(trackId, encoding);
}
};

Expand Down Expand Up @@ -222,7 +236,7 @@ export const Client = ({
? JSON.parse(trackMetadata?.trim() || createDefaultTrackMetadata(trackInfo.type))
: undefined;

const trackId = await api?.addTrack(
const trackId = await reactClient?.addTrack(
track,
trackInfo.stream,
metadata,
Expand Down Expand Up @@ -251,7 +265,7 @@ export const Client = ({
const addAudioTrack = async (trackInfo: DeviceInfo) => {
const track: MediaStreamTrack = trackInfo.stream?.getAudioTracks()[0];
if (!trackInfo.stream || !track) return;
const trackId = await api?.addTrack(
const trackId = await reactClient?.addTrack(
track,
trackInfo.stream,
attachMetadata ? JSON.parse(trackMetadata?.trim() || createDefaultTrackMetadata(trackInfo.type)) : undefined,
Expand Down Expand Up @@ -325,7 +339,7 @@ export const Client = ({
) : (
<button
className="btn btn-sm btn-success"
disabled={!token}
disabled={!token || status === "connected"}
onClick={() => {
if (!token) {
showToastError("Cannot connect to Jellyfish server because token is empty");
Expand Down Expand Up @@ -475,7 +489,7 @@ export const Client = ({
disabled={!isClientMetadataCorrect || fullState.status !== "joined"}
onClick={() => {
const metadata = checkJSON(clientMetadata) ? JSON.parse(clientMetadata) : null;
api?.updatePeerMetadata(metadata);
reactClient?.updatePeerMetadata(metadata);
}}
>
Update
Expand Down Expand Up @@ -511,7 +525,7 @@ export const Client = ({
trackMetadata={trackMetadata ?? ""}
removeTrack={(trackId) => {
if (!trackId) return;
api?.removeTrack(tracks[trackId].serverId || "");
reactClient?.removeTrack(tracks[trackId].serverId || "");
dispatch({
type: "SET_TRACK_STREAMED",
roomId: roomId,
Expand Down
62 changes: 35 additions & 27 deletions src/containers/Room.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useLocalStorageState } from "../components/LogSelector";
import { REFETCH_ON_SUCCESS } from "./JellyfishInstance";
import { JsonComponent } from "../components/JsonComponent";
import { Client } from "./Client";
import { Client, ClientContextProvider } from "./Client";
import { CopyToClipboardButton } from "../components/CopyButton";
import { ComponentHLS, Room as RoomAPI } from "../server-sdk";
import { useServerSdk } from "../components/ServerSdkContext";
Expand Down Expand Up @@ -153,15 +153,20 @@ export const Room = ({ roomId, refetchIfNeeded, refetchRequested }: RoomProps) =
const currentPeerCounter = peerCounter;
setPeerCounter((prev) => (prev >= Number.MAX_SAFE_INTEGER ? 0 : prev + 1));

roomApi?.addPeer(roomId, { type: "webrtc", options: { enableSimulcast: true } }).then((response) => {
addToken(response.data.data.peer.id, response.data.data.token);
setPeerOrder((prev) => {
const copy = { ...prev };
copy[response.data.data.peer.id] = currentPeerCounter;
return copy;
roomApi
?.addPeer(roomId, {
type: "webrtc",
options: { enableSimulcast: true },
})
.then((response) => {
addToken(response.data.data.peer.id, response.data.data.token);
setPeerOrder((prev) => {
const copy = { ...prev };
copy[response.data.data.peer.id] = currentPeerCounter;
return copy;
});
refetchIfNeededInner();
});
refetchIfNeededInner();
});
}}
>
Create peer
Expand Down Expand Up @@ -228,24 +233,27 @@ export const Room = ({ roomId, refetchIfNeeded, refetchRequested }: RoomProps) =
.map(({ id }) => {
if (!id) return null;
return (
<Client
key={id}
roomId={roomId}
peerId={id}
token={token[id] || null}
id={id}
refetchIfNeeded={refetchIfNeededInner}
remove={() => {
roomApi?.deletePeer(roomId, id);
}}
removeToken={() => {
removeToken(id);
}}
setToken={(token: string) => {
addToken(id, token);
}}
hlsComponent={hlsComponent}
/>
<ClientContextProvider key={id} roomId={roomId} peerId={id}>
<Client
key={id}
roomId={roomId}
peerId={id}
token={token[id] || null}
id={id}
status={roomState?.peers.find((peer) => peer.id === id)?.status}
refetchIfNeeded={refetchIfNeededInner}
remove={() => {
roomApi?.deletePeer(roomId, id);
}}
removeToken={() => {
removeToken(id);
}}
setToken={(token: string) => {
addToken(id, token);
}}
hlsComponent={hlsComponent}
/>
</ClientContextProvider>
);
})}
</div>
Expand Down
5 changes: 3 additions & 2 deletions src/containers/RoomsContext.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { createContext, ReactNode, useContext, useReducer } from "react";
import { groupBy } from "rambda";
import { Peer as PeerApi, Room as RoomAPI } from "../server-sdk";
import { create, CreateJellyfishClient } from "@jellyfish-dev/react-client-sdk/experimental";
import { create, CreateJellyfishClient } from "@jellyfish-dev/react-client-sdk";
import { LocalTrack } from "./Client";
import { NEW_CLIENT_CREATE_CONFIG } from "../config";

export type RoomContext = {
state: AppStore;
Expand Down Expand Up @@ -118,7 +119,7 @@ const roomReducer: Reducer = (state, action) => {
const peersList: PeerState[] = action.room.peers.map((peer) => ({
id: peer.id,
peerStatus: peer,
client: prevPeers?.[peer.id]?.client || create<unknown, unknown>(),
client: prevPeers?.[peer.id]?.client || create<unknown, unknown>(NEW_CLIENT_CREATE_CONFIG),
tracks: prevPeers?.[peer.id]?.tracks || [],
}));

Expand Down
6 changes: 3 additions & 3 deletions src/containers/StreamedTrackCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export const StreamedTrackCard = ({
trackInfo.encodings?.includes("h") || false,
]);

const client = state.rooms[roomId].peers[peerId].client;
const api = client.useSelector((s) => s.connectivity.api);
const createReactClientResult = state.rooms[roomId].peers[peerId].client;
const reactClient = createReactClientResult.useSelector((s) => s.client);

const simulcast = useState<boolean>(simulcastTransfer);
const [expandedTrackId, setExpandedTrackId] = useState<boolean>(false);
Expand All @@ -52,7 +52,7 @@ export const StreamedTrackCard = ({
const metadata = checkJSON(newTrackMetadata) ? JSON.parse(newTrackMetadata) : null;
const trackId = trackInfo.serverId;
if (!trackId) throw new Error("Server id is not present!");
api?.updateTrackMetadata(trackId, metadata);
reactClient?.updateTrackMetadata(trackId, metadata);
setUserTracksMetadata((prev) => ({
...(prev ? prev : {}),
[trackId]: metadata,
Expand Down
2 changes: 1 addition & 1 deletion src/containers/StreamingSettingsCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TrackEncoding } from "@jellyfish-dev/react-client-sdk/.";
import { TrackEncoding } from "@jellyfish-dev/react-client-sdk";
import { StreamingDeviceSelector } from "../components/StreamingDeviceSelector";
import { StreamingSettingsPanel } from "./StreamingSettingsPanel";
import { DeviceTile } from "../components/DeviceTile";
Expand Down
Loading