diff --git a/.changeset/early-hats-tell.md b/.changeset/early-hats-tell.md new file mode 100644 index 000000000..dceb487ac --- /dev/null +++ b/.changeset/early-hats-tell.md @@ -0,0 +1,7 @@ +--- +"@livekit/components-core": patch +"@livekit/components-react": patch + +--- + +Add useStartVideo hook + update livekit client diff --git a/docs/storybook/package.json b/docs/storybook/package.json index fba52aa64..a8b52fa9b 100644 --- a/docs/storybook/package.json +++ b/docs/storybook/package.json @@ -13,7 +13,7 @@ "dependencies": { "@livekit/components-react": "workspace:*", "@livekit/components-styles": "workspace:*", - "livekit-client": "^1.12.0", + "livekit-client": "^1.15.1", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/examples/nextjs/package.json b/examples/nextjs/package.json index ad99890f8..5ceb6dec3 100644 --- a/examples/nextjs/package.json +++ b/examples/nextjs/package.json @@ -11,7 +11,7 @@ "dependencies": { "@livekit/components-react": "workspace:*", "@livekit/components-styles": "workspace:*", - "livekit-client": "^1.12.0", + "livekit-client": "^1.15.1", "livekit-server-sdk": "^1.0.3", "next": "^12.2.4", "react": "^18.2.0", diff --git a/packages/core/package.json b/packages/core/package.json index a67c6dedf..7a3de3484 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -41,7 +41,7 @@ "rxjs": "^7.8.0" }, "peerDependencies": { - "livekit-client": "^1.12.0", + "livekit-client": "^1.15.1", "tslib": "^2.6.2" }, "devDependencies": { diff --git a/packages/core/src/components/startVideo.ts b/packages/core/src/components/startVideo.ts new file mode 100644 index 000000000..561e50069 --- /dev/null +++ b/packages/core/src/components/startVideo.ts @@ -0,0 +1,13 @@ +import type { Room } from 'livekit-client'; +import { log } from '../logger'; +import { roomVideoPlaybackAllowedObservable } from '../observables/room'; +import { prefixClass } from '../styles-interface'; + +export function setupStartVideo() { + const handleStartVideoPlayback = async (room: Room) => { + log.info('Start Video for room: ', room); + await room.startAudio(); + }; + const className: string = prefixClass('start-audio-button'); + return { className, roomVideoPlaybackAllowedObservable, handleStartVideoPlayback }; +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index fcbc34c8b..032a72c19 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -16,6 +16,7 @@ export * from './components/mediaTrack'; export * from './components/participantTile'; export * from './components/chat'; export * from './components/startAudio'; +export * from './components/startVideo'; export * from './components/chatToggle'; export * from './components/focusToggle'; export * from './components/clearPinButton'; diff --git a/packages/core/src/observables/room.ts b/packages/core/src/observables/room.ts index b407f6461..d809b628c 100644 --- a/packages/core/src/observables/room.ts +++ b/packages/core/src/observables/room.ts @@ -225,6 +225,15 @@ export function roomAudioPlaybackAllowedObservable(room: Room) { return observable; } +export function roomVideoPlaybackAllowedObservable(room: Room) { + const observable = observeRoomEvents(room, RoomEvent.VideoPlaybackStatusChanged).pipe( + map((room) => { + return { canPlayVideo: room.canPlaybackVideo }; + }), + ); + return observable; +} + export function createActiveDeviceObservable(room: Room, kind: MediaDeviceKind) { return roomEventSelector(room, RoomEvent.ActiveDeviceChanged).pipe( filter(([kindOfDevice]) => kindOfDevice === kind), diff --git a/packages/react/package.json b/packages/react/package.json index a0d508bd1..479681746 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -53,7 +53,7 @@ "usehooks-ts": "^2.9.1" }, "peerDependencies": { - "livekit-client": "^1.12.0", + "livekit-client": "^1.15.1", "react": ">=18", "react-dom": ">=18", "tslib": "^2.6.2" diff --git a/packages/react/src/hooks/useStartVideo.ts b/packages/react/src/hooks/useStartVideo.ts new file mode 100644 index 000000000..e6664ce46 --- /dev/null +++ b/packages/react/src/hooks/useStartVideo.ts @@ -0,0 +1,49 @@ +import { setupStartVideo } from '@livekit/components-core'; +import type { Room } from 'livekit-client'; +import * as React from 'react'; +import { useEnsureRoom } from '../context'; +import { mergeProps } from '../mergeProps'; +import { useObservableState } from './internal'; + +/** @alpha */ +export interface UseStartVideoProps { + room?: Room; + props: React.ButtonHTMLAttributes; +} + +/** + * In some browsers to start video playback in low power mode, the user must perform a user-initiated event such as clicking a button. + * The `useStartVideo` hook returns an object with a boolean `canPlayVideo` flag + * that indicates whether video playback is allowed in the current context, + * as well as a `startVideo` function that can be called in a button `onClick` callback to start video playback in the current context. + * + * @alpha + */ +export function useStartVideo({ room, props }: UseStartVideoProps) { + const roomEnsured = useEnsureRoom(room); + const { className, roomVideoPlaybackAllowedObservable, handleStartVideoPlayback } = React.useMemo( + () => setupStartVideo(), + [], + ); + const observable = React.useMemo( + () => roomVideoPlaybackAllowedObservable(roomEnsured), + [roomEnsured, roomVideoPlaybackAllowedObservable], + ); + const { canPlayVideo } = useObservableState(observable, { + canPlayVideo: roomEnsured.canPlaybackVideo, + }); + + const mergedProps = React.useMemo( + () => + mergeProps(props, { + className, + onClick: () => { + handleStartVideoPlayback(roomEnsured); + }, + style: { display: canPlayVideo ? 'none' : 'block' }, + }), + [props, className, canPlayVideo, handleStartVideoPlayback, roomEnsured], + ); + + return { mergedProps, canPlayVideo }; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b4a49e6eb..15fb0c7cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,8 +51,8 @@ importers: specifier: workspace:* version: link:../../packages/styles livekit-client: - specifier: ^1.12.0 - version: 1.15.0 + specifier: ^1.15.1 + version: 1.15.1 react: specifier: ^18.2.0 version: 18.2.0 @@ -115,8 +115,8 @@ importers: specifier: workspace:* version: link:../../packages/styles livekit-client: - specifier: ^1.12.0 - version: 1.15.0 + specifier: ^1.15.1 + version: 1.15.1 livekit-server-sdk: specifier: ^1.0.3 version: 1.2.7 @@ -158,8 +158,8 @@ importers: specifier: ^5.0.0 version: 5.0.0 livekit-client: - specifier: ^1.12.0 - version: 1.15.0 + specifier: ^1.15.1 + version: 1.15.1 loglevel: specifier: ^1.8.1 version: 1.8.1 @@ -210,8 +210,8 @@ importers: specifier: ^2.0.0 version: 2.0.0 livekit-client: - specifier: ^1.12.0 - version: 1.15.0 + specifier: ^1.15.1 + version: 1.15.1 tslib: specifier: ^2.6.2 version: 2.6.2 @@ -10742,8 +10742,8 @@ packages: /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - /livekit-client@1.15.0: - resolution: {integrity: sha512-uyp1sIFeOdezYBn9J0FnrMuG8uPgR4fwWPENodNisJC999xJwTSV3xVLX76AAnfky3IJoJehU4gY2UqoyXjm2w==} + /livekit-client@1.15.1: + resolution: {integrity: sha512-ewCnRWbYhGnOFWpXEhj7mFBhQt3VecK/Uq/Rfgekq/Z5i6obqfh5Epd3/ZXG2q8CkKc0dFM8bFrxeWwd/HbpgA==} dependencies: '@bufbuild/protobuf': 1.4.2 events: 3.3.0