From 7a51b09664448bc0be11d9f58dbf1902b57916a4 Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Tue, 15 Oct 2024 21:29:54 +0200 Subject: [PATCH] wip allow starting a recording from the frontend --- .../features/rooms/livekit/api/recordRoom.ts | 56 +++++++++++++++++++ .../controls/Options/OptionsMenuItems.tsx | 2 + .../controls/Options/RecordingMenuItem.tsx | 52 +++++++++++++++++ src/frontend/src/stores/egress.ts | 11 ++++ 4 files changed, 121 insertions(+) create mode 100644 src/frontend/src/features/rooms/livekit/api/recordRoom.ts create mode 100644 src/frontend/src/features/rooms/livekit/components/controls/Options/RecordingMenuItem.tsx create mode 100644 src/frontend/src/stores/egress.ts diff --git a/src/frontend/src/features/rooms/livekit/api/recordRoom.ts b/src/frontend/src/features/rooms/livekit/api/recordRoom.ts new file mode 100644 index 00000000..c463c5d0 --- /dev/null +++ b/src/frontend/src/features/rooms/livekit/api/recordRoom.ts @@ -0,0 +1,56 @@ +import { fetchServerApi } from './fetchServerApi' +import { buildServerApiUrl } from './buildServerApiUrl' +import { useRoomData } from '../hooks/useRoomData' +import { useParams } from 'wouter' + +export const useRecordRoom = () => { + const data = useRoomData() + const { roomId: roomSlug } = useParams() + + const recordRoom = () => { + if (!data || !data?.livekit) { + throw new Error('Room data is not available') + } + if (!roomSlug) { + throw new Error('Room ID is not available') + } + return fetchServerApi( + buildServerApiUrl( + data.livekit.url, + '/twirp/livekit.Egress/StartRoomCompositeEgress' + ), + data.livekit.token, + { + method: 'POST', + body: JSON.stringify({ + room_name: data.livekit.room, + audio_only: true, + file_outputs: [ + { + file_extension: 'ogg', + filepath: `{room_name}_{time}_${roomSlug}`, + }, + ], + }), + } + ) + } + + const stopRecordingRoom = (egressId: string) => { + if (!data || !data?.livekit) { + throw new Error('Room data is not available') + } + return fetchServerApi( + buildServerApiUrl(data.livekit.url, '/twirp/livekit.Egress/StopEgress'), + data.livekit.token, + { + method: 'POST', + body: JSON.stringify({ + egressId, + }), + } + ) + } + + return { recordRoom, stopRecordingRoom } +} diff --git a/src/frontend/src/features/rooms/livekit/components/controls/Options/OptionsMenuItems.tsx b/src/frontend/src/features/rooms/livekit/components/controls/Options/OptionsMenuItems.tsx index d84e4cb6..e7dc868c 100644 --- a/src/frontend/src/features/rooms/livekit/components/controls/Options/OptionsMenuItems.tsx +++ b/src/frontend/src/features/rooms/livekit/components/controls/Options/OptionsMenuItems.tsx @@ -10,6 +10,7 @@ import { Dispatch, SetStateAction } from 'react' import { DialogState } from './OptionsButton' import { Separator } from '@/primitives/Separator' import { useSidePanel } from '../../../hooks/useSidePanel' +import { RecordingMenuItem } from '@/features/rooms/livekit/components/controls/Options/RecordingMenuItem' // @todo try refactoring it to use MenuList component export const OptionsMenuItems = ({ @@ -34,6 +35,7 @@ export const OptionsMenuItems = ({ {t('effects')} +
diff --git a/src/frontend/src/features/rooms/livekit/components/controls/Options/RecordingMenuItem.tsx b/src/frontend/src/features/rooms/livekit/components/controls/Options/RecordingMenuItem.tsx new file mode 100644 index 00000000..935e8e8a --- /dev/null +++ b/src/frontend/src/features/rooms/livekit/components/controls/Options/RecordingMenuItem.tsx @@ -0,0 +1,52 @@ +import { MenuItem } from 'react-aria-components' +import { menuItemRecipe } from '@/primitives/menuItemRecipe.ts' +import { RiPauseCircleLine, RiRecordCircleLine } from '@remixicon/react' +import { useRecordRoom } from '@/features/rooms/livekit/api/recordRoom.ts' +import { useState } from 'react' +import { egressStore } from '@/stores/egress.ts' +import { useSnapshot } from 'valtio' + +export const RecordingMenuItem = () => { + const { recordRoom, stopRecordingRoom } = useRecordRoom() + + const egressSnap = useSnapshot(egressStore) + const egressId = egressSnap.egressId + + const [isPending, setIsPending] = useState(false) + + const handleAction = async () => { + if (egressId) { + setIsPending(true) + egressStore.egressIsStopping = true + const response = await stopRecordingRoom(egressId) + console.log(response) + egressStore.egressId = undefined + setIsPending(false) + } else { + setIsPending(true) + const response = await recordRoom() + egressStore.egressId = response['egress_id'] as string + setIsPending(false) + } + } + + return ( + + {egressId ? ( + <> + + ArrĂȘter l'enregistrement + + ) : ( + <> + + Enregistrer la rĂ©union + + )} + + ) +} diff --git a/src/frontend/src/stores/egress.ts b/src/frontend/src/stores/egress.ts new file mode 100644 index 00000000..a06270bc --- /dev/null +++ b/src/frontend/src/stores/egress.ts @@ -0,0 +1,11 @@ +import { proxy } from 'valtio' + +type State = { + egressId: string | undefined + egressIsStopping: boolean +} + +export const egressStore = proxy({ + egressId: undefined, + egressIsStopping: false, +})