diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b9e9bfa..dd2e9ee8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to ## [Unreleased] +### Added + +- ✨(frontend) add 1080p sending resolution option #1660 + ### Fixed - 🐛(frontend) keep the sending resolution picked while the camera is off #1667 diff --git a/src/frontend/src/features/settings/components/tabs/VideoTab.tsx b/src/frontend/src/features/settings/components/tabs/VideoTab.tsx index 6ae71bbc..7b307031 100644 --- a/src/frontend/src/features/settings/components/tabs/VideoTab.tsx +++ b/src/frontend/src/features/settings/components/tabs/VideoTab.tsx @@ -18,6 +18,7 @@ import { saveVideoPublishResolution, saveVideoSubscribeQuality, userChoicesStore, + VIDEO_RESOLUTIONS, VideoResolution, } from '@/stores/userChoices' import { RowWrapper } from './layout/RowWrapper' @@ -70,7 +71,7 @@ export const VideoTab = ({ id }: VideoTabProps) => { isDisabled: true, } - const handleVideoResolutionChange = async (key: 'h720' | 'h360' | 'h180') => { + const handleVideoResolutionChange = async (key: VideoResolution) => { saveVideoPublishResolution(key) const videoTrack = localParticipant.getTrackPublication( Track.Source.Camera @@ -124,20 +125,13 @@ export const VideoTab = ({ id }: VideoTabProps) => { }, [videoDeviceId, videoElement]) const resolutionItems = useMemo(() => { - return [ - { - value: 'h720', - label: `${t('resolution.publish.items.high')} (720p)`, - }, - { - value: 'h360', - label: `${t('resolution.publish.items.medium')} (360p)`, - }, - { - value: 'h180', - label: `${t('resolution.publish.items.low')} (180p)`, - }, - ] + const labels: Record = { + h1080: `${t('resolution.publish.items.veryHigh')} (1080p)`, + h720: `${t('resolution.publish.items.high')} (720p)`, + h360: `${t('resolution.publish.items.medium')} (360p)`, + h180: `${t('resolution.publish.items.low')} (180p)`, + } + return VIDEO_RESOLUTIONS.map((value) => ({ value, label: labels[value] })) }, [t]) const videoQualityItems = useMemo(() => { diff --git a/src/frontend/src/locales/de/settings.json b/src/frontend/src/locales/de/settings.json index a58f264b..8060155e 100644 --- a/src/frontend/src/locales/de/settings.json +++ b/src/frontend/src/locales/de/settings.json @@ -56,6 +56,7 @@ "publish": { "label": "Wähle die maximale Auflösung beim Senden", "items": { + "veryHigh": "Sehr hohe Auflösung", "high": "Hohe Auflösung", "medium": "Mittlere Auflösung", "low": "Niedrige Auflösung" diff --git a/src/frontend/src/locales/en/settings.json b/src/frontend/src/locales/en/settings.json index 62aa37b8..79cb983f 100644 --- a/src/frontend/src/locales/en/settings.json +++ b/src/frontend/src/locales/en/settings.json @@ -56,6 +56,7 @@ "publish": { "label": "Select your sending resolution (max.)", "items": { + "veryHigh": "Very high definition", "high": "High definition", "medium": "Standard definition", "low": "Low definition" diff --git a/src/frontend/src/locales/es/settings.json b/src/frontend/src/locales/es/settings.json index 5c62bca1..96ae7d12 100644 --- a/src/frontend/src/locales/es/settings.json +++ b/src/frontend/src/locales/es/settings.json @@ -56,6 +56,7 @@ "publish": { "label": "Selecciona tu resolución de envío (máx.)", "items": { + "veryHigh": "Muy alta definición", "high": "Alta definición", "medium": "Definición estándar", "low": "Baja definición" diff --git a/src/frontend/src/locales/fr/settings.json b/src/frontend/src/locales/fr/settings.json index 9878ecc7..85b8a944 100644 --- a/src/frontend/src/locales/fr/settings.json +++ b/src/frontend/src/locales/fr/settings.json @@ -56,6 +56,7 @@ "publish": { "label": "Sélectionner votre résolution d'envoi (max.)", "items": { + "veryHigh": "Très haute définition", "high": "Haute définition", "medium": "Définition standard", "low": "Basse définition" diff --git a/src/frontend/src/locales/nl/settings.json b/src/frontend/src/locales/nl/settings.json index 3c9d3f10..331c3a2e 100644 --- a/src/frontend/src/locales/nl/settings.json +++ b/src/frontend/src/locales/nl/settings.json @@ -56,6 +56,7 @@ "publish": { "label": "Selecteer uw verzendresolutie (max.)", "items": { + "veryHigh": "Zeer hoge definitie", "high": "Hoge definitie", "medium": "Standaarddefinitie", "low": "Lage definitie" diff --git a/src/frontend/src/stores/userChoices.ts b/src/frontend/src/stores/userChoices.ts index de64a07d..04ed51d6 100644 --- a/src/frontend/src/stores/userChoices.ts +++ b/src/frontend/src/stores/userChoices.ts @@ -10,7 +10,12 @@ import { } from '@livekit/components-core' import { VideoQuality } from 'livekit-client' -export type VideoResolution = 'h720' | 'h360' | 'h180' +export const VIDEO_RESOLUTIONS = ['h1080', 'h720', 'h360', 'h180'] as const + +export type VideoResolution = (typeof VIDEO_RESOLUTIONS)[number] + +const isVideoResolution = (value: unknown): value is VideoResolution => + VIDEO_RESOLUTIONS.includes(value as VideoResolution) export type LocalUserChoices = Omit & { processorConfig?: ProcessorConfig @@ -21,13 +26,17 @@ export type LocalUserChoices = Omit & { } function getUserChoicesState(): LocalUserChoices { - return { + const stored: LocalUserChoices = { noiseReductionEnabled: false, audioOutputDeviceId: 'default', // Use 'default' to match LiveKit's standard device selection behavior videoPublishResolution: 'h720', videoSubscribeQuality: VideoQuality.HIGH, ...loadUserChoices(), } + if (!isVideoResolution(stored.videoPublishResolution)) { + stored.videoPublishResolution = 'h720' + } + return stored } export const userChoicesStore = proxy(getUserChoicesState())