fix(voice): never auto-select AV1 or HEVC for screen sharing (#2111)

This commit is contained in:
Hampus authored and GitHub committed 2026-08-30 02:05:21 +02:00
1 parent 059bcc6c53
commit 3b1eb56713
13 files changed
+555 -387

No files matched your search

@@ -42,8 +42,10 @@ import {UnreadBadgeCustomizationControl} from '@app/features/user/components/mod
import {
EmulatedDecodeCodecCapControl,
OpenH264Control,
ScreenShareAv1OptInControl,
ScreenShareCodecControl,
ScreenShareEncoderControls,
ScreenShareHevcOptInControl,
ScreenSharePreviewBehaviorControl,
} from '@app/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls';
import {
@@ -83,6 +85,8 @@ export const DIRECT_CONTROL_ITEM_IDS = new Set([
'voice-video-new-device-alerts',
'voice-video-connection-volume-controls',
'voice-video-screen-share-codec',
'voice-video-screen-share-av1-opt-in',
'voice-video-screen-share-hevc-opt-in',
'voice-video-emulated-decode-codec-cap',
'voice-video-openh264-codec',
'voice-video-screen-share-preview-behavior',
@@ -96,7 +100,6 @@ export const DIRECT_CONTROL_ITEM_IDS = new Set([
export const FULL_WIDTH_CONTROL_ITEM_IDS = new Set([
'appearance-voice-channel-join-behavior',
'voice-video-screen-share-codec',
'voice-video-screen-share-preview-behavior',
]);
@@ -122,6 +125,8 @@ export const COMPACT_SWITCH_CONTROL_ITEM_IDS = new Set([
'voice-video-new-device-alerts',
'voice-video-connection-volume-controls',
'voice-video-openh264-codec',
'voice-video-screen-share-av1-opt-in',
'voice-video-screen-share-hevc-opt-in',
'advanced-unread-badge-customization',
'client-developer-mode',
'accessibility-stay-interactive-unfocused',
@@ -268,6 +273,14 @@ export const AdvancedSettingControl = observer(({item}: {item: SearchableSetting
return (
<ScreenShareCodecControl data-flx="user.advanced-setting-direct-controls.advanced-setting-control.screen-share-codec-control" />
);
case 'voice-video-screen-share-av1-opt-in':
return (
<ScreenShareAv1OptInControl data-flx="user.advanced-setting-direct-controls.advanced-setting-control.screen-share-av1-opt-in-control" />
);
case 'voice-video-screen-share-hevc-opt-in':
return (
<ScreenShareHevcOptInControl data-flx="user.advanced-setting-direct-controls.advanced-setting-control.screen-share-hevc-opt-in-control" />
);
case 'voice-video-emulated-decode-codec-cap':
return (
<EmulatedDecodeCodecCapControl data-flx="user.advanced-setting-direct-controls.advanced-setting-control.emulated-decode-codec-cap-control" />
@@ -11,7 +11,6 @@ import {SwitchGroup, SwitchGroupItem} from '@app/features/ui/components/SwitchGr
import PiP from '@app/features/ui/state/PiP';
import {getElectronAPI, isDesktop} from '@app/features/ui/utils/NativeUtils';
import styles from '@app/features/user/components/modals/tabs/AdvancedSettingsTab.module.css';
import {CodecSelectorSection} from '@app/features/user/components/modals/tabs/components/CodecSelectorSection';
import {CompactComboboxRow} from '@app/features/user/components/modals/tabs/components/CompactComboboxRow';
import PrivacyPreferences from '@app/features/user/state/PrivacyPreferences';
import * as VoiceSettingsCommands from '@app/features/voice/commands/VoiceSettingsCommands';
@@ -24,12 +23,18 @@ import type {
ScreenShareScalabilityModePreference,
ScreenShareSoftwareQuality,
} from '@app/features/voice/utils/CodecCapabilityDetector';
import {
getCodecCapabilityReport,
selectAutomaticScreenShareCodec,
} from '@app/features/voice/utils/CodecCapabilityDetector';
import {getGpuEncoderReportSync, loadGpuEncoderReport} from '@app/features/voice/utils/GpuEncoderCapabilities';
import {setOpenH264Enabled} from '@app/features/voice/utils/OpenH264Status';
import {CODEC_DISPLAY_LABEL} from '@app/features/voice/utils/ScreenShareCodecPolicy';
import {msg} from '@lingui/core/macro';
import {useLingui} from '@lingui/react/macro';
import {GearIcon} from '@phosphor-icons/react';
import {observer} from 'mobx-react-lite';
import {useCallback, useEffect} from 'react';
import {useCallback, useEffect, useState} from 'react';
const OPENH264_LABEL_DESCRIPTOR = msg({
message: 'OpenH264 Video Codec provided by Cisco Systems, Inc.',
@@ -210,9 +215,104 @@ const resolveScreenShareBitrateInput = (
return getNearestNumericOptionValue(valueInMbps, options);
};
export const ScreenShareCodecControl = observer(() => (
<CodecSelectorSection data-flx="user.advanced-settings-tab.advanced-video-controls.screen-share-codec-control.codec-selector-section" />
));
const PREFERRED_SCREEN_SHARE_CODEC_DESCRIPTOR = msg({
message: 'Preferred screen share codec',
comment: 'Accessible label for the advanced screen-share codec preference select.',
});
const AUTOMATIC_CODEC_OPTION_DESCRIPTOR = msg({
message: 'Automatic ({codec})',
comment: 'Option label for the screen-share codec select. codec is the automatically selected codec label.',
});
const AV1_REQUIRES_OPT_IN_OPTION_DESCRIPTOR = msg({
message: 'AV1 (requires opt-in)',
comment:
'Option label for the screen-share codec select while the AV1 opt-in is off and the option is disabled. AV1 is a codec name and should stay literal.',
});
const H265_REQUIRES_OPT_IN_OPTION_DESCRIPTOR = msg({
message: 'H.265 (requires opt-in)',
comment:
'Option label for the screen-share codec select while the HEVC opt-in is off and the option is disabled. H.265 is a codec name and should stay literal.',
});
const AV1_SCREEN_SHARE_OPT_IN_DESCRIPTOR = msg({
message: 'Allow AV1 for screen sharing',
comment: 'Switch label for the AV1 screen-share opt-in. AV1 is a codec name and should stay literal.',
});
const HEVC_SCREEN_SHARE_OPT_IN_DESCRIPTOR = msg({
message: 'Allow H.265 (HEVC) for screen sharing',
comment:
'Switch label for the H.265/HEVC screen-share opt-in. H.265 and HEVC are codec names and should stay literal.',
});
const SCREEN_SHARE_CODEC_OPTION_ORDER = ['av1', 'h265', 'h264', 'vp9', 'vp8'] as const;
export const ScreenShareCodecControl = observer(() => {
const {i18n} = useLingui();
const encoderMode = VoiceSettings.getScreenShareEncoderMode();
const [gpuReport, setGpuReport] = useState(() => getGpuEncoderReportSync());
useEffect(() => {
if (gpuReport) return;
let cancelled = false;
void loadGpuEncoderReport().then((report) => {
if (!cancelled) setGpuReport(report);
});
return () => {
cancelled = true;
};
}, [gpuReport]);
const automaticCodec = selectAutomaticScreenShareCodec(encoderMode).codec;
const av1OptIn = VoiceSettings.getScreenShareAv1OptIn();
const hevcOptIn = VoiceSettings.getScreenShareHevcOptIn();
const codecCapabilities = getCodecCapabilityReport();
const options: ReadonlyArray<ComboboxOption<CodecPreference>> = [
{value: 'auto', label: i18n._(AUTOMATIC_CODEC_OPTION_DESCRIPTOR, {codec: CODEC_DISPLAY_LABEL[automaticCodec]})},
...SCREEN_SHARE_CODEC_OPTION_ORDER.map((codec) => ({
value: codec,
label:
codec === 'av1' && !av1OptIn
? i18n._(AV1_REQUIRES_OPT_IN_OPTION_DESCRIPTOR)
: codec === 'h265' && !hevcOptIn
? i18n._(H265_REQUIRES_OPT_IN_OPTION_DESCRIPTOR)
: CODEC_DISPLAY_LABEL[codec],
isDisabled: !codecCapabilities[codec].supported,
})),
];
return (
<Combobox<CodecPreference, false>
value={VoiceSettings.getPreferredScreenShareCodec()}
options={options}
onChange={(value) => VoiceSettingsCommands.update({preferredScreenShareCodec: value})}
density="compact"
isSearchable={false}
aria-label={i18n._(PREFERRED_SCREEN_SHARE_CODEC_DESCRIPTOR)}
data-flx="user.advanced-settings-tab.select.preferred-screen-share-codec"
/>
);
});
export const ScreenShareAv1OptInControl = observer(() => {
const {i18n} = useLingui();
return (
<Switch
ariaLabel={i18n._(AV1_SCREEN_SHARE_OPT_IN_DESCRIPTOR)}
value={VoiceSettings.getScreenShareAv1OptIn()}
onChange={(value) => VoiceSettingsCommands.update({screenShareAv1OptIn: value})}
compact
data-flx="user.advanced-settings-tab.switch.screen-share-av1-opt-in"
/>
);
});
export const ScreenShareHevcOptInControl = observer(() => {
const {i18n} = useLingui();
return (
<Switch
ariaLabel={i18n._(HEVC_SCREEN_SHARE_OPT_IN_DESCRIPTOR)}
value={VoiceSettings.getScreenShareHevcOptIn()}
onChange={(value) => VoiceSettingsCommands.update({screenShareHevcOptIn: value})}
compact
data-flx="user.advanced-settings-tab.switch.screen-share-hevc-opt-in"
/>
);
});
export const EmulatedDecodeCodecCapControl = observer(() => {
const {i18n} = useLingui();
@@ -1,167 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import type {AutomaticScreenShareCodecSelection} from '@app/features/voice/utils/CodecCapabilityDetector';
import {CODEC_DISPLAY_LABEL} from '@app/features/voice/utils/ScreenShareCodecPolicy';
import type {I18n} from '@lingui/core';
import {msg} from '@lingui/core/macro';
const AUTO_DESCRIPTION_FIREFOX_VP8_DESCRIPTOR = msg({
message: 'Automatic would use {codecName} because Firefox screen sharing works most reliably with it.',
comment:
'Description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as VP8 and should not be translated. Keep Firefox as a product name.',
});
const AUTO_DESCRIPTION_NON_CHROMIUM_H264_DESCRIPTOR = msg({
message:
'Automatic would use {codecName} because this browser supports it and it is the best fallback outside Chromium.',
comment:
'Description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as H.264 and should not be translated. Keep Chromium as a product name.',
});
const AUTO_DESCRIPTION_DESKTOP_NON_CHROMIUM_H264_DESCRIPTOR = msg({
message:
'Automatic would use {codecName} because your computer supports it and it is the best fallback outside Chromium.',
comment:
'Desktop-client description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as H.264 and should not be translated. Keep Chromium as a product name.',
});
const AUTO_DESCRIPTION_NON_CHROMIUM_VP8_DESCRIPTOR = msg({
message: 'Automatic would use {codecName} because this browser does not expose H.264, so VP8 is the safest fallback.',
comment:
'Description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as VP8 and should not be translated. Keep codec names literal.',
});
const AUTO_DESCRIPTION_DESKTOP_NON_CHROMIUM_VP8_DESCRIPTOR = msg({
message:
'Automatic would use {codecName} because your computer does not expose H.264, so VP8 is the safest fallback.',
comment:
'Desktop-client description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as VP8 and should not be translated. Keep codec names literal.',
});
const AUTO_DESCRIPTION_HARDWARE_AV1_DESCRIPTOR = msg({
message:
'Automatic would use {codecName} because your GPU can encode it in hardware, with the best compression for screen sharing.',
comment:
'Description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as AV1 and should not be translated. Keep GPU as an acronym.',
});
const AUTO_DESCRIPTION_HARDWARE_H264_DESCRIPTOR = msg({
message:
'Automatic would use {codecName} because your GPU can encode it in hardware and it is the most compatible screen-share default.',
comment:
'Description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as H.264 and should not be translated. Keep GPU as an acronym.',
});
const AUTO_DESCRIPTION_HARDWARE_H265_DESCRIPTOR = msg({
message:
'Automatic would use {codecName} because your GPU can encode it in hardware, with excellent compression and low CPU usage.',
comment:
'Description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as H.265 and should not be translated. Keep GPU as an acronym.',
});
const AUTO_DESCRIPTION_HARDWARE_VP9_DESCRIPTOR = msg({
message:
'Automatic would use {codecName} because your GPU can encode it in hardware and it gives strong screen-share quality.',
comment:
'Description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as VP9 and should not be translated. Keep GPU as an acronym.',
});
const AUTO_DESCRIPTION_SOFTWARE_AV1_DESCRIPTOR = msg({
message: 'Automatic would use {codecName} because software encoding is preferred and this browser exposes AV1.',
comment:
'Description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as AV1 and should not be translated.',
});
const AUTO_DESCRIPTION_DESKTOP_SOFTWARE_AV1_DESCRIPTOR = msg({
message: 'Automatic would use {codecName} because software encoding is preferred and your computer exposes AV1.',
comment:
'Desktop-client description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as AV1 and should not be translated.',
});
const AUTO_DESCRIPTION_SOFTWARE_H265_DESCRIPTOR = msg({
message: 'Automatic would use {codecName} because no hardware encoder is available and this browser exposes H.265.',
comment:
'Description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as H.265 and should not be translated.',
});
const AUTO_DESCRIPTION_DESKTOP_SOFTWARE_H265_DESCRIPTOR = msg({
message: 'Automatic would use {codecName} because no hardware encoder is available and your computer exposes H.265.',
comment:
'Desktop-client description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as H.265 and should not be translated.',
});
const AUTO_DESCRIPTION_SOFTWARE_VP9_DESCRIPTOR = msg({
message: 'Automatic would use {codecName} because software encoding is preferred and this browser exposes VP9.',
comment:
'Description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as VP9 and should not be translated.',
});
const AUTO_DESCRIPTION_DESKTOP_SOFTWARE_VP9_DESCRIPTOR = msg({
message: 'Automatic would use {codecName} because software encoding is preferred and your computer exposes VP9.',
comment:
'Desktop-client description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as VP9 and should not be translated.',
});
const AUTO_DESCRIPTION_SOFTWARE_H264_DESCRIPTOR = msg({
message: 'Automatic would use {codecName} because no higher-quality encoder is available and H.264 is compatible.',
comment:
'Description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as H.264 and should not be translated.',
});
const AUTO_DESCRIPTION_SOFTWARE_VP8_DESCRIPTOR = msg({
message:
'Automatic would use {codecName} because software encoding is preferred and VP8 is the safest software fallback.',
comment:
'Description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as VP8 and should not be translated.',
});
const AUTO_DESCRIPTION_OPENH264_REQUIRED_DESCRIPTOR = msg({
message:
'Automatic would use {codecName} because no video encoder is exposed. On Linux, OpenH264 may need to be installed.',
comment:
'Description shown under the Automatic option in the screen-share codec radio group. {codecName} is a codec label such as H.264 and should not be translated. Keep OpenH264 and Linux literal.',
});
export function getAutomaticDescription(
i18n: I18n,
selection: AutomaticScreenShareCodecSelection,
options: {isDesktopClient?: boolean} = {},
): string {
const codecName = CODEC_DISPLAY_LABEL[selection.codec];
switch (selection.reason) {
case 'firefox-vp8':
return i18n._(AUTO_DESCRIPTION_FIREFOX_VP8_DESCRIPTOR, {codecName});
case 'non-chromium-h264':
return i18n._(
options.isDesktopClient
? AUTO_DESCRIPTION_DESKTOP_NON_CHROMIUM_H264_DESCRIPTOR
: AUTO_DESCRIPTION_NON_CHROMIUM_H264_DESCRIPTOR,
{codecName},
);
case 'non-chromium-vp8':
return i18n._(
options.isDesktopClient
? AUTO_DESCRIPTION_DESKTOP_NON_CHROMIUM_VP8_DESCRIPTOR
: AUTO_DESCRIPTION_NON_CHROMIUM_VP8_DESCRIPTOR,
{codecName},
);
case 'hardware-av1':
return i18n._(AUTO_DESCRIPTION_HARDWARE_AV1_DESCRIPTOR, {codecName});
case 'hardware-h265':
return i18n._(AUTO_DESCRIPTION_HARDWARE_H265_DESCRIPTOR, {codecName});
case 'hardware-h264':
return i18n._(AUTO_DESCRIPTION_HARDWARE_H264_DESCRIPTOR, {codecName});
case 'hardware-vp9':
return i18n._(AUTO_DESCRIPTION_HARDWARE_VP9_DESCRIPTOR, {codecName});
case 'software-av1':
return i18n._(
options.isDesktopClient
? AUTO_DESCRIPTION_DESKTOP_SOFTWARE_AV1_DESCRIPTOR
: AUTO_DESCRIPTION_SOFTWARE_AV1_DESCRIPTOR,
{codecName},
);
case 'software-h265':
return i18n._(
options.isDesktopClient
? AUTO_DESCRIPTION_DESKTOP_SOFTWARE_H265_DESCRIPTOR
: AUTO_DESCRIPTION_SOFTWARE_H265_DESCRIPTOR,
{codecName},
);
case 'software-vp9':
return i18n._(
options.isDesktopClient
? AUTO_DESCRIPTION_DESKTOP_SOFTWARE_VP9_DESCRIPTOR
: AUTO_DESCRIPTION_SOFTWARE_VP9_DESCRIPTOR,
{codecName},
);
case 'software-h264':
return i18n._(AUTO_DESCRIPTION_SOFTWARE_H264_DESCRIPTOR, {codecName});
case 'software-vp8':
return i18n._(AUTO_DESCRIPTION_SOFTWARE_VP8_DESCRIPTOR, {codecName});
case 'openh264-required':
return i18n._(AUTO_DESCRIPTION_OPENH264_REQUIRED_DESCRIPTOR, {codecName});
}
}
@@ -1,62 +0,0 @@
/* SPDX-License-Identifier: AGPL-3.0-or-later */
.codecPicker {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.codecRadioGroup {
gap: 0.25rem;
}
.codecLabelRow {
display: flex;
align-items: center;
gap: 0.5rem;
min-width: 0;
}
.codecLabel {
color: var(--text-primary);
font-size: 0.9375rem;
font-weight: 500;
line-height: 1.4;
}
.codecBadge {
flex: 0 0 auto;
border-radius: 62.4375rem;
padding: 0.0625rem 0.5rem;
background-color: var(--background-modifier-accent);
color: var(--text-primary-muted);
font-size: 0.6875rem;
font-weight: 600;
line-height: 1.1rem;
text-transform: uppercase;
letter-spacing: 0.04em;
border: 0.0625rem solid transparent;
}
.codecBadgeRecommended {
background-color: var(--brand-primary);
color: white;
border-color: var(--brand-primary);
}
.codecHint {
margin: 0;
color: var(--status-warning);
font-size: 0.8125rem;
line-height: 1.35;
}
.codecAdvancedLink {
padding: 0;
border: 0;
background: transparent;
color: inherit;
cursor: pointer;
font: inherit;
text-decoration: underline;
}
@@ -1,148 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {
getCachedDesktopTroubleshootingSettings,
getDesktopTroubleshootingSettings,
} from '@app/features/devtools/utils/DesktopTroubleshootingUtils';
import {ComponentBus} from '@app/features/platform/utils/ComponentBus';
import type {RadioOption} from '@app/features/ui/radio_group/RadioGroup';
import {RadioGroup} from '@app/features/ui/radio_group/RadioGroup';
import {isDesktop} from '@app/features/ui/utils/NativeUtils';
import styles from '@app/features/user/components/modals/tabs/components/CodecSelectorSection.module.css';
import {getUserSettingsTabLabel} from '@app/features/user/components/settings_utils/SettingsConstants';
import * as VoiceSettingsCommands from '@app/features/voice/commands/VoiceSettingsCommands';
import VoiceSettings from '@app/features/voice/state/VoiceSettings';
import {
type CodecPreference,
getCodecCapabilityReport,
getLiveKitSupportedCodecs,
selectAutomaticScreenShareCodec,
} from '@app/features/voice/utils/CodecCapabilityDetector';
import {
getGpuEncoderReportSync,
type HardwareEncodeReport,
loadGpuEncoderReport,
} from '@app/features/voice/utils/GpuEncoderCapabilities';
import {CODEC_DISPLAY_LABEL} from '@app/features/voice/utils/ScreenShareCodecPolicy';
import {msg} from '@lingui/core/macro';
import {Trans, useLingui} from '@lingui/react/macro';
import {clsx} from 'clsx';
import {observer} from 'mobx-react-lite';
import {useCallback, useEffect, useMemo, useState} from 'react';
import {getAutomaticDescription} from './CodecSelectorDescription';
const AUTO_DESCRIPTOR = msg({
message: 'Automatic',
comment: 'Label for the auto codec option in the screen-share codec radio group. Keep it concise.',
});
const RECOMMENDED_DESCRIPTOR = msg({
message: 'Recommended',
comment: 'Badge shown next to the auto codec option in the screen-share codec radio group. Keep it concise.',
});
const SCREEN_SHARE_VIDEO_CODEC_DESCRIPTOR = msg({
message: 'Screen share video codec',
comment: 'Accessible label for the screen-share codec radio group.',
});
interface CodecRadioOption extends RadioOption<CodecPreference> {
value: CodecPreference;
}
export const CodecSelectorSection = observer(() => {
const {i18n} = useLingui();
const isDesktopClient = isDesktop();
const advancedSettingsLabel = getUserSettingsTabLabel(i18n, 'advanced_settings');
const preference = VoiceSettings.getPreferredScreenShareCodec();
const encoderMode = VoiceSettings.getScreenShareEncoderMode();
const [gpuReport, setGpuReport] = useState<HardwareEncodeReport | null>(() => getGpuEncoderReportSync());
const [hardwareAccelDisabled, setHardwareAccelDisabled] = useState<boolean | null>(
() => getCachedDesktopTroubleshootingSettings()?.disableHardwareAcceleration ?? null,
);
useEffect(() => {
if (gpuReport) return;
let cancelled = false;
void loadGpuEncoderReport().then((report) => {
if (!cancelled) setGpuReport(report);
});
return () => {
cancelled = true;
};
}, [gpuReport]);
useEffect(() => {
if (!isDesktopClient || hardwareAccelDisabled !== null) return;
let cancelled = false;
void getDesktopTroubleshootingSettings().then((settings) => {
if (!cancelled && settings) setHardwareAccelDisabled(settings.disableHardwareAcceleration);
});
return () => {
cancelled = true;
};
}, [hardwareAccelDisabled, isDesktopClient]);
const report = useMemo(() => getCodecCapabilityReport(), [gpuReport, hardwareAccelDisabled]);
const liveKitCodecs = useMemo(() => getLiveKitSupportedCodecs(), []);
const automaticSelection = useMemo(
() => selectAutomaticScreenShareCodec(encoderMode),
[encoderMode, gpuReport, hardwareAccelDisabled],
);
const options = useMemo<ReadonlyArray<CodecRadioOption>>(() => {
const autoOption: CodecRadioOption = {
value: 'auto',
name: (
<div className={styles.codecLabelRow} data-flx="user.codec-selector-section.codec-label-row">
<span className={styles.codecLabel} data-flx="user.codec-selector-section.codec-label">
{i18n._(AUTO_DESCRIPTOR)}
</span>
<span
className={clsx(styles.codecBadge, styles.codecBadgeRecommended)}
data-flx="user.codec-selector-section.codec-badge"
>
{i18n._(RECOMMENDED_DESCRIPTOR)}
</span>
</div>
),
desc: getAutomaticDescription(i18n, automaticSelection, {isDesktopClient}),
};
const codecOptions = liveKitCodecs.map<CodecRadioOption>((codec) => ({
value: codec,
name: CODEC_DISPLAY_LABEL[codec],
disabled: !report[codec].supported,
}));
return [autoOption, ...codecOptions];
}, [automaticSelection, liveKitCodecs, report, i18n.locale, isDesktopClient]);
const handleChange = useCallback((value: CodecPreference) => {
VoiceSettingsCommands.update({preferredScreenShareCodec: value});
}, []);
const openAdvancedSettingsTab = useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
event.preventDefault();
ComponentBus.dispatch('USER_SETTINGS_TAB_SELECT', {tab: 'advanced_settings'});
}, []);
const hardwareAccelOff = isDesktopClient && hardwareAccelDisabled === true;
return (
<div className={styles.codecPicker} data-flx="user.codec-selector-section.codec-picker">
<RadioGroup<CodecPreference>
aria-label={i18n._(SCREEN_SHARE_VIDEO_CODEC_DESCRIPTOR)}
options={options}
value={preference}
onChange={handleChange}
className={styles.codecRadioGroup}
data-flx="user.codec-selector-section.radio-group.change"
/>
{hardwareAccelOff ? (
<p className={styles.codecHint} data-flx="user.codec-selector-section.codec-hint">
<Trans>
Hardware acceleration is off, so codecs will encode on your CPU.{' '}
<button
type="button"
className={styles.codecAdvancedLink}
onClick={openAdvancedSettingsTab}
data-flx="user.codec-selector-section.codec-advanced-link.open-advanced-settings-tab.button"
>
Turn it back on in {advancedSettingsLabel}
</button>
.
</Trans>
</p>
) : null}
</div>
);
});