💩(frontend) mute remote participants
Messy code file organization, but functions are okay. Functional, but not well-designed and likely hard to maintain. Shipping it, creating technical debt here. Will be reused for interactions with LiveKit server API.
This commit is contained in:
committed by
aleb_the_flash
parent
c8cc9909ba
commit
e06e9d1496
@@ -0,0 +1,5 @@
|
|||||||
|
export const buildServerApiUrl = (origin: string, path: string) => {
|
||||||
|
const sanitizedOrigin = origin.replace(/\/$/, '')
|
||||||
|
const sanitizedPath = path.replace(/^\//, '')
|
||||||
|
return `${sanitizedOrigin}/${sanitizedPath}`
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { ApiError } from '@/api/ApiError'
|
||||||
|
|
||||||
|
export const fetchServerApi = async <T = Record<string, unknown>>(
|
||||||
|
url: string,
|
||||||
|
token: string,
|
||||||
|
options?: RequestInit
|
||||||
|
): Promise<T> => {
|
||||||
|
const response = await fetch(url, {
|
||||||
|
...options,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
...options?.headers,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const result = await response.json()
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new ApiError(response.status, result)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { Participant, Track } from 'livekit-client'
|
||||||
|
import Source = Track.Source
|
||||||
|
import { fetchServerApi } from './fetchServerApi'
|
||||||
|
import { buildServerApiUrl } from './buildServerApiUrl'
|
||||||
|
import { useRoomData } from '../hooks/useRoomData'
|
||||||
|
|
||||||
|
export const useMuteParticipant = () => {
|
||||||
|
const data = useRoomData()
|
||||||
|
|
||||||
|
const muteParticipant = (participant: Participant) => {
|
||||||
|
if (!data || !data?.livekit) {
|
||||||
|
throw new Error('Room data is not available')
|
||||||
|
}
|
||||||
|
const trackSid = participant.getTrackPublication(
|
||||||
|
Source.Microphone
|
||||||
|
)?.trackSid
|
||||||
|
|
||||||
|
if (!trackSid) {
|
||||||
|
throw new Error('Missing audio track')
|
||||||
|
}
|
||||||
|
return fetchServerApi(
|
||||||
|
buildServerApiUrl(
|
||||||
|
data.livekit.url,
|
||||||
|
'twirp/livekit.RoomService/MutePublishedTrack'
|
||||||
|
),
|
||||||
|
data.livekit.token,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
room: data.livekit.room,
|
||||||
|
identity: participant.identity,
|
||||||
|
muted: true,
|
||||||
|
track_sid: trackSid,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return { muteParticipant }
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ import { RiMicOffLine } from '@remixicon/react'
|
|||||||
import { TooltipWrapper } from '@/primitives/TooltipWrapper.tsx'
|
import { TooltipWrapper } from '@/primitives/TooltipWrapper.tsx'
|
||||||
import { Button, Dialog, P } from '@/primitives'
|
import { Button, Dialog, P } from '@/primitives'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
import { useMuteParticipant } from '@/features/rooms/livekit/api/muteParticipant'
|
||||||
|
|
||||||
const MuteAlertDialog = ({
|
const MuteAlertDialog = ({
|
||||||
isOpen,
|
isOpen,
|
||||||
@@ -52,6 +53,7 @@ type MicIndicatorProps = {
|
|||||||
|
|
||||||
const MicIndicator = ({ participant }: MicIndicatorProps) => {
|
const MicIndicator = ({ participant }: MicIndicatorProps) => {
|
||||||
const { t } = useTranslation('rooms')
|
const { t } = useTranslation('rooms')
|
||||||
|
const { muteParticipant } = useMuteParticipant()
|
||||||
const { isMuted } = useTrackMutedIndicator({
|
const { isMuted } = useTrackMutedIndicator({
|
||||||
participant: participant,
|
participant: participant,
|
||||||
source: Source.Microphone,
|
source: Source.Microphone,
|
||||||
@@ -98,7 +100,9 @@ const MicIndicator = ({ participant }: MicIndicatorProps) => {
|
|||||||
</TooltipWrapper>
|
</TooltipWrapper>
|
||||||
<MuteAlertDialog
|
<MuteAlertDialog
|
||||||
isOpen={isAlertOpen}
|
isOpen={isAlertOpen}
|
||||||
onSubmit={() => setIsAlertOpen(false)}
|
onSubmit={() =>
|
||||||
|
muteParticipant(participant).then(() => setIsAlertOpen(false))
|
||||||
|
}
|
||||||
onClose={() => setIsAlertOpen(false)}
|
onClose={() => setIsAlertOpen(false)}
|
||||||
name={name}
|
name={name}
|
||||||
/>
|
/>
|
||||||
|
|||||||
12
src/frontend/src/features/rooms/livekit/hooks/useRoomData.ts
Normal file
12
src/frontend/src/features/rooms/livekit/hooks/useRoomData.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiRoom } from '@/features/rooms/api/ApiRoom'
|
||||||
|
import { useRoomContext } from '@livekit/components-react'
|
||||||
|
import { useParams } from 'wouter'
|
||||||
|
import { keys } from '@/api/queryKeys'
|
||||||
|
import { queryClient } from '@/api/queryClient'
|
||||||
|
|
||||||
|
export const useRoomData = (): ApiRoom | undefined => {
|
||||||
|
const room = useRoomContext()
|
||||||
|
const { roomId } = useParams()
|
||||||
|
const queryKey = [keys.room, roomId, room.localParticipant.name]
|
||||||
|
return queryClient.getQueryData<ApiRoom>(queryKey)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user