diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 674766d7ca..ab2d4a1de5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,5 +1,4 @@ @raviteja83 @KaustubhKumar05 -@amar-1995 @hdz-666 @ygit \ No newline at end of file diff --git a/README.md b/README.md index 07fd77dc2a..a34d228c3c 100644 --- a/README.md +++ b/README.md @@ -5,18 +5,20 @@ This monorepo contains all the packages required to integrate 100ms on the web. ## What is included? The packages folder contains all the SDK's of 100ms. Here is a brief overview of them: + | Directory | Package | Description | Link | |--|--|--|--| | `hms-video-store` | `@100mslive/hms-video-store` | This package contains the core SDK and the reactive store parts. | [README](./packages/hms-video-store) | -| `react-icons` | `@100mslive/react-icons` | This contains all the icons used in the 100ms prebuilt. | [README](./packages/react-icons) | | `react-sdk` | `@100mslive/react-sdk` | This contains the base React Hooks and some commonly used functionalities as React Hooks. | [README](./packages/react-sdk) | | `roomkit-react` | `@100mslive/roomkit-react`| This contains the React components used in the Prebuilt and the Prebuilt component itself. | [README](./packages/roomkit-react) | -| `roomkit-web` | `@100mslive/roomkit-web` | This is a web component port of the `HMSPrebuilt` component from the `roomkit-react`. If you are not using React,this can be used as a web component. | [README](./packages/roomkit-web)| +| `roomkit-web` | `@100mslive/roomkit-web` | This is a web component port of the `HMSPrebuilt` component from the `roomkit-react`. If you are not using React, this can be used as a web component. | [README](./packages/roomkit-web)| +| `hls-player` | `@100mslive/hls-player` | This is a HLS player offered by 100ms that can be used to play live video streams. | [README](./packages/hls-player) | +| `hms-whiteboard` | `@100mslive/hms-whiteboard` | This contains APIs for integrating Whiteboard collaboration into your conferencing sessions. | [README](./packages/hms-whiteboard) | +| `hms-virtual-background` | `@100mslive/hms-virtual-background` | This contains the Virtual Background plugin provided by 100ms. | [README](./packages/hms-virtual-background) | +| `react-icons` | `@100mslive/react-icons` | This contains all the icons used in the 100ms prebuilt. | [README](./packages/react-icons) | For full documentation, visit [100ms.live/docs](https://www.100ms.live/docs) -
- ## How to integrate? The 100ms SDK gives you everything you need to build scalable, high-quality live video and audio experiences. @@ -26,19 +28,17 @@ The 100ms SDK gives you everything you need to build scalable, high-quality live 1. ## Custom UI - 100ms SDKs are powerful and highly extensible to build and support all custom experiences and UI. - **Related packages include:** `@100mslive/react-sdk`, `@100mslive/hms-video-store` and `@100mslive/react-icons`. - - Get started with integrating the SDK using the [How to Guide](https://www.100ms.live/docs/javascript/v2/how-to-guides/install-the-sdk/integration).
+ - Get started with integrating the SDK using the [How to Guide](https://www.100ms.live/docs/javascript/v2/how-to-guides/install-the-sdk/integration). > Navigate to `react-sdk` for the base React Hooks and some commonly used functionalities by clicking [here](./packages/react-sdk). 2. ## 100ms Prebuilt - 100ms Prebuilt is a high-level abstraction with no-code customization that enables you to embed video conferencing and/or live streaming UI—with a few lines of code. - **Related packages include:** `roomkit-react` and `roomkit-web`. - - Get started with 100ms Prebuilt using the [Prebuilt Quickstart for Web](https://www.100ms.live/docs/javascript/v2/quickstart/prebuilt-quickstart).
+ - Get started with 100ms Prebuilt using the [Prebuilt Quickstart for Web](https://www.100ms.live/docs/javascript/v2/quickstart/prebuilt-quickstart). > Navigate to `roomkit-react` for the React components used in Prebuilt and the Prebuilt component itself by clicking [here](./packages/roomkit-react). -
- ![Banner](prebuilt-banner.png) ### 100ms Prebuilt Cross Platform Support @@ -51,9 +51,6 @@ The 100ms SDK gives you everything you need to build scalable, high-quality live | Flutter | [100ms-flutter](https://github.com/100mslive/100ms-flutter/tree/main/packages/hms_room_kit) | [Link](https://www.100ms.live/docs/flutter/v2/quickstart/prebuilt) | [hms_room_kit/example](https://github.com/100mslive/100ms-flutter/tree/main/packages/hms_room_kit/example) | | React Native | [100ms-react-native](https://github.com/100mslive/100ms-react-native/tree/main/packages/react-native-room-kit) | [Link](https://www.100ms.live/docs/react-native/v2/quickstart/prebuilt) | [react-native-room-kit/example](https://github.com/100mslive/100ms-react-native/tree/main/packages/react-native-room-kit/example) | -
-
- ## Setup ### Local Setup @@ -62,7 +59,7 @@ The 100ms SDK gives you everything you need to build scalable, high-quality live if you are using a different version in other projects, use [nvm](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating) to manage node versions. -``` +```bash git clone https://github.com/100mslive/web-sdks.git cd web-sdks yarn install @@ -71,7 +68,7 @@ yarn build ### Running Sample Prebuilt -``` +```bash cd examples/prebuilt-react-integration yarn dev ``` @@ -86,9 +83,7 @@ Run `yarn start` by navigating to the package you are making changes to, the cha For example, if you are making changes in roomkit-react(prebuilt), run `yarn start` in that package. The sample app should auto reload. -> Note: Make sure `yarn build` is run atleast once before using `yarn start` - -
+> Note: Make sure `yarn build` is run atleast once before using `yarn start`. ### Deploying Your Changes @@ -104,17 +99,14 @@ For reference: ![Project Settings](./project-settings.png) -
Once the app has been deployed, you can append the room code at the end of the deployment URL to preview your changes -
- ### Maintaining A Forked Version -Tthe following command will build the roomkit-react package and generate a .tgz file: +The following command will build the roomkit-react package and generate a .tgz file: -``` +```bash yarn && yarn build; cd packages/roomkit-react; yarn pack @@ -142,8 +134,6 @@ import { HMSPrebuilt } from '@100mslive/roomkit-react'; We welcome external contributors or anyone excited to help improve 100ms SDKs. If you'd like to get involved, check out our [contribution guide](./DEVELOPER.MD), and get started exploring the codebase. -
- ## Community & Support - [GitHub Issues](https://github.com/100mslive/web-sdks/issues) - Submit any bugs or errors you encounter using the Web SDKs. diff --git a/packages/hls-player/README.md b/packages/hls-player/README.md index 0dda1052f8..4f62ce8e60 100644 --- a/packages/hls-player/README.md +++ b/packages/hls-player/README.md @@ -1,17 +1,343 @@ -`@100mslive/hls-player` is currently a wrapper on hls.js with easy to use interface and few add-ons for [100ms's interactive live streaming feature](https://www.100ms.live/docs/javascript/v2/how--to-guides/record-and-live-stream/hls/hls). +# 100ms HLS Player -Sample usage: +The `HMSHLSPlayer` is an HLS player offered by 100ms that can be used to play HLS streams. The player takes a URL and video element to play the stream. +## How to integrate HLS Player SDK + +You can use Node package manager or yarn to add HMSHLSPlayer sdk to your project. +Use [@100mslive/hls-player](https://www.npmjs.com/package/@100mslive/hls-player) as the package source. + +```bash +npm i @100mslive/hls-player +``` + +## HMSHLSPlayer methods + +Below shows all the methods exposed from player + +```javascript +interface IHMSHLSPlayer { + /** + * @returns get html video element + */ + getVideoElement(): HTMLVideoElement; + + /** + * set video volumne + * @param { volume } - in range [0,100] + */ + setVolume(volume: number): void; + /** + * + * @returns returns HMSHLSLayer which represents current + * quality. + */ + getLayer(): HMSHLSLayer | null; + /** + * + * @param { HMSHLSLayer } layer - layer we want to set the stream to. + * set { height: auto } to set the layer to auto + */ + setLayer(layer: HMSHLSLayer): void; + /** + * move the video to Live + */ + seekToLivePosition(): Promise; + /** + * play stream + * call this when autoplay error is received + */ + play(): Promise; + /** + * pause stream + */ + pause(): void; + + /** + * It will update the video element current time + * @param seekValue Pass currentTime in second + */ + seekTo(seekValue: number): void; +} +``` + +### How to use Player's HLS Stream + +You create an instance of HMSHLSPlayer like below: + +```javascript +import { HMSHLSPlayer } from '@100mslive/hls-player'; + +// hls url should be provided which player will run. +// second parameter is optional, if you had video element then pass to player else we will create one. +const hlsPlayer = new HMSHLSPlayer(hlsURL, videoEl) + +// if video element is not present, we will create a new video element which can be attached to your ui. +const videoEl = hlsPlayer.getVideoElement(); +``` + +### How to pause and resume the playback + +You call play/pause on the hlsPlayer instance like below: + +```javascript +// return Promise +hmsPlayer.play() + +hmsPlayer.pause() +``` + +### How to seek forward or backward + +You use `seekTo` methods on the hlsPlayer to seek to any position in video, below is given example: + +```javascript +// seekValue Pass currentTime in second +hmsPlayer.seekTo(5) +``` + +### How to seek to live position + +You use `seekToLivePosition` methods on the hlsPlayer instance to go to the live poition like below: + +```javascript +hmsPlayer.seekToLivePosition() +``` + +### How to change volume of HLS playback + +Use volume property to change the volume of HLS player. The volume level is between 0-100. Volume is set to 100 by default. + +```javascript +hlsPlayer.setVolume(50); +``` + +### Set video quality level to hls player + +```javascript +/** +* +* @returns returns HMSHLSLayer which represents current +* quality. +*/ +hlsPlayer.getLayer(): HMSHLSLayer | null; +/** +* +* @param { HMSHLSLayer } layer - layer we want to set the stream to. +* set { height: auto } to set the layer to auto +*/ +hlsPlayer.setLayer(layer: HMSHLSLayer): void; + +// quality interface +interface HMSHLSLayer { + readonly bitrate: number; + readonly height?: number; + readonly id?: number; + readonly width?: number; + url: string; + resolution?: string; +} +``` + +## Events exposed from HMSHLSPlayer + +We are exposing events from our hls player. + +```javascript +enum HMSHLSPlayerEvents { + TIMED_METADATA_LOADED = 'timed-metadata', + SEEK_POS_BEHIND_LIVE_EDGE = 'seek-pos-behind-live-edge', + + CURRENT_TIME = 'current-time', + AUTOPLAY_BLOCKED = 'autoplay-blocked', + + MANIFEST_LOADED = 'manifest-loaded', + LAYER_UPDATED = 'layer-updated', + + ERROR = 'error', + PLAYBACK_STATE = 'playback-state', + STATS = 'stats', +} +``` + +### Playback state + +```javascript +enum HLSPlaybackState { + playing, + paused, +} +interface HMSHLSPlaybackState { + state: HLSPlaybackState; +} +hlsPlayer.on(HMSHLSPlayerEvents.PLAYBACK_STATE, (event: HMSHLSPlayerEvents, data: HMSHLSPlaybackState): void => {}); ``` -import { - HLSPlaybackState, -} from "@100mslive/hls-player"; -// hlsUrl is the url in which the hls stream is ongoing -// videoElement is the video element where you want to play the stream -const player = new HMSHLSPlayer(hlsUrl, videoElement); -player.play() +### HLS Stats +```javascript +interface HlsPlayerStats { + /** Estimated bandwidth in bits/sec. Could be used to show connection speed. */ + bandwidthEstimate?: number; + /** The bitrate of the current level that is playing. Given in bits/sec */ + bitrate?: number; + /** the amount of video available in forward buffer. Given in ms */ + bufferedDuration?: number; + /** how far is the current playback from live edge.*/ + distanceFromLive?: number; + /** total Frames dropped since started watching the stream. */ + droppedFrames?: number; + /** the m3u8 url of the current level that is being played */ + url?: string; + /** the resolution of the level of the video that is being played */ + videoSize?: { + height: number; + width: number; + }; +} + +hlsPlayer.on(HMSHLSPlayerEvents.STATS, (event: HMSHLSPlayerEvents, data: HlsPlayerStats): void => {}); +``` + +### Manifest loaded data + +Hls player will provide a manifest which will provide a data like different quality layer once url is loaded. + +```javascript +interface HMSHLSManifestLoaded { + layers: HMSHLSLayer[]; +} +hlsPlayer.on(HMSHLSPlayerEvents.MANIFEST_LOADED, (event: HMSHLSPlayerEvents, data: HMSHLSManifestLoaded): void => {}); +``` + +### Quality changed data + +```javascript +interface HMSHLSLayerUpdated { + layer: HMSHLSLayer; +} +hlsPlayer.on(HMSHLSPlayerEvents.LAYER_UPDATED, (event: HMSHLSPlayerEvents, data: HMSHLSLayerUpdated): void => {}); +``` + +### Live Event + +Player will let you know if player is plaaying video live or not + +```javascript +interface HMSHLSStreamLive { + isLive: boolean; +} +hlsPlayer.on(HMSHLSPlayerEvents.SEEK_POS_BEHIND_LIVE_EDGE, (event: HMSHLSPlayerEvents, data: HMSHLSStreamLive): void => {}); ``` -More details to be added soon. +### HLS timed-metadata + +HLS player will parse and send the timed-metadata. + +```javascript +interface HMSHLSCue { + id?: string; + payload: string; + duration: number; + startDate: Date; + endDate?: Date; +} +hlsPlayer.on(HMSHLSPlayerEvents.TIMED_METADATA_LOADED, (event: HMSHLSPlayerEvents, data: HMSHLSCue): void => {}); +``` + +### Error handling + +```javascript +interface HMSHLSException { + name: string, + message: string, + description: string, + isTerminal: boolean, // decide if player error will automatically restart(if false) +} +hlsPlayer.on(HMSHLSPlayerEvents.ERROR, (event: HMSHLSPlayerEvents, data: HMSHLSException): void => {}); +hlsPlayer.on(HMSHLSPlayerEvents.AUTOPLAY_BLOCKED, (event: HMSHLSPlayerEvents, data: HMSHLSException): void => {}); +``` + +### Video current time + +```javascript +hlsPlayer.on(HMSHLSPlayerEvents.CURRENT_TIME, (event: HMSHLSPlayerEvents, data: number): void => {}); +``` + +### Example for events usage + +Below are the simple example of how to use hls player's event + +```javascript +const isPlaying = false; +const playbackEventHandler = data => isPlaying = data.state === HLSPlaybackState.paused; +hlsPlayer.on(HMSHLSPlayerEvents.PLAYBACK_STATE, playbackEventHandler); +``` + +## HLS Player example + +Below is a simple example in which hls-player will be used in your app. + +```javascript +// Vanilla JavaScript Example +import { HLSPlaybackState, HMSHLSPlayer, HMSHLSPlayerEvents } from "@100mslive/hls-player"; + +const videoEl; // reference for video element +const hlsUrl; // reference to hls url + +// variable to handle ui and take some actions +let isLive = true, isPaused = false, isAutoBlockedPaused = false; + +const handleError = data => console.error("[HLSView] error in hls", data); +const handleNoLongerLive = ({ isLive }) => isLive = isLive; + +const playbackEventHandler = data => isPaused = (data.state === HLSPlaybackState.paused); + +const handleAutoplayBlock = data => isAutoBlockedPaused = !!data; + +const hlsPlayer = new HMSHLSPlayer(hlsUrl, videoEl); + +hlsPlayer.on(HMSHLSPlayerEvents.SEEK_POS_BEHIND_LIVE_EDGE, handleNoLongerLive); +hlsPlayer.on(HMSHLSPlayerEvents.ERROR, handleError); +hlsPlayer.on(HMSHLSPlayerEvents.PLAYBACK_STATE, playbackEventHandler); +hlsPlayer.on(HMSHLSPlayerEvents.AUTOPLAY_BLOCKED, handleAutoplayBlock); +``` + +```jsx +// React Example +import { HLSPlaybackState, HMSHLSPlayer, HMSHLSPlayerEvents } from "@100mslive/hls-player"; +import { useEffect, useState } from 'react'; + +const videoEl; // reference for video element +const hlsUrl; // reference to hls url + +// variable to handle ui and take some actions +const [isVideoLive, setIsVideoLive] = useState(true); +const [isHlsAutoplayBlocked, setIsHlsAutoplayBlocked] = useState(false); +const [isPaused, setIsPaused] = useState(false); + +useEffect(() => { + const handleError = data => console.error("[HLSView] error in hls", data); + const handleNoLongerLive = ({ isLive }) => { + setIsVideoLive(isLive); + }; + + const playbackEventHandler = data => + setIsPaused(data.state === HLSPlaybackState.paused); + + const handleAutoplayBlock = data => setIsHlsAutoplayBlocked(!!data); + const hlsPlayer = new HMSHLSPlayer(hlsUrl, videoEl); + + hlsPlayer.on(HMSHLSPlayerEvents.SEEK_POS_BEHIND_LIVE_EDGE, handleNoLongerLive); + hlsPlayer.on(HMSHLSPlayerEvents.ERROR, handleError); + hlsPlayer.on(HMSHLSPlayerEvents.PLAYBACK_STATE, playbackEventHandler); + hlsPlayer.on(HMSHLSPlayerEvents.AUTOPLAY_BLOCKED, handleAutoplayBlock); + return () => { + hlsPlayer.off(HMSHLSPlayerEvents.SEEK_POS_BEHIND_LIVE_EDGE, handleNoLongerLive); + hlsPlayer.off(HMSHLSPlayerEvents.ERROR, handleError); + hlsPlayer.off(HMSHLSPlayerEvents.PLAYBACK_STATE, playbackEventHandler); + hlsPlayer.off(HMSHLSPlayerEvents.AUTOPLAY_BLOCKED, handleAutoplayBlock); + } +}, []); + +``` diff --git a/packages/hls-player/package.json b/packages/hls-player/package.json index af5c74f56e..5e0334e5ed 100644 --- a/packages/hls-player/package.json +++ b/packages/hls-player/package.json @@ -39,5 +39,13 @@ "@100mslive/hls-stats": "0.4.24", "eventemitter2": "^6.4.9", "hls.js": "1.4.12" - } + }, + "keywords": [ + "hls", + "video", + "player", + "webrtc", + "conferencing", + "100ms" + ] } diff --git a/packages/hms-virtual-background/README.md b/packages/hms-virtual-background/README.md index ac8a38d7c4..2009879b50 100755 --- a/packages/hms-virtual-background/README.md +++ b/packages/hms-virtual-background/README.md @@ -1,13 +1,238 @@ -## installation +# Virtual Background with Effects SDK -**with npm:** +Virtual background plugin helps in customising one’s background. The customising options are blurring the background or replacing it with a static image. This guide provides an overview of usage of the virtual background plugin of 100ms. -```npm i --save @100mslive/hms-virtual-background``` +## Pre-requisites -**with yarn** +Get the 100ms VirtualBackground Package** (Supported since version 1.11.28) -```yarn add @100mslive/hms-virtual-background``` +```bash section=GetHMSVirtualBackgroundPackage sectionIndex=1 +npm install --save @100mslive/hms-virtual-background@latest +``` -## Usage +## Features -Refer our [docs](https://www.100ms.live/docs/javascript/v2/plugins/virtual-background#start-and-stop-virtual-background) for usage. \ No newline at end of file +The following features are currently supported under the `HMSEffectsPlugin` class: + +```js +/** + * Sets the blur intensity. + * @param {number} blur - The blur intensity, ranging from 0 to 1. + * @returns {void} + */ +setBlur(blur) {} + +/** + * Sets the virtual background using the provided media URL. + * @param {HMSEffectsBackground} url - The media URL to set as the virtual background. + * Alternatively, the background image can be downloaded beforehand and passed to setBackground as objectURL + * @returns {void} + */ +setBackground(url) {} + +/** + * Retrieves the name of the plugin. + * @returns {string} The name of the plugin, 'HMSEffects'. + */ +getName() {} + +/** + * Retrieves the currently enabled background type or media URL. + * @returns {string|MediaStream|MediaStreamTrack|HTMLVideoElement} The background type or media URL. + */ +getBackground() {} + +/** + * Sets the preset quality of the virtual background. + * Options: "balanced" | "quality" + * The 'quality' preset has a higher CPU usage than the 'balanced' preset which is the default + * @param {string} preset - The preset quality to set. + * @returns {Promise} + */ +setPreset(preset) {} + +/** + * Retrieves the active preset quality of the virtual background. + * @returns {string} The active preset quality. + */ +getPreset() {} + +/** + * Clears all applied filters. + * @returns {void} + */ +removeEffects() {} + +/** + * Stops the plugin. + * @returns {void} + */ +stop() {} + +``` + +Callbacks supported by the plugin: + +On initialization, after the required resources are downloaded by the plugin: + +``` +const effectsPlugin = new HMSEffectsPlugin(, () => console.log("Plugin initialised")); + +``` + +On resolution change (on device rotation or when the video aspect ratio changes): + +``` +effectsPlugin.onResolutionChange = (width: number, height: number) => { + console.log(`Resolution changed to ${width}x${height}`) +} +``` + +## Instantiate Virtual Background + +The SDK key for effects is needed to instantiate the `HMSEffectsPlugin` class: + +```jsx + const effectsKey = useHMSStore(selectEffectsKey); +``` + +It is recommended to initialise the object in a separate file to prevent multiple initialisations on re-renders and keep the UI level code independent of internal calls by the SDK. + + +```js +import { HMSEffectsPlugin, HMSVirtualBackgroundTypes } from '@100mslive/hms-virtual-background'; + +export class VBPlugin { + private effectsPlugin?: HMSEffectsPlugin | undefined; + + initialisePlugin = (effectsSDKKey?: string) => { + if (this.getVBObject()) { + return; + } + if (effectsSDKKey) { + this.effectsPlugin = new HMSEffectsPlugin(effectsSDKKey); + } + }; + + getBackground = () => { + return this.effectsPlugin?.getBackground(); + }; + + getBlurAmount = () => { + return this.effectsPlugin?.getBlurAmount(); + }; + + getVBObject = () => { + return this.effectsPlugin; + }; + + getName = () => { + return this.effectsPlugin?.getName(); + }; + + setBlur = async (blurPower: number) => { + this.effectsPlugin?.setBlur(blurPower); + }; + + setBackground = async (mediaURL: string) => { + this.effectsPlugin?.setBackground(mediaURL); + }; + + setPreset = (preset: string) => { + this.effectsPlugin.setPreset(preset); + }; + + getPreset = () => { + return this.effectsPlugin?.getPreset() || ''; + }; + + removeEffects = async () => { + this.effectsPlugin?.removeEffects(); + }; + + reset = () => { + this.effectsPlugin = undefined; + }; +} + +export const VBHandler = new VBPlugin(); +``` + +## Building the UI + +The following snippet illustrates how to add the plugin to the video and manage the UI state to preserve configuration: + +```jsx +import { + selectEffectsKey, + selectIsLocalVideoPluginPresent + selectLocalVideoTrackID, + useHMSStore, +} from '@100mslive/react-sdk'; +import { + HMSEffectsPlugin, + HMSVirtualBackgroundTypes +} from '@100mslive/hms-virtual-background'; +import { VBHandler } from './VBHandler'; + +export const VirtualBackgroundPicker = () => { + const hmsActions = useHMSActions(); + // Get the effects SDK key here + const effectsKey = useHMSStore(selectEffectsKey); + const trackId = useHMSStore(selectLocalVideoTrackID); + const isPluginAdded = useHMSStore(selectIsLocalVideoPluginPresent(VBHandler?.getName() || '')); + + // State can be used to show active selection + const [background, setBackground] = useState( + VBHandler.getBackground() as string | HMSVirtualBackgroundTypes, + ); + + useEffect(() => { + if (!track?.id) { + return; + } + if (!isPluginAdded) { + let vbObject = VBHandler.getVBObject(); + if (!vbObject) { + VBHandler.initialisePlugin(effectsKey); + vbObject = VBHandler.getVBObject(); + if (effectsKey) { + hmsActions.addPluginsToVideoStream([vbObject as HMSEffectsPlugin]); + } + } + } + }, [hmsActions, isPluginAdded, effectsKey, track?.id]); + + // UI code for media picker can go here +} + +``` + +This handles initialisation and adding the plugin to the video stream. The plugin takes a few seconds on first load during initialisation. Subsequent filter and effect selections should take less than a second to reflect. + +The methods can be called via the `VBHandler` object: +```jsx +const setBackground = async(mediaURL : string) => { + await VBHandler?.setBackground(mediaURL); + // The selection can be highlighted using the activeBackground state + setActiveBackground(mediaURL); +} + +const setBlur = async(blurAmount: number) => { + await VBHandler?.setBlur(blurAmount); + setActiveBackground(HMSVirtualBackgroundTypes.BLUR); +} + +const removeEffects = async() => { + await VBHandler.removeEffects(); + setActiveBackground(HMSVirtualBackgroundTypes.NONE); +} +``` + + +The full implementation can be viewed in the [roomkit-react package](https://github.com/100mslive/web-sdks/blob/main/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBPicker.tsx). + + +## Supported Browsers + +Effects virtual background is supported on Safari, Firefox and Chromium based browsers.
diff --git a/packages/hms-whiteboard/README.md b/packages/hms-whiteboard/README.md new file mode 100644 index 0000000000..2ba01efa5a --- /dev/null +++ b/packages/hms-whiteboard/README.md @@ -0,0 +1,120 @@ +# 100ms Whiteboard + +The 100ms SDK provides robust APIs for integrating whiteboard collaboration into your conferencing sessions. Participants can engage in real-time by drawing, writing, and collaborating on a shared digital whiteboard. This documentation outlines how to implement the start and stop functionality for a whiteboard and display it within an iframe or embed it as a React component. + +## Requirements + +- React 18 or higher +- Webpack 5 or higher if you're using it to bundle your app +- User roles must be configured to enable whiteboard functionality via the 100ms dashboard for starting or viewing the whiteboard. [Refer here](https://www.100ms.live/docs/get-started/v2/get-started/features/whiteboard#enabling-and-configuring-the-whiteboard). +- If you're on React and are not using the `@100mslive/roomkit-react` package, install the `@100mslive/hms-whiteboard` package. + +```bash +yarn add @100mslive/hms-whiteboard +``` + +## Opening and Closing the Whiteboard + +JavaScript users can use the `selectPermissions` selector which fetches the whiteboard specific permissions array from the local peer's role permissions. + +React users can check for the `toggle` function returned by the utility hook `useWhiteboard`. + +```js +// Vanilla JavaScript Example +import { selectPermissions, selectWhiteboard } from '@100mslive/hms-video-store'; + +const permissions = hmsStore.getState(selectPermissions)?.whiteboard; // Array<'read' | 'write' | 'admin'> +const isAdmin = !!permissions?.includes('admin'); +const whiteboard = hmsStore.getState(selectWhiteboard); +const isOwner = whiteboard?.owner === localPeerUserId; + +const toggle = async () => { + if (!isAdmin) { + return; + } + + if (whiteboard?.open) { + isOwner && (await actions.interactivityCenter.whiteboard.close()); + } else { + await actions.interactivityCenter.whiteboard.open(); + } +}; + +// usage +const toggleButton = document.getElementById('toggle-whiteboard'); +// non-admin users cannot toggle the whiteboard +toggleButton.disabled = !isAdmin; +toggleButton.onclick = toggle; +``` + +```jsx +// React Example +import React from 'react'; +import { useWhiteboard } from '@100mslive/react-sdk'; + +export const WhiteboardToggle = () => { + const { toggle, open, isOwner } = useWhiteboard(); + + // non-admin users cannot toggle the whiteboard + if (!toggle) { + return null; + } + + return ( + + ); +}; +``` + +## Displaying the Collaborative Whiteboard + +You can display the whiteboard when it's open by embedding it as an iframe or as a React component for more fine-grained controls, if your app is built using React. + +```js +// Vanilla JavaScript Example +import { selectWhiteboard } from '@100mslive/hms-video-store'; + +const whiteboard = hmsStore.subscribe((whiteboard) => { + if (whiteboard?.open && whiteboard?.url) { + const whiteboardIframe = document.createElement('iframe'); + whiteboardIframe.src = whiteboard.url; + } else { + const whiteboardIframe = document.getElementById('whiteboard'); + whiteboardIframe?.remove(); + } +}, selectWhiteboard); +``` + +```jsx +// React Example +import React from 'react'; +import { useWhiteboard } from '@100mslive/react-sdk'; +import { Whiteboard } from '@100mslive/hms-whiteboard'; +import '@100mslive/hms-whiteboard/index.css'; + +const WhiteboardEmbed = () => { + const { token, endpoint } = useWhiteboard(); + + if (!token) { + return null; + } + + return ( +
+ { + console.log(store, editor); + }} + /> +
+ ); +}; +``` + +Whiteboard related CSS needs to be imported in your app's top level CSS files using `@import '@100mslive/hms-whiteboard/index.css';`(recommended) or in one of your top level JS file using `import '@100mslive/hms-whiteboard/index.css';`. + +Note that if you're using `@100mslive/roomkit-react` you'll need to import `@100mslive/roomkit-react/index.css` accordingly. diff --git a/packages/hms-whiteboard/package.json b/packages/hms-whiteboard/package.json index 1323e9215e..258c33362a 100644 --- a/packages/hms-whiteboard/package.json +++ b/packages/hms-whiteboard/package.json @@ -58,5 +58,14 @@ "rollup-plugin-import-css": "^3.5.0", "rollup-plugin-terser": "^7.0.2", "typescript": "^5.2.2" - } + }, + "keywords": [ + "whiteboard", + "tldraw", + "streaming", + "video", + "webrtc", + "conferencing", + "100ms" + ] }