fix: centralize screen share pipeline to fix 270p resolution ramp-up failure

Screen sharing was publishing at h360 (640x360) and never ramping to target
resolution due to stale closure in setTimeout, wrong initial quality anchor,
and 5 competing code paths with inconsistent bitrates.

- Create utils/screenShare.ts as single source of truth for all screen share ops
- Publish at target resolution from the start (not h360 → ramp)
- Read store at call time in timers (eliminates stale closure bug)
- Use maintain-resolution for screen content, maintain-framerate for camera
- Fix OS-level "Stop sharing" not resetting store or restoring AEC
- Enable dynacast for SFU quality signaling
- Reconcile QUALITY_MAP to canonical bitrates across all 7 files
This commit is contained in:
Jannis Braun
2026-02-23 03:25:52 +01:00
parent 82eee04946
commit 7e7de41718
7 changed files with 211 additions and 161 deletions
@@ -1,7 +1,5 @@
import React, { useRef, useEffect } from 'react';
import { useVoiceStore } from '../../stores/voiceStore';
import { getActiveRoom } from '../../hooks/useLiveKit';
import { VideoPresets, VideoPreset } from 'livekit-client';
interface VideoQualityPopoverProps {
open: boolean;
@@ -10,23 +8,14 @@ interface VideoQualityPopoverProps {
}
const PRESETS = [
{ value: '1080p60' as const, label: '1080p 60fps', desc: '1920x1080, 10000 kbps' },
{ value: '1080p' as const, label: '1080p 30fps', desc: '1920x1080, 5000 kbps' },
{ value: '720p60' as const, label: '720p 60fps', desc: '1280x720, 5000 kbps' },
{ value: '720p' as const, label: '720p 30fps', desc: '1280x720, 3000 kbps' },
{ value: '540p' as const, label: '540p 30fps', desc: '960x540, 1500 kbps' },
{ value: '360p' as const, label: '360p 30fps', desc: '640x360, 800 kbps' },
{ value: '1080p60' as const, label: '1080p 60fps', desc: '1920x1080, 12000 kbps' },
{ value: '1080p' as const, label: '1080p 30fps', desc: '1920x1080, 8000 kbps' },
{ value: '720p60' as const, label: '720p 60fps', desc: '1280x720, 8000 kbps' },
{ value: '720p' as const, label: '720p 30fps', desc: '1280x720, 5000 kbps' },
{ value: '540p' as const, label: '540p 30fps', desc: '960x540, 2000 kbps' },
{ value: '360p' as const, label: '360p 30fps', desc: '640x360, 1000 kbps' },
] as const;
const QUALITY_MAP: Record<string, VideoPreset> = {
'1080p60': new VideoPreset(1920, 1080, 15_000_000, 60),
'1080p': new VideoPreset(1920, 1080, 8_000_000, 30),
'720p60': new VideoPreset(1280, 720, 8_000_000, 60),
'720p': new VideoPreset(1280, 720, 5_000_000, 30),
'540p': new VideoPreset(960, 540, 2_000_000, 30),
'360p': new VideoPreset(640, 360, 1_000_000, 30),
};
export function VideoQualityPopover({ open, onClose, anchorRect }: VideoQualityPopoverProps) {
const popoverRef = useRef<HTMLDivElement>(null);
const videoQuality = useVoiceStore((s) => s.videoQuality);