From 26a90456f7d9937ee0b5b857578519eca4e48795 Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Thu, 17 Jul 2025 16:28:48 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=B8(frontend)=20add=20alert=20for=20me?= =?UTF-8?q?dia=20devices=20already=20in=20use?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../features/rooms/components/Conference.tsx | 24 +++++++++++++- .../components/MediaDeviceErrorAlert.tsx | 33 +++++++++++++++++++ src/frontend/src/locales/de/rooms.json | 13 ++++++++ src/frontend/src/locales/en/rooms.json | 13 ++++++++ src/frontend/src/locales/fr/rooms.json | 13 ++++++++ src/frontend/src/locales/nl/rooms.json | 13 ++++++++ 6 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 src/frontend/src/features/rooms/components/MediaDeviceErrorAlert.tsx diff --git a/src/frontend/src/features/rooms/components/Conference.tsx b/src/frontend/src/features/rooms/components/Conference.tsx index 3ee174c7..e7b82d3e 100644 --- a/src/frontend/src/features/rooms/components/Conference.tsx +++ b/src/frontend/src/features/rooms/components/Conference.tsx @@ -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 }) + } + }} > {showInviteDialog && ( @@ -142,6 +160,10 @@ export const Conference = ({ onClose={() => setShowInviteDialog(false)} /> )} + setMediaDeviceError({ error: null, kind: null })} + /> diff --git a/src/frontend/src/features/rooms/components/MediaDeviceErrorAlert.tsx b/src/frontend/src/features/rooms/components/MediaDeviceErrorAlert.tsx new file mode 100644 index 00000000..bc240869 --- /dev/null +++ b/src/frontend/src/features/rooms/components/MediaDeviceErrorAlert.tsx @@ -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 ( + +

{t(`${error}.body.${kind}`)}

+ +
+ ) +} diff --git a/src/frontend/src/locales/de/rooms.json b/src/frontend/src/locales/de/rooms.json index 3deed51a..4db7930d 100644 --- a/src/frontend/src/locales/de/rooms.json +++ b/src/frontend/src/locales/de/rooms.json @@ -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", diff --git a/src/frontend/src/locales/en/rooms.json b/src/frontend/src/locales/en/rooms.json index ee5f22eb..1b5c4c3e 100644 --- a/src/frontend/src/locales/en/rooms.json +++ b/src/frontend/src/locales/en/rooms.json @@ -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", diff --git a/src/frontend/src/locales/fr/rooms.json b/src/frontend/src/locales/fr/rooms.json index aa92064c..a3d5a077 100644 --- a/src/frontend/src/locales/fr/rooms.json +++ b/src/frontend/src/locales/fr/rooms.json @@ -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", diff --git a/src/frontend/src/locales/nl/rooms.json b/src/frontend/src/locales/nl/rooms.json index 1a085d75..56d9bc0a 100644 --- a/src/frontend/src/locales/nl/rooms.json +++ b/src/frontend/src/locales/nl/rooms.json @@ -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",