mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 21:45:31 +09:00
feat(app): pick screen share bitrate up to the limit (#3411)
This commit is contained in:
1 parent
e0640d68ff
commit
c17091768c
52 files changed
+879
-242
No files matched your search
@@ -102,6 +102,25 @@ const MIRROR_CAMERA_DESCRIPTOR = msg({
|
||||
message: 'Mirror camera',
|
||||
comment: 'Switch label in the video tab for flipping the local camera preview horizontally.',
|
||||
});
|
||||
const SCREEN_SHARE_BITRATE_DESCRIPTOR = msg({
|
||||
message: 'Bitrate',
|
||||
comment: 'Short label in the video tab for the screen share video bitrate select. Keep it concise.',
|
||||
});
|
||||
const SCREEN_SHARE_BITRATE_DESCRIPTION_DESCRIPTOR = msg({
|
||||
message:
|
||||
'With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth.',
|
||||
comment:
|
||||
'Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.',
|
||||
});
|
||||
const SCREEN_SHARE_BITRATE_AUTOMATIC_DESCRIPTOR = msg({
|
||||
message: 'Automatic',
|
||||
comment: 'Default option of the screen share bitrate select in the video tab.',
|
||||
});
|
||||
const SCREEN_SHARE_BITRATE_MBPS_DESCRIPTOR = msg({
|
||||
message: '{bitrate} Mbps',
|
||||
comment:
|
||||
'Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.',
|
||||
});
|
||||
const SCREEN_SHARE_QUALITY_DESCRIPTOR = msg({
|
||||
message: 'Screen share quality',
|
||||
comment: 'Short label in the video tab. Keep it concise.',
|
||||
@@ -176,6 +195,7 @@ export const VideoTab: React.FC<VideoTabProps> = observer(
|
||||
const screenShareState = resolveUserVideoTabScreenShareState({
|
||||
quality: screenShareQuality,
|
||||
hintSetting: screenShareContentHint,
|
||||
bitrate: voiceSettings.getScreenShareBitrateBudget(),
|
||||
selfHosted: !showPremium,
|
||||
});
|
||||
const screenshareResolutionOptions: ReadonlyArray<ComboboxOption<OfferedScreenShareResolution>> =
|
||||
@@ -189,6 +209,15 @@ export const VideoTab: React.FC<VideoTabProps> = observer(
|
||||
value,
|
||||
label: i18n._(FPS_DESCRIPTOR, {frameRate: value}),
|
||||
}));
|
||||
const bitrateOptions: ReadonlyArray<ComboboxOption<number | null>> = [
|
||||
{value: null, label: i18n._(SCREEN_SHARE_BITRATE_AUTOMATIC_DESCRIPTOR)},
|
||||
...screenShareState.bitrateOptions.map((value) => ({
|
||||
value,
|
||||
label: i18n._(SCREEN_SHARE_BITRATE_MBPS_DESCRIPTOR, {
|
||||
bitrate: i18n.number(value / 1_000_000, {maximumFractionDigits: 1}),
|
||||
}),
|
||||
})),
|
||||
];
|
||||
const handleCameraPreview = async () => {
|
||||
const granted = await requestPermission();
|
||||
if (granted) {
|
||||
@@ -387,6 +416,19 @@ export const VideoTab: React.FC<VideoTabProps> = observer(
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{hasHigherQuality && (
|
||||
<CompactComboboxRow<number | null>
|
||||
label={i18n._(SCREEN_SHARE_BITRATE_DESCRIPTOR)}
|
||||
description={i18n._(SCREEN_SHARE_BITRATE_DESCRIPTION_DESCRIPTOR)}
|
||||
options={bitrateOptions}
|
||||
value={screenShareState.bitrate}
|
||||
onChange={(value) => VoiceSettingsCommands.update({screenShareBitrate: value})}
|
||||
isSearchable={false}
|
||||
controlWidth="small"
|
||||
dataFlx="user.video-tab.select.screen-share-bitrate-change"
|
||||
data-flx="user.user-video-tab.video-tab.compact-combobox-row.screen-share-bitrate-change"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.actionRow} data-flx="user.video-tab.advanced-video-settings-section">
|
||||
<span className={styles.actionLabel} data-flx="user.video-tab.advanced-video-settings-label">
|
||||
|
||||
@@ -12,6 +12,7 @@ import type {ScreenShareContentHint} from '@app/features/voice/utils/CodecCapabi
|
||||
import {
|
||||
resolveScreenShareFrameRate,
|
||||
resolveScreenShareTarget,
|
||||
type ScreenShareBitrateBudget,
|
||||
type ScreenShareContext,
|
||||
type ScreenShareQualityInput,
|
||||
SUPPORTED_SCREEN_SHARE_FRAME_RATES,
|
||||
@@ -35,10 +36,15 @@ const FREE_SCREEN_SHARE_RESOLUTIONS: ReadonlyArray<OfferedScreenShareResolution>
|
||||
const PREMIUM_SCREEN_SHARE_RESOLUTIONS: ReadonlyArray<OfferedScreenShareResolution> = ['high', 'ultra', 'source'];
|
||||
const FREE_SCREEN_SHARE_FRAME_RATES: ReadonlyArray<SupportedScreenShareFrameRate> = [15, 30];
|
||||
const PREMIUM_SCREEN_SHARE_FRAME_RATES: ReadonlyArray<SupportedScreenShareFrameRate> = [15, 30, 60];
|
||||
const SCREEN_SHARE_BITRATE_STEPS_BPS: ReadonlyArray<number> = [
|
||||
2_000_000, 4_000_000, 6_000_000, 8_000_000, 10_000_000, 15_000_000, 20_000_000, 25_000_000, 30_000_000, 40_000_000,
|
||||
50_000_000,
|
||||
];
|
||||
|
||||
export interface UserVideoTabScreenShareInput {
|
||||
quality: ScreenShareQualityInput;
|
||||
hintSetting: ScreenShareContentHint;
|
||||
bitrate: ScreenShareBitrateBudget;
|
||||
selfHosted: boolean;
|
||||
}
|
||||
|
||||
@@ -52,6 +58,8 @@ export interface UserVideoTabScreenShareState {
|
||||
frameRate: SupportedScreenShareFrameRate;
|
||||
resolutionOptions: ReadonlyArray<UserVideoTabResolutionOption>;
|
||||
frameRateOptions: ReadonlyArray<SupportedScreenShareFrameRate>;
|
||||
bitrate: number | null;
|
||||
bitrateOptions: ReadonlyArray<number>;
|
||||
preset: Exclude<StreamingMode, 'custom'> | null;
|
||||
presetOverriddenByContext: boolean;
|
||||
saved: {resolution: OfferedScreenShareResolution; frameRate: SupportedScreenShareFrameRate} | null;
|
||||
@@ -82,8 +90,20 @@ function buildFrameRateOptions(
|
||||
return SUPPORTED_SCREEN_SHARE_FRAME_RATES.filter((value) => value === effective || offered.includes(value));
|
||||
}
|
||||
|
||||
function buildBitrateOptions(budget: ScreenShareBitrateBudget): ReadonlyArray<number> {
|
||||
const offered = new Set(SCREEN_SHARE_BITRATE_STEPS_BPS.filter((value) => value < budget.ceilingBps));
|
||||
offered.add(budget.ceilingBps);
|
||||
if (budget.chosenBps !== null) offered.add(budget.chosenBps);
|
||||
return [...offered].sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
export function resolveUserVideoTabScreenShareState(input: UserVideoTabScreenShareInput): UserVideoTabScreenShareState {
|
||||
const target = resolveScreenShareTarget({...input.quality, sourceDimensions: null, hintSetting: input.hintSetting});
|
||||
const target = resolveScreenShareTarget({
|
||||
...input.quality,
|
||||
sourceDimensions: null,
|
||||
hintSetting: input.hintSetting,
|
||||
bitrate: input.bitrate,
|
||||
});
|
||||
const resolution = offeredScreenShareResolution(target.resolution);
|
||||
return {
|
||||
resolution,
|
||||
@@ -95,6 +115,8 @@ export function resolveUserVideoTabScreenShareState(input: UserVideoTabScreenSha
|
||||
resolution,
|
||||
),
|
||||
frameRateOptions: buildFrameRateOptions(input.quality.entitled, target.frameRate),
|
||||
bitrate: input.bitrate.chosenBps,
|
||||
bitrateOptions: buildBitrateOptions(input.bitrate),
|
||||
preset: input.quality.mode === 'custom' ? null : input.quality.mode,
|
||||
presetOverriddenByContext: selectStreamSettingsPresetOverriddenByContext(input.quality.mode, input.quality.context),
|
||||
saved: target.tierLimited
|
||||
|
||||
Reference in new issue
Block a user