diff --git a/fluxer_app/src/features/gateway/events/GatewayReady.ts b/fluxer_app/src/features/gateway/events/GatewayReady.ts index 240c130c3..48a148a74 100644 --- a/fluxer_app/src/features/gateway/events/GatewayReady.ts +++ b/fluxer_app/src/features/gateway/events/GatewayReady.ts @@ -45,7 +45,6 @@ import Users from '@app/features/user/state/Users'; import WebAuthnCredentials, {type WebAuthnCredential} from '@app/features/user/state/WebAuthnCredentials'; import MediaEngine from '@app/features/voice/engine/MediaEngineFacade'; import RtcRegions from '@app/features/voice/state/RtcRegions'; -import VoiceSettings from '@app/features/voice/state/VoiceSettings'; import type {RtcRegionResponse, Channel as WireChannel} from '@fluxer/schema/src/domains/channel/ChannelSchemas'; import type {UserPrivate, User as WireUser} from '@fluxer/schema/src/domains/user/UserResponseSchemas'; import {runInAction} from 'mobx'; @@ -145,7 +144,6 @@ function handleReadyInternal(data: ReadyPayload, context: GatewayHandlerContext) void accountStorage.updateAccountUserData(user.id, userData); void AccountManager.updateAccountUserData(user.id, userData); } - VoiceSettings.handleGatewayReady(data.user); Authentication.handleGatewayReady({user: data.user}); void PremiumCommands.refreshPremiumState().catch((error) => { logger.warn('Failed to refresh premium state after READY', error); diff --git a/fluxer_app/src/features/user/events/UserUpdate.ts b/fluxer_app/src/features/user/events/UserUpdate.ts index 7ae95b4a0..c4159d3ea 100644 --- a/fluxer_app/src/features/user/events/UserUpdate.ts +++ b/fluxer_app/src/features/user/events/UserUpdate.ts @@ -6,7 +6,6 @@ import Messages from '@app/features/messaging/state/MessagingMessages'; import Permission from '@app/features/permissions/state/Permission'; import QuickSwitcher from '@app/features/search/state/QuickSwitcher'; import Users from '@app/features/user/state/Users'; -import VoiceSettings from '@app/features/voice/state/VoiceSettings'; import type {User} from '@fluxer/schema/src/domains/user/UserResponseSchemas'; interface UserUpdatePayload { @@ -20,7 +19,6 @@ interface UserUpdatePayload { export function handleUserUpdate(data: UserUpdatePayload, _context: GatewayHandlerContext): void { Users.handleUserUpdate(data as User); - VoiceSettings.handleUserUpdate(data); Messages.handleUserUpdate({user: {id: data.id}}); Permission.handleUserUpdate(data.id); QuickSwitcher.recomputeIfOpen(); diff --git a/fluxer_app/src/features/voice/components/modals/CameraPreviewModal.tsx b/fluxer_app/src/features/voice/components/modals/CameraPreviewModal.tsx index c36debdc5..58ee33487 100644 --- a/fluxer_app/src/features/voice/components/modals/CameraPreviewModal.tsx +++ b/fluxer_app/src/features/voice/components/modals/CameraPreviewModal.tsx @@ -631,8 +631,8 @@ const CameraPreviewModalContent = observer((props: CameraPreviewModalProps) => { VoiceSettings.videoDeviceId, VoiceSettings.backgroundImageId, VoiceSettings.mirrorCamera, - VoiceSettings.cameraResolution, - VoiceSettings.videoFrameRate, + VoiceSettings.getCameraResolution(), + VoiceSettings.getVideoFrameRate(), voiceBackgroundsAvailable, ]); const voiceSettings = VoiceSettings; diff --git a/fluxer_app/src/features/voice/state/VoiceSettings.ts b/fluxer_app/src/features/voice/state/VoiceSettings.ts index 0e8bc3aeb..7f23955a1 100644 --- a/fluxer_app/src/features/voice/state/VoiceSettings.ts +++ b/fluxer_app/src/features/voice/state/VoiceSettings.ts @@ -19,7 +19,6 @@ import { type VoiceProcessingMode, } from '@app/features/voice/utils/VoiceProcessingProfile'; import {clampVoiceVolumePercent} from '@app/features/voice/utils/VoiceVolumeUtils'; -import type {UserPrivate} from '@fluxer/schema/src/domains/user/UserResponseSchemas'; import {makeAutoObservable} from 'mobx'; export type VoiceBackgroundMediaKind = 'static' | 'animated' | 'video'; @@ -53,6 +52,8 @@ const VIDEO_FRAME_RATE_MAX = 120; const VIDEO_FRAME_RATE_DEFAULT = 30; const DEFAULT_BROWSER_NOISE_SUPPRESSION = true; const DEFAULT_DEEP_FILTER_NOISE_SUPPRESSION = false; +const FREE_VIDEO_FRAME_RATE_MAX = 30; +const PREMIUM_SCREENSHARE_RESOLUTIONS: ReadonlySet = new Set(['high', 'ultra', 'source']); export const CAMERA_EFFECT_STRENGTH_MIN = 0; export const CAMERA_EFFECT_STRENGTH_MAX = 100; export const CAMERA_EFFECT_STRENGTH_DEFAULT = 50; @@ -388,10 +389,11 @@ class VoiceSettings { private listeners = new Set<() => void>(); constructor() { - makeAutoObservable( + makeAutoObservable( this, { listeners: false, + hasHigherVideoQuality: false, getInputDeviceId: false, getOutputDeviceId: false, getVideoDeviceId: false, @@ -572,7 +574,6 @@ class VoiceSettings { 'lastScreenShareSource', 'prioritizeSpeakingParticipants', ]); - this.updateSettings({}); } get showVoiceConnectionId(): boolean { @@ -663,47 +664,6 @@ class VoiceSettings { this.adaptiveScreenShareQualityPrefV2 = value; } - handleGatewayReady(user: UserPrivate): void { - if (this.isUserPremium(user.premium_type)) { - return; - } - if (!this.hasHigherVideoQuality()) { - this.sanitizePremiumSettings(); - } - } - - handleUserUpdate(user: Partial): void { - if (user.premium_type === undefined) { - return; - } - if (this.isUserPremium(user.premium_type)) { - return; - } - if (!this.hasHigherVideoQuality()) { - this.sanitizePremiumSettings(); - } - } - - private isUserPremium(premiumType: number | null | undefined): boolean { - return premiumType != null && premiumType > 0; - } - - private sanitizePremiumSettings(): void { - if ( - this.screenshareResolution === 'high' || - this.screenshareResolution === 'ultra' || - this.screenshareResolution === 'source' - ) { - this.screenshareResolution = 'medium'; - } - if (this.cameraResolution === 'high') { - this.cameraResolution = 'medium'; - } - if (this.videoFrameRate > 30) { - this.videoFrameRate = 30; - } - } - private hasHigherVideoQuality(): boolean { const featureFlag = isLimitToggleEnabled( { @@ -797,6 +757,9 @@ class VoiceSettings { } getCameraResolution(): CameraResolution { + if (this.cameraResolution === 'high' && !this.hasHigherVideoQuality()) { + return 'medium'; + } return this.cameraResolution; } @@ -805,10 +768,16 @@ class VoiceSettings { } getScreenshareResolution(): ScreenshareResolution { + if (PREMIUM_SCREENSHARE_RESOLUTIONS.has(this.screenshareResolution) && !this.hasHigherVideoQuality()) { + return 'medium'; + } return this.screenshareResolution; } getVideoFrameRate(): number { + if (this.videoFrameRate > FREE_VIDEO_FRAME_RATE_MAX && !this.hasHigherVideoQuality()) { + return FREE_VIDEO_FRAME_RATE_MAX; + } return this.videoFrameRate; }