🚸(frontend) add alert for media devices already in use
Show explicit warning when microphone/camera are occupied by other applications. Helps users understand permission failures and reminds them to close other video conferencing apps. Spotted issue through Crisp support - users often forget to quit other webconfs that don't auto-disconnect when alone.
This commit is contained in:
@@ -2,7 +2,12 @@ import { useEffect, useMemo, useState } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { LiveKitRoom } from '@livekit/components-react'
|
||||
import { DisconnectReason, Room, RoomOptions } from 'livekit-client'
|
||||
import {
|
||||
DisconnectReason,
|
||||
MediaDeviceFailure,
|
||||
Room,
|
||||
RoomOptions,
|
||||
} from 'livekit-client'
|
||||
import { keys } from '@/api/queryKeys'
|
||||
import { queryClient } from '@/api/queryClient'
|
||||
import { Screen } from '@/layout/Screen'
|
||||
@@ -18,6 +23,7 @@ import { css } from '@/styled-system/css'
|
||||
import { BackgroundProcessorFactory } from '../livekit/components/blur'
|
||||
import { LocalUserChoices } from '@/stores/userChoices'
|
||||
import { navigateTo } from '@/navigation/navigateTo'
|
||||
import { MediaDeviceErrorAlert } from './MediaDeviceErrorAlert'
|
||||
|
||||
export const Conference = ({
|
||||
roomId,
|
||||
@@ -86,6 +92,13 @@ export const Conference = ({
|
||||
const room = useMemo(() => new Room(roomOptions), [roomOptions])
|
||||
|
||||
const [showInviteDialog, setShowInviteDialog] = useState(mode === 'create')
|
||||
const [mediaDeviceError, setMediaDeviceError] = useState<{
|
||||
error: MediaDeviceFailure | null
|
||||
kind: MediaDeviceKind | null
|
||||
}>({
|
||||
error: null,
|
||||
kind: null,
|
||||
})
|
||||
|
||||
const { t } = useTranslation('rooms')
|
||||
if (isCreateError) {
|
||||
@@ -132,6 +145,11 @@ export const Conference = ({
|
||||
navigateTo('feedback', { duplicateIdentity: true })
|
||||
}
|
||||
}}
|
||||
onMediaDeviceFailure={(e, kind) => {
|
||||
if (e == MediaDeviceFailure.DeviceInUse && !!kind) {
|
||||
setMediaDeviceError({ error: e, kind })
|
||||
}
|
||||
}}
|
||||
>
|
||||
<VideoConference />
|
||||
{showInviteDialog && (
|
||||
@@ -142,6 +160,10 @@ export const Conference = ({
|
||||
onClose={() => setShowInviteDialog(false)}
|
||||
/>
|
||||
)}
|
||||
<MediaDeviceErrorAlert
|
||||
{...mediaDeviceError}
|
||||
onClose={() => setMediaDeviceError({ error: null, kind: null })}
|
||||
/>
|
||||
</LiveKitRoom>
|
||||
</Screen>
|
||||
</QueryAware>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { MediaDeviceFailure } from 'livekit-client'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Button, Dialog, P } from '@/primitives'
|
||||
|
||||
export type MediaDeviceErrorAlertProps = {
|
||||
error?: MediaDeviceFailure | null
|
||||
kind?: MediaDeviceKind | null
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
export const MediaDeviceErrorAlert = ({
|
||||
error,
|
||||
kind,
|
||||
onClose,
|
||||
}: MediaDeviceErrorAlertProps) => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'mediaErrorDialog' })
|
||||
|
||||
if (!error || !kind) return
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
role="alertdialog"
|
||||
isOpen={!!error}
|
||||
onClose={onClose}
|
||||
title={t(`${error}.title.${kind}`)}
|
||||
>
|
||||
<P>{t(`${error}.body.${kind}`)}</P>
|
||||
<Button variant="text" size="sm" onPress={onClose}>
|
||||
{t('close')}
|
||||
</Button>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
@@ -60,6 +60,19 @@
|
||||
"description": "Teilen Sie diesen Link mit Personen, die Sie zum Meeting einladen möchten.",
|
||||
"permissions": "Personen mit diesem Link benötigen keine Erlaubnis, um diesem Meeting beizutreten."
|
||||
},
|
||||
"mediaErrorDialog": {
|
||||
"DeviceInUse": {
|
||||
"title": {
|
||||
"audioinput": "Mikrofon konnte nicht aktiviert werden",
|
||||
"videoinput": "Kamera konnte nicht aktiviert werden"
|
||||
},
|
||||
"body": {
|
||||
"audioinput": "Ihr Mikrofon wird bereits in einem anderen Tab oder von einer anderen Anwendung verwendet, was die Aktivierung in diesem Videoanruf verhindert. Wenn Sie möchten, schließen Sie den anderen Tab oder die Anwendung, um es hier zu verwenden.",
|
||||
"videoinput": "Ihre Kamera wird bereits in einem anderen Tab oder von einer anderen Anwendung verwendet, was die Aktivierung in diesem Videoanruf verhindert. Wenn Sie möchten, schließen Sie den anderen Tab oder die Anwendung, um sie hier zu verwenden."
|
||||
}
|
||||
},
|
||||
"close": "OK"
|
||||
},
|
||||
"error": {
|
||||
"createRoom": {
|
||||
"heading": "Authentifizierung erforderlich",
|
||||
|
||||
@@ -60,6 +60,19 @@
|
||||
"description": "Share this link with people you want to invite to the meeting.",
|
||||
"permissions": "People with this link do not need your permission to join this meeting."
|
||||
},
|
||||
"mediaErrorDialog": {
|
||||
"DeviceInUse": {
|
||||
"title": {
|
||||
"audioinput": "Microphone Activation Failed",
|
||||
"videoinput": "Camera Activation Failed"
|
||||
},
|
||||
"body": {
|
||||
"audioinput": "Your microphone is already in use by another tab or application, which prevents it from being activated in this video call. If you wish, close the other tab or application to use it here.",
|
||||
"videoinput": "Your camera is already in use by another tab or application, which prevents it from being activated in this video call. If you wish, close the other tab or application to use it here."
|
||||
}
|
||||
},
|
||||
"close": "OK"
|
||||
},
|
||||
"error": {
|
||||
"createRoom": {
|
||||
"heading": "Authentication Required",
|
||||
|
||||
@@ -60,6 +60,19 @@
|
||||
"description": "Partagez ce lien avec les personnes que vous souhaitez inviter à la réunion.",
|
||||
"permissions": "Les personnes disposant de ce lien n'ont pas besoin de votre autorisation pour rejoindre cette réunion."
|
||||
},
|
||||
"mediaErrorDialog": {
|
||||
"DeviceInUse": {
|
||||
"title": {
|
||||
"audioinput": "Activation microphone impossible",
|
||||
"videoinput": "Activation caméra impossible"
|
||||
},
|
||||
"body": {
|
||||
"audioinput": "Votre microphone est déjà utilisé dans un autre onglet ou une autre application, ce qui empêche son activation dans cette visioconférence. Si vous le souhaitez, fermez l'autre onglet ou application pour l'utiliser ici.",
|
||||
"videoinput": "Votre caméra est déjà utilisée dans un autre onglet ou une autre application, ce qui empêche son activation dans cette visioconférence. Si vous le souhaitez, fermez l'autre onglet ou application pour l'utiliser ici."
|
||||
}
|
||||
},
|
||||
"close": "OK"
|
||||
},
|
||||
"error": {
|
||||
"createRoom": {
|
||||
"heading": "Authentification requise",
|
||||
|
||||
@@ -60,6 +60,19 @@
|
||||
"description": "Deel deze link met mensen die u wilt uitnodigen voor de vergadering.",
|
||||
"permissions": "Mensen met deze link hebben uw toestemming niet nodig om deel te nemen aan deze vergadering."
|
||||
},
|
||||
"mediaErrorDialog": {
|
||||
"DeviceInUse": {
|
||||
"title": {
|
||||
"audioinput": "Microfoon activeren mislukt",
|
||||
"videoinput": "Camera activeren mislukt"
|
||||
},
|
||||
"body": {
|
||||
"audioinput": "Je microfoon wordt al gebruikt door een ander tabblad of een andere toepassing, waardoor deze niet geactiveerd kan worden in dit videogesprek. Sluit indien gewenst het andere tabblad of de toepassing om je microfoon hier te gebruiken.",
|
||||
"videoinput": "Je camera wordt al gebruikt door een ander tabblad of een andere toepassing, waardoor deze niet geactiveerd kan worden in dit videogesprek. Sluit indien gewenst het andere tabblad of de toepassing om je camera hier te gebruiken."
|
||||
}
|
||||
},
|
||||
"close": "OK"
|
||||
},
|
||||
"error": {
|
||||
"createRoom": {
|
||||
"heading": "Verificatie vereist",
|
||||
|
||||
Reference in New Issue
Block a user