mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 05:25:40 +09:00
refactor(voice): clamp premium video quality at read time (#2380)
This commit is contained in:
1 parent
12c6fb7b7f
commit
501adff13d
4 files changed
+15
-50
No files matched your search
@@ -45,7 +45,6 @@ import Users from '@app/features/user/state/Users';
|
|||||||
import WebAuthnCredentials, {type WebAuthnCredential} from '@app/features/user/state/WebAuthnCredentials';
|
import WebAuthnCredentials, {type WebAuthnCredential} from '@app/features/user/state/WebAuthnCredentials';
|
||||||
import MediaEngine from '@app/features/voice/engine/MediaEngineFacade';
|
import MediaEngine from '@app/features/voice/engine/MediaEngineFacade';
|
||||||
import RtcRegions from '@app/features/voice/state/RtcRegions';
|
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 {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 type {UserPrivate, User as WireUser} from '@fluxer/schema/src/domains/user/UserResponseSchemas';
|
||||||
import {runInAction} from 'mobx';
|
import {runInAction} from 'mobx';
|
||||||
@@ -145,7 +144,6 @@ function handleReadyInternal(data: ReadyPayload, context: GatewayHandlerContext)
|
|||||||
void accountStorage.updateAccountUserData(user.id, userData);
|
void accountStorage.updateAccountUserData(user.id, userData);
|
||||||
void AccountManager.updateAccountUserData(user.id, userData);
|
void AccountManager.updateAccountUserData(user.id, userData);
|
||||||
}
|
}
|
||||||
VoiceSettings.handleGatewayReady(data.user);
|
|
||||||
Authentication.handleGatewayReady({user: data.user});
|
Authentication.handleGatewayReady({user: data.user});
|
||||||
void PremiumCommands.refreshPremiumState().catch((error) => {
|
void PremiumCommands.refreshPremiumState().catch((error) => {
|
||||||
logger.warn('Failed to refresh premium state after READY', error);
|
logger.warn('Failed to refresh premium state after READY', error);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import Messages from '@app/features/messaging/state/MessagingMessages';
|
|||||||
import Permission from '@app/features/permissions/state/Permission';
|
import Permission from '@app/features/permissions/state/Permission';
|
||||||
import QuickSwitcher from '@app/features/search/state/QuickSwitcher';
|
import QuickSwitcher from '@app/features/search/state/QuickSwitcher';
|
||||||
import Users from '@app/features/user/state/Users';
|
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';
|
import type {User} from '@fluxer/schema/src/domains/user/UserResponseSchemas';
|
||||||
|
|
||||||
interface UserUpdatePayload {
|
interface UserUpdatePayload {
|
||||||
@@ -20,7 +19,6 @@ interface UserUpdatePayload {
|
|||||||
|
|
||||||
export function handleUserUpdate(data: UserUpdatePayload, _context: GatewayHandlerContext): void {
|
export function handleUserUpdate(data: UserUpdatePayload, _context: GatewayHandlerContext): void {
|
||||||
Users.handleUserUpdate(data as User);
|
Users.handleUserUpdate(data as User);
|
||||||
VoiceSettings.handleUserUpdate(data);
|
|
||||||
Messages.handleUserUpdate({user: {id: data.id}});
|
Messages.handleUserUpdate({user: {id: data.id}});
|
||||||
Permission.handleUserUpdate(data.id);
|
Permission.handleUserUpdate(data.id);
|
||||||
QuickSwitcher.recomputeIfOpen();
|
QuickSwitcher.recomputeIfOpen();
|
||||||
|
|||||||
@@ -631,8 +631,8 @@ const CameraPreviewModalContent = observer((props: CameraPreviewModalProps) => {
|
|||||||
VoiceSettings.videoDeviceId,
|
VoiceSettings.videoDeviceId,
|
||||||
VoiceSettings.backgroundImageId,
|
VoiceSettings.backgroundImageId,
|
||||||
VoiceSettings.mirrorCamera,
|
VoiceSettings.mirrorCamera,
|
||||||
VoiceSettings.cameraResolution,
|
VoiceSettings.getCameraResolution(),
|
||||||
VoiceSettings.videoFrameRate,
|
VoiceSettings.getVideoFrameRate(),
|
||||||
voiceBackgroundsAvailable,
|
voiceBackgroundsAvailable,
|
||||||
]);
|
]);
|
||||||
const voiceSettings = VoiceSettings;
|
const voiceSettings = VoiceSettings;
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import {
|
|||||||
type VoiceProcessingMode,
|
type VoiceProcessingMode,
|
||||||
} from '@app/features/voice/utils/VoiceProcessingProfile';
|
} from '@app/features/voice/utils/VoiceProcessingProfile';
|
||||||
import {clampVoiceVolumePercent} from '@app/features/voice/utils/VoiceVolumeUtils';
|
import {clampVoiceVolumePercent} from '@app/features/voice/utils/VoiceVolumeUtils';
|
||||||
import type {UserPrivate} from '@fluxer/schema/src/domains/user/UserResponseSchemas';
|
|
||||||
import {makeAutoObservable} from 'mobx';
|
import {makeAutoObservable} from 'mobx';
|
||||||
|
|
||||||
export type VoiceBackgroundMediaKind = 'static' | 'animated' | 'video';
|
export type VoiceBackgroundMediaKind = 'static' | 'animated' | 'video';
|
||||||
@@ -53,6 +52,8 @@ const VIDEO_FRAME_RATE_MAX = 120;
|
|||||||
const VIDEO_FRAME_RATE_DEFAULT = 30;
|
const VIDEO_FRAME_RATE_DEFAULT = 30;
|
||||||
const DEFAULT_BROWSER_NOISE_SUPPRESSION = true;
|
const DEFAULT_BROWSER_NOISE_SUPPRESSION = true;
|
||||||
const DEFAULT_DEEP_FILTER_NOISE_SUPPRESSION = false;
|
const DEFAULT_DEEP_FILTER_NOISE_SUPPRESSION = false;
|
||||||
|
const FREE_VIDEO_FRAME_RATE_MAX = 30;
|
||||||
|
const PREMIUM_SCREENSHARE_RESOLUTIONS: ReadonlySet<ScreenshareResolution> = new Set(['high', 'ultra', 'source']);
|
||||||
export const CAMERA_EFFECT_STRENGTH_MIN = 0;
|
export const CAMERA_EFFECT_STRENGTH_MIN = 0;
|
||||||
export const CAMERA_EFFECT_STRENGTH_MAX = 100;
|
export const CAMERA_EFFECT_STRENGTH_MAX = 100;
|
||||||
export const CAMERA_EFFECT_STRENGTH_DEFAULT = 50;
|
export const CAMERA_EFFECT_STRENGTH_DEFAULT = 50;
|
||||||
@@ -388,10 +389,11 @@ class VoiceSettings {
|
|||||||
private listeners = new Set<() => void>();
|
private listeners = new Set<() => void>();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
makeAutoObservable<this, 'listeners' | 'notifyListeners'>(
|
makeAutoObservable<this, 'hasHigherVideoQuality' | 'listeners' | 'notifyListeners'>(
|
||||||
this,
|
this,
|
||||||
{
|
{
|
||||||
listeners: false,
|
listeners: false,
|
||||||
|
hasHigherVideoQuality: false,
|
||||||
getInputDeviceId: false,
|
getInputDeviceId: false,
|
||||||
getOutputDeviceId: false,
|
getOutputDeviceId: false,
|
||||||
getVideoDeviceId: false,
|
getVideoDeviceId: false,
|
||||||
@@ -572,7 +574,6 @@ class VoiceSettings {
|
|||||||
'lastScreenShareSource',
|
'lastScreenShareSource',
|
||||||
'prioritizeSpeakingParticipants',
|
'prioritizeSpeakingParticipants',
|
||||||
]);
|
]);
|
||||||
this.updateSettings({});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get showVoiceConnectionId(): boolean {
|
get showVoiceConnectionId(): boolean {
|
||||||
@@ -663,47 +664,6 @@ class VoiceSettings {
|
|||||||
this.adaptiveScreenShareQualityPrefV2 = value;
|
this.adaptiveScreenShareQualityPrefV2 = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleGatewayReady(user: UserPrivate): void {
|
|
||||||
if (this.isUserPremium(user.premium_type)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.hasHigherVideoQuality()) {
|
|
||||||
this.sanitizePremiumSettings();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleUserUpdate(user: Partial<UserPrivate>): 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 {
|
private hasHigherVideoQuality(): boolean {
|
||||||
const featureFlag = isLimitToggleEnabled(
|
const featureFlag = isLimitToggleEnabled(
|
||||||
{
|
{
|
||||||
@@ -797,6 +757,9 @@ class VoiceSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCameraResolution(): CameraResolution {
|
getCameraResolution(): CameraResolution {
|
||||||
|
if (this.cameraResolution === 'high' && !this.hasHigherVideoQuality()) {
|
||||||
|
return 'medium';
|
||||||
|
}
|
||||||
return this.cameraResolution;
|
return this.cameraResolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -805,10 +768,16 @@ class VoiceSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getScreenshareResolution(): ScreenshareResolution {
|
getScreenshareResolution(): ScreenshareResolution {
|
||||||
|
if (PREMIUM_SCREENSHARE_RESOLUTIONS.has(this.screenshareResolution) && !this.hasHigherVideoQuality()) {
|
||||||
|
return 'medium';
|
||||||
|
}
|
||||||
return this.screenshareResolution;
|
return this.screenshareResolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
getVideoFrameRate(): number {
|
getVideoFrameRate(): number {
|
||||||
|
if (this.videoFrameRate > FREE_VIDEO_FRAME_RATE_MAX && !this.hasHigherVideoQuality()) {
|
||||||
|
return FREE_VIDEO_FRAME_RATE_MAX;
|
||||||
|
}
|
||||||
return this.videoFrameRate;
|
return this.videoFrameRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user