When someone starts or stops speaking, the layout will often be recomputed only to find out that there is ultimately no layout change. We can ignore these redundant updates to avoid re-rendering the InCallView and Grid components, which are relatively slow.
For that specific, common case, this reduces JS CPU usage by as much as 70% in my testing.
It's very uncommon to have this debug option enabled, and yet it currently causes the footer to re-render on every layout update, which is a small but avoidable cost.
I don't believe this affects the cost of running the useSprings hook, but it at least skips the animation frames that would otherwise follow, so it's worth a try.
It turns out that the timers which repeatedly poll the RTP stats of each video track all run independently of each other and can add up to a small but constant sink of CPU. Meanwhile we can replace these timers with HTMLVideoElement 'resize' event listeners, which is way more efficient and reacts instantly to orientation changes.
A change in a tile's speaking indicator could cause its entire tree of context menu components to re-render, which is expensive. Isolating the behavior subscriptions in their own component avoids this.
With the React Compiler, our component code is transformed at build time to automatically apply various forms of memoization. This changes the runtime semantics of our code a little bit and therefore could surface new bugs in the next release cycle in case any components fail to follow the rules of React. See https://react.dev/learn/react-compiler for more information.
This results in a small bundle size increase and modest performance gains, but I think it's worth it given the potential for larger performance gains once we tune the component structure a bit more.
* Update ghcr.io/element-hq/element-web:develop Docker digest to 0183c0a
* Update end-to-end tests to work with auto-collapsing room list
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Robin <robin@robin.town>
On the combined Storybook docs page for the call footer, the layout switches would not show the correct state until you hovered over them because they all shared the same input name and thus were interpreted as belonging to the same radio group.
It reduces confusion when reading snapshots if class names are still scoped to their respective CSS modules. It also discourages the use of class names in tests, which is a good thing. (https://testing-library.com/docs/guiding-principles)
Thanks to Johannes for the suggestion.
The rule should only care about enclosing function/class scopes. For example if an ObservableScope is received as a parameter to a function and then simply used inside an 'if' block (technically a different scope), that's not a problem.
Previously we were hiding the entire app bar on mobile phones in landscape orientation. However now that the app bar supports a small 'subtitle' element, we should show only the subtitle in this case to match the designs.
The subtitle still hides on tap, just like the footer.
On mobile, the ringing status indicator is supposed to display in the header rather than on a tile. The exact layout differs between Android and iOS. To get it right I had to refactor AppBar to use CSS grid templates.
(Also, I changed my mind about the exact ringing data I needed out of CallViewModel - sorry. A little move of the ringtone audio renderer into its own component was necessary to accommodate that.)
It was rather confusing that matrixLivekitMembers$ gives you objects of type RemoteMatrixLivekitMembers and yet the *local* member would often be among these. I've attempted to clear this up. To my knowledge this wasn't creating any bugs.
The rule of thumb to avoid resource leaks is that you should never call ObservableScope methods in a callback unless the ObservableScope is directly passed to or created inside that callback. I had a go at codifying this as a lint rule.
I noticed that calls to createDisplayNameBehavior$ and createAvatarUrlBehavior$ were technically leaking resources since they reused the ObservableScope from their outer scope, which in practice lasts for the entire lifetime of the CallViewModel. This would not have had any noticeable effect unless you had other participants leave and rejoin the same call many thousands of times.
I found our code's internal model of ringing a little overgrown (it had superfluous states like 'unknown') and difficult to extend with metadata or callbacks relating to ring attempts. By modeling ringing instead as a stream of ring attempts, where each attempt has an intent, a recipient, and an eventual outcome (accept/decline/timeout), I find it more natural to work with.
This makes room for a future 'try again' callback to allow ringing someone again after a timeout, and also forced me to look for a simpler solution to the duplicate leave sound effects. I exposed the intent of the ringing attempt to the call UI so I can later use it in the header.
The designs actually never want us to show the settings button in the footer if an app bar is in use (as in Element X mobile apps), so just avoid showing it at all in that case.
Because the type of header that we use in Element X (an 'app bar') lives in a different place in the document than the other headers, it needs a special branch to propagate the right insets.
* Posthog: drop $initial_person_info from outgoing events
* Posthog: migrate from sanitize_properties to before_send
* strip URL fields from $set / $set_once
* enable mask_personal_data_properties
* review
* update tests to check for `delete` (not anymore `=null`)
rename: `applyPrivacyFilters`->`santizeSensitiveData`
---------
Co-authored-by: Timo K <toger5@hotmail.de>
* Add Posthog events for Call reconnect including the reason
* Expose single trackCallReconnecting() entry point on PosthogAnalytics
* Track reconnect duration and align with existing analytics pattern
* Refactor combined$ to return [connected, reason] tuple
* Update firefoxUserPrefs to allow getUserMedia and enumerateDevices on CI
---------
Co-authored-by: Valere <bill.carson@valrsoft.com>
Co-authored-by: Robin <robin@robin.town>
Co-authored-by: Timo K <toger5@hotmail.de>
* add MeidaMuteAndSwitchButton
* User button in footer
* Add tests
* update styling (dark bg on menu open + chevron white + chevron up)
* fix tests
* add storybook to CI
only add storybook with storybook label
test names
another env name test
TestName
new default name
remove label condition
Update pr-deploy.yaml
* Update pr-deploy.yaml
* add toggle example to default component
* hook up footer select actions
* fix video audio button (swapped) and lable in story
* make `delayed_leave_event_delay_ms` and `network_error_retry_ms` mandatory
* Support delegation for legacy jwt request
* Calculate `maximumNetworkErrorRetryCount` based on timeouts
* add storybook to CI
only add storybook with storybook label
test names
another env name test
TestName
new default name
remove label condition
Update pr-deploy.yaml
* rename things to check if we actually run the latests ci
* cleanup things used for testing
* Update deploy-to-netlify.yaml
* use package instead of custom environment_name
* final cleanup
By adding viewport-fit=cover to the <meta name="viewport"> header, the page now requests to be displayed edge-to-edge across the entire screen. This gives us control over what we display around camera cut-outs and system navigation UI, if the user agent supports it. I then adjusted the styles of various UI elements to ensure that they still lie within the screen's safe area.
* Update compound-web to 9.3.0 and update Buttons from "sm" to "md".
* Clean up the liast bits
* Update snaps too
* fix test, need to dismiss a new dialog
---------
Co-authored-by: Valere <bill.carson@valrsoft.com>
Run `yarn i18n` to extract new translation keys for the media quality
settings, and update the DeveloperSettingsTab snapshot to include the
Camera quality, Screen sharing, and Audio processing sections.
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>
- 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>
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>
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>
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 #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>
They were not properly being contained to where the MediaView is supposed to appear, causing them to all stack up on the first screen share in the spotlight tile.
6667fc54c0 changed this CSS selector that shows buttons on hover to only target the buttons in the bottom right corner of the spotlight tile, causing the forward/back buttons to stay invisible.
This approach is more flexible in that it allows even the local participant to share their screen in CallViewModel tests, and more rigorous in that it ensures that application code is reacting specifically to track publications.
If you manage to move your floating video tile to the bottom of the screen in a small landscape window, the footer obscures the tile when shown. The designs want us to smoothly move the floating tile out of the way in this case.
This adds two new intents: start_call_voice and join_existing_voice. I need the latter in order to implement Element Web's new incoming call toasts, in which you can turn off your video before joining a group call. The other one, start_call_voice, exists more for completeness than anything; we don't currently want to allow users to start voice calls in group chats in our messenger clients, but maybe Cinny would, for instance.
- use the new domain logic to discover the transport
- then try to authenticate
- Also fix the bug in multi sfu where active$ not updated on delayId change
If you are the only participant in the call, the expanded spotlight layout would redundantly show your media in both the spotlight and PiP tiles. This is a regression; in versions 0.16.1 and earlier we would avoid showing the same user twice.
Taking Valere's suggestion of giving them the 'switch' role. Also, the aria-label attributes were redundant (having tooltips already gives the buttons aria-labelledby).
Add comments on existing code
Extracted a specific android controller for isolation and better testing
lint fixes
Fix device update logic and more tests
better typescript
In landscape orientation the button would be buried underneath the footer, which would block interaction with it. This commit changes the footer to not show in cases where a button has been pressed.
Timo and I agreed previously that we should ditch the class pattern for view models and instead have them be interfaces which are simply created by functions. They're more straightforward to write, mock, and instantiate this way.
The code for media view models and media items is pretty much the last remaining instance of the class pattern. Since I was about to introduce a new media view model for ringing, I wanted to get this refactor out of the way first rather than add to the technical debt.
This refactor also makes things a little easier for https://github.com/element-hq/element-call/pull/3747 by extracting volume controls into their own module.
To correctly implement the legacy "oldest membership" mode, we need the code to be more nuanced about the local transport. Specifically, it needs to allow for the transport we advertise in our membership to be different from the transport that we connect to and publish media on. Otherwise, if these two are yoked together, members will resend their memberships whenever an SFU hop occurs, which an attacker could use to cause an amplified wave of state changes.
It's always worth having logs for when state holders are created or destroyed (these are often the most interesting things happening in the application), so I thought it would be nice to have generateItems always log for you when it's doing that.
once)
The local jwt token needs to be aquired via the right endpoint. The
endpoint defines how our rtcBackendIdentity is computed. Based on us
using sticky events or state events we also need to use the right
endpoint. This cannot be done generically in the connection manager. The
jwt token now is computed in the localTransport and the resolved sfu
config is passed to the connection manager.
Add JWT endpoint version and SFU config support Pin matrix-js-sdk to a
specific commit and update dev auth image tag. Propagate SFU config and
JWT endpoint choice through local transport, ConnectionManager and
Connection; add JwtEndpointVersion enum and LocalTransportWithSFUConfig
type. Add NO_MATRIX_2 auth error and locale string, thread
rtcBackendIdentity through UI props, and include related test, CSS and
minor imports updates
On second glance, the way that we determined a media tile to be 'waiting for media' was too implicit for my taste. It would appear on a surface reading to depend on whether a participant was currently publishing any video. But in reality, the 'video' object was always defined as long as a LiveKit participant existed, so in reality it depended on just the participant. We should show this relationship more explicitly by moving the computation into the view model, where it can depend on the participant directly.
We would show 'waiting for media' on participants that were connected but had no published tracks, because we were filtering them out of the remote participants list on connections. I believe this was done in an attempt to limit our view to only the participants that have a matching MatrixRTC membership. But that's fully redundant to the "Matrix-LiveKit members" module, which actually has the right information to do this (the MatrixRTC memberships).
This fixes a regression on the development branch: the layout switcher would not respond to input while the window mode is 'flat' (i.e. while a mobile phone is in landscape orientation). See https://github.com/element-hq/element-call/pull/3605#discussion_r2586226422 for more context.
I was having a little trouble interpreting the emergent behavior of the layout switching code, so I refactored it in the process into a form that I think is a more direct description of the behavior we want (while not making it as terse as my original implementation).
Semantically, behaviors are only meaningful for as long as their scope is running. Setting a behavior's value to an empty array once its scope ends is not guaranteed to work (as it depends on execution order of how the scope is ended), and subscribers should be robust enough to handle clean-up of all connections at the end of the scope either way.
Since we now bundle a trusted Element Call widget with our messenger applications and this widget reports analytics to an endpoint determined by the messenger app, there is no longer any reason to compute a different analytics ID from the one used by the messenger app.
While looking into what had regressed https://github.com/element-hq/element-call/issues/3588, I found that 28047217b8 had filled in a couple of behaviors with non-reactive default values, the "natural window mode" behavior being among them. This meant that the app would no longer determine the correct window mode upon joining a call, instead always guessing "normal" as the value. This change restores its reactivity.
* playwright: Fix error boundary mgmt or openId errors
* do not use tap for important logic
* fix lint
---------
Co-authored-by: Timo K <toger5@hotmail.de>
* Update docs for 'rageshake.submit_url' to use the dedicated subdomain
* Update Netlify preview deployment to use the dedicated subdomain for 'rageshake.submit_url'
Rename several classes/behaviors to factory-style creators and adapt
call wiring and tests accordingly:
- Replace ConnectionManager class with createConnectionManager$ which
returns transports$, connectionManagerData$, connections$
- Convert MatrixLivekitMerger to createMatrixLivekitMembers$
(matrixLivekitMerger$)
- Rename sessionBehaviors$, localMembership$, localTransport$ to
createSessionMembershipsAndTransports$, createLocalMembership$,
createLocalTransport$
- Adjust participant types and hook up connectOptions$; expose join via
localMembership.requestConnect
- Update tests to use the new factory APIs
- Replace MatrixLivekitItem with MatrixLivekitMember, add displayName$
and participantId, and use explicit LiveKit participant types
- Make sessionBehaviors$ accept a props object and return a typed
RxRtcSession
- Update CallViewModel to use the new session behaviors, rebuild media
items from matrixLivekitMembers, handle missing connections and use
participantId-based keys
- Change localMembership/localTransport to accept Behavior-based
options, read options.value for enterRTCSession, and fix advertised
transport selection order
- Update tests and minor UI adjustments (settings modal livekitRooms
stubbed) and fix JSON formatting in locales
Remove preferStickyEvents and multiSfu in favor of a MatrixRTCMode
enum/setting (Legacy, Compatibil, Matrix_2_0). Move session join/leave,
track pause/resume, and config error handling out of CallViewModel into
the localMembership module. Update developer settings UI, i18n strings,
and related RTC session helpers and wiring accordingly.
npm has recently limited the lifetime of all access tokens to 90 days (https://gh.io/npm-token-changes), so it would be a bit inconvenient to stick to our current access token-based method of publishing releases. Meanwhile npm has implemented a more secure publishing method based on OIDC in which you tell the registry that a particular GitHub Actions workflow should be a "trusted publisher" for a given package, and then the CLI will authenticate automatically. (https://docs.npmjs.com/trusted-publishers)
I've already set trusted publishing up on the registry side, and since we're already granting the job permission to generate ID tokens for provenance, there should be no additional lines of config needed to make it work. Let's take away the access token and see how this goes next time we release.
While we still ought to eventually port these tests in some way, the presence of these empty test files is causing a Vitest failure, so it's easiest to just let them go and refer to Git history when we do want to reference them next.
* add sticky event support
- use new js-sdk
- use custom synapse
- don't filter rooms by existing call state events
Signed-off-by: Timo K <toger5@hotmail.de>
* enable sticky events in the joinSessionConfig
Signed-off-by: Timo K <toger5@hotmail.de>
* Remove unused useNewMembershipmanager setting
* Add prefer sticky setting]
* Fixup call detection logic to allow sticky events
* lint
* update docker image
* More tidy
* update checksum
* bump js-sdk fix sticky events type
Signed-off-by: Timo K <toger5@hotmail.de>
* fix demo
Signed-off-by: Timo K <toger5@hotmail.de>
* always use multi sfu if we are using sticky events.
Signed-off-by: Timo K <toger5@hotmail.de>
* review
Signed-off-by: Timo K <toger5@hotmail.de>
* lint
Signed-off-by: Timo K <toger5@hotmail.de>
* Always consider multi-SFU mode enabled when using sticky events
CallViewModel would pass the wrong transport to enterRtcSession when the user enabled sticky events but didn't manually enable multi-SFU mode as well. This likely would've added some confusion to our attempts to test these modes.
* Fix test type errors
* add todo comment
Signed-off-by: Timo K <toger5@hotmail.de>
---------
Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Half-Shot <will@half-shot.uk>
Co-authored-by: Robin <robin@robin.town>
The execution of certain Observables related to a local or remote connection would continue even after we stopped caring about said connection because we were failing to give these state holders a proper ObservableScope of their own, separate from the CallViewModel's longer-lived scope. With this commit they now have scopes managed by generateKeyed$.
Previously we had a ViewModel class which was responsible for little more than creating an ObservableScope. However, since this ObservableScope would be created implicitly upon view model construction, it became a tad bit harder for callers to remember to eventually end the scope (as you wouldn't just have to remember to end ObservableScopes, but also to destroy ViewModels). Requiring the scope to be specified explicitly by the caller also makes it possible for the caller to reuse the scope for other purposes, reducing the number of scopes mentally in flight that need tending to, and for all state holders (not just view models) to be handled uniformly by helper functions such as generateKeyed$.
Note that this effectively *reverts* 3ac2aa8526 because this branch now has what is a better UX (at least I think so): the in-call view is presented instantly when pressing the join button. Errors that occur during initial connection procedures will be surfaced more uniformly.
useCallViewKeyboardShortcuts() changed a param from `setMicrophoneMuted` to `setAudioEnabled`, the boolean arg of the callback is inverse tht it used to be
* Add media hints for notification events.
* Prevent showing calling view when disconnected from Livekit. (#3491)
* Refactor disconnection handling
* Use "unknown"
* Update signature
* Add tests
* Expose livekitConnectionState directly
* fix whoopsie
* Update dependency livekit-client to v2.15.7 (#3496)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* Fix the interactivity of buttons while reconnecting or in earpiece mode (#3486)
* Fix the interactivity of buttons while reconnecting or in earpiece mode
When we're in one of these modes, we need to ensure that everything above the overlay (the header and footer buttons) is interactive, while everything obscured by the overlay (the media tiles) is non-interactive and removed from the accessibility tree. It's not a very easy task to trap focus *outside* an element, so the best solution I could come up with is to set tabindex="-1" manually on all interactive elements belonging to the media tiles.
* Write a Playwright test for reconnecting
* fix lints
Signed-off-by: Timo K <toger5@hotmail.de>
* fix test
Signed-off-by: Timo K <toger5@hotmail.de>
* enable http2 for matrx-rtc host to allow the jwt service to talk to the SFU
* remove rate limit for delayed events
* more time to connect to livekit SFU
* Due to a Firefox issue we set the start anchor for the tab test to the Mute microphone button
* adapt to most recent Element Web version
* Use the "End call" button as proofe for a started call
* Currrenty disabled due to recent Element Web
- not indicating the number of participants
- bypassing Lobby
* linting
* disable 'can only interact with header and footer while reconnecting' for firefox
---------
Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Timo <16718859+toger5@users.noreply.github.com>
Co-authored-by: Timo K <toger5@hotmail.de>
Co-authored-by: fkwp <github-fkwp@w4ve.de>
* Log when a track is unpublished or runs into an error (#3495)
* default mute states (unmuted!) in widget mode (embedded + intent) (#3494)
* default mute states (unmuted!) in widget mode (embedded + intent)
Signed-off-by: Timo K <toger5@hotmail.de>
* review
Signed-off-by: Timo K <toger5@hotmail.de>
* introduce a cache for the url params.
Signed-off-by: Timo K <toger5@hotmail.de>
* Add an option to skip the cache.
Signed-off-by: Timo K <toger5@hotmail.de>
---------
Signed-off-by: Timo K <toger5@hotmail.de>
* Apply new hint code
* missed a bit
* fix intent
* Automatically update intent on mute change
* update packages
* lint
* Fix tests
* fix merge fails
---------
Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Robin <robin@robin.town>
Co-authored-by: Timo <16718859+toger5@users.noreply.github.com>
Co-authored-by: Timo K <toger5@hotmail.de>
Co-authored-by: fkwp <github-fkwp@w4ve.de>
This ensures that we don't see a mistaken 'reconnecting' toast while we're hanging up (and also that the leave sound gets a chance to play in widgets once again).
* remove redis, since we dont use it
* update localhost TLS certificat to add *.othersite.m.localhost wildcard
* allow for federation
* Add services and config files for Matrix site othersite.m.localhost
* add element web instance app.othersite.m.localhost
* update README
* exclude synapse database for othersite.m.localhost
* linting
* make ring$ a behavior and add code comments to justify/explain the change.
Signed-off-by: Timo K <toger5@hotmail.de>
* Add test: reproduce "ring does not stop" race.
Signed-off-by: Timo K <toger5@hotmail.de>
---------
Signed-off-by: Timo K <toger5@hotmail.de>
* Add ring notification to UserIntent.StartNewCallDM
Signed-off-by: Timo K <toger5@hotmail.de>
* Add more tests (refactor to compute + get)
Signed-off-by: Timo K <toger5@hotmail.de>
---------
Signed-off-by: Timo K <toger5@hotmail.de>
* default mute states (unmuted!) in widget mode (embedded + intent)
Signed-off-by: Timo K <toger5@hotmail.de>
* review
Signed-off-by: Timo K <toger5@hotmail.de>
* introduce a cache for the url params.
Signed-off-by: Timo K <toger5@hotmail.de>
* Add an option to skip the cache.
Signed-off-by: Timo K <toger5@hotmail.de>
---------
Signed-off-by: Timo K <toger5@hotmail.de>
* Fix the interactivity of buttons while reconnecting or in earpiece mode
When we're in one of these modes, we need to ensure that everything above the overlay (the header and footer buttons) is interactive, while everything obscured by the overlay (the media tiles) is non-interactive and removed from the accessibility tree. It's not a very easy task to trap focus *outside* an element, so the best solution I could come up with is to set tabindex="-1" manually on all interactive elements belonging to the media tiles.
* Write a Playwright test for reconnecting
* fix lints
Signed-off-by: Timo K <toger5@hotmail.de>
* fix test
Signed-off-by: Timo K <toger5@hotmail.de>
* enable http2 for matrx-rtc host to allow the jwt service to talk to the SFU
* remove rate limit for delayed events
* more time to connect to livekit SFU
* Due to a Firefox issue we set the start anchor for the tab test to the Mute microphone button
* adapt to most recent Element Web version
* Use the "End call" button as proofe for a started call
* Currrenty disabled due to recent Element Web
- not indicating the number of participants
- bypassing Lobby
* linting
* disable 'can only interact with header and footer while reconnecting' for firefox
---------
Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Timo <16718859+toger5@users.noreply.github.com>
Co-authored-by: Timo K <toger5@hotmail.de>
Co-authored-by: fkwp <github-fkwp@w4ve.de>
* add wait for pickup overlay
Signed-off-by: Timo K <toger5@hotmail.de>
* refactor and leave logic
Signed-off-by: Timo K <toger5@hotmail.de>
* recursive play sound logic
Signed-off-by: Timo K <toger5@hotmail.de>
* review
Signed-off-by: Timo K <toger5@hotmail.de>
* text color
Signed-off-by: Timo K <toger5@hotmail.de>
* overlay styling and interval fixes
Signed-off-by: Timo K <toger5@hotmail.de>
* fix permissions and styling
Signed-off-by: Timo K <toger5@hotmail.de>
* fix always getting pickup sound
Signed-off-by: Timo K <toger5@hotmail.de>
* Add sound effects for declined,timeout and ringtone
* better ringtone
* Integrate sounds
* Ensure leave sound does not play
* Remove unused blocked sound
* fix test
* Improve tests
* Loop ring sound inside Audio context for better perf.
* lint
* better ringtone
* Update to delay ringtone logic.
* lint + fix test
* Tidy up ring sync and add comments.
* lint
* Refactor onLeave to take a sound so we don't need to repeat the sound
* fix import
---------
Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Timo K <toger5@hotmail.de>
After a membership manager error, clicking the 'reconnect' button did nothing. This is because we were forgetting to clear the external error state, causing it to transition directly back to the same error state.
With this change I'm also taking care to not show the standard "Connection to the server has been lost" banner in the call view, since that is now covered by the 'reconnecting' message.
* bump js-sdk to Allow multiple rtc sessions per room (with different sessionDescriptions)
* Allow new state key string-packing format for widget mode
* bump js-sdk to latest version (with merged multi session PR)
Signed-off-by: Timo K <toger5@hotmail.de>
---------
Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Timo K <toger5@hotmail.de>
* Introduce condigurable auto leave option
* Read url params for auto leave
* add tests
* rename url param to `autoLeave`
* lint
Signed-off-by: Timo K <toger5@hotmail.de>
* fix scope in CallViewModel tests
Signed-off-by: Timo K <toger5@hotmail.de>
* use auto leave in DM case
Signed-off-by: Timo K <toger5@hotmail.de>
* Make last once leave logic based on matrix user id (was participant id before)
Signed-off-by: Timo K <toger5@hotmail.de>
* add test for multi device auto leave
Signed-off-by: Timo K <toger5@hotmail.de>
---------
Signed-off-by: Timo K <toger5@hotmail.de>
* Add a fullscreen button that uses the element request Fullscreen browser api
Signed-off-by: Timo K <toger5@hotmail.de>
* use body instead of root node
Signed-off-by: Timo K <toger5@hotmail.de>
---------
Signed-off-by: Timo K <toger5@hotmail.de>
* Stop reading deprecated config options
* add PR-Breaking-Change as one of the possible PR- prefix labels
Signed-off-by: Timo K <toger5@hotmail.de>
---------
Signed-off-by: Timo K <toger5@hotmail.de>
* Set available devices to empty map on safari.
Signed-off-by: Timo K <toger5@hotmail.de>
* better safari check
Signed-off-by: Timo K <toger5@hotmail.de>
---------
Signed-off-by: Timo K <toger5@hotmail.de>
I believe that the issue we were originally investigating using these increased timeouts was the fault of my earlier ISP in SW Virginia. I can't recall reproducing the exact issue on other networks.
0e0fba6575 added the ability to send call notification events when starting a call, but I forgot to give the widget the right capabilities to do this. The effect was that notifications just wouldn't send in widget mode.
* refactor UrlParams to use a preset intent system
* change defaults for intend headers
* add: getEnumParam to ParamParser
* remove deprecated url params
* only allow skip lobby in widget (more strict needs test adjustment)
* fix tests that now require the url to be a widget url
Co-authored-by: Robin <robin@robin.town>
---------
Co-authored-by: Robin <robin@robin.town>
* Send notification events when starting a call
Previously this has been the responsibility of the hosting application (Element Web / Element X), but I would like to move this responsibility to Element Call itself to make it even more lightweight to integrate Element Call into a widget-capable client.
* use RTCNotification event
* add url param
* bump to latest js-sdk
* remove everything decline related
* use notification type in url params
* fix url .md docs
* back to `head=develop` and using js-sdk with send notification feature
* format
---------
Co-authored-by: Timo <toger5@hotmail.de>
This hook is simpler in its implementation (therefore hopefully more correct & performant) and enforces a type-level distinction between raw Observables and Behaviors.
Rather than the 'share screen' button. Small screens are most likely to be mobile devices which wouldn't have the ability to share their screen, anyways.
* Add a global control for toggling earpiece mode
This will be used by Element X to show an earpiece toggle button in the header.
* Add an earpiece overlay
* Fix header
The header needs to be passed forward as a string to some components and as a bool (hideHeader) to others.
Also use a enum instead of string options.
* fix top clipping with header
* hide app bar in pip
* revert android overlay app_bar
* Modernize AppBarContext
* Style header icon color as desired and switch earpice/speaker icon
* fix initial selection when using controlled media
* Add "Back to video" button
* fix tests
* remove dead code
* add snapshot test
* fix back to video button
* Request capability to learn the room name
We now need the room name in order to implement the mobile (widget-based) designs with the app bar.
* Test the CallViewModel output switcher directly
---------
Co-authored-by: Timo <toger5@hotmail.de>
* bugfix: #3344 Reconnecting to the same SFU on membership change
* fixup! commit error
* Keep useActiveLivekitFocus from changing focus spuriously
* Remove redundant fix for spurious focus changes
We've now fixed it at the source by prohibiting state changes in useActiveLivekitFocus itself.
---------
Co-authored-by: Robin <robin@robin.town>
* Replace useContext with use
The docs recommend the use hook because it is simpler and allows itself to be called conditionally.
* Simplify our context providers
React 19 lets you omit the '.Provider' bit.
* Add `onBackButtonPressed` controls api
* Update docs/controls.md
Co-authored-by: Robin <robin@robin.town>
---------
Co-authored-by: Robin <robin@robin.town>
* Refactor media devices to live outside React as Observables
This moves the media devices state out of React to further our transition to a MVVM architecture in which we can more easily model and store complex application state. I have created an AppViewModel to act as the overarching state holder for any future non-React state we end up creating, and the MediaDevices reside within this. We should move more application logic (including the CallViewModel itself) there in the future.
* Address review feedback
* Fixes from ios debugging session: (#3342)
- dont use preferred vs selected concept in controlled media. Its not needed since we dont use the id for actual browser media devices (the id's are not even actual browser media devices)
- add more logging
- add more conditions to not accidently set a deviceId that is not a browser deviceId but one provided via controlled.
---------
Co-authored-by: Timo <16718859+toger5@users.noreply.github.com>
We didn't need the complexity of the (admittedly very small) React hook, and the package hasn't declared compatibility with React 19, so let's just switch to copying things manually via copy-to-clipboard.
* Build Docker image on slim base
* Run Playwright tests against Docker container
For Playwright end-to-end tests in CI, instead of running a development
webserver with `yarn dev`, build and deploy a Docker container for
Element Call and use that as the webserver to test against.
* Shut down playwright webserver gracefully
When using a containerized webserver, this stops the container once
tests finish.
* Increase Playwright timeout in CI
---------
Co-authored-by: fkwp <github-fkwp@w4ve.de>
* Avoid reactivity bugs in how we track external state
Many of our hooks which attempt to bridge external state from an EventEmitter or EventTarget into React had subtle bugs which could cause them to fail to react to certain updates. The conditions necessary for triggering these bugs are explained by the tests that I've included.
In the majority of cases, I don't think we were triggering these bugs in practice. They could've become problems if we refactored our components in certain ways. The one concrete case I'm aware of in which we actually triggered such a bug was the race condition with the useRoomEncryptionSystem shared secret logic (addressed by a1110af6d5).
But, particularly with all the weird reactivity issues we're debugging this week, I think we need to eliminate the possibility that any of the bugs in these hooks are the cause of our current headaches.
* Reuse useTypedEventEmitterState in useLocalStorage
* Fix type error
We forgot to tell React that we need the audio renderer to react to changes in the set of MatrixRTC participants; instead we had it referencing rtcSession.memberships non-reactively.
Now, I'm not 100% confident that this is going to fix the "speaking from the void" issues observed in the wild, because I can't reproduce them and, in my testing, the InCallView component always seemed to be rendered redundantly when the MatrixRTC participants change, even though we hadn't explicitly stated that it needs to react. (This makes sense as we haven't memoized the component.) But it's worth a shot.
* Simplify key local storage management.
* Refactor useLivekit to only ever connect to one room.
This change also tries to make the code more explicit so that we only do the things we really need to do and rely less on react updating everything correctly.
It also surfaces, that we are currently implementing useLivekit in a way, so that we can change the encryption system on the fly and recreate the room. I am not sure this is a case we need to support?
* simplify the useLivekit hook even more
This is possible because we concluded that we do not need to be able to hot reload the e2ee system.
* review
* linter
* Update src/room/InCallView.tsx
Co-authored-by: Robin <robin@robin.town>
---------
Co-authored-by: Robin <robin@robin.town>
This gives us the additional insurance of breaking the Safari media acquisition loop at the source by admitting that they can be spurious in practice. Safari, why!?
Because we're now requiring the 'Prevent blocked' check to pass before merging a PR, GitHub Actions now expects it to be associated with the latest Git ref of the PR's branch whenever the branch is updated. Therefore we need to re-run the workflow on the 'synchronize' event.
Because the latest version requires eslint-plugin-unicorn v57, which requires eslint v9, and eslint-plugin-matrix-org is not yet compatible with eslint v9.
* Disable device switching when in controlled audio devices mode
* Temporarily switch matrix-js-sdk to robin/embedded-no-update-state
To allow us to test this change on Element X, which does not yet support the update_state action.
* Also add a check for controlled audio devices in useAudioContext
* use develop branch
* fix tests
---------
Co-authored-by: Robin <robin@robin.town>
- `MediaDevice`->`MediaDeviceHandle`
- use just one provider and switch inside the
MediaDevicesProvider between: controlledAudioOutput, webViewAudioOutput
- fix muteAllAudio
fix left right to match chromium + safari
(firefox is swapped)
earpice as setting
Simpler code and documentation
The doc explains, what this class actually does and why it is so complicated.
Signed-off-by: Timo K <toger5@hotmail.de>
use only one audioContext, remove (non working) standby fallback
echo "[yarn-linker] The pre-commit hook has disabled .links.yaml and MODIFIED the yarn.lock file. Review the staged changes (the hook added yarn.lock, was this desired?) and run \`git commit \` again if they look okay. The post-commit hook will re-enable your links."
# Checks if there currently is linking configured. Informs the user to disable linking before committing.
PNPMFILE=.pnpmfile.cjs
if test -f "$PNPMFILE"; then
echo "[pnpm-linker] The pre-commit hook detected $PNPMFILE which implies you have linked packages in your pnpm-lock.yaml. Run pnpm links:off and commit again. See also linking.md."
// TODO: Re-enable once oxlint supports lint rules that rely on TypeScript type-awareness.
// "eslint-plugin-rxjs"
],
"categories":{
"correctness":"error",
"perf":"error"
},
"options":{
"denyWarnings":true,
"typeAware":true
},
"env":{
"builtin":true
},
"rules":{
"element-call/copyright-header":[
"error",
"/*\nCopyright %%CURRENT_YEAR%% Element Creations Ltd.\n\nSPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial\nPlease see LICENSE in the repository root for full details.\n*/\n\n"
and [LiveKit](https://livekit.io/). It runs in multiple deployment contexts — as a
standalone web app and as a widget embedded in Element Web, Element X iOS, and
Element X Android. It is also the primary R&D foundation for MatrixRTC, which means
its architecture, maintainability, and flexibility are held to a high standard.
We welcome contributions from the community. This document explains how to
contribute effectively so that both you and the maintainers get the best outcome.
## Issue First Policy
> [!IMPORTANT]
> Before writing a single line of code for a new feature or UI change, you **must**
> open an issue and have the approach agreed with the maintainers.
>
> **We will not review or merge feature or UI pull requests that arrive without a
> corresponding, pre-approved issue.**
This is not gatekeeping — it's how we prevent wasted effort on both sides. Element
Call must work correctly across multiple deployment contexts and meet specific product
and design requirements. It is also a fast-moving codebase that underpins ongoing
MatrixRTC development. A PR that looks reasonable in isolation can easily conflict
with in-progress work, planned architecture changes, or design decisions that haven't
been publicly documented yet.
The issue is where we resolve all of that **before** anyone writes code.
**Bug fixes** are no exception — most confirmed bugs should already have an issue anyways, existing issues that are marked as bugs have an implicit maintainer approval. If the solution for the bug is controversial it is highly recommended to discuss the approach in the issue before opening a PR.
## Contribution Workflow
1.**Open an issue** using the [Enhancement request](https://github.com/element-hq/element-call/issues/new?template=enhancement.yml) template.
2.**Wait for feedback.** A maintainer will comment on the issue **within two weeks**. The use case and approach will get dicussed.
This may involve questions, suggestions, or a request to adjust scope.
This also allows to bring design and product into the loop before code gets created.
3.**Get a green light.** Wait for explicit approval from a maintainer before starting
implementation.
4.**Implement.** Write the code against the agreed approach.
5.**Open a PR.** Link to the issue in your PR description and satisfy the checklist
in the PR template.
## Code Quality
Element Call moves fast and the codebase must stay clean and maintainable.
- **Take responsibility for AI-generated code.** AI tools can be a useful aid, but we expect all the generated code to be understood and reasoned about by the contributor. Questions by the maintainers should be answered without just forwarding them to AI. The maintainers also have access to AI tools. If your contribution is just transporting messages between LLM <-> maintaines all our time is better used if the maintainers decide to interact with AI for this specific problem by themselves.
- **Think across deployment contexts.** Changes must work correctly in both standalone
and widget modes. Consider how your change interacts with Element Web, Element X
iOS, and Element X Android.
- **Write tests.** New functionality should be covered by tests. Where it is feasible,
existing uncovered code touched by your PR should also gain tests.
The file is located at `backend/dev_tls_local-ca.crt`. Transfer it via:
- Matrix room
- AirDrop for iphone
### IOS Setup
**Install the certificate profile on iPhone**
- Open the `dev_tls_local-ca.crt` file on your iPhone
- You'll see "Profile Downloaded"
- Go to **Settings → General → VPN & Device Management** (or **Settings → General → Profiles**)
- Tap the "Element Call Dev CA" profile
- Tap **Install** and enter your passcode
- Confirm by tapping **Install** again
**Enable full trust (Critical!)**
- Go to **Settings → General → About → Certificate Trust Settings**
- Under "Enable Full Trust for Root Certificates"
- Toggle **ON** for "Element Call Dev CA"
- Confirm the security warning
**Access Element Call**
Find your laptop's IP address (e.g., `192.168.0.122`) and use one of these URLs in Safari to validate:
```
https://192-168-0-122.nip.io:3000/
```
**For Element X iOS Developer Tools**
In Element X's developer settings, set the Element Call URL to the nip.io url (replace . with - in the IP address):
```
https://192-168-0-122.nip.io:3000/room
```
### Android Setup
**Transfer the CA certificate to your Android device**
The file is located at `backend/dev_tls_local-ca.crt`.
**Install the certificate**
This might vary by Android version and manufacturer, but generally:
- Open **Settings** search for "CA Certificate"/"Certificate"
- Tap **Install a certificate** or **Install from storage**
- Select **CA certificate**
- Confirm the security warning
- Navigate to and select the `dev_tls_local-ca.crt` file
- Give it a name like "Element Call Dev CA"
**Access Element Call**
Find your laptop's IP address (e.g., `192.168.0.122`) and use one of these URLs in Chrome to validate:
```
https://192-168-0-122.nip.io:3000/
```
**For Element X Android Developer Tools**
In Element X's developer settings, set the Element Call URL to the nip.io url (replace . with - in the IP address):
```
https://192-168-0-122.nip.io:3000/room
```
### Why nip.io?
[nip.io](https://nip.io) is a free wildcard DNS service that automatically resolves domain names containing IP addresses. For example, `192-168-0-122.nip.io` automatically resolves to `192.168.0.122`. This means:
- No need to regenerate certificates when your laptop's IP changes
- Works from any device without DNS configuration
- iOS/Android treat it as a proper domain name, not an IP address
- One-time certificate setup works for all future IP addresses
> [!IMPORTANT]
> Make sure your network router doesn't enforce DNS rebinding protection (which will
> break nip.io). If it does, try allow-listing nip.io in your router's administration interface.
A few aspects of Element Call's interface can be controlled through a global API on the `window`:
A few aspects of Element Call's interface can be controlled through a global API on the `window`.
## Picture-in-picture
-`controls.canEnterPip(): boolean` Determines whether it's possible to enter picture-in-picture mode.
-`controls.enablePip(): void` Puts the call interface into picture-in-picture mode. Throws if not in a call.
-`controls.disablePip(): void` Takes the call interface out of picture-in-picture mode, restoring it to its natural display mode. Throws if not in a call.
-`controls.onPipMediaOrientationUpdate: ((orientation: "landscape"|"portrait") => void) | undefined` Callback called whenever the PiP media orientation changes.
The client should track this value to already initiate the pip in the right orientation.
It should update the orientation of the current Pip window when called.
## Audio devices
On mobile platforms (iOS, Android), web views do not reliably support selecting audio output devices such as the main speaker, earpiece, or headset. To address this limitation, the following functions allow the hosting application (e.g., Element Web, Element X) to manage audio devices via exposed JavaScript interfaces. These functions must be enabled using the URL parameter `controlledAudioDevices` to take effect.
-`controls.setAvailableAudioDevices(devices: { id: string, name: string, forEarpiece?: boolean, isEarpiece?: boolean isSpeaker?: boolean, isExternalHeadset?: boolean }[]): void` Sets the list of available audio outputs. `forEarpiece` is used on iOS only.
It flags the device that should be used if the user selects earpiece mode. This should be the main stereo loudspeaker of the device.
-`controls.onAudioDeviceSelect: ((id: string) => void) | undefined` Callback called whenever the user or application selects a new audio output.
-`controls.setAudioDevice(id: string): void` Sets the selected audio device in Element Call's menu. This should be used if the OS decides to automatically switch to Bluetooth, for example.
-`controls.setAudioEnabled(enabled: boolean)` Enables/disables all audio output from the application. Output is enabled by default.
-`controls.onAudioPlaybackStarted: ((id: string) => void) | undefined`: This will be called the first time we start
playing audio in the webview. It can be helpful to do device setup on the native app when the webviews audio is ready.
In particular android is using it to setup the output channel so that the call volume can
be controlled by the hardware volume rocker.
## Element Call button delegation
Callbacks for buttons in EC that are handled by the native application
-`showNativeAudioDevicePicker: (() => void) | undefined`. Callback called whenever the user presses the output button in the settings menu.
This button is only shown on iOS. (`/iPad|iPhone|iPod|Mac/.test(navigator.userAgent)`)
-`onBackButtonPressed: (() => void) | undefined`. Callback when the webview detects a tab on the header's back button.
| **Responsibility for regulatory compliance** | The administrator that is deploying the app is responsible for compliance with any applicable regulations (e.g. privacy) | The developer of the messenger app is responsible for compliance |
| **Analytics consent** | Element Call will show a consent UI. | Element Call will not show a consent UI. The messenger app should only provide the embedded Element Call with the [analytics URL parameters](./url-params.md#embedded-only-parameters) if consent has been granted. |
| **Analytics consent** | Element Call will show a consent UI. | Element Call will not show a consent UI. The messenger app should only provide the embedded Element Call with the [analytics URL parameters](./url_params.md#embedded-only-parameters) if consent has been granted. |
| **Analytics data** | Element Call will send data to the Posthog, Sentry and Open Telemetry targets specified by the administrator in the `config.json` | Element Call will send data to the Posthog and Sentry targets specified in the URL parameters by the messenger app |
### Using the embedded package within a messenger app
@@ -25,8 +25,8 @@ The basics are:
1. Add the appropriate platform dependency as given for a [release](https://github.com/element-hq/element-call/releases), or use the embedded tarball. e.g. `npm install @element-hq/element-call-embedded@0.9.0`
2. Include the assets from the platform dependency in the build process. e.g. copy the assets during a [Webpack](https://github.com/element-hq/element-web/blob/247cd8d56d832d006d7dfb919d1042529d712b59/webpack.config.js#L677-L682) build.
3. Use the `index.html` entrypointof the imported assets when you are constructing the WebView or iframe. e.g. using a [relative path in a webapp](https://github.com/element-hq/element-web/blob/247cd8d56d832d006d7dfb919d1042529d712b59/src/models/Call.ts#L680), or on the the Android [WebViewAssetLoader](https://github.com/element-hq/element-x-android/blob/fe5aab6588ecdcf9354a3bfbd9e97c1b31175a8f/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/DefaultCallWidgetProvider.kt#L20)
4. Set any of the [embedded-only URL parameters](./url-params.md#embedded-only-parameters) that you need.
3. Use the `index.html` entrypointof the imported assets when you are constructing the WebView or iframe. e.g. using a [relative path in a webapp](https://github.com/element-hq/element-web/blob/247cd8d56d832d006d7dfb919d1042529d712b59/src/models/Call.ts#L680), or on the the Android [WebViewAssetLoader](https://github.com/element-hq/element-x-android/blob/fe5aab6588ecdcf9354a3bfbd9e97c1b31175a8f/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/DefaultCallWidgetProvider.kt#L20)
4. Set any of the [embedded-only URL parameters](./url_params.md#embedded-only-parameters) that you need.
## Widget vs standalone mode
@@ -35,5 +35,5 @@ Element Call is developed using the [js-sdk](https://github.com/matrix-org/matri
As a widget, the app only uses the core calling (MatrixRTC) parts. The rest (authentication, sending events, getting room state updates about calls) is done by the hosting client.
Element Call and the hosting client are connected via the widget API.
Element Call detects that it is run as a widget if a widgetId is defined in the url parameters. If `widgetId` is present then Element Call will try to connect to the client via the widget postMessage API using the parameters provided in [Url Format and parameters
](./url-params.md).
Element Call detects that it is run as a widget if `widgetId` is defined in the url parameters. If `widgetId` is present then Element Call will try to connect to the client via the widget postMessage API using the parameters provided in [Url Format and parameters
If you want to make changes to a package that Element Call depends on and see those changes applied in real time, you can create a link to a local copy of the package. Yarn has a command for this (`yarn link`), but it's not recommended to use it as it ends up modifying package.json with details specific to your development environment.
Run:
Instead, you can use our little 'linker' plugin. Create a file named `.links.yaml` in the Element Call project directory, listing the names and paths of any dependencies you want to link. For example:
Run: 'git commit' with links enabled to test the git pre-commit hook.
Run: 'pnpm links:off' to be able to commit again
Run: 'git config --local core.hooksPath ""' to allow committing with linking (not recommended)
Run: 'rm links.cjs' & 'git config --local core.hooksPath ""' to fully revert what this script did
```
# Developing with linked packages
If you want to make changes to a package that Element Call depends on and see those changes applied in real time, you can create a link to a local copy of the package. `pnpm` has a command for this (`pnpm link`), but it's not recommended to use it as it ends up modifying package.json with details specific to your development environment.
Instead, create a file named `.links.cjs` in the Element Call project directory (or run `./scripts/setup-linking.sh` to create a template), listing the names and paths of any dependencies you want to link. For example:
Background: The presence of the `.pnpmfile.cjs` adds a field to the `pnpm-lock.yaml` called: `pnpmfileChecksum`. This field is a checksum of the content of the `.pnpmfile.cjs` file.
`pnpm install --frozen-lockfile`**fails** if there is a `.pnpmfile.cjs` but no `pnpmfileChecksum` or vice versa (or on mismatch).
_TLDR: running with `--ignore-pnpmfile` will fail if `pnpmfileChecksum` is present._
#### `pnpmfileChecksum` + renovate bot
When the renovate bot creates a PR it runs `pnpm install --ignore-pnpmfile`. This means that the `pnpmfileChecksum` in the lockfile will be **empty**.
This breaks builds that **don't** ignore the `.pnpmfile.cjs`-file. (CI that runs on the renovate PR)
From here we have two possible paths:
- ignore `.pnpmfile.cjs` in all CI builds (CI will also fail if we accidently add it locally).
- fixup the `pnpm-lock.yaml` in the renovate PR to contain the correct `pnpmfileChecksum`.
Ignoring in all CI builds means that CI will always fail if we enable the linking system.
This is annoying but can be worked around with the git hook we provide that at least lets us know that we are
commiting with enabled linking.
Only if we remember setting it back/disbale linking (or let ourselves remember by the git hook) the CI will work.
#### Summary
- We will always run into conflicts with the `pnpmfileChecksum` because in renovate prs it will be empty (`--ignore-pnpmfile`)
- To keep it simple we set `--ignore-pnpmfile` in all of our CI builds to see issues immediately.
- The only solution is to never have a `.pnpmfile.cjs` in the repository when pushing.
- This way there will never be a commit with `pnpmfileChecksum` in the lockfile.
- renovate (which uses `--ignore-pnpmfile` which we cannot disable) and other CI will work.
- We are able to use the linking system locally if we `cp` this file from the scripts folder into `./` on demand.
-`pnpm links:on` and `pnpm links:off` + `./scripts/setup-linking.sh` will help us with this.
[MSC4195: MatrixRTC using LiveKit backend](https://github.com/hughns/matrix-spec-proposals/blob/hughns/matrixrtc-livekit/proposals/4195-matrixrtc-livekit.md).
@@ -86,10 +86,11 @@ to implement
In the context of MatrixRTC, we suggest using a single hostname for backend
communication by implementing endpoint routing within a reverse proxy setup. For
- [MatrixRTC with Synology Container Manager (Docker)](https://ztfr.de/matrixrtc-with-synology-container-manager-docker/)
- [Encrypted & Scalable Video Calls: How to deploy an Element Call backend with Synapse Using Docker-Compose](https://willlewis.co.uk/blog/posts/deploy-element-call-backend-with-synapse-and-docker-compose/)
- [Element Call einrichten: Verschlüsselte Videoanrufe mit Element X und Matrix Synapse](https://www.cleveradmin.de/blog/2025/04/matrixrtc-element-call-backend-einrichten/)
- [MatrixRTC Back-End for Synapse with Docker Compose and Traefik](https://forge.avontech.net/kstro1/matrixrtc-docker-traefik/)
## 🛠️ Tools
- [A Matrix server sanity tester including tests for proper MatrixRTC setup](https://codeberg.org/spaetz/testmatrix)
| [Full](./embedded-standalone.md) | All | `https://element_call.domain/room` |
| [Embedded](./embedded-standalone.md) | Remote URL | `https://element_call.domain/` n.b. no `/room` part |
| [Embedded](./embedded-standalone.md) | Embedded within messenger app | Platform dependent, but you load the `index.html` file without a `/room` part |
| [Full](./embedded_standalone.md) | All | `https://element_call.domain/room` |
| [Embedded](./embedded_standalone.md) | Remote URL | `https://element_call.domain/` n.b. no `/room` part |
| [Embedded](./embedded_standalone.md) | Embedded within messenger app | Platform dependent, but you load the `index.html` file without a `/room` part |
## Parameters
### Common Parameters
These parameters are relevant to both [widget](./embedded-standalone.md) and [standalone](./embedded-standalone.md) modes:
These parameters are relevant to both [widget](./embedded_standalone.md) and [standalone](./embedded_standalone.md) modes:
| Name | Values | Required for widget | Required for SPA | Description |
| `allowIceFallback` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Allows use of fallback STUN servers for ICE if the user's homeserver doesn’t provide any. |
| `analyticsID` (deprecated: use `posthogUserId` instead) | Posthog analytics ID | No| No | Available only with user's consent for sharing telemetry in Element Web. |
| `appPrompt` | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Prompts the user to launch the native mobile app upon entering a room, applicable only on Android and iOS, and must be enabled in config. |
| `confineToRoom`| `true` or `false` | No, defaults to `false` | No, defaults to `false` | Keeps the user confined to the current call/room. |
| `displayName`| | No | No | Display name used for auto-registration. |
| `enableE2EE` (deprecated) | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Legacy flag to enable end-to-end encryption, not used in the `livekit` branch. |
| `fontScale`| A decimal number such as `0.9` | No, defaults to `1.0` | No, defaults to `1.0` | Factor by which to scale the interface's font size. |
| `fonts`| | No | No | Defines the font(s) used by the interface. Multiple font parameters can be specified: `?font=font-one&font=font-two...`. |
| `hideHeader` | `true` or `false`| No, defaults to `false` | No, defaults to `false` | Hides the room header when in a call. |
| `hideScreensharing`| `true` or `false` | No, defaults to `false` | No, defaults to `false` | Hides the screen-sharing button. |
| `homeserver`| | Not applicable | No | Homeserver for registering a new (guest) user, configures non-default guest user server when creating a spa link. |
| `intent` | `start_call` or `join_existing`| No, defaults to `start_call` | No, defaults to `start_call` | The intent of the user with respect to the call. e.g. if they clicked a Start Call button, this would be `start_call`. If it was a Join Call button, it would be `join_existing`. |
| `lang` | [BCP 47](https://www.rfc-editor.org/info/bcp47) code| No | No | The language the app should use. |
| `password`| | No | No | E2EE password when using a shared secret. (For individual sender keys in embedded mode this is not required.) |
| `perParticipantE2EE`| `true` or `false` | No, defaults to `false` | No, defaults to `false`| Enables per participant encryption with Keys exchanged over encrypted matrix room messages. |
| `roomId`| [Matrix Room ID](https://spec.matrix.org/v1.12/appendices/#room-ids) | Yes | No | Anything about what room we're pointed to should be from useRoomIdentifier which parses the path and resolves alias with respect to the default server name, however roomId is an exception as we need the room ID in embedded widget mode, and not the room alias (or even the via params because we are not trying to join it). This is also not validated, where it is in `useRoomIdentifier()`. |
| `showControls`| `true` or `false` | No, defaults to `true` | No, defaults to `true` | Displays controls like mute, screen-share, invite, and hangup buttons during a call. |
| `skipLobby` (deprecated: use `intent` instead) | `true` or `false` | No. If `intent` is explicitly `start_call` then defaults to `true`. Otherwise defaults to `false` | No, defaults to `false` | Skips the lobby to join a call directly, can be combined with preload in widget. When `true` the audio and video inputs will be muted by default. (This means there currently is no way to start without muted video if one wants to skip the lobby. Also not in widget mode.) |
| `theme`| One of: `light`, `dark`, `light-high-contrast`, `dark-high-contrast` | No, defaults to `dark` | No, defaults to `dark` | UI theme to use. |
| `viaServers` | Comma separated list of [Matrix Server Names](https://spec.matrix.org/v1.12/appendices/#server-name) | Not applicable | No | Homeserver for joining a room, non-empty value required for rooms not on the user’s default homeserver. |
| Name | Values | Required for widget | Required for SPA | Description |
| `intent` | `start_call`, `join_existing`, `start_call_voice`, `join_existing_voice`, `start_call_dm`, `join_existing_dm`, `start_call_dm_voice`, or `join_existing_dm_voice`. | No, defaults to `start_call` | No, defaults to `start_call` | The intent is a special url parameter that defines the defaults for all the other parameters. In most cases it should be enough to only set the intent to setup element-call. |
| `allowIceFallback` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Allows use of fallback STUN servers for ICE if the user's homeserver doesn’t provide any. |
| `posthogUserId`| Posthog analytics ID | No| No | Available only with user's consent for sharing telemetry in Element Web. |
| `confineToRoom` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Keeps the user confined to the current call/room. |
| `displayName`| | No | No | Display name used for auto-registration. |
| `enableE2EE` (deprecated) | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Legacy flag to enable end-to-end encryption, not used in the `livekit` branch. |
| `fontScale` | A decimal number such as `0.9` | No, defaults to `1.0` | No, defaults to `1.0` | Factor by which to scale the interface's font size. |
| `fonts`| | No | No | Defines the font(s) used by the interface. Multiple font parameters can be specified: `?font=font-one&font=font-two...`. |
| `header`| `none`, `standard` or `app_bar`| No, defaults to `standard` | No, defaults to `standard` | The style of headers to show. `standard` is the default arrangement, `none` hides the header entirely, and `app_bar` produces a header with a back button like you might see in mobile apps. The callback for the back button is `window.controls.onBackButtonPressed`. |
| `hideScreensharing` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Hides the screen-sharing button. |
| `homeserver`| | Not applicable | No | Homeserver for registering a new (guest) user, configures non-default guest user server when creating a spa link. |
| `lang` | [BCP 47](https://www.rfc-editor.org/info/bcp47) code | No | No | The language the app should use. |
| `password` | | No | No| E2EE password when using a shared secret. (For individual sender keys in embedded mode this is not required.) |
| `perParticipantE2EE`| `true` or `false` | No, defaults to `false` | No, defaults to `false` | Enables per participant encryption with Keys exchanged over encrypted matrix room messages. |
| `controlledAudioDevices` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Whether the [global JS controls for audio devices](./controls.md#audio-devices) should be enabled, allowing the list of audio devices to be controlled by the app hosting Element Call. |
| `roomId` | [Matrix Room ID](https://spec.matrix.org/v1.12/appendices/#room-ids) | Yes | No | Anything about what room we're pointed to should be from useRoomIdentifier which parses the path and resolves alias with respect to the default server name, however roomId is an exception as we need the room ID in embedded widget mode, and not the room alias (or even the via params because we are not trying to join it). This is also not validated, where it is in `useRoomIdentifier()`. |
| `showControls` | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Displays controls like mute, screen-share, invite, and hangup buttons during a call. |
| `skipLobby` (deprecated: use `intent` instead) | `true` or `false` | No. If `intent` is explicitly `start_call` then defaults to `true`. Otherwise defaults to `false` | No, defaults to `false` | Skips the lobby to join a call directly, can be combined with preload in widget. When `true` the audio and video inputs will be muted by default. (This means there currently is no way to start without muted video if one wants to skip the lobby. Also not in widget mode.) |
| `theme` | One of: `light`, `dark`, `light-high-contrast`, `dark-high-contrast` | No, defaults to `dark` | No, defaults to `dark` | UI theme to use. |
| `background`| One of: `solid`, `gradient` | No, defaults to `gradient` | No, defaults to `gradient` | Visual style of the page background. |
| `viaServers` | Comma separated list of [Matrix Server Names](https://spec.matrix.org/v1.12/appendices/#server-name) | Not applicable | No | Homeserver for joining a room, non-empty value required for rooms not on the user’s default homeserver. |
| `sendNotificationType` | `ring` or `notification` | No | No | Will send a "ring" or "notification" `m.rtc.notification` event if the user is the first one in the call. |
| `autoLeave` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Whether the app should automatically leave the call when there is no one left in the call. |
| `waitForCallPickup` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | When sending a notification, show UI that the app is awaiting an answer, play a dial tone, and (in widget mode) auto-close the widget once the notification expires. |
### Widget-only parameters
These parameters are only supported in [widget](./embedded-standalone.md) mode.
These parameters are only supported in [widget](./embedded_standalone.md) mode.
| `baseUrl` | | Yes | The base URL of the homeserver to use for media lookups. |
| `deviceId` | Matrix device ID | Yes | The Matrix device ID for the widget host. |
| `parentUrl` | | Yes | The url used to send widget action postMessages. This should be the domain of the client or the webview the widget is hosted in. (in case the widget is not in an Iframe but in a dedicated webview we send the postMessages same WebView the widget lives in. Filtering is done in the widget so it ignores the messages it receives from itself) |
| `posthogUserId` | Posthog user identifier | No | This replaces the `analyticsID` parameter |
| `preload` | `true` or `false` | No, defaults to `false` | Pauses app before joining a call until an `io.element.join` widget action is seen, allowing preloading. |
| `returnToLobby` | `true` or `false` | No, defaults to `false` | Displays the lobby in widget mode after leaving a call; shows a blank page if set to `false`. Useful for video rooms. |
| `userId` | [Matrix User Identifier](https://spec.matrix.org/v1.12/appendices/#user-identifiers) | Yes | The Matrix user ID. |
| `widgetId` | [MSC2774](https://github.com/matrix-org/matrix-spec-proposals/pull/2774) format widget ID | Yes | The id used by the widget. The presence of this parameter implies that element call will not connect to a homeserver directly and instead tries to establish postMessage communication via the `parentUrl`. |
| `baseUrl` | | Yes | The base URL of the homeserver to use for media lookups. |
| `deviceId` | Matrix device ID | Yes | The Matrix device ID for the widget host. |
| `parentUrl` | | Yes | The url used to send widget action postMessages. This should be the domain of the client or the webview the widget is hosted in. (In case the widget is not in an Iframe but in a dedicated webview, we send the postMessages in the same WebView the widget lives in. Filtering is done in the widget so it ignores the messages it receives from itself.) |
| `posthogUserId` | Posthog user identifier | No | This replaces the `analyticsID` parameter |
| `preload` | `true` or `false` | No, defaults to `false` | Pauses app before joining a call until an `io.element.join` widget action is seen, allowing preloading. |
| `returnToLobby` | `true` or `false` | No, defaults to `false` | Displays the lobby in widget mode after leaving a call; shows a blank page if set to `false`. Useful for video rooms. |
| `userId` | [Matrix User Identifier](https://spec.matrix.org/v1.12/appendices/#user-identifiers) | Yes | The Matrix user ID. |
| `widgetId` | [MSC2774](https://github.com/matrix-org/matrix-spec-proposals/pull/2774) format widget ID | Yes | The id used by the widget. The presence of this parameter implies that element call will not connect to a homeserver directly and instead tries to establish postMessage communication via the `parentUrl`. |
### Embedded-only parameters
These parameters are only supported in the [embedded](./embedded-standalone.md) package of Element Call and will be ignored in the [full](./embedded-standalone.md) package.
These parameters are only supported in the [embedded](./embedded_standalone.md) package of Element Call and will be ignored in the [full](./embedded_standalone.md) package.
| `posthogApiHost` | Posthog server URL | No | e.g. `https://posthog-element-call.element.io`. Only supported in embedded package. In full package the value from config is used. |
| `posthogApiKey` | Posthog project API key | No | Only supported in embedded package. In full package the value from config is used. |
| `rageshakeSubmitUrl` | Rageshake server URL endpoint | No | e.g. `https://element.io/bugreports/submit`. In full package the value from config is used. |
| `rageshakeSubmitUrl` | Rageshake server URL endpoint | No | e.g. `https://rageshakes.element.io/api/submit`. In full package the value from config is used. |
| `sentryDsn` | Sentry [DSN](https://docs.sentry.io/concepts/key-terms/dsn-explainer/) | No | In full package the value from config is used. |
| `sentryEnvironment` | Sentry [environment](https://docs.sentry.io/concepts/key-terms/key-terms/) | No | In full package the value from config is used. |
* Node types that introduce a new non-module scope. A getChild() call nested
* inside any of these is considered "not at the top level".
*/
constFUNCTION_OR_CLASS_TYPES=newSet([
"FunctionDeclaration",
"FunctionExpression",
"ArrowFunctionExpression",
"ClassBody",
]);
construle=ESLintUtils.RuleCreator(
()=>"https://github.com/element-hq/element-call",
)({
name:"no-top-level-logger-get-child",
meta:{
type:"problem",
docs:{
description:
"Disallow calling logger.getChild() at the top level of a module."+
"`getChild` has to be called after the rageshake logger `init()`."+
"If it is called at the top level the child logger will never be setup for rageshakes.",
},
messages:{
noTopLevelGetChild:
"Do not call logger.getChild() at the top level of a module; move it inside a function or class instead that gets called after rageshake logger `init()` is called.",
},
schema:[],
},
create(context){
// Tracks the local binding names that refer to the logger imported from
// 'matrix-js-sdk/lib/logger', e.g. both `logger` and `rootLogger` in:
// import { logger } from "matrix-js-sdk/lib/logger";
// import { logger as rootLogger } from "matrix-js-sdk/lib/logger";
"analytics_notice":"Когато участвате в тази бета, вие съгласявате сес събирането на анонимни данни, които използваме, за да подобрим продукта. Повечето информация за данните, които следим, можете да намерите в нашата <2>Политика за поверителност</2> и нашата <6>Политика за бисквитки</6>.",
"call_ended_view":{
"create_account_button":"Създай акаунт",
"create_account_prompt":"<0>Защо не настройте парола за да запазите акаунта си?</0><1>Ще можете да запазите името и аватара си за бъдещи разговори</1>",
"not_now_button":"Несега, върни се на началния екран"
"feedback_done":"<0>Благодаря за обратната връзка!</0>",
"headline":"{{displayName}}, разговорът Ви приключи.",
"not_now_button":"Несега, върни се на началния екран",
"analytics_notice":"Účastí v této beta verzi souhlasíte se shromažďováním anonymních údajů, které používáme ke zlepšování produktu. Více informací o tom, které údaje sledujeme, najdete v našich <2>Zásadách ochrany osobních údajů</2> a <6>Zásadách používání souborů cookie</6>.",
"app_selection_modal":{
"continue_in_browser":"Pokračovat v prohlížeči",
"open_in_app":"Otevřít v aplikaci",
"text":"Jste připraveni se připojit?",
"title":"Vybrat aplikaci"
},
"call_ended_view":{
"create_account_button":"Vytvořit účet",
"create_account_prompt":"<0>Proč neskončit nastavením hesla, abyste mohli účet použít znovu?</0><1>Budete si moci nechat své jméno a nastavit si avatar pro budoucí hovory </1>",
@@ -55,13 +49,23 @@
"profile":"Profil",
"reaction":"Reakce",
"reactions":"Reakce",
"reconnecting":"Opětovné spojení...",
"settings":"Nastavení",
"unencrypted":"Nešifrováno",
"username":"Uživatelské jméno",
"video":"Video"
},
"developer_mode":{
"always_show_iphone_earpiece":"Zobrazit možnost sluchátek pro iPhone na všech platformách",
"show_non_member_tiles":"Zobrazit dlaždice pro nečlenská média",
"url_params":"Parametry URL",
"use_new_membership_manager":"Použijte novou implementaci volání MembershipManager",
"use_to_device_key_transport":"Použít přenos klíčů do zařízení. Tím se vrátíte k přenosu klíčů do místnosti, když jiný účastník hovoru pošle klíč místnosti"
"url_params":"Parametry URL"
},
"disconnected_banner":"Připojení k serveru bylo ztraceno.",
"error":{
"call_is_not_supported":"Volání není podporováno",
"call_not_found":"Volání nebylo nalezeno",
"call_not_found_description":"<0>Zdá se, že tento odkaz nepatří k žádnému existujícímu volání. Zkontrolujte, zda máte správný odkaz, nebo <1>vytvořte nový</1>.</0>",
"call_not_found_description":"<0>Zdá se, že tento odkaz nepatří k žádnému existujícímu hovoru. Zkontrolujte, zda máte správný odkaz, nebo<2> vytvořte nový</2>.</0>",
"connection_lost":"Spojení ztraceno",
"connection_lost_description":"Hovor byl přerušen.",
"e2ee_unsupported":"Nekompatibilní prohlížeč",
"e2ee_unsupported_description":"Váš webový prohlížeč nepodporuje šifrované hovory. Mezi podporované prohlížeče patří Chrome, Safari a Firefox 117+.",
"failed_to_start_livekit":"Nepodařilo se navázat připojení k Livekitu",
"generic":"Něco se pokazilo.",
"generic_description":"Odeslání protokolů ladění nám pomůže vystopovat problém.",
"insufficient_capacity":"Nedostatečná kapacita",
"insufficient_capacity_description":"Server dosáhl své maximální kapacity a v tuto chvíli se nemůžete připojit k hovoru. Zkuste to později nebo se obraťte na správce serveru, pokud problém přetrvává.",
"matrix_rtc_focus_missing":"Server není nakonfigurován pro práci s {{brand}}. Obraťte se na správce serveru (Doména: {{domain}}, Kód chyby: {{ errorCode }}).",
"matrix_rtc_transport_missing":"Server není nakonfigurován pro práci s {{brand}}. Obraťte se na správce serveru (Doména: {{domain}}, Kód chyby: {{ errorCode }}).",
"membership_manager":"Chyba Správce členství",
"membership_manager_description":"Správce členství musel být ukončen. To je způsobeno mnoha po sobě jdoucími neúspěšnými síťovými požadavky.",
"no_matrix_2_authorization_service":"Autorizační služba vašeho mediálního serveru (SFU) je zastaralá.",
"open_elsewhere":"Otevřeno na jiné kartě",
"open_elsewhere_description":"{{brand}} byl otevřen v jiné záložce. Pokud to nezní správně, zkuste stránku znovu načíst.",
"room_creation_restricted":"Nepodařilo se vytvořit hovor",
"room_creation_restricted_description":"Vytváření hovorů může být omezeno pouze na oprávněné uživatele. Zkuste to znovu později nebo se obraťte na správce serveru, pokud problém přetrvává.",
"unexpected_ec_error":"Došlo k neočekávané chybě (<0>Error Code:</0> <1>{{ errorCode }}</1>). Obraťte se prosím na správce serveru."
},
"group_call_loader":{
@@ -104,6 +126,11 @@
"knock_reject_heading":"Přístup odepřen",
"reason":"Důvod"
},
"handset":{
"overlay_back_button":"Zpět do režimu reproduktoru",
"overlay_description":"Funguje pouze při používání aplikace",
"analytics_notice":"Ved at deltage i denne beta giver du samtykke til indsamling af anonyme data, som vi bruger til at forbedre produktet. Du kan finde flere oplysninger om, hvilke data vi sporer, i vores <2>fortrolighedspolitik</2> og vores <6>cookiepolitik</6>.",
"app_selection_modal":{
"continue_in_browser":"Fortsæt i browseren",
"open_in_app":"Åbn i appen",
"text":"Klar til at deltage?",
"title":"Vælg app"
},
"call_ended_view":{
"create_account_button":"Opret konto",
"create_account_prompt":"<0>Hvorfor ikke afslutte med at oprette en adgangskode for at beholde din konto? </0><1>Du kan beholde dit navn og indstille en avatar til brug ved fremtidige opkald </1>",
@@ -55,12 +49,14 @@
"profile":"Profil",
"reaction":"Reaktion",
"reactions":"Reaktioner",
"reconnecting":"Genopretter forbindelse…",
"settings":"Indstillinger",
"unencrypted":"Ikke krypteret",
"username":"Brugernavn",
"video":"Video"
},
"developer_mode":{
"always_show_iphone_earpiece":"Vis mulighed for iPhone-høretelefon på alle platforme",
"crypto_version":"Krypto-version: {{version}}",
"debug_tile_layout_label":"Fejlfinding af fliselayout",
"device_id":"Enheds-id: {{id}}",
@@ -70,17 +66,15 @@
"livekit_server_info":"LiveKit Serverinfo",
"livekit_sfu":"LiveKit SFU: {{url}}",
"matrix_id":"Matrix ID: {{id}}",
"mute_all_audio":"Slå al lyd fra (deltagere, reaktioner, deltagelseslyde)",
"show_non_member_tiles":"Vis fliser for medier fra ikke-medlemmer",
"url_params":"URL-parametre",
"use_new_membership_manager":"Brug den nye implementering af opkaldet MembershipManager",
"use_to_device_key_transport":"Bruges til at transportere enhedsnøgler. Dette vil falde tilbage til transport af værelsesnøgler, når et andet opkaldsmedlem sender en rumnøgle"
"url_params":"URL-parametre"
},
"disconnected_banner":"Forbindelsen til serveren er gået tabt.",
"error":{
"call_is_not_supported":"Opkald er ikke understøttet",
"call_not_found":"Opkald ikke fundet",
"call_not_found_description":"<0>Det link ser ikke ud til at høre til et eksisterende opkald. Tjek at du har det rigtige link, eller<1> opret et nyt</1>.</0>",
"call_not_found_description":"<0>Det link ser ikke ud til at høre til et eksisterende opkald. Tjek at du har det rigtige link, eller <2> opret et nyt</2>.</0>",
"connection_lost":"Forbindelsen gik tabt",
"connection_lost_description":"Du blev afbrudt fra opkaldet.",
"e2ee_unsupported":"Inkompatibel browser",
@@ -89,9 +83,10 @@
"generic_description":"Indsendelse af fejlfindingslogfiler hjælper os med at spore problemet.",
"insufficient_capacity_description":"Serveren har nået sin maksimale kapacitet, og du kan ikke deltage i opkaldet på dette tidspunkt. Prøv igen senere, eller kontakt din serveradministrator, hvis problemet fortsætter.",
"matrix_rtc_focus_missing":"Serveren er ikke konfigureret til at arbejde med {{brand}}{{domain}}. Kontakt venligst din serveradministrator (domæne:{{domain}}, fejlkode: {{ errorCode }}).",
"open_elsewhere":"Åbnet i en anden fane",
"open_elsewhere_description":"{{brand}} er blevet åbnet i en anden fane. Hvis det ikke lyder rigtigt, kan du prøve at genindlæse siden.",
"room_creation_restricted":"Kunne ikke oprette opkald",
"room_creation_restricted_description":"Oprettelse af opkald er muligvis begrænset til autoriserede brugere. Prøv igen senere, eller kontakt din serveradministrator, hvis problemet fortsætter.",
"unexpected_ec_error":"Der opstod en uventet fejl (<0>Fejlkode:</0> <1> {{ errorCode }}</1>). Kontakt venligst din serveradministrator."
},
"group_call_loader":{
@@ -103,6 +98,11 @@
"knock_reject_heading":"Adgang nægtet",
"reason":"Årsag: {{reason}}"
},
"handset":{
"overlay_back_button":"Tilbage til højttalertilstand",
"overlay_description":"Virker kun, når du bruger appen",
"overlay_title":"Telefon-højtaler"
},
"hangup_button_label":"Afslut opkald",
"header_label":"Element Ring hjem",
"header_participants_label":"Deltagere",
@@ -164,12 +164,18 @@
"effect_volume_description":"Juster den lydstyrke som reaktioner og håndsoprækninger afspilles med.",
"analytics_notice":"Mit der Teilnahme an der Beta akzeptierst du die Sammlung von anonymen Daten, die wir zur Verbesserung des Produkts verwenden. Weitere Informationen zu den von uns erhobenen Daten findest du in unserer <2>Datenschutzerklärung</2> und unseren <6>Cookie-Richtlinien</6>.",
"app_selection_modal":{
"continue_in_browser":"Weiter im Browser",
"open_in_app":"In der App öffnen",
"text":"Bereit, beizutreten?",
"title":"App auswählen"
},
"call_ended_view":{
"create_account_button":"Konto erstellen",
"create_account_prompt":"<0>Warum vergibst du nicht abschließend ein Passwort, um dein Konto zu erhalten?</0><1>Du kannst deinen Namen behalten und ein Profilbild für zukünftige Anrufe festlegen.</1>",
@@ -55,6 +49,7 @@
"profile":"Profil",
"reaction":"Reaktion",
"reactions":"Reaktionen",
"reconnecting":"Verbindung wird wiederhergestellt...",
"settings":"Einstellungen",
"unencrypted":"Nicht verschlüsselt",
"username":"Benutzername",
@@ -63,6 +58,14 @@
"developer_mode":{
"always_show_iphone_earpiece":"iPhone-Ohrhörer-Option auf allen Plattformen anzeigen",
"crypto_version":"Krypto-Version: {{version}}",
"custom_livekit_url":{
"current_url":"Derzeit eingestellt auf: ",
"from_config":"Derzeit ist keine spezielle (benutzerdefinierte) URL eingestellt. Daher wird automatisch die URL verwendet, die entweder via „.well-known“ oder in der Webbrowser-Konfiguration („config“) hinterlegt ist.",
"label":"Benutzerdefinierte Livekit-URL",
"reset":"Zurücksetzen der benutzerdefinierten URL",
"description":"Kompatibel mit Homeservern ohne Sticky Events Support, wobei alle beteiligten Element Call Clients v0.17.0 oder neuer sein müssen.",
"label":"Kompatibilität: State Events & Multi-SFU"
},
"Legacy":{
"description":"Kompatibel mit älteren Versionen von Element Call, welche Multi-SFU nicht unterstützen",
"label":"Legacy: State Events und \"Oldest Membership\" SFU"
},
"Matrix_2_0":{
"description":"Nur mit Homeservern kompatibel, die Sticky Events unterstützen, wobei alle beteiligten Element Call Clients Version v0.17.0 oder neuer sein müssen.",
"label":"Matrix 2.0: Sticky Events und Multi-SFU"
},
"title":"MatrixRTC Modus"
},
"matrix_id":"Matrix-ID: {{id}}",
"mute_all_audio":"Stummschalten aller Audiosignale (Teilnehmer, Reaktionen, Beitrittsgeräusche)",
"use_to_device_key_transport":"To-Device media E2EE Schlüssel-Transport verwenden. Falls ein anderer Teilnehmer bereits den Raumschlüssel-Transport verwendet, wird automatisch auf Raumschlüssel-Transport zurückgegriffen."
"url_params":"URL-Parameter"
},
"disconnected_banner":"Die Verbindung zum Server wurde getrennt.",
"error":{
"call_is_not_supported":"Anrufe werden nicht unterstützt",
"call_not_found":"Anruf nicht gefunden",
"call_not_found_description":"<0>Dieser Link scheint zu keinem bestehenden Anruf zu gehören. Vergewissern Sie sich, dass Sie den richtigen Link haben, oder <1> erstellen Sie einen neuen</1>.</0>",
"call_not_found_description":"<0>Dieser Link scheint zu keinem bestehenden Anruf zu gehören. Es sollte geprüft werden, ob der Link korrekt ist, oder <2>ein neuer erstellt werden</2>.</0>",
"connection_lost":"Verbindung verloren",
"connection_lost_description":"Ihre Verbindung zum Anruf wurde unterbrochen.",
"e2ee_unsupported":"Inkompatibler Browser",
"e2ee_unsupported_description":"Ihr Webbrowser unterstützt keine verschlüsselten Anrufe. Zu den unterstützten Browsern gehören Chrome, Safari und Firefox 117+.",
"failed_to_start_livekit":"LiveKit-Verbindung konnte nicht hergestellt werden",
"generic":"Etwas ist schief gelaufen",
"generic_description":"Durch das Senden von Debugprotokollen können wir das Problem leichter eingrenzen.",
"insufficient_capacity_description":"Der Server hat seine maximale Kapazität erreicht, daher ist ein Beitritt zum Anruf derzeit nicht möglich. Bitte später erneut versuchen oder den Serveradministrator kontaktieren, falls das Problem weiterhin besteht.",
"matrix_rtc_focus_missing":"Der Server ist nicht für die Verwendung mit {{brand}} konfiguriert. Bitte den Serveradministrator kontaktieren (Domain: {{domain}}, Fehlercode: {{ errorCode }}).",
"matrix_rtc_transport_missing":"Der Server ist nicht für die Verwendung mit {{brand}} konfiguriert. Bitte den Server Admin kontaktieren (Domain: {{domain}}, Fehlercode: {{ errorCode }}).",
"membership_manager":"Fehler im MatrixRTC Mitgliedschaftsmanager",
"membership_manager_description":"Der MatrixRTC Mitgliedschaftsmanager wurde unerwartet aufgrund fehlgeschlagener Netzwerkanfragen beendet.",
"no_matrix_2_authorization_service":"Der Autorisierungsdienst des Medien Servers (SFU) ist veraltet.",
"open_elsewhere":"In einem anderen Tab geöffnet",
"open_elsewhere_description":"{{brand}} wurde in einem anderen Tab geöffnet. Wenn das nicht richtig klingt, versuchen Sie, die Seite neu zu laden.",
"open_elsewhere_description":"{{brand}} wurde in einem anderen Tab geöffnet. Wenn das nicht richtig klingt, versuche, die Seite neu zu laden.",
"room_creation_restricted":"Anruf konnte nicht erstellt werden",
"room_creation_restricted_description":"Das Erstellen von Anrufen ist nur für autorisierte Nutzer möglich. Versuche es später erneut oder kontaktiere deinen Serveradministrator, falls das Problem weiterhin besteht.",
"unexpected_ec_error":"Ein unerwarteter Fehler ist aufgetreten (<0>Fehlercode: </0> <1>{{ errorCode }}</1>). Bitte den Serveradministrator kontaktieren."
},
"group_call_loader":{
@@ -105,6 +126,11 @@
"knock_reject_heading":"Zugriff verweigert",
"reason":"Grund: {{reason}}"
},
"handset":{
"overlay_back_button":"Zurück zum Lautsprechermodus",
"overlay_description":"Nur wenn App im Vordergrund nutzbar",
"overlay_title":"Ohrhörer Modus"
},
"hangup_button_label":"Anruf beenden",
"header_label":"Element Call-Startseite",
"header_participants_label":"Teilnehmende",
@@ -173,9 +199,11 @@
"devices":{
"camera":"Kamera",
"camera_numbered":"Kamera {{n}}",
"change_device_button":"Audiogerät wechseln",
"default":"Standard",
"default_named":"Standard<2> ({{name}} )</2>",
"earpiece":"Ohrhörer",
"handset":"Ohrhörer",
"loudspeaker":"Lautsprecher",
"microphone":"Mikrofon",
"microphone_numbered":"Mikrofon{{n}}",
"speaker":"Lautsprecher",
@@ -190,9 +218,9 @@
"opt_in_description":"<0></0><1></1>Du kannst deine Zustimmung durch Abwählen dieses Kästchens zurückziehen. Falls du dich aktuell in einem Anruf befindest, wird diese Einstellung nach dem Ende des Anrufs wirksam.",
"preferences_tab":{
"developer_mode_label":"Entwickler-Modus",
"developer_mode_label_description":"Aktivieren Sie den Entwicklermodus und zeigen Sie die Registerkarte mit den Entwicklereinstellungen an.",
"developer_mode_label_description":"Aktiviere den Entwicklermodus und zeige Entwicklereinstellungen an.",
"introduction":"Hier können zusätzliche Optionen für individuelle Anforderungen eingestellt werden.",
"reactions_play_sound_description":"Spielen Sie einen Soundeffekt ab, wenn jemand eine Reaktion auf einen Anruf sendet.",
"reactions_play_sound_description":"Spiele einen Soundeffekt ab, wenn jemand eine Reaktion auf einen Anruf sendet.",
"analytics_notice":"Συμμετέχοντας σε αυτή τη δοκιμαστική έκδοση, συναινείτε στη συλλογή ανώνυμων δεδομένων, τα οποία χρησιμοποιούμε για τη βελτίωση του προϊόντος. Μπορείτε να βρείτε περισσότερες πληροφορίες σχετικά με το ποια δεδομένα καταγράφουμε στην <2>Πολιτική απορρήτου</2> και στην <6>Πολιτική cookies</6>.",
"app_selection_modal":{
"continue_in_browser":"Συνέχεια στο πρόγραμμα περιήγησης",
"open_in_app":"Ανοίξτε στην εφαρμογή",
"text":"Έτοιμοι να συμμετάσχετε?",
"title":"Επιλέξτε εφαρμογή"
},
"call_ended_view":{
"create_account_button":"Δημιουργία λογαριασμού",
"create_account_prompt":"<0>Γιατί να μην ολοκληρώσετε με τη δημιουργία ενός κωδικού πρόσβασης για τη διατήρηση του λογαριασμού σας;</0><1>Θα μπορείτε να διατηρήσετε το όνομά σας και να ορίσετε ένα avatar για χρήση σε μελλοντικές κλήσεις.</1>",
"analytics_notice":"By participating in this beta, you consent to the collection of anonymous data, which we use to improve the product. You can find more information about which data we track in our <2>Privacy Policy</2> and our <6>Cookie Policy</6>.",
"app_selection_modal":{
"continue_in_browser":"Continue in browser",
"open_in_app":"Open in the app",
"text":"Ready to join?",
"title":"Select app"
},
"call_ended_view":{
"create_account_button":"Create account",
"create_account_prompt":"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>",
@@ -55,6 +50,7 @@
"profile":"Profile",
"reaction":"Reaction",
"reactions":"Reactions",
"reconnecting":"Reconnecting…",
"settings":"Settings",
"unencrypted":"Not encrypted",
"username":"Username",
@@ -63,6 +59,14 @@
"developer_mode":{
"always_show_iphone_earpiece":"Show iPhone earpiece option on all platforms",
"crypto_version":"Crypto version: {{version}}",
"custom_livekit_url":{
"current_url":"Currently set to: ",
"from_config":"Currently, no overwrite is set. Url from config is used.",
"label":"Custom Livekit-url",
"reset":"Reset overwrite",
"save":"Save",
"saving":"Saving..."
},
"debug_tile_layout_label":"Debug tile layout",
"device_id":"Device ID: {{id}}",
"duplicate_tiles_label":"Number of additional tile copies per participant",
@@ -71,29 +75,53 @@
"livekit_server_info":"LiveKit Server Info",
"livekit_sfu":"LiveKit SFU: {{url}}",
"matrix_id":"Matrix ID: {{id}}",
"matrixRTCMode":{
"Comptibility":{
"description":"Compatible with homeservers that do not support sticky events (but all other EC clients are v0.17.0 or later)",
"label":"Compatibility: state events & multi SFU"
},
"Legacy":{
"description":"Compatible with old versions of EC that do not support multi SFU",
"label":"Legacy: state events & oldest membership SFU"
},
"Matrix_2_0":{
"description":"Compatible only with homservers supporting sticky events and all EC clients v0.17.0 or later",
"label":"Matrix 2.0: sticky events & multi SFU"
},
"title":"MatrixRTC mode"
},
"mute_all_audio":"Mute all audio (participants, reactions, join sounds)",
"show_non_member_tiles":"Show tiles for non-member media",
"url_params":"URL parameters",
"use_new_membership_manager":"Use the new implementation of the call MembershipManager",
"use_to_device_key_transport":"Use to device key transport. This will fallback to room key transport when another call member sent a room key"
"url_params":"URL parameters"
},
"disconnected_banner":"Connectivity to the server has been lost.",
"error":{
"call_is_not_supported":"Call is not supported",
"call_not_found":"Call not found",
"call_not_found_description":"<0>That link doesn't appear to belong to any existing call. Check that you have the right link, or <1>create a new one</1>.</0>",
"call_not_found_description":"<0>That link doesn't appear to belong to any existing call. Check that you have the right link, or <2>create a new one</2>.</0>",
"connection_lost":"Connection lost",
"connection_lost_description":"You were disconnected from the call.",
"e2ee_unsupported":"Incompatible browser",
"e2ee_unsupported_description":"Your web browser does not support encrypted calls. Supported browsers include Chrome, Safari, and Firefox 117+.",
"failed_to_start_livekit":"Failed to start Livekit connection",
"generic":"Something went wrong",
"generic_description":"Submitting debug logs will help us track down the problem.",
"insufficient_capacity":"Insufficient capacity",
"insufficient_capacity_description":"The server has reached its maximum capacity and you cannot join the call at this time. Try again later, or contact your server admin if the problem persists.",
"matrix_rtc_focus_missing":"The server is not configured to work with {{brand}}. Please contact your server admin (Domain: {{domain}}, Error Code: {{ errorCode }}).",
"livekit_connection_error":"Failed to connect to Livekit server",
"livekit_connection_error_description":"An error occurred while connecting to the Livekit server (<1>Reason:</1> <2>{{ reason }}</2>).",
"matrix_rtc_transport_missing":"The server is not configured to work with {{brand}}. Please contact your server admin (Domain: {{domain}}, Error Code: {{ errorCode }}).",
"membership_manager":"Membership Manager Error",
"membership_manager_description":"The Membership Manager had to shut down. This is caused by many consecutive failed network requests.",
"no_matrix_2_authorization_service":"The authorization service for your media server (SFU) is out of date.",
"open_elsewhere":"Opened in another tab",
"open_elsewhere_description":"{{brand}} has been opened in another tab. If that doesn't sound right, try reloading the page.",
"peer_connection_timeout":"Connection timeout",
"peer_connection_timeout_description":"Connection to the media server timed out. Try switching to a different network or disabling your VPN. If the problem persists, see our <0>troubleshooting guide</0> or contact your server administrator.",
"room_creation_restricted":"Failed to create call",
"room_creation_restricted_description":"Call creation might be restricted to authorized users only. Try again later, or contact your server admin if the problem persists.",
"sticky_events_required":"Homeserver does not support Matrix 2.0 calls",
"sticky_events_required_description":"This deployment is configured to use Matrix 2.0 call mode, but the homeserver does not advertise support for sticky events (MSC4354). Ask your server admin to upgrade, or switch the deployment to a compatible mode.",
"unexpected_ec_error":"An unexpected error occurred (<0>Error Code:</0> <1>{{ errorCode }}</1>). Please contact your server admin."
},
"group_call_loader":{
@@ -105,6 +133,11 @@
"knock_reject_heading":"Access denied",
"reason":"Reason: {{reason}}"
},
"handset":{
"overlay_back_button":"Back to Speaker Mode",
"overlay_description":"Only works while using app",
"overlay_title":"Handset Mode"
},
"hangup_button_label":"End call",
"header_label":"Element Call Home",
"header_participants_label":"Participants",
@@ -119,6 +152,7 @@
},
"layout_grid_label":"Grid",
"layout_spotlight_label":"Spotlight",
"layout_switch_label":"Layout",
"lobby":{
"ask_to_join":"Request to join call",
"join_as_guest":"Join as guest",
@@ -162,31 +196,47 @@
"room_auth_view_ssla_caption":"By clicking \"Join call now\", you agree to our <2>Software and Services License Agreement (SSLA)</2>",
"screenshare_button_label":"Share screen",
"settings":{
"advanced_camera_description":"Configure resolution, framerate, bitrate, and codec for camera video. Changes apply on next call join.",
"advanced_camera_label":"Advanced camera settings",
"advanced_screen_share_description":"Configure resolution, framerate, bitrate, and codec for screen sharing",
"feedback_tab_thank_you":"Thanks, we received your feedback!",
"feedback_tab_title":"Feedback",
"framerate_label":"Framerate",
"noise_suppression_label":"Noise suppression",
"opt_in_description":"<0></0><1></1>You may withdraw consent by unchecking this box. If you are currently in a call, this setting will take effect at the end of the call.",
"preferences_tab":{
"developer_mode_label":"Developer mode",
@@ -198,7 +248,9 @@
"reactions_show_label":"Show reactions",
"show_hand_raised_timer_description":"Show a timer when a participant raises their hand",
"show_hand_raised_timer_label":"Show hand raise duration"
"analytics_notice":"Al participar en esta beta, consientes a la recogida de datos anónimos, los cuales usaremos para mejorar el producto. Puedes encontrar más información sobre que datos recogemos en nuestra <2>Política de privacidad</2> y en nuestra <5>Política sobre Cookies</5>.",
"app_selection_modal":{
"continue_in_browser":"Continuar en el navegador",
"open_in_app":"Abrir en la aplicación",
"text":"¿Listo para unirte?",
"title":"Selecciona aplicación"
},
"call_ended_view":{
"create_account_button":"Crear cuenta",
"create_account_prompt":"<0>¿Por qué no mantienes tu cuenta estableciendo una contraseña?</0><1>Podrás mantener tu nombre y establecer un avatar para usarlo en futuras llamadas</1>",
@@ -28,30 +29,142 @@
"feedback_prompt":"<0>Nos encantaría conocer tu opinión para que podamos mejorar tu experiencia</0>",
"headline":"{{displayName}}, tu llamada ha finalizado.",
"not_now_button":"Ahora no, volver a la pantalla de inicio",
"reconnect_button":"Reconnectar",
"survey_prompt":"¿Cómo ha ido?"
},
"call_name":"Nombre de la llamada",
"common":{
"analytics":"Analíticas",
"audio":"Audio",
"avatar":"Avatar",
"back":"Regresar",
"display_name":"Nombre a mostrar",
"encrypted":"Cifrado",
"home":"Inicio",
"loading":"Cargando…",
"next":"Próximo",
"options":"Opciones",
"password":"Contraseña",
"preferences":"Preferencias",
"profile":"Perfil",
"reaction":"Reacción",
"reactions":"Reacciones",
"reconnecting":"Reconectando…",
"settings":"Ajustes",
"username":"Nombre de usuario"
"unencrypted":"Sin cifrar",
"username":"Nombre de usuario",
"video":"Vídeo"
},
"developer_mode":{
"always_show_iphone_earpiece":"Mostrar la opción de auricular del iPhone en todas las plataformas",
"description":"Compatible con servidores privados que no admiten eventos persistentes (pero todos los demás clientes de EC son v0.17.0 o posteriores)",
"label":"Compatibilidad: eventos de estado y SFU múltiple"
},
"Legacy":{
"description":"Compatible con versiones antiguas de EC que no admiten SFU múltiple.",
"label":"Legado: eventos estatales y membresía más antigua SFU"
},
"Matrix_2_0":{
"description":"Compatible solo con servidores domésticos que admiten eventos persistentes y todos los clientes EC v0.17.0 o posterior",
"label":"Matrix 2.0: eventos persistentes y SFU múltiple"
},
"title":"Modo MatrixRTC"
},
"matrix_id":"Matrix ID: {{id}}",
"mute_all_audio":"Silenciar todo el audio (participantes, reacciones, sonidos de unirse)",
"show_connection_stats":"Mostrar estadísticas de conexión",
"url_params":"Parámetros URL"
},
"disconnected_banner":"Se perdió la conectividad con el servidor.",
"error":{
"call_is_not_supported":"La llamada no es compatible",
"call_not_found":"Llamada no encontrada",
"call_not_found_description":"<0>Ese enlace no parece pertenecer a ninguna llamada existente. Comprueba que tienes el enlace correcto o <2>crea uno nuevo</2>.</0>",
"connection_lost":"Conexión interrumpida",
"connection_lost_description":"Se cortadó la llamada.",
"e2ee_unsupported":"Navegador incompatible",
"e2ee_unsupported_description":"Tu navegador web no admite llamadas cifradas. Los navegadores compatibles son Chrome, Safari y Firefox 117+.",
"failed_to_start_livekit":"No se ha podido iniciar la conexión Livekit.",
"generic":"Algo salió mal",
"generic_description":"Enviar registros de depuración nos ayudará a localizar el problema.",
"insufficient_capacity":"Capacidad insuficiente",
"insufficient_capacity_description":"El servidor ha alcanzado su capacidad máxima y no puedes unirte a la llamada en el momento. Inténtalo más tarde o contacta el administrador del servidor si el problema persiste.",
"matrix_rtc_transport_missing":"El servidor no está configurado para trabajar con{{brand}} . Por favor, póngase en contacto con el administrador de su servidor (Dominio:{{domain}} Código de error:{{ errorCode }} ).",
"membership_manager":"Error del administrador de miembros",
"membership_manager_description":"El Administrador de Membresías tuvo que cerrarse debido a numerosas solicitudes de red fallidas consecutivas.",
"no_matrix_2_authorization_service":"El servicio de autorización de su servidor multimedia (SFU) está desactualizado.",
"open_elsewhere":"Abierto en otra pestaña",
"open_elsewhere_description":"{{brand}}Se ha abierto en otra pestaña. Si no suena bien, intenta recargar la página.",
"room_creation_restricted":"Falló crear llamada",
"room_creation_restricted_description":"La creación de llamadas podría estar restringida solo a usuarios autorizados. Inténtelo de nuevo más tarde o póngase en contacto con el administrador del servidor si el problema persiste.",
"unexpected_ec_error":"Se produjo un error inesperado (<0> Código de error:</0><1>{{ errorCode }}</1> ) Por favor, contacta el administrador de su servidor."
},
"group_call_loader":{
"banned_body":"Has sido expulsado de la sala.",
"banned_heading":"Bloqueado",
"call_ended_body":"Te han retirado de la llamada.",
"call_ended_heading":"Llamada finalizada",
"knock_reject_body":"Su solicitud para unirse fue rechazada.",
"knock_reject_heading":"Acceso denegado",
"reason":"Razón:{{reason}}"
},
"handset":{
"overlay_back_button":"Volver al modo altavoz",
"overlay_description":"Solo funciona mientras se utiliza la aplicación.",
"overlay_title":"Modo teléfono"
},
"hangup_button_label":"Finalizar llamada",
"header_label":"Inicio de Element Call",
"header_participants_label":"Participantes",
"invite_modal":{
"link_copied_toast":"Enlace copiado al portapapeles",
"title":"Invita a esta llamada"
},
"join_existing_call_modal":{
"join_button":"Si, unirse a la llamada",
"text":"Esta llamada ya existe, ¿te gustaría unirte?",
"title":"¿Unirse a llamada existente?"
},
"layout_grid_label":"Grilla",
"layout_spotlight_label":"Foco",
"lobby":{
"join_button":"Unirse a la llamada"
"ask_to_join":"Solicitar unirse a la llamada",
"join_as_guest":"Unirse como invitado",
"join_button":"Unirse a la llamada",
"leave_button":"Volver a recientes",
"waiting_for_invite":"¡Solicitud enviada! Esperando permiso para unir..."
},
"log_in":"Iniciar sesión",
"logging_in":"Iniciando sesión…",
"login_auth_links":"<0>Crear una cuenta</0> o <2>Acceder como invitado</2>",
"login_auth_links_prompt":"¿Aún no se ha registrado?",
"body":"Otro usuario en esta llamada está teniendo problemas. Para diagnosticar estos problemas nos gustaría recopilar un registro de depuración.",
"title":"Petición de registros de depuración"
@@ -59,30 +172,83 @@
"rageshake_send_logs":"Enviar registros de depuración",
"rageshake_sending":"Enviando…",
"rageshake_sending_logs":"Enviando registros de depuración…",
"rageshake_sent":"¡Gracias!",
"recaptcha_dismissed":"Recaptcha cancelado",
"recaptcha_not_loaded":"No se ha cargado el Recaptcha",
"recaptcha_ssla_caption":"Este sitio está protegido por ReCAPTCHA y se aplican las <2> política de privacidad</2> y<6> Condiciones de servicio</6>de Google aplican.<9></9> Al hacer clic en \"Registrarse\", se acepta nuestros <12> Acuerdo de licencia de software y servicios (SSLA)</12>",
"return_home_button":"Volver a la pantalla de inicio",
"room_auth_view_continue_button":"Continuar",
"room_auth_view_ssla_caption":"Al hacer clic en \"Unirse a la llamada ahora\", acepta nuestros<2> Acuerdo de licencia de software y servicios (SSLA)</2>",
"screenshare_button_label":"Compartir pantalla",
"settings":{
"audio_tab":{
"effect_volume_description":"Ajusta el volumen al que se reproducen las reacciones y los efectos de subir la mano.",
"effect_volume_label":"Volumen de efectos de sonido"
},
"background_blur_header":"Fondo",
"background_blur_label":"Desenfocar el fondo del vídeo",
"blur_not_supported_by_browser":"(El desenfoque de fondo no esta sopportado de este dispositivo).",
"developer_tab_title":"Desarrollador",
"devices":{
"camera":"Cámara",
"camera_numbered":"Cámara {{n}}",
"change_device_button":"Cambiar dispositivo de audio",
"default":"Por defecto",
"default_named":"Por defecto<2> ({{name}})</2>",
"handset":"Dispositivo",
"loudspeaker":"Altavoz",
"microphone":"Micrófono",
"microphone_numbered":"Micrófono {{n}}",
"speaker":"Altavoz",
"speaker_numbered":"Altavoz {{n}}"
},
"feedback_tab_body":"Si tienes algún problema o simplemente quieres darnos tu opinión, por favor envíanos una breve descripción.",
"feedback_tab_send_logs_label":"Incluir registros de depuración",
"feedback_tab_thank_you":"¡Gracias, hemos recibido tus comentarios!",
"feedback_tab_title":"Danos tu opinión",
"opt_in_description":"<0></0><1></1>Puedes retirar tu consentimiento desmarcando esta casilla. Si estás en una llamada, este ajuste se aplicará al final de esta."
"opt_in_description":"<0></0><1></1>Puedes retirar tu consentimiento desmarcando esta casilla. Si estás en una llamada, este ajuste se aplicará al final de esta.",
"preferences_tab":{
"developer_mode_label":"Modo desarrollador",
"developer_mode_label_description":"Activa el modo de desarrollador y muestra la pestaña de configuración de desarrollador.",
"introduction":"Aquí puedes configurar opciones adicionales para una experiencia mejorada.",
"reactions_play_sound_description":"Reproduce un sonido cuando alguien envíe una reacción en una llamada.",
"reactions_play_sound_label":"Reproduce sonidos de reacción",
"reactions_show_description":"Muestra una animación cuando alguien envíe una reacción.",
"reactions_show_label":"Mostrar reacciones",
"show_hand_raised_timer_description":"Mostrar un temporizador cuando un participante levante la mano",
"show_hand_raised_timer_label":"Mostrar la duración de la subida de la mano"
"analytics_notice":"Nõustudes selle beetaversiooni kasutamisega, sa nõustud ka toote arendamiseks kasutatavate anonüümsete andmete kogumisega. Täpsemat teavet kogutavate andmete kohta leiad meie <2>Privaatsuspoliitikast</2> ja meie <6>Küpsiste kasutamise reeglitest</6>.",
"app_selection_modal":{
"continue_in_browser":"Jätka veebibrauseris",
"open_in_app":"Ava rakenduses",
"text":"Oled valmis liituma?",
"title":"Vali rakendus"
},
"call_ended_view":{
"create_account_button":"Loo konto",
"create_account_prompt":"<0>Kas soovid salasõna seadistada ja sellega oma kasutajakonto alles jätta?</0><1>Nii saad säilitada oma nime ja määrata profiilipildi, mida saad kasutada tulevastes kõnedes</1>",
@@ -55,44 +50,78 @@
"profile":"Profiil",
"reaction":"Reaktsioon",
"reactions":"Reageerimised",
"reconnecting":"Ühendan uuesti…",
"settings":"Seadistused",
"unencrypted":"Krüptimata",
"username":"Kasutajanimi",
"video":"Video"
},
"developer_mode":{
"always_show_iphone_earpiece":"Näita iPhone'i kuulari valikut kõikidel platvormidel",
"description":"Ühildub koduserveritega, mis ei toeta määratud kestusega sündmuseid (kuid kõik teised EC kliendid on v0.17.0 või hilisemad)",
"label":"Ühilduvus: olekusündmused ja mitu meediaedastusserverit (SFU)"
},
"Legacy":{
"description":"Ühildub EC vanemate versioonidega, millel puudub mitme meediaedastusserveri (SFU) tugi",
"label":"Vana lahendus: oleku üritused ja vanim meediaedastusserver (SFU)"
},
"Matrix_2_0":{
"description":"Ühildub ainult määratud kestusega sündmuseid toetavate koduserveritega ja kõigi EC-klientidega alates versioonist 0.17.0",
"label":"Matrix 2.0: määratud kestusega sündmused ja mitu meediaedastusserverit (SFU)"
},
"title":"MatrixRTC režiim"
},
"matrix_id":"Matrixi kasutajatunnus: {{id}}",
"mute_all_audio":"Summuta kõik helid (osalejad, regeerimised, liitumise helid)",
"show_connection_stats":"Näita ühenduse statistikat",
"show_non_member_tiles":"Näita ka mitteseotud meedia paane",
"url_params":"Võrguaadressi parameetrid",
"use_new_membership_manager":"Kasuta kõne liikmelisuse halduri (MembershipManager) uut implementatsiooni",
"use_to_device_key_transport":"Kasuta seadmepõhist krüptovõtmete vahetust. Kui jututoa liige peaks saatma jututoakohase krüptovõtme, siis kasuta jututoakohast võtmevahetust"
"url_params":"Võrguaadressi parameetrid"
},
"disconnected_banner":"Võrguühendus serveriga on katkenud.",
"error":{
"call_is_not_supported":"Kõne pole toetatud",
"call_not_found":"Kõnet ei leidu",
"call_not_found_description":"<0>See link ei tundu olema seotud ühegi olemasoleva kõnega. Kontrolli, et sul on õige link või <1>loo uus</1>.</0>",
"call_not_found_description":"<0>See link ei tundu olema seotud ühegi olemasoleva kõnega. Kontrolli, et sul on õige link või <2>loo uus</2>.</0>",
"connection_lost":"Ühendus on katkenud",
"connection_lost_description":"Sinu ühendus selle kõnega on katkenud.",
"e2ee_unsupported":"Mitteühilduv brauser",
"e2ee_unsupported_description":"Sinu veebibrauser ei toeta krüptitud kõnesid. Toimivad veebibrauserid on Chrome, Safari, ja Firefox 117+.",
"failed_to_start_livekit":"Ei õnnestunud käivitada Livekiti ühendust",
"generic":"Midagi läks valesti",
"generic_description":"Silumis- ja vealogide saatmine võib aidata meid vea põhjuseni jõuda.",
"insufficient_capacity":"Mittepiisav jõudlus",
"insufficient_capacity_description":"Serveri jõudluse ülempiir on hetkel ületatud ja sa ei saa hetkel selle kõnega liituda. Proovi hiljem uuesti või kui probleem kestab kauem, siis võta ühendust serveri haldajaga.",
"matrix_rtc_focus_missing":"See server pole seadistatud töötama rakendusega {{brand}}. Palun võta ühendust serveri halduriga (domeen: {{domain}}, veakood: {{ errorCode }}).",
"livekit_connection_error":"Livekiti serveriga ühendamine ei õnnestunud",
"livekit_connection_error_description":"Livekiti serveriga ühendamisel tekkis viga (<1>Põhjus: </1> <2>{{ reason }}</2>).",
"matrix_rtc_transport_missing":"See server pole seadistatud töötama rakendusega {{brand}}. Palun võta ühendust serveri halduriga (domeen: {{domain}}, veakood: {{ errorCode }}).",
"membership_manager_description":"Liikmelisuse haldur pidi oma töö lõpetama. Selle põhjuseks olid paljud järjestikused ebaõnnestunud võrgupäringud.",
"no_matrix_2_authorization_service":"Sinu meediaedastusserveri (SFU) autoriseerimisteenus on aegunud.",
"open_elsewhere":"Avatud teisel vahekaardil",
"open_elsewhere_description":"{{brand}} on avatud teisel vahekaardil. Kui see ei tundu olema õige, proovi selle lehe uuesti laadimist.",
"peer_connection_timeout":"Ühendus aegus",
"peer_connection_timeout_description":"Meediaserveriga ühenduspäring aegus. Proovi kasutada muud võrku või keelata VPN-i kasutamine. Kui probleem püsib, vaata meie <0> veaotsingu juhendit</0> või võta ühendust oma serveri peakasutajaga.",
"room_creation_restricted":"Kõne loomine ei õnnestunud",
"room_creation_restricted_description":"Kõne loomine võib olla lubatud ainult volitatud kasutajatele. Proovi hiljem uuesti või probleemi püsimisel võta ühendust oma serveri haldajaga.",
"sticky_events_required":"Koduserver ei toeta Matrix 2.0 kõnesid",
"sticky_events_required_description":"See server on seadistatud kasutama Matrix 2.0 kõnerežiimi, kuid koduserver ei teata, et tal selleks vajalike sündmuste (MSC4354) tugi. Palu serveri peakasutajal see uuendada või kasuta koduserveris ühilduvat režiimi.",
"overlay_description":"See toimib vaid rakenduse kasutamise ajal",
"overlay_title":"Telefonirežiim"
},
"hangup_button_label":"Lõpeta kõne",
"header_label":"Avaleht: Element Call",
"header_participants_label":"Osalejad",
@@ -118,6 +152,7 @@
},
"layout_grid_label":"Ruudustik",
"layout_spotlight_label":"Rambivalgus",
"layout_switch_label":"Paigutus",
"lobby":{
"ask_to_join":"Küsi võimalust liituda kõnega",
"join_as_guest":"Liitu külalisena",
@@ -170,10 +205,14 @@
"blur_not_supported_by_browser":"(Tausta hägustamine pole selles seadmes toetatud.)",
"developer_tab_title":"Arendaja",
"devices":{
"activating":"Aktiveerin…",
"camera":"Kaamera",
"camera_numbered":"Kaamera {{n}}",
"change_device_button":"Muuda heliseadet",
"default":"Vaikimisi",
"default_named":"Vaikimisi <2>({{name}})</2>",
"handset":"Telefon",
"loudspeaker":"Valjuhääldi",
"microphone":"Mikrofon",
"microphone_numbered":"Mikrofon {{n}}",
"speaker":"Kõlar",
@@ -206,6 +245,7 @@
"stop_video_button_label":"Peata videovoog",
"submitting":"Saadan…",
"switch_camera":"Vaheta kaamerat",
"technical_details":"Tehnilised üksikasjad",
"unauthenticated_view_body":"Sa pole veel registreerunud? <2>Loo kasutajakonto</2>",
"unauthenticated_view_login_button":"Logi oma kontosse sisse",
"unauthenticated_view_ssla_caption":"Klõpsides „Jätka“ nõustud sa meie <2>Tarkvara ja teenuste litsentseerimise lepinguga (Software and Services License Agreement - SSLA)</2>",
"analytics_notice":"Osallistumalla tähän betaan hyväksyt nimettömien tietojen keräämisen, joita käytämme tuotteen parantamiseen. Löydät lisätietoa siitä, mitä tietoja seuraamme meidän <2> Tietosuojakäytännöstä</2> ja <6>Evästekäytännöstä</6> .",
"app_selection_modal":{
"continue_in_browser":"Jatka selaimessa",
"open_in_app":"Avaa sovelluksessa",
"text":"Oletko valmis liittymään?",
"title":"Valitse sovellus"
},
"call_ended_view":{
"create_account_button":"Luo tili",
"create_account_prompt":"<0>Miksi et viimeistelisi määrittämällä salasanaa tilisi säilyttämiseksi?</0><1>Voit säilyttää nimesi ja asettaa avatarin käytettäväksi tulevissa puheluissa</1>",
@@ -55,13 +50,23 @@
"profile":"Profiili",
"reaction":"Reaktio",
"reactions":"Reaktiot",
"reconnecting":"Yhdistetään uudelleen...",
"settings":"Asetukset",
"unencrypted":"Ei salattu",
"username":"Käyttäjänimi",
"video":"Video"
},
"developer_mode":{
"always_show_iphone_earpiece":"Näytä iPhone korvakaiutinvaihtoehto kaikilla alustoilla",
"crypto_version":"Kryptoversio: {{version}}",
"custom_livekit_url":{
"current_url":"Tällä hetkellä asetettu: ",
"from_config":"Tällä hetkellä ei ole asetettu päällekirjoitusta. Käytetään URL-osoitetta well-known tiedostosta tai konfiguraatiosta.",
"description":"Yhteensopiva kotipalvelimien kanssa, jotka eivät tue tarttuvia tapahtumia (mutta kaikki muut EC-sovellukset ovat v0.17.0 tai uudempia)",
"label":"Yhteensopivuus: tilatapahtumat ja useat SFU:t"
},
"Legacy":{
"description":"Yhteensopiva vanhempien EC-versioiden kanssa, jotka eivät tue useita SFU:ita",
"label":"Vanha: tilatapahtumat ja vanhimman jäsenen SFU"
},
"Matrix_2_0":{
"description":"Yhteensopiva vain tarttuvia tapahtumia tukevien kotipalvelimien ja kaikkien EC-sovelluksien v0.17.0 tai uudempien kanssa",
"label":"Matrix 2.0: tarttuvat tapahtumat ja useat SFU:t"
},
"title":"MatrixRTC-tila"
},
"matrix_id":"Matrix tunnus: {{id}}",
"mute_all_audio":"Mykistä kaikki ääni (osallistujat, reaktiot, liittymisäänet)",
"use_new_membership_manager":"Käytä uutta puhelun MembershipManagerin toteutusta",
"use_to_device_key_transport":"Käytä laitteen avainten kuljetusta. Tämä palaa huoneen avainten siirtoon, kun toinen puhelun jäsen lähettää huoneavaimen"
"url_params":"URL-parametrit"
},
"disconnected_banner":"Yhteys palvelimeen on katkennut.",
"error":{
"call_is_not_supported":"Puhelua ei tueta",
"call_not_found":"Puhelua ei löydy",
"call_not_found_description":"<0>Kyseinen linkki ei näytä kuuluvan mihinkään olemassa olevaan puheluun. Tarkista, että sinulla on oikea linkki, tai <1>luo uusi linkki</1>.</0>",
"call_not_found_description":"<0>Kyseinen linkki ei näytä kuuluvan mihinkään olemassa olevaan puheluun. Tarkista, että sinulla on oikea linkki, tai <2>luo uusi linkki</2>.</0>",
"insufficient_capacity_description":"Palvelin on saavuttanut maksimikapasiteettinsa, etkä voi liittyä puheluun tällä hetkellä. Yritä myöhemmin uudelleen tai ota yhteyttä palvelimen ylläpitäjään, jos ongelma jatkuu.",
"matrix_rtc_focus_missing":"Palvelinta ei ole määritetty toimimaan {{brand}} -sovelluksen kanssa. Ota yhteyttä palvelimen ylläpitäjään (Verkkotunnus: {{domain}}, Virhekoodi: {{ errorCode }}).",
"livekit_connection_error_description":"Livekit-palvelimeen yhteyden muodostamisessa tapahtui virhe (<1>Syy: </1> <2>{{ reason }}</2>).",
"matrix_rtc_transport_missing":"Palvelinta ei ole määritetty toimimaan {{brand}} -sovelluksen kanssa. Ota yhteyttä palvelimen ylläpitäjään (Verkkotunnus: {{domain}}, Virhekoodi: {{ errorCode }}).",
"membership_manager":"Jäsenyydenhallinnan virhe",
"membership_manager_description":"Jäsenyyshallinta jouduttiin sulkemaan. Tämä johtui useista peräkkäisistä epäonnistuneista verkkopyynnöistä.",
"no_matrix_2_authorization_service":"Mediapalvelimesi (SFU) valtuutuspalvelu on vanhentunut.",
"open_elsewhere":"Avattu toisessa välilehdessä",
"open_elsewhere_description":"{{brand}} on avattu toisessa välilehdessä. Jos tämä ei kuulosta oikealta, yritä ladata sivu uudelleen.",
"peer_connection_timeout_description":"Yhteys mediapalvelimeen aikakatkaistiin. Kokeile vaihtaa verkkoa tai poistaa VPN käytöstä. Jos ongelma jatkuu, katso <0>vianetsintäoppaamme</0> tai ota yhteyttä palvelimesi ylläpitäjään.",
"room_creation_restricted_description":"Puheluiden luominen saattaa olla rajoitettu vain valtuutetuille käyttäjille. Yritä myöhemmin uudelleen tai ota yhteyttä palvelimen ylläpitäjään, jos ongelma jatkuu.",
"sticky_events_required":"Kotipalvelin ei tue Matrix 2.0 -puheluita",
"sticky_events_required_description":"Tämä asennus on määritetty käyttämään Matrix 2.0 -puhelutilaa, mutta kotipalvelin ei mainosta tukea tarttuville tapahtumille (MSC4354). Pyydä palvelimen järjestelmänvalvojaa päivittämään tai vaihtamaan asennus yhteensopivaan tilaan.",
"unexpected_ec_error":"Tapahtui odottamaton virhe (<0>Virhekoodi:</0> <1>{{ errorCode }}</1>). Ota yhteyttä palvelimen ylläpitäjään."
},
"group_call_loader":{
@@ -103,6 +133,11 @@
"knock_reject_heading":"Pääsy kielletty",
"reason":"Syy: {{reason}}"
},
"handset":{
"overlay_back_button":"Takaisin kaiutintilaan",
"overlay_description":"Toimii vain sovellusta käytettäessä",
"overlay_title":"Luuritila"
},
"hangup_button_label":"Lopeta puhelu",
"header_label":"Element Call Etusivu",
"header_participants_label":"Osallistujat",
@@ -117,6 +152,7 @@
},
"layout_grid_label":"Ruudukko",
"layout_spotlight_label":"Valokeila",
"layout_switch_label":"Asettelu",
"lobby":{
"ask_to_join":"Pyydä liittymistä puheluun",
"join_as_guest":"Liity vieraana",
@@ -169,10 +205,14 @@
"blur_not_supported_by_browser":"(Tämä laite ei tue taustan sumennusta.)",
"developer_tab_title":"Kehittäjä",
"devices":{
"activating":"Aktivoidaan…",
"camera":"Kamera",
"camera_numbered":"Kamera {{n}}",
"change_device_button":"Vaihda äänilaite",
"default":"Oletus",
"default_named":"Oletus <2>({{name}})</2>",
"handset":"Luuri",
"loudspeaker":"Kaiutin",
"microphone":"Mikrofoni",
"microphone_numbered":"Mikrofoni {{n}}",
"speaker":"Kaiutin",
@@ -205,6 +245,7 @@
"stop_video_button_label":"Lopeta video",
"submitting":"Lähetetään…",
"switch_camera":"Vaihda kameraa",
"technical_details":"Tekniset tiedot",
"unauthenticated_view_body":"Etkö ole vielä rekisteröitynyt? <2>Luo tili</2>",
"analytics_notice":"En participant à cette beta, vous consentez à la collecte de données anonymes, qui seront utilisées pour améliorer le produit. Vous trouverez plus d’informations sur les données collectées dans notre <2>Politique de vie privée</2> et notre <5>Politique de cookies</5>.",
"app_selection_modal":{
"continue_in_browser":"Continuer dans le navigateur",
"open_in_app":"Ouvrir dans l’application",
"text":"Prêt à rejoindre?",
"title":"Choisissez l’application"
},
"call_ended_view":{
"create_account_button":"Créer un compte",
"create_account_prompt":"<0>Pourquoi ne pas créer un mot de passe pour conserver votre compte?</0><1>Vous pourrez garder votre nom et définir un avatar pour vos futurs appels</1>",
@@ -33,20 +34,67 @@
},
"call_name":"Nom de l’appel",
"common":{
"analytics":"Statistiques d'utilisation",
"audio":"Audio",
"avatar":"Avatar",
"back":"Retour",
"display_name":"Nom d’affichage",
"encrypted":"Chiffré",
"home":"Accueil",
"loading":"Chargement…",
"next":"Suivant",
"options":"Options",
"password":"Mot de passe",
"preferences":"Préférences",
"profile":"Profil",
"reaction":"Réaction",
"reactions":"Réactions",
"reconnecting":"Reconnexion",
"settings":"Paramètres",
"unencrypted":"Non chiffré",
"username":"Nom d’utilisateur",
"video":"Vidéo"
},
"developer_mode":{
"always_show_iphone_earpiece":"Afficher l'option écouteur iPhone sur toutes les plateformes",
"crypto_version":"Version crypto: {{version}}",
"debug_tile_layout_label":"Disposition des tuiles de débogage",
"device_id":"Id. de l'appareil",
"duplicate_tiles_label":"Nombre de copies de tuiles supplémentaires par participant",
"mute_all_audio":"Couper tous les sons (participants, réactions, sons de participation)",
"show_connection_stats":"Afficher les statistiques de connexion",
"url_params":"Paramètres d'URL"
},
"disconnected_banner":"La connexion avec le serveur a été perdue.",
"error":{
"call_is_not_supported":"L'appel n'est pas pris en charge",
"call_not_found":"Appel non trouvé",
"call_not_found_description":"<0>Ce ne correspond à aucun appel existant. Vérifier que vous avez le bon lien, ou <1>créer un nouveau</1>.</0>",
"connection_lost":"Connexion perdue",
"connection_lost_description":"Vous avez été déconnecté de l’appel",
"e2ee_unsupported":"Moteur de recherche incompatible",
"generic":"Un problème est survenu",
"insufficient_capacity":"Capacité insuffisante",
"insufficient_capacity_description":"Le serveur a atteint sa capacité maximale et vous ne pouvez pas rejoindre l'appel pour le moment. Veuillez réessayer plus tard ou contacter l'administrateur du serveur si le problème persiste.",
"unexpected_ec_error":"Une erreur inattendue s'est produite (<0>Code d'erreur :</0> <1>{{ errorCode }}</1>). Veuillez contacter l'administrateur de votre serveur."
},
"group_call_loader":{
"banned_body":"Vous avez été banni du salon.",
"banned_heading":"Banni",
"call_ended_body":"Vous avez été retiré de l’appel.",
"call_ended_heading":"Appel terminé",
"knock_reject_body":"Les membres du salon ont refusé votre demande de participation.",
"knock_reject_heading":"Non autorisé à rejoindre",
"reason":"Motif"
},
"hangup_button_label":"Terminer l’appel",
"header_label":"Accueil Element Call",
"header_participants_label":"Participants",
"invite_modal":{
"link_copied_toast":"Lien copié dans le presse-papier",
"title":"Inviter dans cet appel"
@@ -59,15 +107,24 @@
"layout_grid_label":"Grille",
"layout_spotlight_label":"Premier plan",
"lobby":{
"ask_to_join":"Demandez à rejoindre l'appel",
"join_as_guest":"Rejoindre en tant qu'invité",
"join_button":"Rejoindre l’appel",
"leave_button":"Revenir à l’historique des appels"
"leave_button":"Revenir à l’historique des appels",
"waiting_for_invite":"Demande envoyée"
},
"log_in":"Se connecter",
"logging_in":"Connexion…",
"login_auth_links":"<0>Créer un compte</0> Or <2>Accès invité</2>",
"login_auth_links_prompt":"Pas encore inscrit?",
"login_subheading":"Pour continuer vers Element",
"login_title":"Connexion",
"microphone_off":"Microphone éteint",
"microphone_on":"Microphone allumé",
"mute_microphone_button_label":"Couper le microphone",
"participant_count_one":"{{count, number}}",
"participant_count_other":"{{count, number}}",
"qr_code":"Code QR",
"rageshake_button_error_caption":"Réessayer d’envoyer les journaux",
"rageshake_request_modal":{
"body":"Un autre utilisateur dans cet appel a un problème. Pour nous permettre de résoudre le problème, nous aimerions récupérer un journal de débogage.",
@@ -85,17 +142,33 @@
},
"register_auth_links":"<0>Vous avez déjà un compte?</0><1><0>Se connecter</0> Ou <2>Accès invité</2></1>",
"register_confirm_password_label":"Confirmer le mot de passe",
"register_heading":"Créer votre compte",
"return_home_button":"Retour à l’accueil",
"room_auth_view_continue_button":"Continuer",
"screenshare_button_label":"Partage d’écran",
"settings":{
"audio_tab":{
"effect_volume_description":"Régler le volume des effets de réactions et de mains levées.",
"effect_volume_label":"Volume des effets sonores"
},
"background_blur_label":"Flouter l'arrière-plan de la vidéo",
"blur_not_supported_by_browser":"(Le flou d'arrière-plan n'est pas pris en charge par cet appareil.)",
"developer_tab_title":"Développeur",
"devices":{
"speaker_numbered":"Haut-parleur {{n}}"
},
"feedback_tab_body":"Si vous rencontrez des problèmes, ou vous voulez simplement faire un commentaire, faites-en une courte description ci-dessous.",
"feedback_tab_send_logs_label":"Inclure les journaux de débogage",
"feedback_tab_thank_you":"Merci, nous avons reçu vos commentaires!",
"feedback_tab_title":"Commentaires",
"opt_in_description":"<0></0><1></1>Vous pouvez retirer votre consentement en décochant cette case. Si vous êtes actuellement en communication, ce paramètre prendra effet à la fin de l’appel."
"opt_in_description":"<0></0><1></1>Vous pouvez retirer votre consentement en décochant cette case. Si vous êtes actuellement en communication, ce paramètre prendra effet à la fin de l’appel.",
"preferences_tab":{
"reactions_play_sound_label":"Jouer le son des réactions",
"reactions_show_label":"Afficher les réactions",
"show_hand_raised_timer_label":"Afficher la durée de la main levée"
"analytics_notice":"Dengan bergabung dalam beta ini, Anda mengizinkan kami untuk mengumpulkan data anonim, yang kami gunakan untuk meningkatkan produk ini. Anda dapat mempelajari lebih lanjut tentang data apa yang kami lacak dalam <2>Kebijakan Privasi</2> dan <5>Kebijakan Kuki</5> kami.",
"app_selection_modal":{
"continue_in_browser":"Lanjutkan dalam peramban",
"open_in_app":"Buka dalam aplikasi",
"text":"Siap untuk bergabung?",
"title":"Pilih plikasi"
},
"analytics_notice":"Dengan bergabung dalam beta ini, Anda mengizinkan kami untuk mengumpulkan data anonim, yang kami gunakan untuk meningkatkan produk ini. Anda dapat mempelajari lebih lanjut tentang data apa yang kami lacak dalam <2>Kebijakan Privasi</2> dan <6>Kebijakan Kuki</6> kami.",
"call_ended_view":{
"create_account_button":"Buat akun",
"create_account_prompt":"<0>Kenapa tidak selesaikan dengan mengatur sebuah kata sandi untuk menjaga akun Anda?</0><1>Anda akan dapat tetap menggunakan nama Anda dan atur sebuah avatar untuk digunakan dalam panggilan di masa mendatang</1>",
@@ -55,12 +49,14 @@
"profile":"Profil",
"reaction":"Reaksi",
"reactions":"Reaksi",
"reconnecting":"Menghubungkan kembali…",
"settings":"Pengaturan",
"unencrypted":"Tidak terenkripsi",
"username":"Nama pengguna",
"video":"Video"
},
"developer_mode":{
"always_show_iphone_earpiece":"Tampilkan opsi lubang suara iPhone di semua platform",
"mute_all_audio":"Bisukan semua audio (suara peserta, reaksi, bergabung)",
"show_connection_stats":"Tampilkan statistik koneksi",
"show_non_member_tiles":"Tampilkan ubin untuk media non-anggota",
"url_params":"Parameter URL",
"use_new_membership_manager":"Gunakan implementasi baru dari panggilan MembershipManager",
"use_to_device_key_transport":"Gunakan untuk transportasi kunci perangkat. Ini akan kembali ke transportasi kunci ruangan ketika anggota panggilan lain mengirim kunci ruangan"
"url_params":"Parameter URL"
},
"disconnected_banner":"Koneksi ke server telah hilang.",
"error":{
"call_is_not_supported":"Panggilan tidak didukung",
"call_not_found":"Panggilan tidak ditemukan",
"call_not_found_description":"<0>Tautan itu tampaknya bukan milik panggilan yang ada. Periksa apakah Anda memiliki tautan yang tepat, atau <1> buat yang baru</1>.</0>",
"call_not_found_description":"<0>Tautan itu tampaknya bukan milik panggilan yang ada. Periksa apakah Anda memiliki tautan yang tepat, atau <2> buat yang baru</2>.</0>",
"connection_lost":"Koneksi terputus",
"connection_lost_description":"Anda terputus dari panggilan.",
"e2ee_unsupported":"Peramban tidak kompatibel",
@@ -89,9 +83,10 @@
"generic_description":"Mengirimkan log awakutu akan membantu kami melacak masalah.",
"insufficient_capacity":"Kapasitas tidak mencukupi",
"insufficient_capacity_description":"Server telah mencapai kapasitas maksimum dan Anda tidak dapat bergabung dalam panggilan saat ini. Coba lagi nanti, atau hubungi admin server Anda jika masalah masih berlanjut.",
"matrix_rtc_focus_missing":"Server tidak dikonfigurasi untuk bekerja dengan {{brand}}. Silakan hubungi admin server Anda (Domain: {{domain}}, Kode Kesalahan: {{ errorCode }}).",
"open_elsewhere":"Dibuka di tab lain",
"open_elsewhere_description":"{{brand}} telah dibuka di tab lain. Jika sepertinya tidak benar, coba muat ulang halaman.",
"room_creation_restricted":"Gagal membuat panggilan",
"room_creation_restricted_description":"Pembuatan panggilan mungkin hanya terbatas untuk pengguna yang diizinkan. Coba lagi nanti, atau hubungi admin server Anda jika masalah berlanjut.",
"unexpected_ec_error":"Terjadi kesalahan tak terduga (<0> Kode Kesalahan:</0><1>{{ errorCode }}</1>). Silakan hubungi admin server Anda."
},
"group_call_loader":{
@@ -103,6 +98,11 @@
"knock_reject_heading":"Akses ditolak",
"reason":"Alasan: {{reason}}"
},
"handset":{
"overlay_back_button":"Kembali ke Mode Pembicara",
"overlay_description":"Hanya berfungsi saat menggunakan aplikasi",
"analytics_notice":"Partecipando a questa beta, acconsenti alla raccolta di dati anonimi che usiamo per migliorare il prodotto. Puoi trovare più informazioni su quali dati monitoriamo nella nostra <2>informativa sulla privacy</2> e nell'<5>informativa sui cookie</5>.",
"app_selection_modal":{
"continue_in_browser":"Continua nel browser",
"open_in_app":"Apri nell'app",
"text":"Tutto pronto per entrare?",
"title":"Seleziona app"
},
"analytics_notice":"Partecipando a questa beta, acconsenti alla raccolta di dati anonimi che usiamo per migliorare il prodotto. Puoi trovare più informazioni su quali dati monitoriamo nella nostra <2>informativa sulla privacy</2> e nell'<6>informativa sui cookie</6>.",
"call_ended_view":{
"create_account_button":"Crea profilo",
"create_account_prompt":"<0>Ti va di terminare impostando una password per mantenere il profilo?</0><1>Potrai mantenere il tuo nome e impostare un avatar da usare in chiamate future</1>",
@@ -55,23 +49,49 @@
"profile":"Profilo",
"reaction":"Reazione",
"reactions":"Reazioni",
"reconnecting":"Riconnessione…",
"settings":"Impostazioni",
"unencrypted":"Non cifrata",
"username":"Nome utente",
"video":"Video"
},
"developer_mode":{
"always_show_iphone_earpiece":"Mostra l'opzione auricolare iPhone su tutte le piattaforme",
"from_config":"Al momento non è impostata alcuna sovrascrittura. Viene usato l'URL da well-known o config.",
"label":"URL Livekit personalizzato",
"reset":"Reimposta sovrascrittura",
"save":"Salva",
"saving":"Salvataggio..."
},
"debug_tile_layout_label":"Debug della disposizione dei riquadri",
"device_id":"ID dispositivo: {{id}}",
"duplicate_tiles_label":"Numero di copie di riquadri aggiuntivi per partecipante",
"environment_variables":"Variabili di ambiente",
"hostname":"Nome host: {{hostname}}",
"livekit_server_info":"Informazioni sul server LiveKit",
"livekit_sfu":"SFU LiveKit: {{url}}",
"matrixRTCMode":{
"Comptibility":{
"description":"Compatibile con homeserver che non supportano eventi sticky (ma tutte le altre applicazioni EC sono alla v0.17.0 o successive)",
"label":"Compatibilità: eventi di stato e multi SFU"
},
"Legacy":{
"description":"Compatibile con le vecchie versioni di EC che non supportano multi SFU",
"label":"Classico: event di stato e appartenenza più antica alla SFU"
},
"Matrix_2_0":{
"description":"Compatibile solo con homeserver che supportano eventi sticky e tutte le applicazioni EC alla v0.17.0 o successive",
"label":"Matrix 2.0: eventi sticky e multi SFU"
},
"title":"Modalità MatrixRTC"
},
"matrix_id":"ID Matrix: {{id}}",
"mute_all_audio":"Disattiva tutti gli audio (partecipanti, reazioni, suoni di partecipazione)",
"show_connection_stats":"Mostra le statistiche di connessione",
"show_non_member_tiles":"Mostra i riquadri per i file multimediali non-membri",
"use_new_membership_manager":"Usa la nuova implementazione della chiamata MembershipManager"
"url_params":"Parametri URL"
},
"disconnected_banner":"La connessione al server è stata persa.",
"error":{
@@ -82,13 +102,18 @@
"connection_lost_description":"Sei stato disconnesso dalla chiamata.",
"e2ee_unsupported":"Browser incompatibile",
"e2ee_unsupported_description":"Il tuo browser non supporta le chiamate crittografate. I browser supportati sono Chrome, Safari e Firefox 117+.",
"failed_to_start_livekit":"Impossibile avviare la connessione Livekit",
"generic":"Qualcosa è andato storto",
"generic_description":"L'invio dei registri di debug ci aiuterà a rintracciare il problema.",
"insufficient_capacity":"Capacità insufficiente",
"insufficient_capacity_description":"Il server ha raggiunto la capacità massima e non è possibile partecipare alla chiamata in questo momento. Riprova più tardi o contatta l'amministratore del server se il problema persiste.",
"matrix_rtc_focus_missing":"Il server non è configurato per funzionare con {{brand}}. Contatta l'amministratore del tuo server (Dominio: {{domain}}, codice di errore: {{ errorCode }}).",
"matrix_rtc_transport_missing":"Il server non è configurato per funzionare con {{brand}}. Contatta l'amministratore del tuo server (Dominio: {{domain}}, codice di errore: {{ errorCode }}).",
"membership_manager":"Errore del gestore dei membri",
"membership_manager_description":"Il gestore dei membri ha dovuto chiudersi. Ciò è stato causato da numerose richieste di rete consecutive non riuscite.",
"open_elsewhere":"Aperto in un'altra scheda",
"open_elsewhere_description":"{{brand}} è stato aperto in un'altra scheda. Se non ti sembra corretto, prova a ricaricare la pagina.",
"room_creation_restricted":"Impossibile creare la chiamata",
"room_creation_restricted_description":"La creazione di chiamate potrebbe essere limitata solo agli utenti autorizzati. Riprova più tardi o contatta l'amministratore del server se il problema persiste.",
"unexpected_ec_error":"Si è verificato un errore imprevisto (<0>Codice errore:</0> <1>{{ errorCode }}</1>). Contatta l'amministratore del tuo server."
},
"group_call_loader":{
@@ -100,6 +125,11 @@
"knock_reject_heading":"Partecipazione non consentita",
"reason":"Motivo"
},
"handset":{
"overlay_back_button":"Torna alla modalità altoparlante",
"overlay_description":"Funziona solo mentre si usa l'app",
"overlay_title":"Modalità cornetta"
},
"hangup_button_label":"Termina chiamata",
"header_label":"Inizio di Element Call",
"header_participants_label":"Partecipanti",
@@ -144,6 +174,7 @@
"rageshake_sent":"Grazie!",
"recaptcha_dismissed":"Recaptcha annullato",
"recaptcha_not_loaded":"Recaptcha non caricato",
"recaptcha_ssla_caption":"Questo sito è protetto da ReCAPTCHA e si applicano l'<2>informativa sulla privacy</2> e i <6>termini di servizio</6> di Google.<9></9>Cliccando \"Registra\", accetti il nostro <12>Software and Services License Agreement (SSLA)</12>",
"analytics_notice":"Piedaloties šajā beta versijā, jūs piekrītat anonīmu datu vākšanai, ko mēs izmantojam produkta uzlabošanai. Plašāku informāciju par to, kādus datus mēs izsekojam, varat atrast mūsu <2>konfidencialitātes politikā</2> un mūsu <6>sīkfailu politikā</6>.",
"app_selection_modal":{
"continue_in_browser":"Turpināt pārlūkprogrammā",
"open_in_app":"Atvērt lietotnē",
"text":"Gatavs pievienoties?",
"title":"Izvēlies lietotni"
},
"call_ended_view":{
"create_account_button":"Izveidot kontu",
"create_account_prompt":"<0>Kādēļ nepabeigt ar paroles iestatīšanu, lai paturētu savu kontu?</0><1>Būs iespējams paturēt savu vārdu un iestatīt attēlu izmantošanai turpmākajos zvanos</1>",
"show_non_member_tiles":"Rādīt vietu medijiem no ne-dalībniekiem",
"url_params":"URL parametri",
"use_new_membership_manager":"Izmantojiet jauno zvana MembershipManager versiju"
"url_params":"URL parametri"
},
"disconnected_banner":"Ir zaudēts savienojums ar serveri.",
"error":{
@@ -84,13 +102,19 @@
"connection_lost_description":"Jūs tikāt atvienots no zvana.",
"e2ee_unsupported":"Nesaderīgs pārlūks",
"e2ee_unsupported_description":"Jūsu tīmekļa pārlūkprogramma neatbalsta encrypted zvanus. Atbalstītās pārlūkprogrammas ir Chrome, Safari un Firefox 117+.",
"generic_description":"Atkļūdošanas žurnālu iesniegšana palīdzēs mums izsekot problēmu.",
"insufficient_capacity":"Nepietiekama jauda",
"insufficient_capacity_description":"Serveris ir sasniedzis maksimālo ietilpību, un jūs šobrīd nevarat pievienoties zvanam. Mēģiniet vēlreiz vēlāk vai sazinieties ar servera administratoru, ja problēma joprojām pastāv.",
"matrix_rtc_focus_missing":"Serveris nav konfigurēts darbam ar{{brand}}. Lūdzu, sazinieties ar sava servera administratoru (Domēns: {{domain}}, Kļūdas kods: {{ errorCode }}).",
"matrix_rtc_transport_missing":"Serveris nav konfigurēts darbam ar{{brand}}. Lūdzu, sazinieties ar sava servera administratoru (Domēns: {{domain}}, Kļūdas kods: {{ errorCode }}).",
"membership_manager_description":"Dalības pārvaldnieks bija jāslēdz. To izraisīja daudzi secīgi, neveiksmīgi tīkla pieprasījumi.",
"no_matrix_2_authorization_service":"Jūsu multivides servera (SFU) autorizācijas pakalpojums ir novecojis.",
"open_elsewhere":"Atvērts citā cilnē",
"open_elsewhere_description":"{{brand}} ir atvērts citā cilnē. Ja tas neizklausās pareizi, mēģiniet atkārtoti ielādēt lapu.",
"room_creation_restricted":"Neizdevās izveidot zvanu",
"room_creation_restricted_description":"Zvanu izveide, iespējams, ir atļauta tikai pilnvarotiem lietotājiem. Mēģiniet vēlreiz vēlāk vai sazinieties ar servera administratoru, ja problēma joprojām pastāv.",
"analytics_notice":"Door deel te nemen aan deze bètaversie stemt u in met het verzamelen van anonieme gegevens, die we gebruiken om het product te verbeteren. Meer informatie over welke gegevens we bijhouden, vindt u in ons privacybeleid <2>Privacybeleid</2> en ons cookiebeleid <6>Cookiebeleid</6>.",
"call_ended_view":{
"create_account_button":"Account aanmaken",
"create_account_prompt":"<0>Waarom sluit u niet af met het instellen van een wachtwoord om uw account te bewaren?</0><1>U kunt uw naam behouden en een avatar instellen voor gebruik bij toekomstige gesprekken.</1>",
"feedback_done":"<0>Bedankt voor je feedback!</0>",
"feedback_prompt":"<0>We horen graag uw feedback, zodat we uw ervaring kunnen verbeteren.</0>",
"headline":"{{displayName}}, uw gesprek is beëindigd.",
"not_now_button":"Niet nu, ga terug naar het startscherm.",
"reconnect_button":"Opnieuw verbinden",
"survey_prompt":"Hoe is het gegaan?"
},
"call_name":"Naam van de oproep",
"common":{
"analytics":"Statistieken",
"audio":"Audio",
"avatar":"Avatar",
"back":"Terug",
"display_name":"Weergavenaam",
"encrypted":"Versleuteld",
"home":"Startpagina",
"loading":"Bezig met laden...",
"next":"Volgende",
"options":"Opties",
"password":"Wachtwoord",
"preferences":"Voorkeuren",
"profile":"Profiel",
"reaction":"Reactie",
"reactions":"Reacties",
"reconnecting":"Opnieuw verbinden...",
"settings":"Instellingen",
"unencrypted":"Niet versleuteld",
"username":"Gebruikersnaam",
"video":"Video"
},
"developer_mode":{
"always_show_iphone_earpiece":"iPhone-oortelefoonoptie op alle platformen weergeven",
"custom_livekit_url":{
"save":"Opslaan",
"saving":"Bezig met opslaan..."
},
"matrixRTCMode":{
"title":"MatrixRTC modus"
},
"matrix_id":"Matrix ID:{{id}}",
"mute_all_audio":"Alle audio dempen (deelnemers, reacties, geluiden bij deelname)",
"matrix_rtc_transport_missing":"De server is niet geconfigureerd om te werken met {{brand}}. Neem contact op met uw serverbeheerder (Domein: {{domain}}, Foutcode: {{ errorCode }}).",
"no_matrix_2_authorization_service":"De autorisatieservice voor uw mediaserver (SFU) is verouderd."
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.