feat: advanced media quality settings UI and config-driven defaults#3736
feat: advanced media quality settings UI and config-driven defaults#3736emmick4 wants to merge 7 commits intoelement-hq:livekitfrom
Conversation
Add a `media_quality` section to config.json that allows self-hosters to configure video codec, resolution, bitrate, framerate, and simulcast layers for both camera and screen sharing. This addresses the long-standing request in element-hq#249 for configurable media quality settings. The LiveKit SDK already supports all of these options; this change exposes them through the existing config system. New config.json fields: - media_quality.video_codec: preferred codec (vp8/vp9/h264/av1) - media_quality.video: camera resolution, bitrate, framerate, simulcast layers - media_quality.screen_share: screen share resolution, bitrate, framerate, simulcast layers (enables 3+ layer simulcast for screen sharing) All fields are optional and fall back to the existing defaults (VP8, 720p camera, 1080p screen share) when not specified. Signed-off-by: Ryan Emmick <ryanemmick4@gmail.com>
Adds a "Screen sharing" section to Settings > Video with controls for: - Resolution (576p to 4K) - Framerate (5-60 fps slider) - Bitrate (0.5-15 Mbps slider) - Codec (VP8/VP9/H.264/AV1) Gated behind an "Advanced screen share settings" toggle. When enabled, settings are passed to LiveKit's setScreenShareEnabled as both capture constraints and publish options. When disabled, falls back to config.json media_quality defaults. Settings are persisted in localStorage via the existing Setting<T> system. The Slider component is extended with a tooltipFormatter prop for custom tooltip display. Inspired by pirosuki's advanced-screen-share-settings branch, but reimplemented cleanly: settings are read directly in LocalMember.ts (no signature changes), the existing Slider is extended (no component duplication), and proper form components are used throughout. Signed-off-by: Ryan Emmick <ryanemmick4@gmail.com>
InputField only supports input/textarea, not select. Passing option children caused React to crash rendering children inside a void input. Signed-off-by: Ryan Emmick <ryanemmick4@gmail.com>
…d defaults - Add camera video quality controls (resolution/framerate/bitrate/codec) to Settings > Video, mirroring the screen share settings UI - Add audio processing toggles (echo cancellation, noise suppression, auto gain control) to Settings > Audio, replacing URL-param-only controls - Display raw values inline on all sliders (framerate, bitrate, volume) - Add config-seeded defaults: config.json media_quality values now seed Setting defaults for users who haven't explicitly set preferences - Camera settings are applied when joining a call via ConnectionFactory Signed-off-by: Ryan Emmick <ryanemmick4@gmail.com>
Allows Element Call to be served from a subdirectory (e.g. /widgets/element-call/ in Element Web) without breaking dynamic imports for locales, workers, and other assets that were previously using absolute paths. Signed-off-by: Ryan Emmick <ryanemmick4@gmail.com>
Signed-off-by: Ryan Emmick <ryanemmick4@gmail.com>
Signed-off-by: Ryan Emmick <ryanemmick4@gmail.com>
|
This would be great. Element calls are almost completely useless due to incredibly poor quality. |
|
Thank you for the contribution! |
robintown
left a comment
There was a problem hiding this comment.
Wow, thanks for the thought you put into this change, it really shows! Having these options available for admins & power users is generally quite a welcome addition.
Unfortunately, you caught us while we're still wavering about the fate of Element Call's settings dialog - it might end up being merged with Element Web's existing voice+video settings tab, for instance. And also, while I would love to have advanced settings for frame rate and resolution controls regardless, the team sees the codec and bitrate settings in particular as "unknown territory" - encrypted H.264 simply didn't work yet with some mobile devices in @fkwp's testing, for instance. For the sake of our own ability to support users, we'd prefer to keep those settings rather hidden.
So, the compromise: We can accept this change today as long as the settings UI is safely tucked away in the developer settings tab. Hopefully that's not too out of the way for a motivated user while also communicating the experimental nature of the settings. I do hope we can make a proper home for frame rate and resolution eventually. 🙂
| /** | ||
| * Media quality settings for video and screen sharing. | ||
| * These override the hardcoded LiveKit defaults. | ||
| */ | ||
| media_quality?: { |
There was a problem hiding this comment.
It seems all of these config options (with the exception of screen_share.simulcast_layers) have default values that they imply when unset. In that case, could you set the defaults by adding them to DEFAULT_CONFIG and ResolvedConfigOptions later in this file, rather than in buildPublishOptions?
I like that the ConfigOptions file alone has authority over what the defaults are, that way.
| /** | ||
| * Get LiveKit options, reading from the loaded Config singleton. | ||
| * Falls back to defaults if Config is not yet initialized. | ||
| */ | ||
| export function getLiveKitOptions(): RoomOptions { | ||
| try { | ||
| return buildLiveKitOptions(Config.get().media_quality); | ||
| } catch { | ||
| return buildLiveKitOptions(); | ||
| } | ||
| } |
There was a problem hiding this comment.
I would rather have the app crash if we try to get LiveKit options before the config is available, otherwise we could easily break this feature without realizing. What's maybe not obvious is that the majority of the app already blocks on a loading screen until the config is loaded, so we can reasonably require it in ConnectionFactory for instance.
If that breaks some tests, mockConfig can help.
Why
Element Call currently hardcodes video/audio parameters with no way for users to tune them. Server admins also have no mechanism to set org-wide defaults. Several community requests have asked for these controls.
What
This PR adds three new sections to the Settings modal:
All sliders now display their current value inline (e.g. "Framerate: 30 fps").
A new
media_qualitysection inconfig.jsonlets admins set defaults for video codec, resolution, bitrate, framerate, and simulcast layers. These seed user settings only when the user hasn't explicitly set a preference in localStorage, so user choices always win.The static
defaultLiveKitOptionsexport is replaced bybuildLiveKitOptions()/getLiveKitOptions()which read from config at runtime.Testing strategy
yarn && yarn buildyarn test— 441 tests should passyarn dev:fullchrome://webrtc-internals, find the outbound video track, confirm the codec and resolution match your selectionmedia_qualityblock toconfig.json(e.g.{"video_codec": "vp9"})Note: happy to make any adjustments or split this PR up, haven't done much OSS contributing and just wanted to have these features on my own server. it also lays the scaffolding for more configurable audio and setting quality limits by the server admin
