From 8b8bad024ea3fd657b37f236411dc4f5baadef7f Mon Sep 17 00:00:00 2001 From: "Eswar Prasad Clinton. A" <64120992+eswarclynn@users.noreply.github.com> Date: Fri, 17 May 2024 12:04:15 +0530 Subject: [PATCH 1/9] fix: use delay instead of count to wait for initial whiteboard records (#2903) * fix: add delay to reopen whiteboard * test: add logs and qa creds * fix: set permission state on receiving instance * fix: use delay instead of count to wait for initial records * fix: clean code --- .../hms-whiteboard/src/hooks/StoreClient.ts | 32 ++----- .../src/hooks/useCollaboration.ts | 92 ++++++++++--------- .../src/hooks/useSetEditorPermissions.tsx | 2 + packages/hms-whiteboard/src/utils.ts | 2 +- 4 files changed, 60 insertions(+), 68 deletions(-) diff --git a/packages/hms-whiteboard/src/hooks/StoreClient.ts b/packages/hms-whiteboard/src/hooks/StoreClient.ts index 2ced592e6f..dd4f4d8a90 100644 --- a/packages/hms-whiteboard/src/hooks/StoreClient.ts +++ b/packages/hms-whiteboard/src/hooks/StoreClient.ts @@ -1,6 +1,7 @@ import { GrpcWebFetchTransport } from '@protobuf-ts/grpcweb-transport'; import { Value_Type } from '../grpc/sessionstore'; import { StoreClient } from '../grpc/sessionstore.client'; +import { OPEN_WAIT_TIMEOUT } from '../utils'; interface OpenCallbacks { handleOpen: (values: T[]) => void; @@ -31,28 +32,23 @@ export class SessionStore { }, { abort: this.abortController.signal }, ); - /** - * on open, get key count to call handleOpen with the pre-existing values from the store - * retry if getKeysCount is called before open call is completed - */ - const keyCount = await this.retryForOpen(this.getKeysCount.bind(this)); const initialValues: T[] = []; + let initialised = false; - if (!keyCount) { - handleOpen([]); - } + // on open, wait to call handleOpen with the pre-existing values from the store + setTimeout(() => { + handleOpen(initialValues); + initialised = true; + }, OPEN_WAIT_TIMEOUT); call.responses.onMessage(message => { if (message.value) { if (message.value?.data.oneofKind === 'str') { const record = JSON.parse(message.value.data.str) as T; - if (initialValues.length === keyCount) { + if (initialised) { handleChange(message.key, record); } else { initialValues.push(record); - if (initialValues.length === keyCount) { - handleOpen(initialValues); - } } } } else { @@ -103,16 +99,4 @@ export class SessionStore { delete(key: string) { return this.storeClient.delete({ key }); } - - private async retryForOpen(fn: () => Promise, retries = 3): Promise { - try { - return await fn(); - } catch (error) { - const shouldRetry = (error as Error).message.includes('peer not found') && retries > 0; - if (!shouldRetry) { - return Promise.reject(error); - } - return await this.retryForOpen(fn, retries - 1); - } - } } diff --git a/packages/hms-whiteboard/src/hooks/useCollaboration.ts b/packages/hms-whiteboard/src/hooks/useCollaboration.ts index afc58c0fec..0f19442285 100644 --- a/packages/hms-whiteboard/src/hooks/useCollaboration.ts +++ b/packages/hms-whiteboard/src/hooks/useCollaboration.ts @@ -17,7 +17,7 @@ import { import { DEFAULT_STORE } from './default_store'; import { useSessionStore } from './useSessionStore'; import { useSetEditorPermissions } from './useSetEditorPermissions'; -import { CURRENT_PAGE_KEY, OPEN_DELAY, PAGES_DEBOUNCE_TIME, SHAPES_THROTTLE_TIME } from '../utils'; +import { CURRENT_PAGE_KEY, PAGES_DEBOUNCE_TIME, SHAPES_THROTTLE_TIME } from '../utils'; // mandatory record types required for initialisation of the whiteboard and for a full remote sync const FULL_SYNC_REQUIRED_RECORD_TYPES: TLRecord['typeName'][] = [ @@ -63,37 +63,14 @@ export function useCollaboration({ }, []); const sessionStore = useSessionStore({ token, endpoint, handleError }); + const permissions = useSetEditorPermissions({ token, editor, zoomToContent, handleError }); - useSetEditorPermissions({ token, editor, zoomToContent, handleError }); - - useEffect(() => { - if (!sessionStore) return; - - setStoreWithStatus({ status: 'loading' }); - - const unsubs: (() => void)[] = []; - - // 1. - // Connect store to yjs store and vis versa, for both the document and awareness - - /* -------------------- Document -------------------- */ - - const handleChange = (key: string, value?: TLRecord) => { - // put / remove the records in the store - store.mergeRemoteChanges(() => { - if (!value) { - return store.remove([key as TLRecord['id']]); - } - if (key === CURRENT_PAGE_KEY) { - setCurrentPage(value as TLPage); - } else { - store.put([value]); - } - }); - }; + const handleOpen = useCallback( + (initialRecords: TLRecord[]) => { + if (!sessionStore) { + return; + } - const handleOpen = (initialRecords: TLRecord[]) => { - // 2. // Initialize the tldraw store with the session store server records—or, if the session store // is empty, initialize the session store server with the default tldraw store records. const shouldUseServerRecords = FULL_SYNC_REQUIRED_RECORD_TYPES.every( @@ -118,20 +95,49 @@ export function useCollaboration({ status: 'synced-remote', connectionStatus: 'online', }); - }; + }, + [store, sessionStore], + ); + + const handleChange = useCallback( + (key: string, value?: TLRecord) => { + // put / remove the records in the store + store.mergeRemoteChanges(() => { + if (!value) { + return store.remove([key as TLRecord['id']]); + } + if (key === CURRENT_PAGE_KEY) { + setCurrentPage(value as TLPage); + } else { + transact(() => { + store.put([value]); + if (key === TLINSTANCE_ID) { + store.put([ + { ...value, canMoveCamera: !!zoomToContent, isReadonly: !permissions.includes('write') } as TLInstance, + ]); + } + }); + } + }); + }, + [store, permissions, zoomToContent], + ); + + useEffect(() => { + if (!sessionStore) return; + + setStoreWithStatus({ status: 'loading' }); + + const unsubs: (() => void)[] = []; // Open session and sync the session store changes to the store - // On opening, closing and reopening whiteboard with no delay(in case of role change), the session store server needs time to cleanup on the close before opening again - // so there is a delay here before opening the connection - setTimeout(() => { - sessionStore - .open({ - handleOpen, - handleChange, - handleError, - }) - .then(unsub => unsubs.push(unsub)); - }, OPEN_DELAY); + sessionStore + .open({ + handleOpen, + handleChange, + handleError, + }) + .then(unsub => unsubs.push(unsub)); // Sync store changes to the yjs doc unsubs.push( @@ -187,7 +193,7 @@ export function useCollaboration({ unsubs.forEach(fn => fn()); unsubs.length = 0; }; - }, [store, sessionStore, handleError]); + }, [store, sessionStore, handleChange, handleOpen, handleError]); useEffect(() => { if (!editor || !sessionStore) return; diff --git a/packages/hms-whiteboard/src/hooks/useSetEditorPermissions.tsx b/packages/hms-whiteboard/src/hooks/useSetEditorPermissions.tsx index 1c9626d5da..48a0eac2cc 100644 --- a/packages/hms-whiteboard/src/hooks/useSetEditorPermissions.tsx +++ b/packages/hms-whiteboard/src/hooks/useSetEditorPermissions.tsx @@ -33,4 +33,6 @@ export const useSetEditorPermissions = ({ const isReadonly = !permissions.includes('write'); editor?.updateInstanceState({ isReadonly }); }, [permissions, zoomToContent, editor]); + + return permissions; }; diff --git a/packages/hms-whiteboard/src/utils.ts b/packages/hms-whiteboard/src/utils.ts index 2a15dc5879..1a4fc22de2 100644 --- a/packages/hms-whiteboard/src/utils.ts +++ b/packages/hms-whiteboard/src/utils.ts @@ -19,4 +19,4 @@ export default function decodeJWT(token?: string) { export const CURRENT_PAGE_KEY = 'currentPage'; export const SHAPES_THROTTLE_TIME = 11; export const PAGES_DEBOUNCE_TIME = 200; -export const OPEN_DELAY = 100; +export const OPEN_WAIT_TIMEOUT = 1000; From 40f7c7f82e9d58dd0d08dc8c4bfd087509814ecd Mon Sep 17 00:00:00 2001 From: Kaustubh Kumar Date: Fri, 17 May 2024 13:36:51 +0530 Subject: [PATCH 2/9] feat: custom ice servers in join config --- packages/hms-video-store/src/index.ts | 1 + .../hms-video-store/src/interfaces/config.ts | 13 ++++++++++++- packages/hms-video-store/src/sdk/index.ts | 1 + .../hms-video-store/src/signal/init/index.ts | 17 +++++++++++------ packages/hms-video-store/src/transport/index.ts | 15 ++++++++++----- .../src/transport/models/JoinParameters.ts | 3 +++ .../src/utils/ice-server-config.ts | 11 +++++++++++ packages/react-sdk/src/hooks/usePreviewJoin.ts | 9 +++++++++ yarn.lock | 2 +- 9 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 packages/hms-video-store/src/utils/ice-server-config.ts diff --git a/packages/hms-video-store/src/index.ts b/packages/hms-video-store/src/index.ts index 2b1c4f816d..7e3783a783 100644 --- a/packages/hms-video-store/src/index.ts +++ b/packages/hms-video-store/src/index.ts @@ -53,6 +53,7 @@ export type { HMSQuizLeaderboardResponse, HMSQuizLeaderboardSummary, HMSTranscriptionInfo, + HMSICEServer, } from './internal'; export { EventBus } from './events/EventBus'; diff --git a/packages/hms-video-store/src/interfaces/config.ts b/packages/hms-video-store/src/interfaces/config.ts index 6a2f33e370..6246882735 100644 --- a/packages/hms-video-store/src/interfaces/config.ts +++ b/packages/hms-video-store/src/interfaces/config.ts @@ -5,6 +5,13 @@ import InitialSettings from './settings'; * @link https://docs.100ms.live/javascript/v2/features/preview * @link https://docs.100ms.live/javascript/v2/features/join */ + +export type HMSICEServer = { + urls: string[]; + userName?: string; + password?: string; +}; + export interface HMSConfig { /** * the name of the peer, can be later accessed via peer.name and can also be changed mid call. @@ -53,10 +60,14 @@ export interface HMSConfig { */ autoManageVideo?: boolean; /** - * if this flag is enabled, wake lock will be acquired automatically(if supported) when joining the room, so the device + * if this flag is enabled, wake lock will be acquired automatically (if supported) when joining the room, so the device * will be kept awake. */ autoManageWakeLock?: boolean; + /** + * use custom STUN/TURN servers for media connection (advanced) + */ + iceServers?: HMSICEServer[]; } export interface HMSMidCallPreviewConfig { diff --git a/packages/hms-video-store/src/sdk/index.ts b/packages/hms-video-store/src/sdk/index.ts index a89e83fa72..bd69b5e49a 100644 --- a/packages/hms-video-store/src/sdk/index.ts +++ b/packages/hms-video-store/src/sdk/index.ts @@ -424,6 +424,7 @@ export class HMSSdk implements HMSInterface { this.localPeer!.peerId, { name: config.userName, metaData: config.metaData || '' }, config.autoVideoSubscribe, + config.iceServers, ) .then((initConfig: InitConfig | void) => { initSuccessful = true; diff --git a/packages/hms-video-store/src/signal/init/index.ts b/packages/hms-video-store/src/signal/init/index.ts index e48260e498..0d2d44612d 100644 --- a/packages/hms-video-store/src/signal/init/index.ts +++ b/packages/hms-video-store/src/signal/init/index.ts @@ -1,6 +1,8 @@ import { InitConfig } from './models'; import { ErrorFactory } from '../../error/ErrorFactory'; import { HMSAction } from '../../error/HMSAction'; +import { HMSICEServer } from '../../interfaces'; +import { transformIceServerConfig } from '../../utils/ice-server-config'; import HMSLogger from '../../utils/logger'; const TAG = '[InitService]'; @@ -26,26 +28,26 @@ export default class InitService { userAgent, initEndpoint = 'https://prod-init.100ms.live', region = '', + iceServers, }: { token: string; peerId: string; userAgent: string; initEndpoint?: string; region?: string; + iceServers?: HMSICEServer[]; }): Promise { HMSLogger.d(TAG, `fetchInitConfig: initEndpoint=${initEndpoint} token=${token} peerId=${peerId} region=${region} `); const url = getUrl(initEndpoint, peerId, userAgent, region); try { const response = await fetch(url, { - headers: { - Authorization: `Bearer ${token}`, - }, + headers: { Authorization: `Bearer ${token}` }, }); try { const config = await response.clone().json(); this.handleError(response, config); HMSLogger.d(TAG, `config is ${JSON.stringify(config, null, 2)}`); - return transformInitConfig(config); + return transformInitConfig(config, iceServers); } catch (err) { const text = await response.text(); HMSLogger.e(TAG, 'json error', (err as Error).message, text); @@ -78,9 +80,12 @@ export function getUrl(endpoint: string, peerId: string, userAgent: string, regi } } -export function transformInitConfig(config: any): InitConfig { +export function transformInitConfig(config: any, iceServers?: HMSICEServer[]): InitConfig { return { ...config, - rtcConfiguration: { ...config.rtcConfiguration, iceServers: config.rtcConfiguration?.ice_servers }, + rtcConfiguration: { + ...config.rtcConfiguration, + iceServers: transformIceServerConfig(config.rtcConfiguration?.ice_servers, iceServers), + }, }; } diff --git a/packages/hms-video-store/src/transport/index.ts b/packages/hms-video-store/src/transport/index.ts index 92b8e581d1..6d05a3491c 100644 --- a/packages/hms-video-store/src/transport/index.ts +++ b/packages/hms-video-store/src/transport/index.ts @@ -23,7 +23,7 @@ import { ErrorFactory } from '../error/ErrorFactory'; import { HMSAction } from '../error/HMSAction'; import { HMSException } from '../error/HMSException'; import { EventBus } from '../events/EventBus'; -import { HMSRole } from '../interfaces'; +import { HMSICEServer, HMSRole } from '../interfaces'; import { HMSLocalStream } from '../media/streams/HMSLocalStream'; import { HMSLocalTrack, HMSLocalVideoTrack, HMSTrack } from '../media/tracks'; import { TrackState } from '../notification-manager'; @@ -397,8 +397,9 @@ export default class HMSTransport { peerId: string, customData: { name: string; metaData: string }, autoSubscribeVideo = false, + iceServers?: HMSICEServer[], ): Promise { - const initConfig = await this.connect(token, endpoint, peerId, customData, autoSubscribeVideo); + const initConfig = await this.connect(token, endpoint, peerId, customData, autoSubscribeVideo, iceServers); this.state = TransportState.Preview; this.observer.onStateChange(this.state); return initConfig; @@ -447,6 +448,7 @@ export default class HMSTransport { peerId: string, customData: { name: string; metaData: string }, autoSubscribeVideo = false, + iceServers?: HMSICEServer[], ): Promise { this.setTransportStateForConnect(); this.joinParameters = new JoinParameters( @@ -456,9 +458,10 @@ export default class HMSTransport { customData.metaData, endpoint, autoSubscribeVideo, + iceServers, ); try { - const response = await this.internalConnect(token, endpoint, peerId); + const response = await this.internalConnect(token, endpoint, peerId, iceServers); return response; } catch (error) { const shouldRetry = @@ -474,7 +477,7 @@ export default class HMSTransport { if (shouldRetry) { const task = async () => { - await this.internalConnect(token, endpoint, peerId); + await this.internalConnect(token, endpoint, peerId, iceServers); return Boolean(this.initConfig && this.initConfig.endpoint); }; @@ -898,7 +901,7 @@ export default class HMSTransport { } } - private async internalConnect(token: string, initEndpoint: string, peerId: string) { + private async internalConnect(token: string, initEndpoint: string, peerId: string, iceServers?: HMSICEServer[]) { HMSLogger.d(TAG, 'connect: started ⏰'); const connectRequestedAt = new Date(); try { @@ -908,6 +911,7 @@ export default class HMSTransport { peerId, userAgent: this.store.getUserAgent(), initEndpoint, + iceServers, }); const room = this.store.getRoom(); if (room) { @@ -1093,6 +1097,7 @@ export default class HMSTransport { this.joinParameters!.authToken, this.joinParameters!.endpoint, this.joinParameters!.peerId, + this.joinParameters!.iceServers, ); } diff --git a/packages/hms-video-store/src/transport/models/JoinParameters.ts b/packages/hms-video-store/src/transport/models/JoinParameters.ts index b60829abc7..4e71d97146 100644 --- a/packages/hms-video-store/src/transport/models/JoinParameters.ts +++ b/packages/hms-video-store/src/transport/models/JoinParameters.ts @@ -1,3 +1,5 @@ +import { HMSICEServer } from '../../interfaces'; + export class JoinParameters { constructor( public authToken: string, @@ -6,5 +8,6 @@ export class JoinParameters { public data: string = '', public endpoint: string = 'https://prod-init.100ms.live/init', public autoSubscribeVideo: boolean = false, + public iceServers?: HMSICEServer[], ) {} } diff --git a/packages/hms-video-store/src/utils/ice-server-config.ts b/packages/hms-video-store/src/utils/ice-server-config.ts new file mode 100644 index 0000000000..4af82722f1 --- /dev/null +++ b/packages/hms-video-store/src/utils/ice-server-config.ts @@ -0,0 +1,11 @@ +import { HMSICEServer } from '../interfaces'; + +export const transformIceServerConfig = (defaultConfig?: RTCIceServer[], iceServers?: HMSICEServer[]) => { + if (!iceServers || iceServers.length === 0) { + return defaultConfig; + } + const transformedIceServers = iceServers.map(server => { + return { urls: server.urls, credentialType: 'password', credential: server.password, username: server.userName }; + }); + return transformedIceServers; +}; diff --git a/packages/react-sdk/src/hooks/usePreviewJoin.ts b/packages/react-sdk/src/hooks/usePreviewJoin.ts index fb1b13d85e..8da681b360 100644 --- a/packages/react-sdk/src/hooks/usePreviewJoin.ts +++ b/packages/react-sdk/src/hooks/usePreviewJoin.ts @@ -1,6 +1,7 @@ import { useCallback, useMemo } from 'react'; import { HMSConfigInitialSettings, + HMSICEServer, HMSPreviewConfig, HMSRoomState, selectIsConnectedToRoom, @@ -51,6 +52,11 @@ export interface usePreviewInput { * will be kept awake. */ autoManageWakeLock?: boolean; + + /** + * use custom STUN/TURN servers for media connection (advanced) + */ + iceServers?: HMSICEServer[]; } export interface usePreviewResult { @@ -90,6 +96,7 @@ export const usePreviewJoin = ({ asRole, autoManageVideo, autoManageWakeLock, + iceServers, }: usePreviewInput): usePreviewResult => { const actions = useHMSActions(); const roomState = useHMSStore(selectRoomState); @@ -108,6 +115,7 @@ export const usePreviewJoin = ({ captureNetworkQualityInPreview, autoManageVideo, autoManageWakeLock, + iceServers, }; }, [ name, @@ -119,6 +127,7 @@ export const usePreviewJoin = ({ asRole, autoManageVideo, autoManageWakeLock, + iceServers, ]); const preview = useCallback(async () => { diff --git a/yarn.lock b/yarn.lock index 6be1ed9d7c..9fa5593300 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17941,4 +17941,4 @@ zustand@3.5.7: zustand@^3.6.2: version "3.7.2" resolved "https://registry.yarnpkg.com/zustand/-/zustand-3.7.2.tgz#7b44c4f4a5bfd7a8296a3957b13e1c346f42514d" - integrity sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA== + integrity sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA== \ No newline at end of file From 5ceb12477ee19a6496246448e56a8818da5a986b Mon Sep 17 00:00:00 2001 From: Kaustubh Kumar Date: Fri, 17 May 2024 15:37:17 +0530 Subject: [PATCH 3/9] fix: pass ice server config --- packages/hms-video-store/src/sdk/index.ts | 1 + packages/hms-video-store/src/transport/index.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/hms-video-store/src/sdk/index.ts b/packages/hms-video-store/src/sdk/index.ts index bd69b5e49a..19d0ef83af 100644 --- a/packages/hms-video-store/src/sdk/index.ts +++ b/packages/hms-video-store/src/sdk/index.ts @@ -566,6 +566,7 @@ export class HMSSdk implements HMSInterface { { name: config.userName, metaData: config.metaData! }, config.initEndpoint!, config.autoVideoSubscribe, + config.iceServers, ); HMSLogger.d(this.TAG, `✅ Joined room ${roomId}`); this.analyticsTimer.start(TimedEvent.PEER_LIST); diff --git a/packages/hms-video-store/src/transport/index.ts b/packages/hms-video-store/src/transport/index.ts index 6d05a3491c..8df8228fde 100644 --- a/packages/hms-video-store/src/transport/index.ts +++ b/packages/hms-video-store/src/transport/index.ts @@ -411,11 +411,12 @@ export default class HMSTransport { customData: { name: string; metaData: string }, initEndpoint: string, autoSubscribeVideo = false, + iceServers?: HMSICEServer[], ): Promise { HMSLogger.d(TAG, 'join: started ⏰'); try { if (!this.signal.isConnected || !this.initConfig) { - await this.connect(authToken, initEndpoint, peerId, customData, autoSubscribeVideo); + await this.connect(authToken, initEndpoint, peerId, customData, autoSubscribeVideo, iceServers); } this.validateNotDisconnected('connect'); From 6da6ea401f975e8beb7735c4f7e08c859bd4819e Mon Sep 17 00:00:00 2001 From: amar-1995 Date: Mon, 20 May 2024 05:54:18 +0530 Subject: [PATCH 4/9] fix: resolve pr comment --- .../src/notification-manager/managers/RoomUpdateManager.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/hms-video-store/src/notification-manager/managers/RoomUpdateManager.ts b/packages/hms-video-store/src/notification-manager/managers/RoomUpdateManager.ts index f12733bee6..84ec21d0ac 100644 --- a/packages/hms-video-store/src/notification-manager/managers/RoomUpdateManager.ts +++ b/packages/hms-video-store/src/notification-manager/managers/RoomUpdateManager.ts @@ -128,7 +128,7 @@ export class RoomUpdateManager { if (!transcriptions) { return []; } - const output = transcriptions.map((transcription: TranscriptionNotification) => { + return transcriptions.map((transcription: TranscriptionNotification) => { return { state: transcription.state, mode: transcription.mode, @@ -139,7 +139,6 @@ export class RoomUpdateManager { error: this.toSdkError(transcription?.error), }; }); - return output; } private isRecordingRunning(state?: HMSRecordingState): boolean { if (!state) { From 4755f347584ca4b86f3b195e481949c579f39332 Mon Sep 17 00:00:00 2001 From: Kaustubh Kumar Date: Mon, 20 May 2024 13:51:00 +0530 Subject: [PATCH 5/9] fix: active state for poll, chat, peer list CTAs (#2872) * fix: add autofocus to participant search * fix: autofocus flag in participant_list * fix: autofocus on tab switch * fix: clean up * fix: active state for polls, chat and peerlist --- .../src/Prebuilt/components/Footer/ChatToggle.tsx | 6 +++++- .../src/Prebuilt/components/Footer/ParticipantList.tsx | 6 ++++-- .../src/Prebuilt/components/Footer/PollsToggle.tsx | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/roomkit-react/src/Prebuilt/components/Footer/ChatToggle.tsx b/packages/roomkit-react/src/Prebuilt/components/Footer/ChatToggle.tsx index 8615b3bac4..4800931d32 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Footer/ChatToggle.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Footer/ChatToggle.tsx @@ -21,7 +21,11 @@ export const ChatToggle = ({ onClick }: { onClick?: () => void }) => { }} > - (onClick ? onClick() : toggleChat())} active={!isChatOpen} data-testid="chat_btn"> + (onClick ? onClick() : toggleChat())} + css={{ bg: isChatOpen ? '$surface_brighter' : '' }} + data-testid="chat_btn" + > diff --git a/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.tsx b/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.tsx index 24e72b9b46..8c32d370c1 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.tsx @@ -86,6 +86,7 @@ export const ParticipantList = ({ return { ...filterValue }; }); }, []); + if (peerCount === 0) { return null; } @@ -128,7 +129,7 @@ export const ParticipantList = ({ export const ParticipantCount = () => { const peerCount = useHMSStore(selectPeerCount); const toggleSidepane = useSidepaneToggle(SIDE_PANE_OPTIONS.PARTICIPANTS); - const isParticipantsOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.PARTICIPANTS); + const isPeerListOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.PARTICIPANTS); if (peerCount === 0) { return null; @@ -139,13 +140,13 @@ export const ParticipantCount = () => { w: 'auto', p: '$4', h: 'auto', + bg: isPeerListOpen ? '$surface_brighter' : '', }} onClick={() => { if (peerCount > 0) { toggleSidepane(); } }} - active={!isParticipantsOpen} data-testid="participant_list" > @@ -447,6 +448,7 @@ export const ParticipantSearch = ({ 300, [value, onSearch], ); + return ( { togglePollView(); setUnreadPollQuiz(false); }} - active={!isPollsOpen} + css={{ bg: isPollsOpen ? '$surface_brighter' : '' }} data-testid="polls_btn" > {unreadPollQuiz ? : } From e5f8002326f1ace0a83bbeb5d4883577cd42f16f Mon Sep 17 00:00:00 2001 From: Kaustubh Kumar Date: Mon, 20 May 2024 16:20:59 +0530 Subject: [PATCH 6/9] feat: resizable input (#2911) * feat: resizable input * fix: handle resize on reopening chat * fix: use usecallback --- .../Prebuilt/components/Chat/ChatFooter.tsx | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx b/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx index 51f51f2123..a5b6865219 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx @@ -102,6 +102,19 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo } } }, [defaultSelection, selectedPeer, selectedRole, setRoleSelector, isMobile, isLandscapeHLSStream, elements?.chat]); + + const resetInputHeight = useCallback(() => { + if (inputRef.current) { + inputRef.current.style.height = `${Math.max(32, inputRef.current.value ? inputRef.current.scrollHeight : 0)}px`; + } + }, []); + + const updateInputHeight = useCallback(() => { + if (inputRef.current) { + inputRef.current.style.height = `${Math.max(32, Math.min(inputRef.current.scrollHeight, 24 * 4))}px`; + } + }, []); + const sendMessage = useCallback(async () => { const message = inputRef?.current?.value; if (!message || !message.trim().length) { @@ -116,6 +129,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo await hmsActions.sendBroadcastMessage(message); } inputRef.current.value = ''; + resetInputHeight(); setTimeout(() => { onSend(1); }, 0); @@ -131,6 +145,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo const messageElement = inputRef.current; if (messageElement) { messageElement.value = draftMessage; + updateInputHeight(); } }, [draftMessage]); @@ -197,11 +212,10 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo {selection && ( vo }} autoComplete="off" aria-autocomplete="none" + onChange={updateInputHeight} + onBlur={resetInputHeight} onPaste={e => e.stopPropagation()} onCut={e => e.stopPropagation()} onCopy={e => e.stopPropagation()} From 0414aed096f17875d51a827077bde5925892d991 Mon Sep 17 00:00:00 2001 From: Kaustubh Kumar Date: Mon, 20 May 2024 17:39:09 +0530 Subject: [PATCH 7/9] fix: leaderboard scroll for mweb --- .../Polls/Voting/LeaderboardSummary.tsx | 137 +++++++++--------- 1 file changed, 71 insertions(+), 66 deletions(-) diff --git a/packages/roomkit-react/src/Prebuilt/components/Polls/Voting/LeaderboardSummary.tsx b/packages/roomkit-react/src/Prebuilt/components/Polls/Voting/LeaderboardSummary.tsx index 06475e1b1c..db2489018b 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Polls/Voting/LeaderboardSummary.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Polls/Voting/LeaderboardSummary.tsx @@ -4,6 +4,8 @@ import { ChevronLeftIcon, ChevronRightIcon, CrossIcon } from '@100mslive/react-i import { Box, Flex } from '../../../../Layout'; import { Loading } from '../../../../Loading'; import { Text } from '../../../../Text'; +// @ts-ignore +import { Container } from '../../Streaming/Common'; import { LeaderboardEntry } from './LeaderboardEntry'; import { PeerParticipationSummary } from './PeerParticipationSummary'; // @ts-ignore @@ -32,80 +34,83 @@ export const LeaderboardSummary = ({ pollID }: { pollID: string }) => { const questionCount = quiz.questions?.length || 0; return ( - - - + + + + + setPollView(POLL_VIEWS.VOTE)} + > + + + + {quiz.title} + + + setPollView(POLL_VIEWS.VOTE)} + onClick={toggleSidepane} > - + - - {quiz.title} - - - - - - - - {!viewAllEntries ? : null} + + {!viewAllEntries ? : null} - - Leaderboard - - - Based on score and time taken to cast the correct answer - - - {quizLeaderboard?.entries && - quizLeaderboard.entries - .slice(0, viewAllEntries ? undefined : 5) - .map(question => ( - - ))} - {quizLeaderboard?.entries?.length > 5 && !viewAllEntries ? ( - + Leaderboard + + + Based on score and time taken to cast the correct answer + + setViewAllEntries(true)} > - View All - - ) : null} - - + {quizLeaderboard?.entries && + quizLeaderboard.entries + .slice(0, viewAllEntries ? undefined : 5) + .map(question => ( + + ))} + {quizLeaderboard?.entries?.length > 5 && !viewAllEntries ? ( + setViewAllEntries(true)} + > + View All + + ) : null} + + + + ); }; From 3469f234919afce6822e4f957ca1ae2895f943de Mon Sep 17 00:00:00 2001 From: "Eswar Prasad Clinton. A" <64120992+eswarclynn@users.noreply.github.com> Date: Tue, 21 May 2024 13:44:10 +0530 Subject: [PATCH 8/9] fix: avg_jitter_buffer_delay in ms --- .../src/analytics/stats/SubscribeStatsAnalytics.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hms-video-store/src/analytics/stats/SubscribeStatsAnalytics.ts b/packages/hms-video-store/src/analytics/stats/SubscribeStatsAnalytics.ts index 270201af9e..9eaf2c9999 100644 --- a/packages/hms-video-store/src/analytics/stats/SubscribeStatsAnalytics.ts +++ b/packages/hms-video-store/src/analytics/stats/SubscribeStatsAnalytics.ts @@ -56,7 +56,7 @@ export class SubscribeStatsAnalytics extends BaseStatsAnalytics { const getCalculatedJitterBufferDelay = (trackStats: HMSTrackStats) => trackStats.jitterBufferDelay && trackStats.jitterBufferEmittedCount && - trackStats.jitterBufferDelay / trackStats.jitterBufferEmittedCount; + (trackStats.jitterBufferDelay / trackStats.jitterBufferEmittedCount) * 1000; const calculatedJitterBufferDelay = getCalculatedJitterBufferDelay(trackStats); From f8d4aa05c7f927eba3a3336c8fbb0eaa9a0a131c Mon Sep 17 00:00:00 2001 From: amar-1995 Date: Tue, 21 May 2024 15:08:51 +0530 Subject: [PATCH 9/9] fix: added transcription initialized state --- packages/hms-video-store/src/interfaces/room.ts | 1 + .../src/notification-manager/HMSNotifications.ts | 1 + .../src/reactive-store/HMSSDKActions.ts | 4 ++-- packages/hms-video-store/src/sdk/index.ts | 11 ++++------- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/hms-video-store/src/interfaces/room.ts b/packages/hms-video-store/src/interfaces/room.ts index a67204ccde..db861e0725 100644 --- a/packages/hms-video-store/src/interfaces/room.ts +++ b/packages/hms-video-store/src/interfaces/room.ts @@ -123,6 +123,7 @@ export interface HLSVariant { Transcription related details */ export enum HMSTranscriptionState { + INITIALISED = 'initialised', STARTED = 'started', STOPPED = 'stopped', FAILED = 'failed', diff --git a/packages/hms-video-store/src/notification-manager/HMSNotifications.ts b/packages/hms-video-store/src/notification-manager/HMSNotifications.ts index a30e663cbb..34818e72e3 100644 --- a/packages/hms-video-store/src/notification-manager/HMSNotifications.ts +++ b/packages/hms-video-store/src/notification-manager/HMSNotifications.ts @@ -62,6 +62,7 @@ export enum HMSStreamingState { } export enum HMSTranscriptionState { + INITIALISED = 'initialised', STARTED = 'started', STOPPED = 'stopped', FAILED = 'failed', diff --git a/packages/hms-video-store/src/reactive-store/HMSSDKActions.ts b/packages/hms-video-store/src/reactive-store/HMSSDKActions.ts index fdc550e98a..2fbff74954 100644 --- a/packages/hms-video-store/src/reactive-store/HMSSDKActions.ts +++ b/packages/hms-video-store/src/reactive-store/HMSSDKActions.ts @@ -701,11 +701,11 @@ export class HMSSDKActions { + async stopTranscription(params: sdkTypes.TranscriptionConfig): Promise { await this.sdk.stopTranscription(params); } diff --git a/packages/hms-video-store/src/sdk/index.ts b/packages/hms-video-store/src/sdk/index.ts index 35bf656937..2e4679323f 100644 --- a/packages/hms-video-store/src/sdk/index.ts +++ b/packages/hms-video-store/src/sdk/index.ts @@ -1013,27 +1013,24 @@ export class HMSSdk implements HMSInterface { await this.transport?.signal.stopHLSStreaming(); } - async startTranscription(params?: TranscriptionConfig) { + async startTranscription(params: TranscriptionConfig) { if (!this.localPeer) { throw ErrorFactory.GenericErrors.NotConnected( HMSAction.VALIDATION, - 'No local peer present, cannot start HLS streaming', + 'No local peer present, cannot start transcriptions', ); } - if (!params) { - throw ErrorFactory.GenericErrors.Signalling(HMSAction.VALIDATION, 'No mode is passed to start the transcription'); - } const transcriptionParams: StartTranscriptionRequestParams = { mode: params.mode, }; await this.transport?.signal.startTranscription(transcriptionParams); } - async stopTranscription(params?: TranscriptionConfig) { + async stopTranscription(params: TranscriptionConfig) { if (!this.localPeer) { throw ErrorFactory.GenericErrors.NotConnected( HMSAction.VALIDATION, - 'No local peer present, cannot stop HLS streaming', + 'No local peer present, cannot stop transcriptions', ); } if (!params) {