mirror of
https://github.com/suitenumerique/meet.git
synced 2026-09-02 13:48:26 +00:00
✨(frontend) add 1080p sending resolution option
The sending resolution selector stopped at 720p while `VideoPresets` already exposes `h1080` (1920x1080), so publishers on a good uplink could not make use of the capacity they had. Add "Very high definition (1080p)" above the existing entries, translated in the five supported locales. The default stays `h720`, so nothing changes unless a user goes and picks the new entry. Being explicit about what that costs, since 1080p roughly doubles a publisher's uplink: this is a per-user choice, and an instance operator has no way today to decline it. Whether that warrants a server-side setting alongside the existing `ApiConfig` flags is a call for maintainers — happy to add one if you want it, rather than change the API contract unasked in a frontend PR. While here, make the option list harder to get wrong. Resolutions now come from a single `VIDEO_RESOLUTIONS` tuple that `VideoResolution` derives from, the selector items are built by mapping over it against a `Record<VideoResolution, string>` of labels — so a resolution cannot be added to one and forgotten in the other — and a persisted value that is not in the tuple falls back to `h720` instead of reaching `VideoPresets[...]` as `undefined`, since `loadUserChoices` spreads localStorage without validating it. Known limitation, unchanged by this patch: `restartTrack` passes the resolution as an `ideal` constraint, so a camera that cannot reach the selected height degrades silently. That is already true of 720p on a 480p webcam; 1080p is the first step where the gap is the common case rather than the edge one.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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<VideoResolution, string> = {
|
||||
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(() => {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
"publish": {
|
||||
"label": "Selecteer uw verzendresolutie (max.)",
|
||||
"items": {
|
||||
"veryHigh": "Zeer hoge definitie",
|
||||
"high": "Hoge definitie",
|
||||
"medium": "Standaarddefinitie",
|
||||
"low": "Lage definitie"
|
||||
|
||||
@@ -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<LocalUserChoicesLK, 'username'> & {
|
||||
processorConfig?: ProcessorConfig
|
||||
@@ -21,13 +26,17 @@ export type LocalUserChoices = Omit<LocalUserChoicesLK, 'username'> & {
|
||||
}
|
||||
|
||||
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<LocalUserChoices>(getUserChoicesState())
|
||||
|
||||
Reference in New Issue
Block a user