diff --git a/apps/100ms-custom-app/package.json b/apps/100ms-custom-app/package.json index e2c6d78b70..04256a045c 100644 --- a/apps/100ms-custom-app/package.json +++ b/apps/100ms-custom-app/package.json @@ -3,8 +3,8 @@ "version": "0.1.0", "private": true, "dependencies": { - "@100mslive/react-icons": "0.8.18", - "@100mslive/roomkit-react": "0.1.9", + "@100mslive/react-icons": "0.8.19", + "@100mslive/roomkit-react": "0.1.10", "axios": "^0.21.1", "js-cookies": "^1.0.4", "lodash.merge": "^4.6.2", diff --git a/apps/100ms-custom-app/src/utils/utils.js b/apps/100ms-custom-app/src/utils/utils.js index 6c66086ab0..8da1b1a8ba 100644 --- a/apps/100ms-custom-app/src/utils/utils.js +++ b/apps/100ms-custom-app/src/utils/utils.js @@ -170,16 +170,18 @@ export const getAuthTokenUsingRoomIdRole = async function ({ userId = '', }) { try { - const resp = await fetch(`${apiBasePath}${subdomain}/api/token`, { - method: 'POST', - body: JSON.stringify({ - room_id: roomId, - role, - user_id: userId, - }), - }); - const { token = '' } = await resp.json(); - return token; + if (roomId && role) { + const resp = await fetch(`${apiBasePath}${subdomain}/api/token`, { + method: 'POST', + body: JSON.stringify({ + room_id: roomId, + role, + user_id: userId, + }), + }); + const { token = '' } = await resp.json(); + return token; + } } catch (e) { console.error('failed to getAuthTokenUsingRoomIdRole', e); throw Error('failed to get auth token using roomid and role'); diff --git a/apps/100ms-web/package.json b/apps/100ms-web/package.json index 4e138557b1..1413e06e00 100644 --- a/apps/100ms-web/package.json +++ b/apps/100ms-web/package.json @@ -9,11 +9,11 @@ "src" ], "dependencies": { - "@100mslive/hls-player": "0.1.18", - "@100mslive/hms-virtual-background": "1.11.18", - "@100mslive/react-icons": "0.8.18", - "@100mslive/react-sdk": "0.8.18", - "@100mslive/roomkit-react": "0.1.9", + "@100mslive/hls-player": "0.1.19", + "@100mslive/hms-virtual-background": "1.11.19", + "@100mslive/react-icons": "0.8.19", + "@100mslive/react-sdk": "0.8.19", + "@100mslive/roomkit-react": "0.1.10", "@emoji-mart/data": "^1.0.6", "@emoji-mart/react": "^1.0.1", "@tldraw/tldraw": "^1.18.4", diff --git a/packages/hls-player/package.json b/packages/hls-player/package.json index a044353e4b..4f7d857a4e 100644 --- a/packages/hls-player/package.json +++ b/packages/hls-player/package.json @@ -1,6 +1,6 @@ { "name": "@100mslive/hls-player", - "version": "0.1.18", + "version": "0.1.19", "description": "HLS client library which uses HTML5 Video element and Media Source Extension for playback", "main": "dist/index.cjs.js", "module": "dist/index.js", @@ -31,7 +31,7 @@ "author": "100ms", "license": "MIT", "dependencies": { - "@100mslive/hls-stats": "0.2.18", + "@100mslive/hls-stats": "0.2.19", "eventemitter2": "^6.4.7", "hls.js": "1.4.12" } diff --git a/packages/hls-stats/package.json b/packages/hls-stats/package.json index c4fa78e910..37e6ec18cc 100644 --- a/packages/hls-stats/package.json +++ b/packages/hls-stats/package.json @@ -1,6 +1,6 @@ { "name": "@100mslive/hls-stats", - "version": "0.2.18", + "version": "0.2.19", "description": "A simple library that provides stats for your hls stream", "main": "dist/index.cjs.js", "module": "dist/index.js", diff --git a/packages/hms-noise-suppression/package.json b/packages/hms-noise-suppression/package.json index e8ce8d2d3a..bc5f3bb807 100644 --- a/packages/hms-noise-suppression/package.json +++ b/packages/hms-noise-suppression/package.json @@ -1,5 +1,5 @@ { - "version": "0.9.18", + "version": "0.9.19", "license": "MIT", "main": "dist/index.cjs.js", "typings": "dist/index.d.ts", @@ -37,6 +37,6 @@ "author": "vishaldhull09", "module": "dist/index.js", "devDependencies": { - "@100mslive/hms-video": "0.9.18" + "@100mslive/hms-video": "0.9.19" } } diff --git a/packages/hms-video-store/package.json b/packages/hms-video-store/package.json index 341d28aacf..913b0807be 100644 --- a/packages/hms-video-store/package.json +++ b/packages/hms-video-store/package.json @@ -1,5 +1,5 @@ { - "version": "0.10.18", + "version": "0.10.19", "license": "MIT", "main": "dist/index.cjs.js", "module": "dist/index.js", @@ -41,7 +41,7 @@ "author": "100ms", "sideEffects": false, "dependencies": { - "@100mslive/hms-video": "0.9.18", + "@100mslive/hms-video": "0.9.19", "eventemitter2": "^6.4.7", "immer": "^9.0.6", "reselect": "4.0.0", @@ -51,19 +51,11 @@ "ts-node": "^10.4.0", "tslib": "^2.2.0" }, - "description": "This is an addon to the core sdk provided by 100ms. It abstracts away the intricacies of data management and provides a flux based reactive data store where data flows in only one direction.", - "repository": { - "type": "git", - "url": "git+https://github.com/100mslive/hms-video-store.git" - }, + "description": "@100mslive Core SDK which abstracts the complexities of webRTC while providing a reactive store for data management with a unidirectional data flow", "keywords": [ "video", "webrtc", "conferencing", "100ms" - ], - "bugs": { - "url": "https://github.com/100mslive/hms-video-store/issues" - }, - "homepage": "https://github.com/100mslive/hms-video-store#readme" + ] } diff --git a/packages/hms-video-web/package.json b/packages/hms-video-web/package.json index 239dbf6ba3..78a3c6165b 100644 --- a/packages/hms-video-web/package.json +++ b/packages/hms-video-web/package.json @@ -1,6 +1,6 @@ { "name": "@100mslive/hms-video", - "version": "0.9.18", + "version": "0.9.19", "license": "MIT", "main": "dist/index.cjs.js", "typings": "dist/index.d.ts", diff --git a/packages/hms-virtual-background/package.json b/packages/hms-virtual-background/package.json index ec10ef8cff..f7a4478ab4 100755 --- a/packages/hms-virtual-background/package.json +++ b/packages/hms-virtual-background/package.json @@ -1,5 +1,5 @@ { - "version": "1.11.18", + "version": "1.11.19", "license": "MIT", "main": "dist/index.cjs.js", "typings": "dist/index.d.ts", @@ -30,7 +30,7 @@ "author": "ashish17", "module": "dist/index.js", "devDependencies": { - "@100mslive/hms-video": "0.9.18" + "@100mslive/hms-video": "0.9.19" }, "dependencies": { "@mediapipe/selfie_segmentation": "^0.1.1632777926", diff --git a/packages/react-icons/assets/BluetoothIcon.svg b/packages/react-icons/assets/BluetoothIcon.svg new file mode 100644 index 0000000000..60af6f9365 --- /dev/null +++ b/packages/react-icons/assets/BluetoothIcon.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/packages/react-icons/assets/BlurPersonHighIcon.svg b/packages/react-icons/assets/BlurPersonHighIcon.svg new file mode 100644 index 0000000000..1bb4b581fb --- /dev/null +++ b/packages/react-icons/assets/BlurPersonHighIcon.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/packages/react-icons/assets/BlurPersonLowIcon.svg b/packages/react-icons/assets/BlurPersonLowIcon.svg new file mode 100644 index 0000000000..15811eea54 --- /dev/null +++ b/packages/react-icons/assets/BlurPersonLowIcon.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/packages/react-icons/assets/SparkleIcon.svg b/packages/react-icons/assets/SparkleIcon.svg new file mode 100644 index 0000000000..9016989109 --- /dev/null +++ b/packages/react-icons/assets/SparkleIcon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/react-icons/package.json b/packages/react-icons/package.json index e8a3b2b272..a1bdc6e994 100644 --- a/packages/react-icons/package.json +++ b/packages/react-icons/package.json @@ -4,7 +4,7 @@ "main": "dist/index.cjs.js", "module": "dist/index.js", "typings": "dist/index.d.ts", - "version": "0.8.18", + "version": "0.8.19", "author": "100ms", "license": "MIT", "files": [ diff --git a/packages/react-icons/src/BluetoothIcon.tsx b/packages/react-icons/src/BluetoothIcon.tsx new file mode 100644 index 0000000000..f4b70b13b8 --- /dev/null +++ b/packages/react-icons/src/BluetoothIcon.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import { SVGProps } from 'react'; +const SvgBluetoothIcon = (props: SVGProps) => ( + + + + +); +export default SvgBluetoothIcon; diff --git a/packages/react-icons/src/BlurPersonHighIcon.tsx b/packages/react-icons/src/BlurPersonHighIcon.tsx new file mode 100644 index 0000000000..81a1b11838 --- /dev/null +++ b/packages/react-icons/src/BlurPersonHighIcon.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import { SVGProps } from 'react'; +const SvgBlurPersonHighIcon = (props: SVGProps) => ( + + + + +); +export default SvgBlurPersonHighIcon; diff --git a/packages/react-icons/src/BlurPersonLowIcon.tsx b/packages/react-icons/src/BlurPersonLowIcon.tsx new file mode 100644 index 0000000000..cbad4a8a53 --- /dev/null +++ b/packages/react-icons/src/BlurPersonLowIcon.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; +import { SVGProps } from 'react'; +const SvgBlurPersonLowIcon = (props: SVGProps) => ( + + + + + +); +export default SvgBlurPersonLowIcon; diff --git a/packages/react-icons/src/SparkleIcon.tsx b/packages/react-icons/src/SparkleIcon.tsx new file mode 100644 index 0000000000..909338e0a4 --- /dev/null +++ b/packages/react-icons/src/SparkleIcon.tsx @@ -0,0 +1,14 @@ +import * as React from 'react'; +import { SVGProps } from 'react'; +const SvgSparkleIcon = (props: SVGProps) => ( + + + +); +export default SvgSparkleIcon; diff --git a/packages/react-icons/src/index.ts b/packages/react-icons/src/index.ts index 53ca615ccb..6642166993 100644 --- a/packages/react-icons/src/index.ts +++ b/packages/react-icons/src/index.ts @@ -29,6 +29,9 @@ export { default as BarIcon } from './BarIcon'; export { default as BatteryFullIcon } from './BatteryFullIcon'; export { default as BatteryPowerIcon } from './BatteryPowerIcon'; export { default as BillIcon } from './BillIcon'; +export { default as BluetoothIcon } from './BluetoothIcon'; +export { default as BlurPersonHighIcon } from './BlurPersonHighIcon'; +export { default as BlurPersonLowIcon } from './BlurPersonLowIcon'; export { default as BoltIcon } from './BoltIcon'; export { default as BookIcon } from './BookIcon'; export { default as BookmarkIcon } from './BookmarkIcon'; @@ -217,6 +220,7 @@ export { default as ShrinkIcon } from './ShrinkIcon'; export { default as ShuffleIcon } from './ShuffleIcon'; export { default as SlackIcon } from './SlackIcon'; export { default as SolidCheckCircleIcon } from './SolidCheckCircleIcon'; +export { default as SparkleIcon } from './SparkleIcon'; export { default as SpeakerIcon } from './SpeakerIcon'; export { default as SpotlightIcon } from './SpotlightIcon'; export { default as SquareMenuIcon } from './SquareMenuIcon'; diff --git a/packages/react-sdk/package.json b/packages/react-sdk/package.json index 37a6025393..eef940d948 100644 --- a/packages/react-sdk/package.json +++ b/packages/react-sdk/package.json @@ -4,7 +4,7 @@ "main": "dist/index.cjs.js", "module": "dist/index.js", "typings": "dist/index.d.ts", - "version": "0.8.18", + "version": "0.8.19", "author": "100ms", "license": "MIT", "files": [ @@ -43,7 +43,7 @@ "react": ">=16.8 <19.0.0" }, "dependencies": { - "@100mslive/hms-video-store": "0.10.18", + "@100mslive/hms-video-store": "0.10.19", "react-resize-detector": "^7.0.0", "zustand": "^3.6.2" } diff --git a/packages/roomkit-react/package.json b/packages/roomkit-react/package.json index c314d8cc69..2f1ef89108 100644 --- a/packages/roomkit-react/package.json +++ b/packages/roomkit-react/package.json @@ -10,7 +10,7 @@ "prebuilt", "roomkit" ], - "version": "0.1.9", + "version": "0.1.10", "author": "100ms", "license": "MIT", "files": [ @@ -76,10 +76,10 @@ "react": ">=17.0.2 <19.0.0" }, "dependencies": { - "@100mslive/hls-player": "0.1.18", - "@100mslive/hms-virtual-background": "1.11.18", - "@100mslive/react-icons": "0.8.18", - "@100mslive/react-sdk": "0.8.18", + "@100mslive/hls-player": "0.1.19", + "@100mslive/hms-virtual-background": "1.11.19", + "@100mslive/react-icons": "0.8.19", + "@100mslive/react-sdk": "0.8.19", "@100mslive/types-prebuilt": "0.12.0", "@emoji-mart/data": "^1.0.6", "@emoji-mart/react": "^1.0.1", diff --git a/packages/roomkit-react/src/Modal/Dialog.tsx b/packages/roomkit-react/src/Modal/Dialog.tsx index fe9c7cb2e0..21cca76a07 100644 --- a/packages/roomkit-react/src/Modal/Dialog.tsx +++ b/packages/roomkit-react/src/Modal/Dialog.tsx @@ -1,28 +1,20 @@ import React, { ReactNode, useRef } from 'react'; import { Root } from '@radix-ui/react-dialog'; import { styled } from '@stitches/react'; -import { CSS } from '../Theme'; import { + CustomDialogContent, + CustomDialogOverlay, DialogClose, DialogDefaultCloseIcon, DialogDescription, DialogTitle, - StyledDialogContent, - StyledDialogOverlay, StyledDialogPortal, StyledDialogTrigger, } from './DialogContent'; import { useDialogContainerSelector } from '../hooks/useDialogContainerSelector'; const StyledDialog = styled(Root, {}); -const CustomDialogContent = ({ children, props = {}, css = {} }: { children: ReactNode; props?: any; css?: CSS }) => ( - - {children} - -); -const CustomDialogOverlay = ({ css = {} }: { css?: CSS }) => ( - -); + const CustomDialogPortal = ({ children, container }: { children: ReactNode; container?: HTMLElement | null }) => { const dialogContainerSelector = useDialogContainerSelector(); const containerRef = useRef(null); diff --git a/packages/roomkit-react/src/Modal/DialogContent.tsx b/packages/roomkit-react/src/Modal/DialogContent.tsx index 91a7dae300..8631bae8a7 100644 --- a/packages/roomkit-react/src/Modal/DialogContent.tsx +++ b/packages/roomkit-react/src/Modal/DialogContent.tsx @@ -17,19 +17,19 @@ export const StyledDialogTrigger = styled(DialogPrimitive.Trigger, { appearance: 'none !important', // Needed for safari it shows white overlay }); -export const StyledDialogOverlay = styled(DialogPrimitive.Overlay, { +export const CustomDialogOverlay = styled(DialogPrimitive.Overlay, { backgroundColor: 'rgba(0, 0, 0, 0.5);', - position: 'fixed', + position: 'absolute', inset: 0, }); export const StyledDialogPortal = styled(DialogPrimitive.Portal, {}); -export const StyledDialogContent = styled(DialogPrimitive.Content, { +export const CustomDialogContent = styled(DialogPrimitive.Content, { color: '$on_surface_medium', backgroundColor: '$surface_default', borderRadius: '8px', - position: 'fixed', + position: 'absolute', top: '50%', left: '50%', border: '$space$px solid $border_bright', diff --git a/packages/roomkit-react/src/Prebuilt/common/constants.js b/packages/roomkit-react/src/Prebuilt/common/constants.js index bb9e4692ba..4aaa2aa6d5 100644 --- a/packages/roomkit-react/src/Prebuilt/common/constants.js +++ b/packages/roomkit-react/src/Prebuilt/common/constants.js @@ -46,6 +46,8 @@ export const APP_DATA = { activeScreensharePeerId: 'activeScreensharePeerId', disableNotifications: 'disableNotifications', pollState: 'pollState', + background: 'background', + backgroundType: 'backgroundType', }; export const UI_SETTINGS = { isAudioOnly: 'isAudioOnly', @@ -61,6 +63,7 @@ export const SIDE_PANE_OPTIONS = { CHAT: 'Chat', STREAMING: 'STREAMING', POLLS: 'POLLS', + VB: 'VB', }; export const POLL_STATE = { diff --git a/packages/roomkit-react/src/Prebuilt/components/AppData/AppData.jsx b/packages/roomkit-react/src/Prebuilt/components/AppData/AppData.jsx index 1039ce6225..4e206005b8 100644 --- a/packages/roomkit-react/src/Prebuilt/components/AppData/AppData.jsx +++ b/packages/roomkit-react/src/Prebuilt/components/AppData/AppData.jsx @@ -4,7 +4,6 @@ import { selectAvailableRoleNames, selectFullAppData, selectHLSState, - selectIsConnectedToRoom, selectLocalPeerRoleName, selectRolesMap, selectRoomState, @@ -15,7 +14,7 @@ import { } from '@100mslive/react-sdk'; import { normalizeAppPolicyConfig } from '../init/initUtils'; import { UserPreferencesKeys, useUserPreferences } from '../hooks/useUserPreferences'; -import { useIsSidepaneTypeOpen, useSidepaneReset, useSidepaneState, useSidepaneToggle } from './useSidepane'; +import { useIsSidepaneTypeOpen, useSidepaneToggle } from './useSidepane'; import { useSetAppDataByKey } from './useUISettings'; import { APP_DATA, @@ -26,6 +25,7 @@ import { UI_MODE_GRID, UI_SETTINGS, } from '../../common/constants'; +import { VB_EFFECT } from '../VirtualBackground/constants'; export const getAppDetails = appDetails => { try { @@ -67,6 +67,8 @@ const initialAppData = { [APP_DATA.minimiseInset]: false, [APP_DATA.activeScreensharePeerId]: '', [APP_DATA.disableNotifications]: false, + [APP_DATA.background]: VB_EFFECT.NONE, + [APP_DATA.backgroundType]: VB_EFFECT.NONE, [APP_DATA.pollState]: { [POLL_STATE.pollInView]: '', [POLL_STATE.view]: '', @@ -75,21 +77,12 @@ const initialAppData = { export const AppData = React.memo(({ appDetails, tokenEndpoint }) => { const hmsActions = useHMSActions(); - const isConnected = useHMSStore(selectIsConnectedToRoom); - const sidePane = useSidepaneState(); - const resetSidePane = useSidepaneReset(); const [preferences = {}] = useUserPreferences(UserPreferencesKeys.UI_SETTINGS); const roleNames = useHMSStore(selectAvailableRoleNames); const rolesMap = useHMSStore(selectRolesMap); const localPeerRole = useHMSStore(selectLocalPeerRoleName); const appData = useHMSStore(selectFullAppData); - useEffect(() => { - if (!isConnected && sidePane && sidePane !== SIDE_PANE_OPTIONS.PARTICIPANTS) { - resetSidePane(); - } - }, [isConnected, sidePane, resetSidePane]); - useEffect(() => { hmsActions.initAppData({ ...initialAppData, diff --git a/packages/roomkit-react/src/Prebuilt/components/AppData/useSidepane.js b/packages/roomkit-react/src/Prebuilt/components/AppData/useSidepane.js index 05a386a47b..d0e99386a1 100644 --- a/packages/roomkit-react/src/Prebuilt/components/AppData/useSidepane.js +++ b/packages/roomkit-react/src/Prebuilt/components/AppData/useSidepane.js @@ -60,7 +60,7 @@ export const usePollViewToggle = () => { }; /** - * reset's the sidepane value + * resets the sidepane value */ export const useSidepaneReset = () => { const hmsActions = useHMSActions(); diff --git a/packages/roomkit-react/src/Prebuilt/components/Connection/ConnectionIndicator.tsx b/packages/roomkit-react/src/Prebuilt/components/Connection/ConnectionIndicator.tsx index f401acd0e0..2267172f64 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Connection/ConnectionIndicator.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Connection/ConnectionIndicator.tsx @@ -39,7 +39,7 @@ export const ConnectionIndicator = ({ } if (downlinkQuality === 0) { return ( - + @@ -48,7 +48,7 @@ export const ConnectionIndicator = ({ } const size = isTile ? 12 : 16; return ( - + import('../../plugins/VirtualBackground/VirtualBackground')); export const Footer = ({ screenType, @@ -82,11 +82,7 @@ export const Footer = ({ > {isMobile ? : null} - {isMobile ? null : ( - }> - - - )} + {isMobile ? null : } { const peerCount = useHMSStore(selectPeerCount); const toggleSidepane = useSidepaneToggle(SIDE_PANE_OPTIONS.PARTICIPANTS); const isParticipantsOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.PARTICIPANTS); - useEffect(() => { - if (isParticipantsOpen && peerCount === 0) { - toggleSidepane(); - } - }, [isParticipantsOpen, peerCount, toggleSidepane]); if (peerCount === 0) { return null; diff --git a/packages/roomkit-react/src/Prebuilt/components/Header/Header.tsx b/packages/roomkit-react/src/Prebuilt/components/Header/Header.tsx index a93c98ff11..abea666ef3 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Header/Header.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Header/Header.tsx @@ -7,7 +7,7 @@ import { Logo, SpeakerTag } from './HeaderComponents'; // @ts-ignore: No implicit any import { LiveStatus, RecordingStatus, StreamActions } from './StreamActions'; // @ts-ignore: No implicit any -import { AudioOutputActions, CamaraFlipActions } from './common'; +import { AudioActions, CamaraFlipActions } from './common'; export const Header = () => { const roomState = useHMSStore(selectRoomState); @@ -40,7 +40,7 @@ export const Header = () => { {isMobile ? ( <> - + ) : null} diff --git a/packages/roomkit-react/src/Prebuilt/components/Header/common.jsx b/packages/roomkit-react/src/Prebuilt/components/Header/common.jsx index bd9a1222a3..a61d03eeff 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Header/common.jsx +++ b/packages/roomkit-react/src/Prebuilt/components/Header/common.jsx @@ -8,7 +8,14 @@ import { useHMSActions, useHMSStore, } from '@100mslive/react-sdk'; -import { CameraFlipIcon, CheckIcon, CrossIcon, SpeakerIcon } from '@100mslive/react-icons'; +import { + BluetoothIcon, + CameraFlipIcon, + CheckIcon, + CrossIcon, + HeadphonesIcon, + SpeakerIcon, +} from '@100mslive/react-icons'; import { HorizontalDivider } from '../../../Divider'; import { Label } from '../../../Label'; import { Box, Flex } from '../../../Layout'; @@ -49,48 +56,64 @@ export const CamaraFlipActions = () => { ); }; -export const AudioOutputActions = () => { +// It will handle and show audio input devices in Mweb while audio output devices in desktop +export const AudioActions = () => { const { allDevices, selectedDeviceIDs, updateDevice } = useDevices(); - const { audioOutput } = allDevices; + // don't show speaker selector where the API is not supported, and use // a generic word("Audio") for Mic. In some cases(Chrome Android for e.g.) this changes both mic and speaker keeping them in sync. const shouldShowAudioOutput = 'setSinkId' in HTMLMediaElement.prototype; + const { audioInput, audioOutput } = allDevices; + let availableAudioDevices = audioInput; + let selectedAudio = selectedDeviceIDs.audioInput; + if (shouldShowAudioOutput) { + availableAudioDevices = audioOutput; + selectedAudio = selectedDeviceIDs.audioOutput; + } + const hmsActions = useHMSActions(); + const audioFiltered = availableAudioDevices?.find(item => !!item.label); + const currentSelection = availableAudioDevices?.find(item => item.deviceId === selectedAudio); - /** - * Chromium browsers return an audioOutput with empty label when no permissions are given - */ - const audioOutputFiltered = audioOutput?.filter(item => !!item.label) ?? []; - if (!shouldShowAudioOutput || !audioOutputFiltered?.length > 0) { + if (!audioFiltered) { return null; } + let AudioIcon = ; + if (currentSelection && currentSelection.label.toLowerCase().includes('bluetooth')) { + AudioIcon = ; + } else if (currentSelection && currentSelection.label.toLowerCase().includes('wired')) { + AudioIcon = ; + } return ( - { try { await updateDevice({ deviceId, - deviceType: DeviceType.audioOutput, + deviceType: shouldShowAudioOutput ? DeviceType.audioOutput : DeviceType.audioInput, }); } catch (e) { ToastManager.addToast({ - title: `Error while changing audio output ${e.message || ''}`, + title: `Error while changing audio device ${e.message || ''}`, variant: 'error', }); } }} > - - - - + { + // refresh device as `devicechange` listener won't work in mobile device + await hmsActions.refreshDevices(); + }} + > + {AudioIcon} - + ); }; -const AudioOutputSelectionSheet = ({ outputDevices, outputSelected, onChange, children }) => { +const AudioSelectionSheet = ({ audioDevices, audioSelected, onChange, children }) => { return ( {children} @@ -98,7 +121,7 @@ const AudioOutputSelectionSheet = ({ outputDevices, outputSelected, onChange, ch - Audio Output + Audio @@ -113,16 +136,16 @@ const AudioOutputSelectionSheet = ({ outputDevices, outputSelected, onChange, ch css={{ px: '$8', maxHeight: '80vh', - overflowY: 'scroll', + overflowY: 'auto', }} > - {outputDevices.map(audioDevice => { + {audioDevices.map(audioDevice => { return ( onChange(audioDevice.deviceId)} /> ); diff --git a/packages/roomkit-react/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx b/packages/roomkit-react/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx index d51e7ec3da..6e89cc87d8 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx @@ -20,9 +20,9 @@ export const DesktopLeaveRoom = ({ screenType, endRoom, }: { - leaveRoom: (args: { endstream: boolean }) => void; + leaveRoom: (options?: { endStream?: boolean }) => Promise; screenType: keyof ConferencingScreen; - endRoom: () => void; + endRoom: () => Promise; }) => { const [open, setOpen] = useState(false); const [showLeaveRoomAlert, setShowLeaveRoomAlert] = useState(false); @@ -78,7 +78,7 @@ export const DesktopLeaveRoom = ({ color: '$on_surface_medium', '&:hover': { bg: '$surface_default', color: '$on_surface_high' }, }} - onClick={() => leaveRoom({ endstream: false })} + onClick={async () => await leaveRoom()} data-testid="just_leave_btn" > } - onClick={() => leaveRoom({ endstream: false })} + onClick={async () => await leaveRoom()} css={{ p: 0 }} /> @@ -142,7 +142,7 @@ export const DesktopLeaveRoom = ({ leaveRoom({ endStream: true }) : endRoom} isStreamingOn={isStreamingOn} isModal /> diff --git a/packages/roomkit-react/src/Prebuilt/components/Leave/EndSessionContent.tsx b/packages/roomkit-react/src/Prebuilt/components/Leave/EndSessionContent.tsx index 591c4c2072..07ee712494 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Leave/EndSessionContent.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Leave/EndSessionContent.tsx @@ -11,7 +11,7 @@ export const EndSessionContent = ({ isStreamingOn = false, }: { setShowEndStreamAlert: (value: boolean) => void; - leaveRoom: (args: { endstream: boolean }) => void; + leaveRoom: (options?: { endStream?: boolean }) => Promise; isModal?: boolean; isStreamingOn: boolean; }) => { @@ -50,7 +50,7 @@ export const EndSessionContent = ({ variant="danger" css={{ w: '100%' }} onClick={async () => { - await leaveRoom({ endstream: true }); + await leaveRoom({ endStream: true }); setShowEndStreamAlert(false); }} id="stopStream" diff --git a/packages/roomkit-react/src/Prebuilt/components/Leave/LeaveRoom.tsx b/packages/roomkit-react/src/Prebuilt/components/Leave/LeaveRoom.tsx index b6991166ec..681057a310 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Leave/LeaveRoom.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Leave/LeaveRoom.tsx @@ -46,15 +46,16 @@ export const LeaveRoom = ({ screenType }: { screenType: keyof ConferencingScreen ToastManager.addToast({ title: 'Error in stopping the stream', type: 'error' }); } }; - const endRoom = () => { - hmsActions.endRoom(false, 'End Room'); + + const endRoom = async () => { + await hmsActions.endRoom(false, 'End Room'); }; - const leaveRoom = async ({ endstream = false }) => { - if (endstream || (hlsState.running && peersWithStreamingRights.length === 1)) { + const leaveRoom = async (options: { endStream?: boolean } = { endStream: false }) => { + if (options.endStream || (hlsState.running && peersWithStreamingRights.length === 1)) { await stopStream(); } - hmsActions.leave(); + await hmsActions.leave(); }; if (!permissions || !isConnected) { diff --git a/packages/roomkit-react/src/Prebuilt/components/Leave/LeaveSessionContent.tsx b/packages/roomkit-react/src/Prebuilt/components/Leave/LeaveSessionContent.tsx index c24821f8e6..5f134701a9 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Leave/LeaveSessionContent.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Leave/LeaveSessionContent.tsx @@ -10,7 +10,7 @@ export const LeaveSessionContent = ({ isModal = false, }: { setShowLeaveRoomAlert: (value: boolean) => void; - leaveRoom: (args: { endstream: boolean }) => void; + leaveRoom: (options?: { endStream?: boolean }) => Promise; isModal?: boolean; }) => { return ( @@ -47,7 +47,7 @@ export const LeaveSessionContent = ({ ) : ( ); @@ -274,7 +279,7 @@ export const PreviewControls = ({ hideSettings }: { hideSettings: boolean }) => > - {!isMobile ? : null} + {!isMobile ? : null} {!hideSettings ? : null} diff --git a/packages/roomkit-react/src/Prebuilt/components/RoleChangeRequest/RequestPrompt.tsx b/packages/roomkit-react/src/Prebuilt/components/RoleChangeRequest/RequestPrompt.tsx index bbbc7f036e..1cbd39ddea 100644 --- a/packages/roomkit-react/src/Prebuilt/components/RoleChangeRequest/RequestPrompt.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/RoleChangeRequest/RequestPrompt.tsx @@ -33,10 +33,9 @@ export const RequestPrompt = ({ } return ( - + - - + e.preventDefault()}> {title} diff --git a/packages/roomkit-react/src/Prebuilt/components/Settings/DeviceSettings.jsx b/packages/roomkit-react/src/Prebuilt/components/Settings/DeviceSettings.jsx index 2c81a581c1..38abab0ea0 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Settings/DeviceSettings.jsx +++ b/packages/roomkit-react/src/Prebuilt/components/Settings/DeviceSettings.jsx @@ -1,14 +1,17 @@ import React, { Fragment, useEffect, useRef, useState } from 'react'; +import { useMedia } from 'react-use'; import { DeviceType, selectIsLocalVideoEnabled, selectLocalVideoTrackID, selectVideoTrackByID, useDevices, + useHMSActions, useHMSStore, } from '@100mslive/react-sdk'; import { MicOnIcon, SpeakerIcon, VideoOnIcon } from '@100mslive/react-icons'; import { Box, Button, Dropdown, Flex, StyledVideoTile, Text, Video } from '../../../'; +import { config as cssConfig } from '../../../Theme'; import { DialogDropdownTrigger } from '../../primitives/DropdownTrigger'; import { useUISettings } from '../AppData/useUISettings'; import { useDropdownSelection } from '../hooks/useDropdownSelection'; @@ -30,7 +33,15 @@ const Settings = ({ setHide }) => { const shouldShowAudioOutput = 'setSinkId' in HTMLMediaElement.prototype; const mirrorLocalVideo = useUISettings(UI_SETTINGS.mirrorLocalVideo); const trackSelector = selectVideoTrackByID(videoTrackId); + const hmsActions = useHMSActions(); const track = useHMSStore(trackSelector); + const isMobile = useMedia(cssConfig.media.md); + + useEffect(() => { + if (isMobile) { + hmsActions.refreshDevices(); + } + }, [hmsActions, isMobile]); /** * Chromium browsers return an audioOutput with empty label when no permissions are given diff --git a/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBCollection.tsx b/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBCollection.tsx new file mode 100644 index 0000000000..ba2f381416 --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBCollection.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { Box } from '../../../Layout'; +import { Text } from '../../../Text'; +import { VBOption } from './VBOption'; +import { VB_EFFECT } from './constants'; + +export const VBCollection = ({ + options, + title, + activeBackgroundType = '', + activeBackground = '', +}: { + options: { + title?: string; + icon?: React.JSX.Element; + onClick?: () => Promise; + mediaURL?: string; + type: string; + }[]; + title: string; + activeBackground: HTMLImageElement | string; + activeBackgroundType: string; +}) => { + if (options.length === 0) { + return null; + } + return ( + + + {title} + + + {options.map(option => ( + + {option?.icon} + {option?.title} + + ))} + + + ); +}; diff --git a/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBOption.tsx b/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBOption.tsx new file mode 100644 index 0000000000..d8cbecdf38 --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBOption.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { Box, Flex } from '../../../Layout'; +import { Text } from '../../../Text'; + +const Root = ({ + onClick, + mediaURL, + isActive, + children, +}: { + onClick?: () => Promise; + mediaURL?: string; + isActive: boolean; + children?: React.JSX.Element[]; +}) => ( + await onClick?.()} + > + {children} + +); + +const Title = ({ children }: { children?: string }) => { + return children ? ( + + {children} + + ) : null; +}; + +const Icon = ({ children }: { children?: React.JSX.Element }) => { + return children ? {children} : null; +}; + +export const VBOption = { + Root, + Title, + Icon, +}; diff --git a/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBPicker.jsx b/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBPicker.jsx new file mode 100644 index 0000000000..7cfd4c3859 --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBPicker.jsx @@ -0,0 +1,165 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { + HMSRoomState, + selectIsLargeRoom, + selectIsLocalVideoEnabled, + selectLocalPeer, + selectLocalPeerRole, + selectLocalVideoTrackID, + selectRoomState, + selectVideoTrackByID, + useHMSActions, + useHMSStore, +} from '@100mslive/react-sdk'; +import { BlurPersonHighIcon, CloseIcon, CrossCircleIcon } from '@100mslive/react-icons'; +import { Box, Flex, Video } from '../../../index'; +import { Text } from '../../../Text'; +import { VBCollection } from './VBCollection'; +import { useSidepaneToggle } from '../AppData/useSidepane'; +import { useUISettings } from '../AppData/useUISettings'; +import { SIDE_PANE_OPTIONS, UI_SETTINGS } from '../../common/constants'; +import { defaultMedia, VB_EFFECT, vbPlugin } from './constants'; + +const iconDims = { height: '40px', width: '40px' }; +const MAX_RETRIES = 2; + +export const VBPicker = () => { + const toggleVB = useSidepaneToggle(SIDE_PANE_OPTIONS.VB); + const hmsActions = useHMSActions(); + const role = useHMSStore(selectLocalPeerRole); + const [isVBSupported, setIsVBSupported] = useState(false); + const localPeerVideoTrackID = useHMSStore(selectLocalVideoTrackID); + const localPeer = useHMSStore(selectLocalPeer); + const [background, setBackground] = useState(vbPlugin.background); + const [backgroundType, setBackgroundType] = useState(vbPlugin.backgroundType); + const isVideoOn = useHMSStore(selectIsLocalVideoEnabled); + const mirrorLocalVideo = useUISettings(UI_SETTINGS.mirrorLocalVideo); + const trackSelector = selectVideoTrackByID(localPeer?.videoTrack); + const track = useHMSStore(trackSelector); + const roomState = useHMSStore(selectRoomState); + const isLargeRoom = useHMSStore(selectIsLargeRoom); + const addedPluginToVideoTrack = useRef(false); + + // Hidden in preview as the effect will be visible in the preview tile. Needed inside the room because the peer might not be on-screen + const showVideoTile = isVideoOn && isLargeRoom && roomState !== HMSRoomState.Preview; + + const clearVBState = () => { + setBackground(VB_EFFECT.NONE); + setBackgroundType(VB_EFFECT.NONE); + }; + + useEffect(() => { + if (!localPeerVideoTrackID) { + return; + } + + //check support of plugin + if (vbPlugin) { + const pluginSupport = hmsActions.validateVideoPluginSupport(vbPlugin); + setIsVBSupported(pluginSupport.isSupported); + } + }, [hmsActions, localPeerVideoTrackID]); + + async function disableEffects() { + if (vbPlugin) { + vbPlugin.setBackground(VB_EFFECT.NONE, VB_EFFECT.NONE); + clearVBState(); + } + } + + async function addPlugin({ mediaURL = '', blurPower = 0 }) { + let retries = 0; + try { + if (mediaURL) { + const img = document.createElement('img'); + img.alt = 'VB'; + img.src = mediaURL; + try { + await vbPlugin.setBackground(img, VB_EFFECT.MEDIA); + } catch (e) { + console.error(e); + if (retries++ < MAX_RETRIES) { + await vbPlugin.setBackground(img, VB_EFFECT.MEDIA); + } + } + } else if (blurPower) { + await vbPlugin.setBackground(VB_EFFECT.BLUR, VB_EFFECT.BLUR); + } + setBackground(mediaURL || VB_EFFECT.BLUR); + setBackgroundType(mediaURL ? VB_EFFECT.MEDIA : VB_EFFECT.BLUR); + if (role && !addedPluginToVideoTrack.current) { + await hmsActions.addPluginToVideoTrack(vbPlugin, Math.floor(role.publishParams.video.frameRate / 2)); + addedPluginToVideoTrack.current = true; + } + } catch (err) { + console.error('Failed to apply VB', err); + disableEffects(); + } + } + + useEffect(() => { + if (!isVideoOn) { + toggleVB(); + } + }, [isVideoOn, toggleVB]); + + if (!isVBSupported) { + return null; + } + + return ( + + + + Virtual Background + + + + + + + {showVideoTile ? ( + + ) : null} + + , + type: VB_EFFECT.NONE, + onClick: async () => await disableEffects(), + }, + { + title: 'Blur', + icon: , + type: VB_EFFECT.BLUR, + onClick: async () => await addPlugin({ blurPower: 0.5 }), + }, + ]} + activeBackgroundType={backgroundType || VB_EFFECT.NONE} + activeBackground={vbPlugin.background?.src || vbPlugin.background || VB_EFFECT.NONE} + /> + + ({ + type: VB_EFFECT.MEDIA, + mediaURL, + onClick: async () => await addPlugin({ mediaURL }), + }))} + activeBackgroundType={backgroundType || VB_EFFECT.NONE} + activeBackground={background?.src || background || VB_EFFECT.NONE} + /> + + ); +}; diff --git a/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBToggle.jsx b/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBToggle.jsx new file mode 100644 index 0000000000..dc34ae3331 --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBToggle.jsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { selectIsLocalVideoEnabled, useHMSStore } from '@100mslive/react-sdk'; +import { VirtualBackgroundIcon } from '@100mslive/react-icons'; +import { Tooltip } from '../../../Tooltip'; +import IconButton from '../../IconButton'; +import { useIsSidepaneTypeOpen, useSidepaneToggle } from '../AppData/useSidepane'; +import { isSafari, SIDE_PANE_OPTIONS } from '../../common/constants'; + +export const VBToggle = () => { + const toggleVB = useSidepaneToggle(SIDE_PANE_OPTIONS.VB); + const isVBOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.VB); + const isVideoOn = useHMSStore(selectIsLocalVideoEnabled); + + if (!isVideoOn || isSafari) { + return null; + } + + return ( + + + + + + ); +}; diff --git a/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/constants.ts b/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/constants.ts new file mode 100644 index 0000000000..9a8863bd9e --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/constants.ts @@ -0,0 +1,26 @@ +import { HMSVBPlugin, HMSVirtualBackgroundTypes } from '@100mslive/hms-virtual-background'; + +// Will support all media, setting to image here to test with current plugin interface +export const VB_EFFECT = { + BLUR: 'blur', + BEAUTIFY: 'BEAUTIFY', + NONE: 'none', + MEDIA: 'image', +}; + +export const defaultMedia = [ + 'https://assets.100ms.live/webapp/vb-mini/vb-1.jpg', + 'https://assets.100ms.live/webapp/vb-mini/vb-2.jpg', + 'https://assets.100ms.live/webapp/vb-mini/vb-3.png', + 'https://assets.100ms.live/webapp/vb-mini/vb-4.jpg', + 'https://assets.100ms.live/webapp/vb-mini/vb-5.jpg', + 'https://assets.100ms.live/webapp/vb-mini/vb-6.jpg', + 'https://assets.100ms.live/webapp/vb-mini/vb-7.jpg', + 'https://assets.100ms.live/webapp/vb-mini/vb-8.jpg', + 'https://assets.100ms.live/webapp/vb-mini/vb-9.jpg', + 'https://assets.100ms.live/webapp/vb-mini/vb-10.jpg', + 'https://assets.100ms.live/webapp/vb-mini/vb-11.jpg', + 'https://assets.100ms.live/webapp/vb-mini/vb-12.jpg', +]; + +export const vbPlugin = new HMSVBPlugin(HMSVirtualBackgroundTypes.NONE, HMSVirtualBackgroundTypes.NONE); diff --git a/packages/roomkit-react/src/Prebuilt/components/hooks/useAutoStartStreaming.tsx b/packages/roomkit-react/src/Prebuilt/components/hooks/useAutoStartStreaming.tsx index ca22197581..a20ac95886 100644 --- a/packages/roomkit-react/src/Prebuilt/components/hooks/useAutoStartStreaming.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/hooks/useAutoStartStreaming.tsx @@ -1,6 +1,5 @@ import { useCallback, useEffect, useRef } from 'react'; import { - HMSException, selectIsConnectedToRoom, selectPermissions, useHMSActions, @@ -20,7 +19,7 @@ export const useAutoStartStreaming = () => { const showStreamingUI = useShowStreamingUI(); const hmsActions = useHMSActions(); const isConnected = useHMSStore(selectIsConnectedToRoom); - const { isHLSRunning, isRTMPRunning } = useRecordingStreaming(); + const { isHLSRunning, isRTMPRunning, isRecordingOn } = useRecordingStreaming(); const streamStartedRef = useRef(false); const startHLS = useCallback(async () => { @@ -32,9 +31,7 @@ export const useAutoStartStreaming = () => { streamStartedRef.current = true; await hmsActions.startHLSStreaming(); } catch (error) { - if ((error as HMSException).message?.includes('beam already started')) { - return; - } + console.error(error); streamStartedRef.current = false; setHLSStarted(false); } @@ -47,10 +44,10 @@ export const useAutoStartStreaming = () => { }, [isHLSStarted, isHLSRunning]); useEffect(() => { - if (!isConnected || streamStartedRef.current || !permissions?.hlsStreaming) { + if (!isConnected || streamStartedRef.current || !permissions?.hlsStreaming || isRecordingOn) { return; } - // Is a streaming kit and broadcaster joins + // Is a streaming kit and peer with streaming permissions joins startHLS(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [isConnected]); diff --git a/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx b/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx index b6225a05a8..b6172a281c 100644 --- a/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx +++ b/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx @@ -1,5 +1,5 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; -import { useFullscreen, useMedia, useToggle } from 'react-use'; +import { useFullscreen, useMedia, usePrevious, useToggle } from 'react-use'; import { HLSPlaybackState, HMSHLSPlayer, HMSHLSPlayerEvents } from '@100mslive/hls-player'; import screenfull from 'screenfull'; import { selectAppData, selectHLSState, useHMSActions, useHMSStore } from '@100mslive/react-sdk'; @@ -42,6 +42,7 @@ const HLSView = () => { const controlsRef = useRef(); const controlsTimerRef = useRef(); const [qualityDropDownOpen, setQualityDropDownOpen] = useState(false); + const lastHlsUrl = usePrevious(hlsUrl); const isMobile = useMedia(config.media.md); const isFullScreen = useFullscreen(hlsViewRef, show, { @@ -64,6 +65,11 @@ const HLSView = () => { videoEl?.removeEventListener('waiting', showLoader); }; }, []); + useEffect(() => { + if (streamEnded && lastHlsUrl !== hlsUrl) { + setStreamEnded(false); + } + }, [hlsUrl, streamEnded, lastHlsUrl]); useEffect(() => { const videoElem = videoRef.current; diff --git a/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx b/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx index 0839ffb976..3ceaa618ab 100644 --- a/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx +++ b/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { useMedia } from 'react-use'; import { ConferencingScreen } from '@100mslive/types-prebuilt'; import { selectAppData, selectVideoTrackByPeerID, useHMSStore } from '@100mslive/react-sdk'; @@ -7,8 +7,12 @@ import { SidePaneTabs } from '../components/SidePaneTabs'; import { TileCustomisationProps } from '../components/VideoLayouts/GridLayout'; // @ts-ignore: No implicit Any import VideoTile from '../components/VideoTile'; +// @ts-ignore: No implicit Any +import { VBPicker } from '../components/VirtualBackground/VBPicker'; import { Box, Flex } from '../../Layout'; import { config as cssConfig } from '../../Theme'; +// @ts-ignore: No implicit Any +import { useSidepaneReset } from '../components/AppData/useSidepane'; import { useRoomLayoutConferencingScreen } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen'; import { translateAcross } from '../../utils'; // @ts-ignore: No implicit Any @@ -20,14 +24,15 @@ const SidePane = ({ hideControls = false, }: { screenType: keyof ConferencingScreen; - tileProps: TileCustomisationProps; - hideControls: boolean; + tileProps?: TileCustomisationProps; + hideControls?: boolean; }) => { const isMobile = useMedia(cssConfig.media.md); const sidepane = useHMSStore(selectAppData(APP_DATA.sidePane)); const activeScreensharePeerId = useHMSStore(selectAppData(APP_DATA.activeScreensharePeerId)); const trackId = useHMSStore(selectVideoTrackByPeerID(activeScreensharePeerId))?.id; const { elements } = useRoomLayoutConferencingScreen(); + const resetSidePane = useSidepaneReset(); let ViewComponent; if (sidepane === SIDE_PANE_OPTIONS.POLLS) { ViewComponent = ; @@ -35,6 +40,16 @@ const SidePane = ({ if (sidepane === SIDE_PANE_OPTIONS.PARTICIPANTS || sidepane === SIDE_PANE_OPTIONS.CHAT) { ViewComponent = ; } + if (sidepane === SIDE_PANE_OPTIONS.VB) { + ViewComponent = ; + } + + useEffect(() => { + return () => { + resetSidePane(); + }; + }, [resetSidePane]); + if (!ViewComponent && !trackId) { return null; } @@ -46,7 +61,7 @@ const SidePane = ({ hideMetadataOnTile: tileProps?.hide_metadata_on_tile, objectFit: tileProps?.video_object_fit, }; - + const VB = sidepane === SIDE_PANE_OPTIONS.VB; const mwebStreamingChat = isMobile && sidepane === SIDE_PANE_OPTIONS.CHAT && elements?.chat?.is_overlay; return ( @@ -58,6 +73,7 @@ const SidePane = ({ h: '100%', flexShrink: 0, gap: '$4', + position: 'relative', '@md': { position: mwebStreamingChat ? 'absolute' : '', zIndex: 12 }, }} > @@ -76,7 +92,7 @@ const SidePane = ({ css={{ w: '$100', h: mwebStreamingChat ? '0' : '100%', - p: '$10', + p: VB ? '$10 $6 $10 $10' : '$10', flex: '1 1 0', minHeight: 0, maxHeight: mwebStreamingChat ? '300px' : 'unset', diff --git a/packages/roomkit-web/README.md b/packages/roomkit-web/README.md new file mode 100644 index 0000000000..7390104cbe --- /dev/null +++ b/packages/roomkit-web/README.md @@ -0,0 +1,53 @@ +# `@100mslive/roomkit-web` + +A web component implementation of the HMSPrebuilt component from [roomkit-react](https://www.100ms.live/docs/javascript/v2/quickstart/prebuilt-quickstart) library. + +## Usage + +``` +import '@100mslive/roomkit-web' + +Vue + +YourComponent.vue + + + +``` + +## Props + +`hms-prebuilt` accepts the following props: + +`room-code` (optional if room-id and role are being used instead) +- The room code of the room you want to join. You can get the room code from the [100ms dashboard](https://dashboard.100ms.live). This prop can be skipped if the room-id and role are being provided instead. + +`logo` (optional) +- An image URL as a string which is displayed in the preview screen and header. + +`auth-token` (optional) +- This token is room and role specific. It can be copied from the join room modal on the [dashboard](https://dashboard.100ms.live). Read more about it [here](/get-started/v2/get-started/security-and-tokens#auth-token-for-client-sdks). + +`room-id` (optional unless room-code is not being used) +- The room ID of the room you want to join. You can get the room ID from the [dashboard](https://dashboard.100ms.live). It should be specified with the role prop if the room-code is not being provided. + +`role` (optional unless room-id is specified) +- A string specifying the role of the peer. Should be specified if the room-id is being used to join the room. + +`on-join` (optional) +- A callback function that will be executed after the peer joins the call. + +`on-leave` (optional) +- A callback function that will be executed after the peer leaves the call, the session ends or if the peer gets kicked out. + +`options` (optional) +- A stringified JSON object which accepts the following parameters: + - `userName` (optional): The name to be assigned to the peer. + + - `userId` (optional): The user ID to be assigned to the peer. + +> NOTE: The callbacks on-join and on-leave have to be present on the `window` as of now for them to be triggered. \ No newline at end of file diff --git a/packages/roomkit-web/package.json b/packages/roomkit-web/package.json new file mode 100644 index 0000000000..3af9b24dd2 --- /dev/null +++ b/packages/roomkit-web/package.json @@ -0,0 +1,34 @@ +{ + "name": "@100mslive/roomkit-web", + "version": "0.0.3", + "description": "A web component implementation of 100ms Prebuilt component", + "keywords": [ + "web-components", + "100ms", + "Prebuilt" + ], + "source": "src/index.ts", + "main": "dist/index.cjs.js", + "module": "dist/index.js", + "typings": "dist/index.d.ts", + "author": "100ms", + "license": "MIT", + "files": [ + "dist" + ], + "exports": { + ".": { + "require": "./dist/index.cjs.js", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "sideEffects": false, + "scripts": { + "build": "rm -rf dist && node ../../scripts/build-webapp" + }, + "dependencies": { + "@100mslive/roomkit-react": "0.1.10", + "@r2wc/react-to-web-component": "2.0.2" + } +} diff --git a/packages/roomkit-web/src/index.js b/packages/roomkit-web/src/index.js new file mode 100644 index 0000000000..bc099b10b6 --- /dev/null +++ b/packages/roomkit-web/src/index.js @@ -0,0 +1,15 @@ +import r2wc from '@r2wc/react-to-web-component'; +import { HMSPrebuilt } from '@100mslive/roomkit-react'; + +const HMSPrebuiltWebComponent = r2wc(HMSPrebuilt, { + props: { + roomCode: 'string', + authToken: 'string', + roomId: 'string', + role: 'string', + options: 'json', + onLeave: 'function', + }, +}); + +customElements.define('hms-prebuilt', HMSPrebuiltWebComponent); diff --git a/scripts/build-webapp.js b/scripts/build-webapp.js index 85e448f7a0..3953a1388f 100644 --- a/scripts/build-webapp.js +++ b/scripts/build-webapp.js @@ -3,6 +3,7 @@ const esbuild = require('esbuild'); const PostCssPlugin = require('esbuild-plugin-postcss2'); const autoprefixer = require('autoprefixer'); +// eslint-disable-next-line complexity async function main() { if (fs.existsSync('./dist')) { fs.rmSync('./dist', { recursive: true }, e => { @@ -13,7 +14,12 @@ async function main() { } require('dotenv').config(); const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); - const source = pkg.name === '100ms_edtech_template' ? './src/App.js' : './src/index.ts'; + const source = + pkg.name === '100ms_edtech_template' + ? './src/App.js' + : pkg.name === '@100mslive/roomkit-web' + ? './src/index.js' + : './src/index.ts'; const external = [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})]; const loader = { '.js': 'jsx', '.svg': 'dataurl', '.png': 'dataurl' }; const define = { 'process.env': JSON.stringify(process.env) }; diff --git a/yarn.lock b/yarn.lock index 33e368885c..34b45feb53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3317,6 +3317,18 @@ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== +"@r2wc/core@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@r2wc/core/-/core-1.0.1.tgz#5f1c55b3f0ef63787034382a27204959818c8011" + integrity sha512-3Q/IEvGoJ8E+wy8Y6vo+Hot35z89Ei0Ghr7WAhprxz1LhuCAaA2BIYXY8GjaCvJLGhiOLuiPMWb8DKfbrUzEMg== + +"@r2wc/react-to-web-component@2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@r2wc/react-to-web-component/-/react-to-web-component-2.0.2.tgz#695a077a231c108226d1b3cf69b43dbcfe607c6c" + integrity sha512-HxgWXh6aipgvZ7l31m+AN0mM8KI5jkiCEBnSMBl/UKibVrhFgtsumL8fmLd5/q+OHBJKK0w4e5sAmzY1yu8dpA== + dependencies: + "@r2wc/core" "^1.0.0" + "@radix-ui/number@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.0.0.tgz#4c536161d0de750b3f5d55860fc3de46264f897b"