Compare commits

...

74 Commits

Author SHA1 Message Date
Vlad Piersec
0bf52b613b feat(api): Expose event used for sending browser support 2021-09-22 09:20:56 +03:00
robertpin
584ec7c82e fix(reactions) Reactions improvements (#9964)
* Register shortcuts on mount

* Changed icon for reactions menu

* Enable reactions by default

* Fix unreadCount bug

When having unread messages and sending a reaction the unread count now shows the correct count

* Fix overflow menu bottom color when reactions are enabled

* Revert raise hand icon

* Update raise hand functionality

On desktop show raise button with arrow for reactions. Only show raise hand in the reactions menu on mobile

* Fix lint error

Add required prop to ToolboxButtonWithIcon

* Legacy support for enable reactions

If disableReactions is undefined treat it as true

* Remove unnecessary code

* Fix unread counter showing negative count

* Fix unreadCount with reactions

UnreadCount ignores all reactions messages

* Fixed typo

* Fix background color
2021-09-21 12:30:24 -05:00
robertpin
5f5cac0e01 fix(config,notifications) fix rendering moderator notifications (#9986)
Move DISABLE_FOCUS_INDICATOR from interface_config.js to config.js (disableModeratorIndicator).
2021-09-21 17:38:06 +02:00
Vlad Piersec
0a9b9bb41d fix(responsive-ui): Shrink self view when in portrait mode on mobile web 2021-09-21 16:47:47 +03:00
tmoldovan8x8
5ad98d193a feat(e2ee) disable e2ee when large number of participants 2021-09-21 14:00:23 +03:00
Дамян Минков
4cd5be9d8b chore(deps) lib-jitsi-meet@latest
* fix(JitsiConference) Check for room before calling isFocus method on the room object.
* fix(Jingle) Reverse the order of ssrcs signaled for Firefox. This fixes an issue where the bridge doesn't forward the HD stream from Firefox to other users in the call. The order of the ssrcs produced by the browser is from Highest resolution to lowest whereas the bridge assumes it to be from lowest to highest as is the case in Chrome and Safari.
* fix(codec-selection): Impose VP9 bitrates only when VP9 is the negotiated codec. If Jicofo doesn't offer VP9 but the client expresses a preference for VP9, VP9 bitrates were being imposed before.

609e3d5a1a...3b8baa9d3b
2021-09-20 17:35:08 -05:00
Horatiu Muresan
5514be630d feat(conference-info-header) Make conference info header configurable. (#9638) 2021-09-20 21:12:56 +03:00
hmuresan
6a6146727f fix(notifications) Fix recording start notif not disappearing 2021-09-20 19:08:12 +03:00
Avram Tudor
52e9e90b3a fix(jaas) do not show overriden unsupported browser page for jaas users (#9962) 2021-09-20 11:38:46 +03:00
Alexey Matveev
7ff3b669ee fix(lang) update Russian translation
Co-authored-by: Alexey Matveev <malex@1forma.ru>
2021-09-18 11:15:13 +02:00
Hristo Terezov
e791c4f70c fix(recorder): tile view
In the case of the recorder we were not taking into account that the
local thumbnail is not visible. This was braking the rendering  and
positioning of the thumbnails in tile view.
2021-09-17 18:20:00 -05:00
Дамян Минков
fc75fd9644 chore(deps) lib-jitsi-meet@latest
* fix: Reads shard name and from disco-info if available.
* chore(deps): bump sdp-interop to get another fix for ICE restart
* update sdp-interop to include Unified ICE restart fix

fbf85bdcec...609e3d5a1a
2021-09-17 15:51:23 -05:00
Дамян Минков
62e5d6c139 fix: Fixes undefined error causing to stop reloads.
Jibri was hitting a problem where it reloads and in certain cases (remote user is screensharing) we hit this participant undefined, which stops reload and stops recording.
It is still not obvious why we try to render this on leaving the conference and for a participant that is not in the conference ... this re-render should not happen as this component should be removed from its parent when the participant is not existing.
2021-09-17 15:04:32 -05:00
Saúl Ibarra Corretgé
06d8956bdb android: fix initializing soloader from Activity context
It has to be an application context.
2021-09-17 13:43:45 +02:00
Avram Tudor
adbb5f8ead fix(prejoin) implement ux improvements for mobile (#9939) 2021-09-17 13:12:34 +03:00
Hristo Terezov
32ed2bccec fix(Filmstrip) fix not being able to scroll 2021-09-17 11:22:20 +02:00
Jaya Allamsetty
58d98ad7d3 fix(device-selection) Do not create preview when mic selection is disabled.
This fixes an issue on mobile Safari when audio is lost after the user opens the device selection menu.
2021-09-16 15:41:44 -04:00
Vlad Piersec
e278703c58 fix(context-menus) Don't show volume slider on iOS web 2021-09-16 14:56:55 +03:00
Jaya Allamsetty
042a2cb447 fix(filmstrip) Fix filmstrip on RN when thumbnail reordering is disabled. 2021-09-15 11:29:46 -05:00
Saúl Ibarra Corretgé
a8f281a43e feat((rn,config) add a/b test flag to enable XMPP WebSockets on mobile 2021-09-15 15:26:25 +02:00
paweldomas
663752be2c feat(rn,connection) enable XMPP WebSocket on mobile
Co-authored-by: Saúl Ibarra Corretgé <saghul@jitsi.org>
2021-09-15 15:26:25 +02:00
Vlad Piersec
380ef3da0b fix(feedback): Scroll to the top when opening feedback dialog 2021-09-15 15:21:56 +03:00
Saúl Ibarra Corretgé
07da5940a5 fix(rn,conference) show underlay when tapping navbar buttons 2021-09-15 13:35:33 +02:00
robertpin
ab366b9d94 fix(av-moderation) Advanced moderation improvements (#9935)
* Update moderation in effect notifications

Only display one notification for each media type. Display notification for keyboard shortcuts as well

* Update muted remotely notification

Display name of moderator in the notification

* Fix indentation on moderation menu

* Update text for video moderation

* Added moderator label in participant pane

* Update microphone icon in participant list

For participants that speak, or are noisy, but aren't dominant speaker, the icon in the participant list will look the same as the dominant speaker icon but will not change their position in the list

* Added sound for asked to unmute notification

* Code review changes

* Code review changes

Use simple var instead of function for audio media state

* Move constants to constants file

* Moved constants from notifications to av-moderation
2021-09-15 11:28:44 +03:00
Pawel Domas
bba1917820 fix(conference.js): add tracks to the conference 2021-09-14 18:24:45 -04:00
Saúl Ibarra Corretgé
0833f8c867 feat(rn,conference) show invite button on the top navbar 2021-09-14 15:03:24 +02:00
Saúl Ibarra Corretgé
3bf9c41f08 fix(rn,conference) count fake participants when checking if lonely meeting
A shared video participant counts, so the lonely meeting invite options can
disappear.
2021-09-14 12:50:22 +02:00
Saúl Ibarra Corretgé
0b54e005d7 fix(rn,shared-video) validate URLs to avoid crashes on the native side 2021-09-14 12:50:22 +02:00
Saúl Ibarra Corretgé
b92c1f52d5 fix(shared-video) make placeholder translatable
Also fix capitalization.
2021-09-14 12:50:22 +02:00
tmoldovan8x8
8eaf99586e fix(rn) disable pip while authorising dropbox 2021-09-14 12:37:08 +03:00
tmoldovan8x8
c7ad5b5b26 feat(android) expose channels ids 2021-09-14 12:35:25 +03:00
robertpin
61c3613de0 Show reactions buttons at all times
Don't send reactions via the channel if there's only one participant in the meeting
2021-09-14 12:26:50 +03:00
Horatiu Muresan
b801e0115d fix(context-menus) Fix participant context menus/toolbar overflow menu
- on ipads, long touch open dialog now opens the context menu to the left of the thumbnail as expected
- on ipads, now we close context menus on tap out
- fix case when participant context menu's height > tileview videos' height causing scroll on videos pane
- keep toolbox open while the overflow menu is shown
- keep remote participant video thumbnail in filmstrip visible even if toolbox is hidden, if context menu is opened
- Fix bug where toolbox could be completely disabled
2021-09-14 10:43:52 +03:00
Horatiu Muresan
1add438a1f feat(toolbar-buttons): Add event for notify overwritten toolbar buttons 2021-09-14 10:07:20 +03:00
Hristo Terezov
aadbe59d00 chore(deps) lib-jitsi-meet@latest
* fix(replaceTrack):  Don't wrap Error in Error.

64cdf69ffb...fbf85bdcec
2021-09-13 17:50:56 -05:00
Дамян Минков
350f0fbb27 feat: Whitelists enableUnifiedOnChrome.
Whitelists it, so we can run tests by setting it to false.
2021-09-13 15:23:53 -05:00
Paweł Domas
1db52354fb Use redux for local tracks instead of conference.js (#9920)
* do not use this.local video

* move tracks initialized flag around

* do not use this.localAudio

* untangle use audio/video stream methods

It should be safe to call setVideoMuteStatus and
setAudioMuteStatus regardless of the prejoin page
visibility state.

* add NO-OP to use track methods and fix crash
in _setLocalAudioVideoStreams on not a promise

* use allSettled
2021-09-13 12:33:04 -05:00
Jaya Allamsetty
6711801c3b chore(deps) lib-jitsi-meet@latest
* ref(JitsiConference): don't crash on wrong oldTrack (#1709)

ad1f06d768...64cdf69ffb
2021-09-13 11:49:53 -04:00
csett86
e2443f8d01 lang: update German translation (#9921)
Signed-off-by: Christoph Settgast <csett86@web.de>
2021-09-11 10:58:15 -05:00
dimitardelchev93
11a86a9383 fix: Add different text when disablePolls is enabled/disabled (#9900)
* Add different text when disablePolls is enabled/disabled #9890

* Add different text when disablePolls is enabled/disabled v2 #9890
2021-09-10 13:57:36 -05:00
Jaya Allamsetty
40a485ec6c Thumbnail reordering and participant pane enhancements.
* fix(participant-pane) Use the sorted participant list from redux instead of sorting it on every render making it better performant. Match the participant order with that of the order in the filmstrip. Also move the participants with raised hand to the top of the list.

* ref(filmstrip) Move enableThumbnailReordering flag to testing section.

* fix(participants) Add new selectors for getting sorted participants.
2021-09-10 13:37:05 -04:00
Horatiu Muresan
535bd81d61 fix(context-menu) Hide toolbars when participant context menu opened (#9842)
- hide toolbars only when in tile view
- fix community issue: https://github.com/jitsi/jitsi-meet/issues/9818
2021-09-10 15:17:57 +03:00
robertpin
1dc8bfa631 feat(av-moderation) Updated Advanced moderation (#9875)
Co-authored-by: Vlad Piersec <vlad.piersec@8x8.com>
2021-09-10 14:05:16 +03:00
Saúl Ibarra Corretgé
f2e2d52cfd fix(rn,shared-video,invite-dialog) fix placehoolder text color to be visible 2021-09-10 12:45:04 +02:00
Vlad Piersec
0db2dd0546 fix(prejoin): Change avatar color to match in-meeting one 2021-09-10 10:48:22 +03:00
Izak Glasencnik
6673d12cec feat(external_api): Command to set participant volume 2021-09-09 18:34:34 -05:00
dimitardelchev93
5e152b4a42 feat: Additional setting to order participants in speaker stats (#9751)
* Additional setting to order participants in speaker stats #9742

* Setting to order speaker stats optimisations #9742

* Lint fixes #9742

* Replace APP references #9742

* Lint fixes #9742

* Setting to order speaker stats optimisations 2 #9742

* Lint fixes #9742

* Remove unnecessary param #9742

* Add more speaker-stats reducer _updateStats docs  #9742
2021-09-09 17:46:41 -05:00
dimitardelchev93
db473dfef5 feat: Add configuration to disable chat emoticons #9889 (#9899) 2021-09-09 17:46:28 -05:00
dimitardelchev93
0bad0d9ecf feat: Add configuration to disable removing raised hand on dominant speaker (#9641)
* Add configuration to disable removing raised hand on dominant speaker change

* Fix lint problem

* Avoid dispatching unnecessary action

* Fix lint problem
2021-09-09 16:53:25 -05:00
Jaya Allamsetty
f1bf8e5f9a fix(settings) Disable mic/camera selection on mobile safari.
Creating a preview of the same audio/video track kills the tracks that is already being shared in the conference. Therefore, disable camera/mic selection in the settings dialog while the user is in the call. The devices are selectable from the prejoin screen settings dialog.
2021-09-09 16:28:24 -04:00
Jaya Allamsetty
131d2476ae chore(deps) lib-jitsi-meet@latest
* fix(RTCUtils) Return false for device change checks on mobile Safari.

735943b32d...ad1f06d768
2021-09-09 16:28:01 -04:00
Andrei Gavrilescu
34c55b4eb2 additional bcp47 languages 2021-09-09 14:44:55 -05:00
José Luís Andrade
d83d822818 lang: Complete translation to Portuguese (#9871)
* Complete translation to Portuguese

* "reactions" and "connectedThreePlusMembers" fix
2021-09-09 14:36:21 -05:00
ashiqhassan95
5857620d81 fix(notifications): Added user join notification keys 2021-09-09 13:56:18 -05:00
scott boone
b7cb0a44f2 feat: new prosody module to report census of all rooms (#9901)
* new prosody module to report census of all rooms

* changed to use util to check if it's a test room

* improved docs

* more doc improvements

* updated to use muc_domain_prefix

* facepalm
2021-09-09 13:24:04 -05:00
Saúl Ibarra Corretgé
3bf1a1774f fix(rn,polyfills) fix Performance polyfill
We need to re-override now() to avoid a recursion error. Also I missed the
default export.
2021-09-09 16:41:44 +02:00
Saúl Ibarra Corretgé
d21eb59f24 feat(doc) revamp README 2021-09-09 16:37:32 +02:00
Horatiu Muresan
9a16733950 feat(config) Add config for disabled sound id's
- unify naming for sound id values
2021-09-09 17:18:26 +03:00
Vlad Piersec
d96246dea8 fix(config): Add separate entries for the e2ee labels 2021-09-09 16:16:08 +03:00
abora8x8
a5fc75ed35 feat: Dynamically limit the number of participants in a room (#9880)
* Dynamically limit the number of participants in a room

* Remove log
2021-09-09 08:15:14 -05:00
vp8x8
07d023968a feat(responsive-ui): Keep aspect ratio for filmstrip self view on mobile web (#9848)
* feat(responsive-ui): Keep aspect ratio for filmstrip self view on mobile web

Right now filmstrip displays self view in landscape mode.
With these changes the aspect ratio of the self view will be maintained
so on portrait mode the thumbnail will be displayed vertically.
Of course this makes sense only on mobile web.

* Code review

* Fix height
2021-09-09 16:14:09 +03:00
Tudor D. Pop
d95d52843f feat(config) add connection indicators flags 2021-09-09 14:50:22 +02:00
Saúl Ibarra Corretgé
49be96799a feat(rn) add polyfill for the performance API
Implements: https://developer.mozilla.org/en-US/docs/Web/API/Performance
Ref: https://github.com/oblador/react-native-performance
2021-09-09 10:07:52 +02:00
Jaya Allamsetty
2008c90359 feat: Turn on enableLayerSuspension option by default. (#9894)
* fix(config) Add more info about enableLayerSuspension option.

* chore(deps) lib-jitsi-meet@latest

* Update config.js

Co-authored-by: Saúl Ibarra Corretgé <s@saghul.net>

Co-authored-by: Saúl Ibarra Corretgé <s@saghul.net>
2021-09-08 09:24:37 -05:00
hmuresan
0f01772625 fix(prejoin) Fix buttons positioning for 3rd party 2021-09-08 16:44:04 +03:00
Vlad Piersec
f5dee99131 feat(config): Add config option for e2ee label 2021-09-08 12:33:22 +03:00
Jaya Allamsetty
909c397664 chore(deps) lib-jitsi-meet@latest
* fix(LocalSdpMunger): do not fake video sdp when screen sharing
* fix(JitsiConference) avoid extra processing if the room was left
* fix(moderator) remove unneeded log

b0d27fa8da...28a5355356
2021-09-07 18:16:23 -04:00
Andrei Gavrilescu
f51e65d129 feat(rtcstats): send dominant speaker stats (#9883)
* send dominant speaker stats

* fix lint
2021-09-07 16:20:50 +03:00
Vlad Piersec
56c0edc896 fix(toolbox): Show dominant speaker name only when in conference 2021-09-07 10:22:24 +02:00
Cross
add8265ab9 chore(config) fix spacing
Removed a redundant space under maxBitratesVideo.
2021-09-07 09:40:46 +02:00
tmoldovan8x8
527b96fe00 task(android): updates sdk version 2021-09-06 12:49:09 +03:00
tmoldovan8x8
452b1b7e2e fix(android): renames amplitudereactnative project to use react-native- pattern 2021-09-06 12:29:58 +03:00
hmuresan
a0c3a00e59 chore(config): Whitelist disableRecordAudioNotification config 2021-09-06 11:40:02 +03:00
hmuresan
00b5ce71e0 fix(external-api): Avoid naming event 'error'
- EventEmmitter treats 'error' as a special case and throws error.
2021-09-02 19:37:23 +03:00
290 changed files with 5148 additions and 2228 deletions

118
README.md
View File

@@ -1,82 +1,88 @@
# Jitsi Meet - Secure, Simple and Scalable Video Conferences
# <p align="center">Jitsi Meet</p>
Jitsi Meet is an open-source (Apache) WebRTC JavaScript application that uses [Jitsi Videobridge](https://jitsi.org/videobridge) to provide high quality, [secure](https://jitsi.org/security) and scalable video conferences. Jitsi Meet in action can be seen at [here at the session #482 of the VoIP Users Conference](http://youtu.be/7vFUVClsNh0).
Jitsi Meet is a set of Open Source projects which empower users to use and deploy
video conferencing platforms with state-of-the-art video quality and features.
The Jitsi Meet client runs in your browser, without installing anything on your computer. You can try it out at https://meet.jit.si.
<hr />
Jitsi Meet allows for very efficient collaboration. Users can stream their desktop or only some windows. It also supports shared document editing with Etherpad.
<p align="center">
<img src="https://raw.githubusercontent.com/jitsi/jitsi-meet/master/readme-img1.png" width="900" />
</p>
**NOTE:** If you are looking for Jitsi as a Service (JaaS) please start [here](https://jaas.8x8.vc).
<hr />
## Installation
Amongst others here are the main features Jitsi Meet offers:
On the client side, no installation is necessary. You just point your browser to the URL of your deployment. This section is about installing a Jitsi Meet suite on your server and hosting your own conferencing service.
* Support for all current browsers
* Mobile applications
* Web and native SDKs for integration
* HD audio and video
* Content sharing
* End-to-End Encryption
* Raise hand and reactions
* Chat with private conversations
* Polls
* Virtual backgrounds
Installing Jitsi Meet is a simple experience. For Debian-based system, following the [quick install](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-quickstart) document, which uses the package system. You can also see a demonstration of the process in [this tutorial video](https://jitsi.org/tutorial).
And many more!
For other systems, or if you wish to install all components manually, see the [detailed manual installation instructions](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-manual).
## Using Jitsi Meet
Installation with Docker is also available. Please see the [instruction](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker).
Using Jitsi Meet is straightforward, as it's browser based. Head over to [meet.jit.si](https://meet.jit.si) and give it a try. It's anonymous, scalable and free to use. All browsers are supported!
## Download
Using mobile? No problem, you can either use your mobile web browser or our fully-featured
mobile apps:
| Latest stable release | [![release](https://img.shields.io/badge/release-latest-green.svg)](https://github.com/jitsi/jitsi-meet/releases/latest) |
|---|---|
| Android | Android (F-Droid) | iOS |
|:-:|:-:|:-:|
| [<img src="resources/img/google-play-badge.png" height="50">](https://play.google.com/store/apps/details?id=org.jitsi.meet) | [<img src="resources/img/f-droid-badge.png" height="50">](https://f-droid.org/en/packages/org.jitsi.meet/) | [<img src="resources/img/appstore-badge.png" height="50">](https://itunes.apple.com/us/app/jitsi-meet/id1165103905) |
You can download Debian/Ubuntu binaries:
* [stable](https://download.jitsi.org/stable/) ([instructions](https://jitsi.org/downloads/ubuntu-debian-installations-instructions/))
* [testing](https://download.jitsi.org/testing/) ([instructions](https://jitsi.org/downloads/ubuntu-debian-installations-instructions-for-testing/))
* [nightly](https://download.jitsi.org/unstable/) ([instructions](https://jitsi.org/downloads/ubuntu-debian-installations-instructions-nightly/))
You can download source archives (produced by ```make source-package```):
* [source builds](https://download.jitsi.org/jitsi-meet/src/)
### Mobile apps
* [Android](https://play.google.com/store/apps/details?id=org.jitsi.meet)
[<img src="resources/img/google-play-badge.png" height="50">](https://play.google.com/store/apps/details?id=org.jitsi.meet)
* [Android (F-Droid)](https://f-droid.org/en/packages/org.jitsi.meet/)
[<img src="resources/img/f-droid-badge.png" height="50">](https://f-droid.org/en/packages/org.jitsi.meet/)
* [iOS](https://itunes.apple.com/us/app/jitsi-meet/id1165103905)
[<img src="resources/img/appstore-badge.png" height="50">](https://itunes.apple.com/us/app/jitsi-meet/id1165103905)
You can also sign up for our open beta testing here:
If you are feeling adventurous and want to get an early scoop of the features as they are being
developed you can also sign up for our open beta testing here:
* [Android](https://play.google.com/apps/testing/org.jitsi.meet)
* [iOS](https://testflight.apple.com/join/isy6ja7S)
## Release notes
## Running your own instance
Release notes for Jitsi Meet are maintained on [this repository](https://github.com/jitsi/jitsi-meet-release-notes).
If you'd like to run your own Jitsi Meet installation head over to the [handbook](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-start) to get started.
## Development
We provide Debian packages and a comprehensive Docker setup to make deployments as simple as possible.
Advanced users also have the possibility of building all the components from source.
For web development see [here](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-web), and for mobile see [here](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-mobile).
You can check the latest releases [[here](https://jitsi.github.io/handbook/docs/releases).
## Jitsi as a Service
If you like the branding capabilities of running your own instance but you'd like
to avoid dealing with the complexity of monitoring, scaling and updates, JaaS might be
for you.
[8x8 Jitsi as a Service (JaaS)](https://jaas.8x8.vc) is an enterprise-ready video meeting platform that allows developers, organizations and businesses to easily build and deploy video solutions. With Jitsi as a Service we now give you all the power of Jitsi running on our global platform so you can focus on building secure and branded video experiences.
## Documentation
All the Jitsi Meet documentation is available in [the handbook](https://jitsi.github.io/handbook/).
## Security
For a comprehensive description of all Jitsi Meet's security aspects, please check [this link](https://jitsi.org/security).
For a detailed description of Jitsi Meet's End-to-End Encryption (E2EE) implementation,
please check [this link](https://jitsi.org/e2ee-whitepaper/).
For information on reporting security vulnerabilities in Jitsi Meet, see [SECURITY.md](./SECURITY.md).
## Contributing
If you are looking to contribute to Jitsi Meet, first of all, thank you! Please
see our [guidelines for contributing](CONTRIBUTING.md).
## Embedding in external applications
<br />
<br />
Jitsi Meet provides a very flexible way of embedding in external applications by using the [Jitsi Meet API](doc/api.md).
## Security
The security section here was starting to feel a bit too succinct for the complexity of the topic, so we created a post that covers the topic much more broadly here: https://jitsi.org/security
The section on end-to-end encryption in that document is likely going to be one of the key points of interest: https://jitsi.org/security/#e2ee
## Security issues
For information on reporting security vulnerabilities in Jitsi Meet, see [SECURITY.md](./SECURITY.md).
## Acknowledgements
Jitsi Meet started out as a sample conferencing application using Jitsi Videobridge. It was originally developed by ESTOS' developer Philipp Hancke who then contributed it to the community where development continues with joint forces!
<footer>
<p align="center" style="font-size: smaller;">
Built with ❤️ by the Jitsi team at <a href="https://8x8.com" target="_blank">8x8</a> and our community.
</p>
</footer>

View File

@@ -26,4 +26,4 @@ android.useAndroidX=true
android.enableJetifier=true
appVersion=21.4.0
sdkVersion=3.9.0
sdkVersion=3.9.1

View File

@@ -56,7 +56,7 @@ dependencies {
exclude group: 'com.android.installreferrer'
}
} else {
implementation project(':amplitudereactnative')
implementation project(':react-native-amplitude')
implementation project(':react-native-device-info')
implementation(project(":react-native-google-signin")) {
exclude group: 'com.google.android.gms'
@@ -71,6 +71,7 @@ dependencies {
implementation project(':react-native-default-preference')
implementation project(':react-native-immersive')
implementation project(':react-native-keep-awake')
implementation project(':react-native-performance')
implementation project(':react-native-slider')
implementation project(':react-native-sound')
implementation project(':react-native-splash-screen')

View File

@@ -184,14 +184,21 @@ class DropboxModule
public void onHostResume() {
DbxCredential credential = Auth.getDbxCredential();
if (credential != null && this.promise != null) {
WritableMap result = Arguments.createMap();
result.putString("token", credential.getAccessToken());
result.putString("rToken", credential.getRefreshToken());
result.putDouble("expireDate", credential.getExpiresAt());
if (this.promise != null ) {
if (credential != null) {
WritableMap result = Arguments.createMap();
result.putString("token", credential.getAccessToken());
result.putString("rToken", credential.getRefreshToken());
result.putDouble("expireDate", credential.getExpiresAt());
this.promise.resolve(result);
this.promise = null;
} else {
this.promise.reject("Invalid dropbox credentials");
}
this.promise.resolve(result);
this.promise = null;
}
}
}

View File

@@ -0,0 +1,11 @@
package org.jitsi.meet.sdk;
import java.util.ArrayList;
import java.util.List;
public class NotificationChannels {
static final String ONGOING_CONFERENCE_CHANNEL_ID = "JitsiOngoingConferenceChannel";
static final String ONGOING_CONFERNCE_CHANNEL_NAME = "Ongoing Conference Notifications";
public static List<String> allIds = new ArrayList<String>() {{ add(ONGOING_CONFERENCE_CHANNEL_ID); }};
}

View File

@@ -16,6 +16,9 @@
package org.jitsi.meet.sdk;
import static org.jitsi.meet.sdk.NotificationChannels.ONGOING_CONFERENCE_CHANNEL_ID;
import static org.jitsi.meet.sdk.NotificationChannels.ONGOING_CONFERNCE_CHANNEL_NAME;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -39,9 +42,6 @@ import java.util.Random;
class OngoingNotification {
private static final String TAG = OngoingNotification.class.getSimpleName();
private static final String CHANNEL_ID = "JitsiNotificationChannel";
private static final String CHANNEL_NAME = "Ongoing Conference Notifications";
static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
private static long startingTime = 0;
@@ -60,13 +60,13 @@ class OngoingNotification {
= (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel
= notificationManager.getNotificationChannel(CHANNEL_ID);
= notificationManager.getNotificationChannel(ONGOING_CONFERENCE_CHANNEL_ID);
if (channel != null) {
// The channel was already created, no need to do it again.
return;
}
channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel = new NotificationChannel(ONGOING_CONFERENCE_CHANNEL_ID, ONGOING_CONFERNCE_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(false);
channel.enableVibration(false);
channel.setShowBadge(false);
@@ -84,7 +84,7 @@ class OngoingNotification {
Intent notificationIntent = new Intent(context, context.getClass());
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, ONGOING_CONFERENCE_CHANNEL_ID);
if (startingTime == 0) {
startingTime = System.currentTimeMillis();

View File

@@ -174,7 +174,7 @@ class ReactInstanceManagerHolder {
return;
}
SoLoader.init(activity, /* native exopackage */ false);
SoLoader.init(activity.getApplication(), /* native exopackage */ false);
List<ReactPackage> packages
= new ArrayList<>(Arrays.asList(
@@ -184,6 +184,7 @@ class ReactInstanceManagerHolder {
new com.horcrux.svg.SvgPackage(),
new com.kevinresol.react_native_default_preference.RNDefaultPreferencePackage(),
new com.learnium.RNDeviceInfo.RNDeviceInfo(),
new com.oblador.performance.PerformancePackage(),
new com.ocetnik.timer.BackgroundTimerPackage(),
new com.reactnativecommunity.asyncstorage.AsyncStoragePackage(),
new com.reactnativecommunity.netinfo.NetInfoPackage(),

View File

@@ -1,8 +1,8 @@
rootProject.name = 'jitsi-meet'
include ':app', ':sdk'
include ':amplitudereactnative'
project(':amplitudereactnative').projectDir = new File(rootProject.projectDir, '../node_modules/@amplitude/react-native//android')
include ':react-native-amplitude'
project(':react-native-amplitude').projectDir = new File(rootProject.projectDir, '../node_modules/@amplitude/react-native//android')
include ':react-native-async-storage'
project(':react-native-async-storage').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-async-storage/async-storage/android')
include ':react-native-background-timer'
@@ -21,6 +21,8 @@ include ':react-native-immersive'
project(':react-native-immersive').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-immersive/android')
include ':react-native-keep-awake'
project(':react-native-keep-awake').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keep-awake/android')
include ':react-native-performance'
project(':react-native-performance').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-performance/android')
include ':react-native-slider'
project(':react-native-slider').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/slider/android')
include ':react-native-sound'

View File

@@ -24,6 +24,8 @@ import {
redirectToStaticPage,
reloadWithStoredParams
} from './react/features/app/actions';
import { showModeratedNotification } from './react/features/av-moderation/actions';
import { shouldShowModeratedNotification } from './react/features/av-moderation/functions';
import {
AVATAR_URL_COMMAND,
EMAIL_COMMAND,
@@ -44,7 +46,8 @@ import {
lockStateChanged,
onStartMutedPolicyChanged,
p2pStatusChanged,
sendLocalParticipant
sendLocalParticipant,
_conferenceWillJoin
} from './react/features/base/conference';
import { getReplaceParticipant } from './react/features/base/config/functions';
import {
@@ -119,7 +122,7 @@ import {
maybeOpenFeedbackDialog,
submitFeedback
} from './react/features/feedback';
import { showNotification } from './react/features/notifications';
import { isModerationNotificationDisplayed, showNotification } from './react/features/notifications';
import { mediaPermissionPromptVisibilityChanged, toggleSlowGUMOverlay } from './react/features/overlay';
import { suspendDetected } from './react/features/power-monitor';
import {
@@ -454,27 +457,12 @@ export default {
isSharingScreen: false,
/**
* The local audio track (if any).
* FIXME tracks from redux store should be the single source of truth
* @type {JitsiLocalTrack|null}
*/
localAudio: null,
/**
* The local presenter video track (if any).
* @type {JitsiLocalTrack|null}
*/
localPresenterVideo: null,
/**
* The local video track (if any).
* FIXME tracks from redux store should be the single source of truth, but
* more refactoring is required around screen sharing ('localVideo' usages).
* @type {JitsiLocalTrack|null}
*/
localVideo: null,
/**
* Returns an object containing a promise which resolves with the created tracks &
* the errors resulting from that process.
@@ -728,9 +716,7 @@ export default {
track.mute();
}
});
logger.log(`Initialized with ${tracks.length} local tracks`);
this._localTracksInitialized = true;
con.addEventListener(JitsiConnectionEvents.CONNECTION_FAILED, _connectionFailedHandler);
APP.connection = connection = con;
@@ -887,13 +873,24 @@ export default {
* dialogs in case of media permissions error.
*/
muteAudio(mute, showUI = true) {
const state = APP.store.getState();
if (!mute
&& isUserInteractionRequiredForUnmute(APP.store.getState())) {
&& isUserInteractionRequiredForUnmute(state)) {
logger.error('Unmuting audio requires user interaction');
return;
}
// check for A/V Moderation when trying to unmute
if (!mute && shouldShowModeratedNotification(MEDIA_TYPE.AUDIO, state)) {
if (!isModerationNotificationDisplayed(MEDIA_TYPE.AUDIO, state)) {
APP.store.dispatch(showModeratedNotification(MEDIA_TYPE.AUDIO));
}
return;
}
// Not ready to modify track's state yet
if (!this._localTracksInitialized) {
// This will only modify base/media.audio.muted which is then synced
@@ -907,7 +904,9 @@ export default {
return;
}
if (!this.localAudio && !mute) {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
if (!localAudio && !mute) {
const maybeShowErrorDialog = error => {
showUI && APP.store.dispatch(notifyMicError(error));
};
@@ -961,17 +960,18 @@ export default {
const maybeShowErrorDialog = error => {
showUI && APP.store.dispatch(notifyCameraError(error));
};
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
if (mute) {
try {
await this.localVideo.setEffect(undefined);
await localVideo.setEffect(undefined);
} catch (err) {
logger.error('Failed to remove the presenter effect', err);
maybeShowErrorDialog(err);
}
} else {
try {
await this.localVideo.setEffect(await this._createPresenterStreamEffect());
await localVideo.setEffect(await this._createPresenterStreamEffect());
} catch (err) {
logger.error('Failed to apply the presenter effect', err);
maybeShowErrorDialog(err);
@@ -1013,7 +1013,9 @@ export default {
return;
}
if (!this.localVideo && !mute) {
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
if (!localVideo && !mute) {
const maybeShowErrorDialog = error => {
showUI && APP.store.dispatch(notifyCameraError(error));
};
@@ -1327,14 +1329,14 @@ export default {
APP.conference.roomName,
this._getConferenceOptions());
APP.store.dispatch(conferenceWillJoin(room));
// Filter out the tracks that are muted (except on mobile Safari).
const tracks = isIosMobileBrowser() ? localTracks : localTracks.filter(track => !track.isMuted());
this._setLocalAudioVideoStreams(tracks);
this._room = room; // FIXME do not use this
APP.store.dispatch(_conferenceWillJoin(room));
sendLocalParticipant(APP.store, room);
this._setupListeners();
@@ -1347,7 +1349,7 @@ export default {
* @private
*/
_setLocalAudioVideoStreams(tracks = []) {
return tracks.map(track => {
const promises = tracks.map(track => {
if (track.isAudioTrack()) {
return this.useAudioStream(track);
} else if (track.isVideoTrack()) {
@@ -1356,12 +1358,16 @@ export default {
return this.useVideoStream(track);
}
logger.error(
'Ignored not an audio nor a video track: ', track);
logger.error('Ignored not an audio nor a video track: ', track);
return Promise.resolve();
});
return Promise.allSettled(promises).then(() => {
this._localTracksInitialized = true;
logger.log(`Initialized with ${tracks.length} local tracks`);
});
},
_getConferenceOptions() {
@@ -1383,29 +1389,20 @@ export default {
return new Promise((resolve, reject) => {
_replaceLocalVideoTrackQueue.enqueue(onFinish => {
const state = APP.store.getState();
const oldTrack = getLocalJitsiVideoTrack(APP.store.getState());
// When the prejoin page is displayed localVideo is not set
// so just replace the video track from the store with the new one.
if (isPrejoinPageVisible(state)) {
const oldTrack = getLocalJitsiVideoTrack(state);
logger.debug(`useVideoStream: Replacing ${oldTrack} with ${newTrack}`);
logger.debug(`useVideoStream on the prejoin screen: Replacing ${oldTrack} with ${newTrack}`);
if (oldTrack === newTrack) {
resolve();
onFinish();
return APP.store.dispatch(replaceLocalTrack(oldTrack, newTrack))
.then(resolve)
.catch(error => {
logger.error(`useVideoStream failed on the prejoin screen: ${error}`);
reject(error);
})
.then(onFinish);
return;
}
logger.debug(`useVideoStream: Replacing ${this.localVideo} with ${newTrack}`);
APP.store.dispatch(
replaceLocalTrack(this.localVideo, newTrack, room))
replaceLocalTrack(oldTrack, newTrack, room))
.then(() => {
this.localVideo = newTrack;
this._setSharingScreen(newTrack);
this.setVideoMuteStatus();
})
@@ -1455,23 +1452,18 @@ export default {
useAudioStream(newTrack) {
return new Promise((resolve, reject) => {
_replaceLocalAudioTrackQueue.enqueue(onFinish => {
const state = APP.store.getState();
const oldTrack = getLocalJitsiAudioTrack(APP.store.getState());
// When the prejoin page is displayed localAudio is not set
// so just replace the audio track from the store with the new one.
if (isPrejoinPageVisible(state)) {
const oldTrack = getLocalJitsiAudioTrack(state);
if (oldTrack === newTrack) {
resolve();
onFinish();
return APP.store.dispatch(replaceLocalTrack(oldTrack, newTrack))
.then(resolve)
.catch(reject)
.then(onFinish);
return;
}
APP.store.dispatch(
replaceLocalTrack(this.localAudio, newTrack, room))
replaceLocalTrack(oldTrack, newTrack, room))
.then(() => {
this.localAudio = newTrack;
this.setAudioMuteStatus(this.isLocalAudioMuted());
})
.then(resolve)
@@ -1546,7 +1538,9 @@ export default {
// If system audio was also shared stop the AudioMixerEffect and dispose of the desktop audio track.
if (this._mixerEffect) {
await this.localAudio.setEffect(undefined);
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
await localAudio.setEffect(undefined);
await this._desktopAudioStream.dispose();
this._mixerEffect = undefined;
this._desktopAudioStream = undefined;
@@ -1772,7 +1766,8 @@ export default {
// Create a new presenter track and apply the presenter effect.
if (!this.localPresenterVideo && !mute) {
const { height, width } = this.localVideo.track.getSettings() ?? this.localVideo.track.getConstraints();
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
const { height, width } = localVideo.track.getSettings() ?? localVideo.track.getConstraints();
const isPortrait = height >= width;
const DESKTOP_STREAM_CAP = 720;
@@ -1801,7 +1796,7 @@ export default {
// Apply the constraints on the desktop track.
try {
await this.localVideo.track.applyConstraints(desktopResizeConstraints);
await localVideo.track.applyConstraints(desktopResizeConstraints);
} catch (err) {
logger.error('Failed to apply constraints on the desktop stream for presenter mode', err);
@@ -1809,7 +1804,7 @@ export default {
}
}
const trackHeight = resizeDesktopStream
? this.localVideo.track.getSettings().height ?? DESKTOP_STREAM_CAP
? localVideo.track.getSettings().height ?? DESKTOP_STREAM_CAP
: height;
let effect;
@@ -1824,7 +1819,7 @@ export default {
// Replace the desktop track on the peerconnection.
try {
await this.localVideo.setEffect(effect);
await localVideo.setEffect(effect);
APP.store.dispatch(setVideoMuted(mute, MEDIA_TYPE.PRESENTER));
this.setVideoMuteStatus();
} catch (err) {
@@ -1880,12 +1875,14 @@ export default {
}
if (this._desktopAudioStream) {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
// If there is a localAudio stream, mix in the desktop audio stream captured by the screen sharing
// api.
if (this.localAudio) {
if (localAudio) {
this._mixerEffect = new AudioMixerEffect(this._desktopAudioStream);
await this.localAudio.setEffect(this._mixerEffect);
await localAudio.setEffect(this._mixerEffect);
} else {
// If no local stream is present ( i.e. no input audio devices) we use the screen share audio
// stream as we would use a regular stream.
@@ -2066,10 +2063,10 @@ export default {
});
room.on(JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED, (id, lvl) => {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
let newLvl = lvl;
if (this.isLocalId(id)
&& this.localAudio && this.localAudio.isMuted()) {
if (this.isLocalId(id) && localAudio?.isMuted()) {
newLvl = 0;
}
@@ -2311,6 +2308,7 @@ export default {
APP.UI.addListener(
UIEvents.VIDEO_DEVICE_CHANGED,
cameraDeviceId => {
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
const videoWasMuted = this.isLocalVideoMuted();
sendAnalytics(createDeviceChangedEvent('video', 'input'));
@@ -2318,7 +2316,7 @@ export default {
// If both screenshare and video are in progress, restart the
// presenter mode with the new camera device.
if (this.isSharingScreen && !videoWasMuted) {
const { height } = this.localVideo.track.getSettings();
const { height } = localVideo.track.getSettings();
// dispose the existing presenter track and create a new
// camera track.
@@ -2327,7 +2325,7 @@ export default {
this.localPresenterVideo = null;
return this._createPresenterStreamEffect(height, cameraDeviceId)
.then(effect => this.localVideo.setEffect(effect))
.then(effect => localVideo.setEffect(effect))
.then(() => {
this.setVideoMuteStatus();
logger.log('Switched local video device while screen sharing and the video is unmuted');
@@ -2340,7 +2338,7 @@ export default {
// that can be applied on un-mute.
} else if (this.isSharingScreen && videoWasMuted) {
logger.log('Switched local video device: while screen sharing and the video is muted');
const { height } = this.localVideo.track.getSettings();
const { height } = localVideo.track.getSettings();
this._updateVideoDeviceId();
@@ -2426,13 +2424,15 @@ export default {
return this.useAudioStream(stream);
})
.then(() => {
if (this.localAudio && hasDefaultMicChanged) {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
if (localAudio && hasDefaultMicChanged) {
// workaround for the default device to be shown as selected in the
// settings even when the real device id was passed to gUM because of the
// above mentioned chrome bug.
this.localAudio._realDeviceId = this.localAudio.deviceId = 'default';
localAudio._realDeviceId = localAudio.deviceId = 'default';
}
logger.log(`switched local audio device: ${this.localAudio?.getDeviceId()}`);
logger.log(`switched local audio device: ${localAudio?.getDeviceId()}`);
this._updateAudioDeviceId();
})
@@ -2498,9 +2498,6 @@ export default {
JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED,
this.deviceChangeListener);
}
this.localVideo = null;
this.localAudio = null;
},
/**
@@ -2563,10 +2560,11 @@ export default {
* @private
*/
_updateVideoDeviceId() {
if (this.localVideo
&& this.localVideo.videoType === 'camera') {
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
if (localVideo && localVideo.videoType === 'camera') {
APP.store.dispatch(updateSettings({
cameraDeviceId: this.localVideo.getDeviceId()
cameraDeviceId: localVideo.getDeviceId()
}));
}
@@ -2584,9 +2582,11 @@ export default {
* @private
*/
_updateAudioDeviceId() {
if (this.localAudio) {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
if (localAudio) {
APP.store.dispatch(updateSettings({
micDeviceId: this.localAudio.getDeviceId()
micDeviceId: localAudio.getDeviceId()
}));
}
},
@@ -2600,6 +2600,8 @@ export default {
*/
_onDeviceListChanged(devices) {
const oldDevices = APP.store.getState()['features/base/devices'].availableDevices;
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
APP.store.dispatch(updateDeviceList(devices));
@@ -2607,8 +2609,8 @@ export default {
= mediaDeviceHelper.getNewMediaDevicesAfterDeviceListChanged(
devices,
this.isSharingScreen,
this.localVideo,
this.localAudio);
localVideo,
localAudio);
const promises = [];
const audioWasMuted = this.isLocalAudioMuted();
const videoWasMuted = this.isLocalVideoMuted();
@@ -2631,12 +2633,12 @@ export default {
// simpler):
// If the default device is changed we need to first stop the local streams and then call GUM. Otherwise GUM
// will return a stream using the old default device.
if (requestedInput.audio && this.localAudio) {
this.localAudio.stopStream();
if (requestedInput.audio && localAudio) {
localAudio.stopStream();
}
if (requestedInput.video && this.localVideo) {
this.localVideo.stopStream();
if (requestedInput.video && localVideo) {
localVideo.stopStream();
}
// Let's handle unknown/non-preferred devices
@@ -2716,15 +2718,16 @@ export default {
= mediaType === 'audio'
? this.useAudioStream.bind(this)
: this.useVideoStream.bind(this);
const track = tracks.find(t => t.getType() === mediaType) || null;
// Use the new stream or null if we failed to obtain it.
return useStream(tracks.find(track => track.getType() === mediaType) || null)
return useStream(track)
.then(() => {
if (this.localAudio && hasDefaultMicChanged) {
if (track?.isAudioTrack() && hasDefaultMicChanged) {
// workaround for the default device to be shown as selected in the
// settings even when the real device id was passed to gUM because of
// the above mentioned chrome bug.
this.localAudio._realDeviceId = this.localAudio.deviceId = 'default';
track._realDeviceId = track.deviceId = 'default';
}
mediaType === 'audio'
? this._updateAudioDeviceId()
@@ -2764,14 +2767,13 @@ export default {
* Determines whether or not the audio button should be enabled.
*/
updateAudioIconEnabled() {
const audioMediaDevices
= APP.store.getState()['features/base/devices'].availableDevices.audioInput;
const audioDeviceCount
= audioMediaDevices ? audioMediaDevices.length : 0;
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
const audioMediaDevices = APP.store.getState()['features/base/devices'].availableDevices.audioInput;
const audioDeviceCount = audioMediaDevices ? audioMediaDevices.length : 0;
// The audio functionality is considered available if there are any
// audio devices detected or if the local audio stream already exists.
const available = audioDeviceCount > 0 || Boolean(this.localAudio);
const available = audioDeviceCount > 0 || Boolean(localAudio);
APP.store.dispatch(setAudioAvailable(available));
APP.API.notifyAudioAvailabilityChanged(available);
@@ -2785,13 +2787,14 @@ export default {
= APP.store.getState()['features/base/devices'].availableDevices.videoInput;
const videoDeviceCount
= videoMediaDevices ? videoMediaDevices.length : 0;
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
// The video functionality is considered available if there are any
// video devices detected or if there is local video stream already
// active which could be either screensharing stream or a video track
// created before the permissions were rejected (through browser
// config).
const available = videoDeviceCount > 0 || Boolean(this.localVideo);
const available = videoDeviceCount > 0 || Boolean(localVideo);
APP.store.dispatch(setVideoAvailable(available));
APP.API.notifyVideoAvailabilityChanged(available);
@@ -2809,8 +2812,6 @@ export default {
APP.store.dispatch(destroyLocalTracks());
this._localTracksInitialized = false;
this.localVideo = null;
this.localAudio = null;
// Remove unnecessary event listeners from firing callbacks.
if (this.deviceChangeListener) {

141
config.js
View File

@@ -41,9 +41,16 @@ var config = {
// issues related to insertable streams.
// disableE2EE: false,
// Enables/disables thumbnail reordering in the filmstrip. It is enabled by default unless explicitly
// disabled by the below option.
// enableThumbnailReordering: true,
// Enables XMPP WebSocket (as opposed to BOSH) for the given amount of users.
// mobileXmppWsThreshold: 10 // enable XMPP WebSockets on mobile for 10% of the users
// P2P test mode disables automatic switching to P2P when there are 2
// participants in the conference.
p2pTestMode: false
// p2pTestMode: false,
// Enables the test specific features consumed by jitsi-meet-torture
// testMode: false
@@ -67,8 +74,11 @@ var config = {
// callStatsThreshold: 5 // enable callstats for 5% of the users.
},
// Enables reactions feature.
// enableReactions: false,
// Disables moderator indicators.
// disableModeratorIndicator: false,
// Disables the reactions feature.
// disableReactions: true,
// Disables polls feature.
// disablePolls: false,
@@ -144,9 +154,19 @@ var config = {
// Sets the preferred resolution (height) for local video. Defaults to 720.
// resolution: 720,
// Specifies whether the raised hand will hide when someone becomes a dominant speaker or not
// disableRemoveRaisedHandOnFocus: false,
// Specifies whether there will be a search field in speaker stats or not
// disableSpeakerStatsSearch: false,
// Specifies whether participants in speaker stats should be ordered or not, and with what priority
// speakerStatsOrder: [
// 'role', <- Moderators on top
// 'name', <- Alphabetically by name
// 'hasLeft', <- The ones that have left in the bottom
// ] <- the order of the array elements determines priority
// How many participants while in the tile view mode, before the receiving video quality is reduced from HD to SD.
// Use -1 to disable.
// maxFullResolutionParticipants: 2,
@@ -169,9 +189,10 @@ var config = {
// Enable / disable simulcast support.
// disableSimulcast: false,
// Enable / disable layer suspension. If enabled, endpoints whose HD
// layers are not in use will be suspended (no longer sent) until they
// are requested again.
// Enable / disable layer suspension. If enabled, endpoints whose HD layers are not in use will be suspended
// (no longer sent) until they are requested again. This is enabled by default. This must be enabled for screen
// sharing to work as expected on Chrome. Disabling this might result in low resolution screenshare being sent
// by the client.
// enableLayerSuspension: false,
// Every participant after the Nth will start video muted.
@@ -241,8 +262,9 @@ var config = {
// transcribeWithAppLanguage: true,
// Transcriber language. This settings will only work if "transcribeWithAppLanguage" is explicitly set to false.
// Available languages can be found in lang/language.json.
// preferredTranscribeLanguage: 'en',
// Available languages can be found in
// ./src/react/features/transcribing/transcriber-langs.json.
// preferredTranscribeLanguage: 'en-US',
// Enables automatic turning on captions when recording is started
// autoCaptionOnRecord: false,
@@ -252,6 +274,14 @@ var config = {
// Default value for the channel "last N" attribute. -1 for unlimited.
channelLastN: -1,
// Connection indicators
// connectionIndicators: {
// autoHide: true,
// autoHideTimeout: 5000,
// disabled: false,
// inactiveDisabled: false
// },
// Provides a way for the lastN value to be controlled through the UI.
// When startLastN is present, conference starts with a last-n value of startLastN and channelLastN
// value will be used when the quality level is selected using "Manage Video Quality" slider.
@@ -320,7 +350,7 @@ var config = {
// VP9: {
// low: 100000,
// standard: 300000,
// high: 1200000
// high: 1200000
// }
// },
//
@@ -515,6 +545,43 @@ var config = {
// '__end'
// ],
// Toolbar buttons which have their click event exposed through the API on
// `toolbarButtonClicked` event instead of executing the normal click routine.
// buttonsWithNotifyClick: [
// 'camera',
// 'chat',
// 'closedcaptions',
// 'desktop',
// 'download',
// 'embedmeeting',
// 'etherpad',
// 'feedback',
// 'filmstrip',
// 'fullscreen',
// 'hangup',
// 'help',
// 'invite',
// 'livestreaming',
// 'microphone',
// 'mute-everyone',
// 'mute-video-everyone',
// 'participants-pane',
// 'profile',
// 'raisehand',
// 'recording',
// 'security',
// 'select-background',
// 'settings',
// 'shareaudio',
// 'sharedvideo',
// 'shortcuts',
// 'stats',
// 'tileview',
// 'toggle-camera',
// 'videoquality',
// '__end'
// ],
// List of pre meeting screens buttons to hide. The values must be one or more of the 5 allowed buttons:
// 'microphone', 'camera', 'select-background', 'invite', 'settings'
// hiddenPremeetingButtons: [],
@@ -674,13 +741,39 @@ var config = {
// userRegion: "asia"
},
// Array<string> of disabled sounds.
// Possible values:
// - 'ASKED_TO_UNMUTE_SOUND'
// - 'E2EE_OFF_SOUND'
// - 'E2EE_ON_SOUND'
// - 'INCOMING_MSG_SOUND'
// - 'KNOCKING_PARTICIPANT_SOUND'
// - 'LIVE_STREAMING_OFF_SOUND'
// - 'LIVE_STREAMING_ON_SOUND'
// - 'NO_AUDIO_SIGNAL_SOUND'
// - 'NOISY_AUDIO_INPUT_SOUND'
// - 'OUTGOING_CALL_EXPIRED_SOUND'
// - 'OUTGOING_CALL_REJECTED_SOUND'
// - 'OUTGOING_CALL_RINGING_SOUND'
// - 'OUTGOING_CALL_START_SOUND'
// - 'PARTICIPANT_JOINED_SOUND'
// - 'PARTICIPANT_LEFT_SOUND'
// - 'RAISE_HAND_SOUND'
// - 'RECORDING_OFF_SOUND'
// - 'RECORDING_ON_SOUND'
// - 'TALK_WHILE_MUTED_SOUND'
// disabledSounds: [],
// DEPRECATED! Use `disabledSounds` instead.
// Decides whether the start/stop recording audio notifications should play on record.
// disableRecordAudioNotification: false,
// DEPRECATED! Use `disabledSounds` instead.
// Disables the sounds that play when other participants join or leave the
// conference (if set to true, these sounds will not be played).
// disableJoinLeaveSounds: false,
// DEPRECATED! Use `disabledSounds` instead.
// Disables the sounds that play when a chat message is received.
// disableIncomingMessageSound: false,
@@ -814,15 +907,32 @@ var config = {
// If true, tile view will not be enabled automatically when the participants count threshold is reached.
// disableTileView: true,
// Controls the visibility and behavior of the top header conference info labels.
// If a label's id is not in any of the 2 arrays, it will not be visible at all on the header.
// conferenceInfo: {
// // those labels will not be hidden in tandem with the toolbox.
// alwaysVisible: ['recording', 'local-recording'],
// // those labels will be auto-hidden in tandem with the toolbox buttons.
// autoHide: [
// 'subject',
// 'conference-timer',
// 'participants-count',
// 'e2ee',
// 'transcribing',
// 'video-quality',
// 'insecure-room'
// ]
// },
// Hides the conference subject
// hideConferenceSubject: true,
// Hides the recording label
// hideRecordingLabel: false,
// Hides the conference timer.
// hideConferenceTimer: true,
// Hides the recording label
// hideRecordingLabel: false,
// Hides the participants stats
// hideParticipantsStats: true,
@@ -859,6 +969,7 @@ var config = {
disableRemoteControl
displayJids
externalConnectUrl
e2eeLabels
firefox_fake_device
googleApiApplicationClientID
iAmRecorder
@@ -938,6 +1049,9 @@ var config = {
// 'lobby.notificationTitle', // shown when lobby is toggled and when join requests are allowed / denied
// 'localRecording.localRecording', // shown when a local recording is started
// 'notify.disconnected', // shown when a participant has left
// 'notify.connectedOneMember', // show when a participant joined
// 'notify.connectedTwoMembers', // show when two participants joined simultaneously
// 'notify.connectedThreePlusMembers', // show when more than 2 participants joined simultaneously
// 'notify.grantedTo', // shown when moderator rights were granted to a participant
// 'notify.invitedOneMember', // shown when 1 participant has been invited
// 'notify.invitedThreePlusMembers', // shown when 3+ participants have been invited
@@ -975,6 +1089,9 @@ var config = {
// Prevent the filmstrip from autohiding when screen width is under a certain threshold
// disableFilmstripAutohiding: false,
// Specifies whether the chat emoticons are disabled or not
// disableChatSmileys: false,
// Allow all above example options to include a trailing comma and
// prevent fear when commenting out the last value.
makeJsonParserHappy: 'even if last key had a trailing comma'

View File

@@ -106,9 +106,7 @@ export async function connect(id, password, roomName) {
serviceUrl += `?room=${roomName}`;
// FIXME Remove deprecated 'bosh' option assignment at some point(LJM will be accepting only 'serviceUrl' option
// in future). It's included for the time being for Jitsi Meet and lib-jitsi-meet versions interoperability.
connectionConfig.serviceUrl = connectionConfig.bosh = serviceUrl;
connectionConfig.serviceUrl = serviceUrl;
if (connectionConfig.websocketKeepAliveUrl) {
connectionConfig.websocketKeepAliveUrl += `?room=${roomName}`;

View File

@@ -29,7 +29,7 @@
margin: 8px 16px 8px 0;
}
@media (max-width: 375px) {
@media (max-width: 580px) {
.participants_pane {
height: 100vh;
height: -webkit-fill-available;

View File

@@ -2,7 +2,7 @@
.reactions-menu {
width: 280px;
background: #292929;
background: $menuBG;
box-shadow: 0px 3px 16px rgba(0, 0, 0, 0.6), 0px 0px 4px 1px rgba(0, 0, 0, 0.25);
border-radius: 3px;
padding: 16px;

View File

@@ -1,54 +1,22 @@
.subject {
box-sizing: border-box;
color: #fff;
margin-top: 20px;
position: absolute;
top: -120px;
transition: top .3s ease-in;
width: 100%;
margin-top: -120px;
transition: margin-top .3s ease-in;
z-index: $zindex3;
&.visible {
top: 0;
margin-top: 20px;
}
&.recording {
top: 0;
.subject-details-container {
opacity: 0;
transition: opacity .3s ease-in;
}
.subject-info-container .show-always {
transition: margin-left .3s ease-in;
}
&.visible {
.subject-details-container {
opacity: 1;
}
}
}
}
.subject-details-container {
display: flex;
}
.subject-info-container {
display: flex;
justify-content: center;
max-width: calc(100% - 280px);
margin: 0 auto;
&--full-width {
max-width: 100%;
}
height: 28px;
@media (max-width: 500px) {
flex-wrap: wrap;
max-width: 100%;
}
}
@@ -63,21 +31,47 @@
.subject-text {
background: rgba(0, 0, 0, 0.6);
border-radius: 3px 0px 0px 3px;
box-sizing: border-box;
font-size: 14px;
line-height: 24px;
padding: 2px 16px;
height: 24px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 28px;
padding: 0 16px;
height: 28px;
@media (max-width: 700px) {
max-width: 100px;
}
@media (max-width: 300px) {
display: none;
}
&--content {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.subject-timer {
background: rgba(0, 0, 0, 0.8);
border-radius: 0px 3px 3px 0px;
display: inline-block;
box-sizing: border-box;
font-size: 12px;
line-height: 16px;
line-height: 28px;
min-width: 34px;
padding: 6px 8px;
padding: 0 8px;
height: 28px;
@media (max-width: 300px) {
display: none;
}
}
.details-container {
width: 100%;
display: flex;
justify-content: center;
position: absolute;
top: 0;
height: 48px;
}

View File

@@ -84,6 +84,10 @@
margin-bottom: 3px;
margin-left: $remoteVideoMenuIconMargin;
}
.self-view-mobile-portrait video {
object-fit: contain;
}
}
/**
@@ -112,3 +116,11 @@
transition-delay: 0.1s;
}
}
/**
* Overrides for self view when in portrait mode on mobile.
* This is done in order to keep the aspect ratio.
*/
.vertical-filmstrip .self-view-mobile-portrait #localVideo_container {
object-fit: contain;
}

View File

@@ -98,6 +98,7 @@ $flagsImagePath: "../images/";
@import 'country-picker';
@import 'modals/invite/invite_more';
@import 'modals/security/security';
@import 'modals/mute/mute-dialog';
@import 'e2ee';
@import 'responsive';
@import 'drawer';

View File

@@ -0,0 +1,19 @@
.mute-dialog {
.separator-line {
margin: 24px 0 24px -20px;
padding: 0 20px;
width: 100%;
height: 1px;
background: #5E6D7A;
}
.control-row {
display: flex;
justify-content: space-between;
margin-top: 15px;
label {
font-size: 14px;
}
}
}

View File

@@ -11,7 +11,7 @@
background-color: rgba(0, 0, 0, 0.7);
align-items: center;
display: flex;
padding: 8px 12px;
padding: 14px 16px;
}
&-circle {

View File

@@ -1,16 +1,25 @@
.device {
&-status {
align-items: center;
align-self: stretch;
color: #fff;
display: flex;
font-size: 14px;
font-weight: 400;
justify-content: center;
line-height: 20px;
margin-top: 8px;
padding: 6px;
text-align: center;
&-error {
align-items: flex-start;
background-color: #F8AE1A;
border-radius: 6px;
color: #040404;
padding: 12px 16px;
text-align: left;
}
span {
margin-left: 16px;
}
}
&-icon {
@@ -18,14 +27,8 @@
background-repeat: no-repeat;
display: inline-block;
height: 16px;
margin-right: 10px;
width: 16px;
&--warning {
svg path {
fill: rgba(241, 173, 51, 1);
}
}
&--ok {
svg path {
fill: #189b55;

View File

@@ -6,6 +6,7 @@ $sidePanelWidth: 300px;
.content {
height: auto;
margin: 0 auto;
width: auto;
.new-toolbox {
width: auto;

View File

@@ -3,21 +3,16 @@
width: 100%;
}
&-checkbox-container {
margin-bottom: 16px;
width: 100%;
text-align: center;
}
&-error {
color: white;
background-color: #E04757;
border-radius: 6px;
padding: 4px;
box-sizing: border-box;
color: white;
font-size: 12px;
line-height: 16px;
margin-bottom: 16px;
margin-top: -8px;
font-size: 12px;
padding: 4px;
text-align: center;
width: 100%;
}

View File

@@ -16,6 +16,7 @@
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: 600;
line-height: 24px;
margin-bottom: 16px;
padding: 7px 16px;
@@ -103,7 +104,7 @@
margin-bottom: 32px;
text-align: center;
}
input.field {
background-color: white;
border: none;
@@ -116,11 +117,11 @@
padding: 10px 16px;
text-align: center;
width: 100%;
&.error {
border: 1px solid #E04757;
}
&.focused {
box-shadow: 0px 0px 1px 1.5px black, 0px 0px 1.3px 4px white;
}
@@ -128,10 +129,22 @@
#new-toolbox {
bottom: 0;
margin-bottom: 16px;
position: relative;
transition: none;
.toolbox-content {
margin-bottom: 4px;
}
.toolbox-content-items {
background: transparent;
border-radius: 0;
box-shadow: none;
display: flex;
justify-content: space-evenly;
padding: 8px 0;
}
.toolbox-content,
.toolbox-content-wrapper,
.toolbox-content-items {
@@ -144,7 +157,7 @@
@media (max-width: 1000px) {
flex-direction: column-reverse;
.content {
height: auto;
margin: 0 auto;
@@ -163,17 +176,26 @@
padding: 16px;
width: 100%;
&-controls {
input.field {
font-size: 16px;
padding: 14px 16px;
}
}
.title {
font-size: 20px;
line-height: 28px;
letter-spacing: -0.012;
margin-bottom: 24px;
display: none;
}
}
.con-status {
margin: 16px;
width: calc(100% - 32px);
margin: 0;
width: 100%;
}
.device-status-error {
border-radius: 0;
margin: 0 -16px;
}
input.field {
@@ -183,15 +205,9 @@
.action-btn {
font-size: 16px;
margin-bottom: 8px;
padding: 11px 16px;
}
.toolbox-content-items {
border-radius: 0;
display: flex;
justify-content: space-evenly;
padding: 8px 0;
}
}
input::placeholder {
@@ -208,8 +224,6 @@
width: 100%;
.avatar {
background: #0045B3;
text {
fill: white;
font-size: 26px;
@@ -229,68 +243,3 @@
display: flex;
justify-content: center;
}
@mixin icon-container($bg, $fill) {
.toggle-button-icon-container {
background: $bg;
svg {
fill: $fill
}
}
}
.toggle-button {
border-radius: 6px;
cursor: pointer;
color: #fff;
font-size: 13px;
height: 40px;
margin: 0 auto;
transition: background 0.16s ease-out;
@include flex-centered();
svg {
fill: transparent;
}
label {
cursor: pointer;
}
&:hover {
background: rgba(255, 255, 255, 0.1);
.toggle-button-icon-container {
display: none;
}
}
&-container {
position: relative;
@include flex-centered();
}
&-icon-container {
border-radius: 50%;
left: -22px;
padding: 2px;
position: absolute;
}
&--toggled {
@include icon-container(white, #1C2025);
&:hover {
.toggle-button-icon-container {
display: block;
}
}
.toggle-button-icon-container {
display: block;
}
}
}

0
eslint Normal file
View File

View File

@@ -25,31 +25,11 @@ var interfaceConfig = {
BRAND_WATERMARK_LINK: '',
CLOSE_PAGE_GUEST_HINT: false, // A html text to be shown to guests on the close page, false disables it
/**
* Whether the connection indicator icon should hide itself based on
* connection strength. If true, the connection indicator will remain
* displayed while the participant has a weak connection and will hide
* itself after the CONNECTION_INDICATOR_HIDE_TIMEOUT when the connection is
* strong.
*
* @type {boolean}
*/
CONNECTION_INDICATOR_AUTO_HIDE_ENABLED: true,
/**
* How long the connection indicator should remain displayed before hiding.
* Used in conjunction with CONNECTION_INDICATOR_AUTOHIDE_ENABLED.
*
* @type {number}
*/
CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT: 5000,
/**
* If true, hides the connection indicators completely.
*
* @type {boolean}
*/
CONNECTION_INDICATOR_DISABLED: false,
// Connection indicators (
// CONNECTION_INDICATOR_AUTO_HIDE_ENABLED,
// CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT,
// CONNECTION_INDICATOR_DISABLED) got moved to config.js.
DEFAULT_BACKGROUND: '#474747',
DEFAULT_LOCAL_DISPLAY_NAME: 'me',
@@ -59,7 +39,8 @@ var interfaceConfig = {
DISABLE_DOMINANT_SPEAKER_INDICATOR: false,
DISABLE_FOCUS_INDICATOR: false,
// Deprecated. Please use disableModeratorIndicator from config.js
// DISABLE_FOCUS_INDICATOR: false,
/**
* If true, notifications regarding joining/leaving are no longer displayed.
@@ -185,10 +166,10 @@ var interfaceConfig = {
SHOW_BRAND_WATERMARK: false,
/**
* Decides whether the chrome extension banner should be rendered on the landing page and during the meeting.
* If this is set to false, the banner will not be rendered at all. If set to true, the check for extension(s)
* being already installed is done before rendering.
*/
* Decides whether the chrome extension banner should be rendered on the landing page and during the meeting.
* If this is set to false, the banner will not be rendered at all. If set to true, the check for extension(s)
* being already installed is done before rendering.
*/
SHOW_CHROME_EXTENSION_BANNER: false,
SHOW_DEEP_LINKING_IMAGE: false,

View File

@@ -59,6 +59,7 @@ target 'JitsiMeetSDK' do
pod 'react-native-calendar-events', :path => '../node_modules/react-native-calendar-events'
pod 'react-native-keep-awake', :path => '../node_modules/react-native-keep-awake'
pod 'react-native-netinfo', :path => '../node_modules/@react-native-community/netinfo'
pod 'react-native-performance', :path => '../node_modules/react-native-performance/ios'
pod 'react-native-slider', :path => '../node_modules/@react-native-community/slider'
pod 'react-native-splash-screen', :path => '../node_modules/react-native-splash-screen'
pod 'react-native-video', :path => '../node_modules/react-native-video/react-native-video.podspec'

View File

@@ -288,6 +288,8 @@ PODS:
- React
- react-native-netinfo (4.1.5):
- React
- react-native-performance (2.0.0):
- React-Core
- react-native-slider (3.0.3):
- React
- react-native-splash-screen (3.2.0):
@@ -402,6 +404,7 @@ DEPENDENCIES:
- react-native-calendar-events (from `../node_modules/react-native-calendar-events`)
- react-native-keep-awake (from `../node_modules/react-native-keep-awake`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-performance (from `../node_modules/react-native-performance/ios`)
- "react-native-slider (from `../node_modules/@react-native-community/slider`)"
- react-native-splash-screen (from `../node_modules/react-native-splash-screen`)
- react-native-video (from `../node_modules/react-native-video/react-native-video.podspec`)
@@ -488,6 +491,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-keep-awake"
react-native-netinfo:
:path: "../node_modules/@react-native-community/netinfo"
react-native-performance:
:path: "../node_modules/react-native-performance/ios"
react-native-slider:
:path: "../node_modules/@react-native-community/slider"
react-native-splash-screen:
@@ -575,6 +580,7 @@ SPEC CHECKSUMS:
react-native-calendar-events: 1442fad71a00388f933cfa25512588fec300fcf8
react-native-keep-awake: eba3137546b10003361b37c761f6c429b59814ae
react-native-netinfo: 8d8db463bcc5db66a8ac5c48a7d86beb3b92f61a
react-native-performance: 8edfa2bbc9a2af4a02f01d342118e413a95145e0
react-native-slider: b733e17fdd31186707146debf1f04b5d94aa1a93
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
react-native-video: 1574074179ecaf6a9dd067116c8f31bf9fec15c8
@@ -599,6 +605,6 @@ SPEC CHECKSUMS:
RNWatch: a5320c959c75e72845c07985f3e935e58998f1d3
Yoga: 96b469c5e81ff51b917b92e8c3390642d4ded30c
PODFILE CHECKSUM: 6f4485ed41286517917d47d2170b0de97d32bbfb
PODFILE CHECKSUM: e830b1b5a46d340e22689b146b55dcf24664c6f1
COCOAPODS: 1.10.1

View File

@@ -49,9 +49,11 @@
"messagebox": "",
"nickname": {
"popover": "Kies n bynaam",
"title": ""
"title": "",
"titleWithPolls": ""
},
"title": ""
"title": "",
"titleWithPolls": ""
},
"connectingOverlay": {
"joiningRoom": ""

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "لا يوجد أي رسالة في الاجتماع بعد. ابدأ محادثة هنا.",
"nickname": {
"popover": "اختر لقبًا",
"title": "اكتب لقبًا لاعتماده في المحادثة"
"title": "اكتب لقبًا لاعتماده في المحادثة",
"titleWithPolls": "اكتب لقبًا لاعتماده في المحادثة"
},
"privateNotice": "أرسل رسالة خاصة إلى {{recipient}}",
"title": "محادثة",
"titleWithPolls": "محادثة",
"you": "أنت"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "У канферэнцыі пакуль няма ніякіх паведамленняў. Пачніце размову!",
"nickname": {
"popover": "Калі ласка, пазначце імя",
"title": "Калі ласка, увядзіце імя для выкарыстання чата"
"title": "Калі ласка, увядзіце імя для выкарыстання чата",
"titleWithPolls": "Калі ласка, увядзіце імя для выкарыстання чата"
},
"privateNotice": "Асабістае паведамленне карыстальнiку {{recipient}}",
"title": "Чат",
"titleWithPolls": "Чат",
"you": "Вы"
},
"chromeExtensionBanner": {

View File

@@ -65,10 +65,12 @@
"noMessagesMessage": "Все още няма съобщения в срещата. Започнете разговор тук!",
"nickname": {
"popover": "Избор на име",
"title": "Въведете име, за да обменяте съобщения"
"title": "Въведете име, за да обменяте съобщения",
"titleWithPolls": "Въведете име, за да обменяте съобщения"
},
"privateNotice": "Лично съобщение до {{recipient}}",
"title": "Текстови съобщения",
"titleWithPolls": "Текстови съобщения",
"you": "вие"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Encara no hi ha cap missatge en aquesta reunió. Comenceu una conversa aquí!",
"nickname": {
"popover": "Trieu un sobrenom",
"title": "Introduïu un sobrenom per a usar el xat"
"title": "Introduïu un sobrenom per a usar el xat",
"titleWithPolls": "Introduïu un sobrenom per a usar el xat"
},
"privateNotice": "Missatge privat per a {{recipient}}",
"title": "Xat",
"titleWithPolls": "Xat",
"you": "vós"
},
"chromeExtensionBanner": {

View File

@@ -67,11 +67,13 @@
"messagebox": "Napište zprávu",
"nickname": {
"popover": "Zvolte si přezdívku",
"title": "Vložte přezdívku, abyste mohl/a používat zprávy"
"title": "Vložte přezdívku, abyste mohl/a používat zprávy",
"titleWithPolls": "Vložte přezdívku, abyste mohl/a používat zprávy"
},
"noMessagesMessage": "V setkání zatím nejsou žádné zprávy. Tady můžete začít konverzaci!",
"privateNotice": "Soukromá zpráva pro {{recipient}}",
"title": "Zprávy",
"titleWithPolls": "Zprávy",
"you": "vy"
},
"chromeExtensionBanner": {

View File

@@ -54,10 +54,12 @@
"noMessagesMessage": "Der er ikke nogen beskeder i mødet endnu. Skriv noget!",
"nickname": {
"popover": "Vælg dit navn/alias",
"title": "Indtast et navn/alias for at deltage i chatten"
"title": "Indtast et navn/alias for at deltage i chatten",
"titleWithPolls": "Indtast et navn/alias for at deltage i chatten"
},
"privateNotice": "Privat besked til {{recipient}}",
"title": "Chat",
"titleWithPolls": "Chat",
"you": "Dig"
},
"chromeExtensionBanner": {

View File

@@ -66,15 +66,21 @@
"noMessagesMessage": "Es gibt noch keine Nachricht in dieser Konferenz. Starten Sie hier eine Unterhaltung!",
"nickname": {
"popover": "Wähle einen Alias",
"title": "Geben Sie einen Alias zum Chatten ein"
"title": "Geben Sie einen Alias zum Chatten ein",
"titleWithPolls": "Geben Sie einen Alias zum Chatten ein"
},
"privateNotice": "Private Nachricht an {{recipient}}",
"title": "Chatten",
"you": "Sie",
"message": "Nachricht",
"messageAccessibleTitle": "{{user}} sagt:",
"messageAccessibleTitleMe": "Ich sage:",
"smileysPanel": "Emoji-Auswahl"
"smileysPanel": "Emoji-Auswahl",
"tabs": {
"chat": "Chatten",
"polls": "Umfragen"
},
"title": "Chatten",
"titleWithPolls": "Chatten und Umfragen",
"you": "Sie"
},
"chromeExtensionBanner": {
"installExtensionText": "Installieren Sie die Erweiterung für die Integration von Google Calendar und Office 365",
@@ -243,13 +249,17 @@
"micPermissionDeniedError": "Die Berechtigung zur Verwendung des Mikrofons wurde nicht erteilt. Sie können trotzdem an der Konferenz teilnehmen, aber die anderen Personen können Sie nicht hören. Verwenden Sie die Kamera-Schaltfläche in der Adressleiste, um die Berechtigungen zu erteilen.",
"micTimeoutError": "Audioquelle konnte nicht gestartet werden. Zeitüberschreitung",
"micUnknownError": "Das Mikrofon kann aus einem unbekannten Grund nicht verwendet werden.",
"moderationAudioLabel": "Erlaube Anwesenden die Stummschaltung für sich aufzuheben",
"moderationVideoLabel": "Erlaube Anwesenden ihre Kamera einzuschalten",
"muteEveryoneElseDialog": "Einmal stummgeschaltet, können Sie deren Stummschaltung nicht mehr beenden, aber sie können ihre Stummschaltung jederzeit selbst beenden.",
"muteEveryoneElseTitle": "Alle außer {{whom}} stummschalten?",
"muteEveryoneDialog": "Wollen Sie wirklich alle stummschalten? Sie können deren Stummschaltung nicht mehr beenden, aber sie können ihre Stummschaltung jederzeit selbst beenden.",
"muteEveryoneDialogModerationOn": "Die Anwesenden können eine Anfrage zum Sprechen jederzeit senden.",
"muteEveryoneTitle": "Alle stummschalten?",
"muteEveryoneElsesVideoDialog": "Sobald die Kamera deaktiviert ist, können Sie sie nicht wieder aktivieren, die Teilnehmer können dies aber jederzeit wieder ändern.",
"muteEveryoneElsesVideoTitle": "Die Kamera von allen außer {{whom}} ausschalten?",
"muteEveryonesVideoDialog": "Sind Sie sicher, dass Sie die Kamera von allen Teilnehmern deaktivieren möchten? Sie können sie nicht wieder aktivieren, die Teilnehmer können dies aber jederzeit wieder ändern.",
"muteEveryonesVideoDialogModerationOn": "Die Anwesenden können jederzeit eine Anfrage senden, um ihre Kamera einzuschalten.",
"muteEveryonesVideoDialogOk": "deaktivieren",
"muteEveryonesVideoTitle": "Die Kamera von allen anderen ausschalten?",
"muteEveryoneSelf": "sich selbst",
@@ -382,7 +392,8 @@
"image7" : "Sonnenaufgang",
"desktopShareError": "Desktop konnte nicht freigegeben werden",
"desktopShare": "Desktopfreigabe",
"webAssemblyWarning": "WebAssembly wird nicht unterstützt"
"webAssemblyWarning": "WebAssembly wird nicht unterstützt",
"backgroundEffectError": "Failed to apply background effect."
},
"feedback": {
"average": "Durchschnittlich",
@@ -587,6 +598,8 @@
"moderationStoppedTitle": "Moderation gestoppt",
"moderationToggleDescription": "von {{participantDisplayName}}",
"raiseHandAction": "Melden",
"groupTitle": "Benachrichtigungen",
"reactionSounds": "Interaktionstöne deaktivieren",
"groupTitle": "Benachrichtigungen"
},
"participantsPane": {
@@ -599,20 +612,49 @@
},
"actions": {
"allow": "Anwesenden erlauben:",
"audioModeration": "Für sich selbst die Stummschaltung aufzuheben",
"blockEveryoneMicCamera": "Kamera und Mikrofon von allen sperren",
"invite": "Person einladen",
"askUnmute": "Anfragen, Stummschaltung aufzuheben",
"mute": "Stummschalten",
"muteAll": "Alle stummschalten",
"muteEveryoneElse": "Alle anderen stummschalten",
"startModeration": "Stummschaltung aufheben oder Kamera aktivieren",
"stopEveryonesVideo": "Alle Kameras ausschalten",
"stopVideo": "Kamera ausschalten",
"unblockEveryoneMicCamera": "Kamera und Mikrofon von allen entsperren"
"unblockEveryoneMicCamera": "Kamera und Mikrofon von allen entsperren",
"videoModeration": "Kamera einschalten"
}
},
"passwordSetRemotely": "von einer anderen Person gesetzt",
"passwordDigitsOnly": "Bis zu {{number}} Ziffern",
"polls": {
"create": {
"addOption": "Antwort hinzufügen",
"answerPlaceholder": "Antwort {{index}}",
"create": "Umfrage erstellen",
"cancel": "Abbrechen",
"pollOption" : "Antwort {{index}}",
"pollQuestion" : "Frage",
"questionPlaceholder": "Eine Frage stellen",
"removeOption": "Antwort entfernen",
"send": "Erstellen"
},
"answer": {
"skip": "Überspringen",
"submit": "Speichern"
},
"results": {
"vote": "Vote",
"changeVote": "Antwort ändern",
"empty": "Es gibt bisher keine Umfragen in dieser Konferenz. Sie können hier eine Umfrage starten!",
"hideDetailedResults": "Details verbergen",
"showDetailedResults": "Details anzeigen"
},
"notification": {
"title": "Dieser Konferenz wurde eine Umfrage hinzugefügt",
"description": "Öffnen Sie das Umfragen-Tab um abzustimmen"
}
},
"poweredby": "Betrieben von",
"prejoin": {
"audioAndVideoError": "Audio- und Videofehler:",
@@ -762,6 +804,7 @@
"participantJoined": "Neue Person nimmt teil",
"participantLeft": "Person verlässt die Konferenz",
"playSounds": "Hinweistöne aktiviert",
"reactions": "Interaktionen",
"sameAsSystem": "Wie System ({{label}})",
"selectAudioOutput": "Audioausgabe",
"selectCamera": "Kamera",
@@ -852,7 +895,6 @@
"muteEveryonesVideo": "Alle Kameras ausschalten",
"muteEveryoneElsesVideo": "Alle anderen Kameras ausschalten",
"participants": "Anwesende",
"party": "Konfetti",
"pip": "Bild-in-Bild-Modus ein-/ausschalten",
"privateMessage": "Private Nachricht senden",
"profile": "Profil bearbeiten",
@@ -869,6 +911,7 @@
"shareYourScreen": "Bildschirmfreigabe ein-/ausschalten",
"shortcuts": "Tastenkombinationen ein-/ausblenden",
"show": "Im Vordergrund anzeigen",
"silence": "Stille",
"speakerStats": "Sprechstatistik ein-/ausblenden",
"surprised": "Überrascht",
"tileView": "Kachelansicht ein-/ausschalten",
@@ -893,6 +936,7 @@
"clap": "Klatschen",
"closeChat": "Chat schließen",
"closeReactionsMenu": "Interationsmenü schließen",
"disableReactionSounds": "Sie können die Interaktionstöne für diese Konferenz deaktivieren",
"documentClose": "Geteiltes Dokument schließen",
"documentOpen": "Geteiltes Dokument öffnen",
"download": "Unsere Apps herunterladen",
@@ -928,7 +972,6 @@
"openChat": "Chat öffnen",
"openReactionsMenu": "Interationsmenü öffnen",
"participants": "Anwesende",
"party": "Konfetti",
"pip": "Bild-in-Bild-Modus einschalten",
"privateMessage": "Private Nachricht senden",
"profile": "Profil bearbeiten",
@@ -938,7 +981,7 @@
"reactionClap": "Klatschen senden",
"reactionLaugh": "Lachen senden",
"reactionLike": "Daumen hoch senden",
"reactionParty": "Konfetti senden",
"reactionSilence": "Stille senden",
"reactionSurprised": "Überrascht senden",
"security": "Sicherheitsoptionen",
"Settings": "Einstellungen",
@@ -946,6 +989,7 @@
"sharedvideo": "YouTube-Video teilen",
"shareRoom": "Person einladen",
"shortcuts": "Tastenkürzel anzeigen",
"silence": "Stille",
"speakerStats": "Sprechstatistik",
"startScreenSharing": "Bildschirmfreigabe starten",
"startSubtitles": "Untertitel einschalten",
@@ -1098,6 +1142,7 @@
"enableDialogText": "Mit dem Lobbymodus schützen Sie Ihre Konferenz, damit der Beitritt von Ihnen moderiert werden kann.",
"enterPasswordButton": "Konferenzpasswort eingeben",
"enterPasswordTitle": "Passwort zum Beitreten benutzen",
"errorMissingPassword": "Bitte das Konferenzpasswort eingeben",
"invalidPassword": "Ungültiges Passwort",
"joiningMessage": "Sie treten der Konferenz bei, sobald jemand Ihre Anfrage annimmt.",
"joinWithPasswordMessage": "Beitrittsversuch mit Passwort, bitte warten …",

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "Δεν υπάρχουν μηνύματα στη συνάντηση ακόμα. Ξεκινήστε μια συζήτηση εδώ!",
"nickname": {
"popover": "Επιλέξτε ένα ψευδώνυμο",
"title": "Εισάγετε ένα ψευδώνυμο για τη χρήση της συνομιλίας"
"title": "Εισάγετε ένα ψευδώνυμο για τη χρήση της συνομιλίας",
"titleWithPolls": "Εισάγετε ένα ψευδώνυμο για τη χρήση της συνομιλίας"
},
"privateNotice": "Ιδιωτικό μηνύμα στον / στην {recipient}}",
"title": "Συνομιλία",
"titleWithPolls": "Συνομιλία",
"you": "Εσείς"
},
"chromeExtensionBanner": {

View File

@@ -50,9 +50,11 @@
"messagebox": "Type a message",
"nickname": {
"popover": "Choose a nickname",
"title": "Enter a nickname to use chat"
"title": "Enter a nickname to use chat",
"titleWithPolls": "Enter a nickname to use chat"
},
"title": "Chat",
"titleWithPolls": "Chat",
"you": "",
"privateNotice": "",
"noMessagesMessage": "",

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Ankoraŭ ne estas mesaĝoj en la kunveno. Komencu konversation ĉi tie!",
"nickname": {
"popover": "Elektu kaŝnomon",
"title": "Elektu kaŝnomon por uzi la babilejon"
"title": "Elektu kaŝnomon por uzi la babilejon",
"titleWithPolls": "Elektu kaŝnomon por uzi la babilejon"
},
"privateNotice": "Privata mesaĝo al {{recipient}}",
"title": "Babilejo",
"titleWithPolls": "Babilejo",
"you": "vi"
},
"chromeExtensionBanner": {

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "No hay mensajes en la reunión. ¡Inicie una conversación!",
"nickname": {
"popover": "Selecciona un apodo",
"title": "Introduce un apodo para usar el chat"
"title": "Introduce un apodo para usar el chat",
"titleWithPolls": "Introduce un apodo para usar el chat"
},
"privateNotice": "Mensaje privado para {{recipient}}",
"title": "Chat",
"titleWithPolls": "Chat",
"you": "usted"
},
"chromeExtensionBanner": {

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "No hay mensajes en la reunión. ¡Inicie una conversación!",
"nickname": {
"popover": "Selecciona un apodo",
"title": "Introduce un apodo para usar el chat"
"title": "Introduce un apodo para usar el chat",
"titleWithPolls": "Introduce un apodo para usar el chat"
},
"privateNotice": "Mensaje privado para {{recipient}}",
"title": "Chat",
"titleWithPolls": "Chat",
"you": "usted"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Kirjavahetust pole veel alustatud. Alusta kirjavahetust siin!",
"nickname": {
"popover": "Sisesta nimi",
"title": "Sisesta nimi, et kõnega alustada"
"title": "Sisesta nimi, et kõnega alustada",
"titleWithPolls": "Sisesta nimi, et kõnega alustada"
},
"privateNotice": "Privaatsõnum kasutajale {{recipient}}",
"title": "Kõne",
"titleWithPolls": "Kõne",
"you": "you"
},
"chromeExtensionBanner": {

View File

@@ -64,10 +64,12 @@
"noMessagesMessage": "Bileran oraindik mezurik ez dago. Hasi elkarrizketa hemen!",
"nickname": {
"popover": "Aukeratu goitizena",
"title": "Sartu goitizena txata erabiltzeko"
"title": "Sartu goitizena txata erabiltzeko",
"titleWithPolls": "Sartu goitizena txata erabiltzeko"
},
"privateNotice": "Mezu pribatua {{recipient}}(e)ri",
"title": "Txata",
"titleWithPolls": "Txata",
"you": "zu",
"message": "Mezua",
"messageAccessibleTitle": "{{user}} partaideak zera dio:",

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "هیچ گفتگویی در جلسه وجود ندارد، گفتگو را شما آعاز کنید!",
"nickname": {
"popover": "نام نمایشی خود را وارد نمایید",
"title": "نام نمایشی خود را در گفتگو وارد نمایید"
"title": "نام نمایشی خود را در گفتگو وارد نمایید",
"titleWithPolls": "نام نمایشی خود را در گفتگو وارد نمایید"
},
"privateNotice": "پیام خصوصی به {{recipient}}",
"title": "گفتگو",
"titleWithPolls": "گفتگو",
"you": "شما"
},
"chromeExtensionBanner": {

View File

@@ -49,9 +49,11 @@
"messagebox": "Kirjoita viesti",
"nickname": {
"popover": "Valitse lempinimi",
"title": "Anna chatissä käytettävä lempinimi"
"title": "Anna chatissä käytettävä lempinimi",
"titleWithPolls": "Anna chatissä käytettävä lempinimi"
},
"title": "Chatti"
"title": "Chatti",
"titleWithPolls": "Chatti"
},
"connectingOverlay": {
"joiningRoom": "Yhdistetään kokoukseen…"

View File

@@ -66,7 +66,8 @@
"noMessagesMessage": "Il n'y a pas encore de messages dans cette réunion. Démarrez une conversation ici !",
"nickname": {
"popover": "Choisissez un pseudonyme",
"title": "Entrez un pseudonyme pour utiliser le chat et les sondages"
"title": "Entrez un pseudonyme pour utiliser le chat",
"titleWithPolls": "Entrez un pseudonyme pour utiliser le chat et les sondages"
},
"privateNotice": "Message privé à {{recipient}}",
"message": "Message",
@@ -74,11 +75,12 @@
"messageAccessibleTitleMe": "Je dis: ",
"smileysPanel": "Panneaux des Émojis",
"tabs": {
"chat": "Chat",
"polls": "Sondages"
},
"title": "Chat et Sondages",
"you": "vous"
"chat": "Chat",
"polls": "Sondages"
},
"title": "Chat",
"titleWithPolls": "Chat et Sondages",
"you": "vous"
},
"chromeExtensionBanner": {
"installExtensionText": "Installer l'extension pour l'intégration de Google Calendar et Office 365",

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Il n'y a pas encore de messages dans cette réunion. Démarrez une conversation ici !",
"nickname": {
"popover": "Choisissez un nom d'affichage",
"title": "Entrer un nom d'affichage pour utiliser le clavardage"
"title": "Entrer un nom d'affichage pour utiliser le clavardage",
"titleWithPolls": "Entrer un nom d'affichage pour utiliser le clavardage"
},
"privateNotice": "Message privé à {{recipient}}",
"title": "Clavardage",
"titleWithPolls": "Clavardage",
"you": "vous"
},
"connectingOverlay": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Aínda non hai mensaxes na reunión. Comece unha conversación aquí!",
"nickname": {
"popover": "Escolla un alcume",
"title": "Escriba un alcume para utilizar no chat"
"title": "Escriba un alcume para utilizar no chat",
"titleWithPolls": "Escriba un alcume para utilizar no chat"
},
"privateNotice": "Mensaxe privada para {{recipient}}",
"title": "Chat",
"titleWithPolls": "Chat",
"you": "vostede"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "אין עדיין הודעות בפגישה. התחל שיחה כאן!",
"nickname": {
"popover": "בחר שם משתמש",
"title": "נא להזין שם משתמש בכדי להשתמש בצ'אט"
"title": "נא להזין שם משתמש בכדי להשתמש בצ'אט",
"titleWithPolls": "נא להזין שם משתמש בכדי להשתמש בצ'אט"
},
"privateNotice": "הודעה פרטית אל {{recipient}}",
"title": "צ'אט",
"titleWithPolls": "צ'אט",
"you": "אתה"
},
"chromeExtensionBanner": {

View File

@@ -70,10 +70,12 @@
"noMessagesMessage": "अभी तक मीटिंग में कोई संदेश नहीं आया है। वार्तालाप प्रारंभ करें!",
"nickname": {
"popover": "एक उपनाम चुनें",
"title": "चैट का उपयोग करने के लिए एक उपनाम दर्ज करें"
"title": "चैट का उपयोग करने के लिए एक उपनाम दर्ज करें",
"titleWithPolls": "चैट का उपयोग करने के लिए एक उपनाम दर्ज करें"
},
"privateNotice": "{{recipient}} के लिए निजी संदेश",
"title": "चैट",
"titleWithPolls": "चैट",
"you": "आप"
},
"chromeExtensionBanner": {

View File

@@ -49,9 +49,11 @@
"messagebox": "",
"nickname": {
"popover": "Odaberite nadimak",
"title": "Unesite nadimak za čavrljanje"
"title": "Unesite nadimak za čavrljanje",
"titleWithPolls": "Unesite nadimak za čavrljanje"
},
"title": "Čavrljanje"
"title": "Čavrljanje",
"titleWithPolls": "Čavrljanje"
},
"connectingOverlay": {
"joiningRoom": ""

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "A találkozón még nincsenek üzenetek. Itt kezdhet beszélgetést!",
"nickname": {
"popover": "Becenév kiválasztása",
"title": "Adjon meg egy becenevet a csevegés számára"
"title": "Adjon meg egy becenevet a csevegés számára",
"titleWithPolls": "Adjon meg egy becenevet a csevegés számára"
},
"privateNotice": "Privát üzenet a felhasználónak: {{recipient}}",
"title": "Csevegés",
"titleWithPolls": "Csevegés",
"you": "neked"
},
"connectingOverlay": {

View File

@@ -49,9 +49,11 @@
"messagebox": "",
"nickname": {
"popover": "Ընտրեք մականուն",
"title": ""
"title": "",
"titleWithPolls": ""
},
"title": ""
"title": "",
"titleWithPolls": ""
},
"connectingOverlay": {
"joiningRoom": ""

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "There are no messages in the meeting yet. Start a conversation here!",
"nickname": {
"popover": "Choose a nickname",
"title": "Enter a nickname to use chat"
"title": "Enter a nickname to use chat",
"titleWithPolls": "Enter a nickname to use chat"
},
"privateNotice": "Private message to {{recipient}}",
"title": "Chat",
"titleWithPolls": "Chat",
"you": "you"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Það eru ennþá engin skilaboð á fundinum. Byrjaðu umræðuna hér!",
"nickname": {
"popover": "Veldu gælunafn",
"title": "Settu inn gælunafn/stuttnefni til að nota við spjall"
"title": "Settu inn gælunafn/stuttnefni til að nota við spjall",
"titleWithPolls": "Settu inn gælunafn/stuttnefni til að nota við spjall"
},
"privateNotice": "Einkaskilaboð til {{recipient}}",
"title": "Spjall",
"titleWithPolls": "Spjall",
"you": "þú"
},
"chromeExtensionBanner": {

View File

@@ -70,10 +70,12 @@
"noMessagesMessage": "Non ci sono ancora messaggi nella riunione. Comincia una conversazione, qui!",
"nickname": {
"popover": "Scegli un nickname",
"title": "Inserire un nickname per utilizzare la conversazione"
"title": "Inserire un nickname per utilizzare la conversazione",
"titleWithPolls": "Inserire un nickname per utilizzare la conversazione"
},
"privateNotice": "Messaggio privato per {{recipient}}",
"title": "Conversazione",
"titleWithPolls": "Conversazione",
"you": "tu"
},
"chromeExtensionBanner": {

View File

@@ -72,10 +72,12 @@
"noMessagesMessage": "このミーティングにはまだメッセージがありません。会話を開始してください!",
"nickname": {
"popover": "ニックネームを入力",
"title": "チャットで使用するニックネームを入力してください"
"title": "チャットで使用するニックネームを入力してください",
"titleWithPolls": "チャットで使用するニックネームを入力してください"
},
"privateNotice": "{{recipient}} へのプライベートメッセージ",
"title": "チャット",
"titleWithPolls": "チャット",
"you": "あなた"
},
"chromeExtensionBanner": {

View File

@@ -63,9 +63,11 @@
"messagebox": "Aru izen",
"nickname": {
"popover": "Fren meffer isem",
"title": "Sekcem meffer isem i useqdec n usqerdec"
"title": "Sekcem meffer isem i useqdec n usqerdec",
"titleWithPolls": "Sekcem meffer isem i useqdec n usqerdec"
},
"title": "Asqerdec",
"titleWithPolls": "Asqerdec",
"noMessagesMessage": "Ulac iznan akka tura deg temlilit. Bdu adiwenni da!",
"you": "kečč·kemm",
"fieldPlaceHolder": "Aru izen-inek·inem da"

View File

@@ -69,10 +69,12 @@
"noMessagesMessage": "아직 회의에 메시지가 없습니다. 여기서 대화를 시작하세요!",
"nickname": {
"popover": "닉네임을 선택하세요",
"title": "채팅에서 사용할 닉네임을 입력하세요"
"title": "채팅에서 사용할 닉네임을 입력하세요",
"titleWithPolls": "채팅에서 사용할 닉네임을 입력하세요"
},
"privateNotice": "{{recipient}}에게 보내는 비공개 메시지",
"title": "채팅",
"titleWithPolls": "채팅",
"you": "당신"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Susitikime dar nėra pranešimų. Pradėkite pokalbį čia!",
"nickname": {
"popover": "Pridėkite slapyvardį",
"title": "Norėdami naudoti pokalbį, įveskite slapyvardį"
"title": "Norėdami naudoti pokalbį, įveskite slapyvardį",
"titleWithPolls": "Norėdami naudoti pokalbį, įveskite slapyvardį"
},
"privateNotice": "Asmeninis pranešimas {{gavėjui}}",
"title": "Pokalbis",
"titleWithPolls": "Pokalbis",
"you": "Jūs"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Sapulcē pagaidām nav nevienas ziņas. Uzsāciet saraksti!",
"nickname": {
"popover": "Izvēlieties vārdu",
"title": "Ierakstiet vārdu izmantošanai tērziņā"
"title": "Ierakstiet vārdu izmantošanai tērziņā",
"titleWithPolls": "Ierakstiet vārdu izmantošanai tērziņā"
},
"privateNotice": "Privāta ziņa/paziņojums lietotājam {{recipient}}",
"title": "Tērzēšana",
"titleWithPolls": "Tērzēšana",
"you": "mans vārds"
},
"chromeExtensionBanner": {

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "മീറ്റിംഗിൽ ഇതുവരെ മെസ്സേജുകളൊന്നുമില്ല. ഇവിടെ ഒരു സംഭാഷണം ആരംഭിക്കുക!",
"nickname": {
"popover": "ഒരു വിളിപ്പേര് തിരഞ്ഞെടുക്കുക",
"title": "ചാറ്റ് ഉപയോഗിക്കുന്നതിന് ഒരു വിളിപ്പേര് നൽകുക"
"title": "ചാറ്റ് ഉപയോഗിക്കുന്നതിന് ഒരു വിളിപ്പേര് നൽകുക",
"titleWithPolls": "ചാറ്റ് ഉപയോഗിക്കുന്നതിന് ഒരു വിളിപ്പേര് നൽകുക"
},
"privateNotice": " {{recipient}}-ലേക്കുള്ള സ്വകാര്യ സന്ദേശം",
"title": "ചാറ്റ്",
"titleWithPolls": "ചാറ്റ്",
"you": "നിങ്ങൾ"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Энэ хуралд ямар ч зурвас байхгүй. Эндээс зурвасаа эхлүүл!",
"nickname": {
"popover": "Нэр бичнэ үү",
"title": "Нэрээ оруулна уу"
"title": "Нэрээ оруулна уу",
"titleWithPolls": "Нэрээ оруулна уу"
},
"privateNotice": "Хувийн зурвас {{recipient}}",
"title": "Чат",
"titleWithPolls": "Чат",
"you": "чи"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "अद्याप मीटिंगमध्ये कोणतेही संदेश नाहीत. येथे संभाषण सुरू करा!",
"nickname": {
"popover": "टोपणनाव निवडा",
"title": "चॅट वापरण्यासाठी टोपणनाव प्रविष्ट करा"
"title": "चॅट वापरण्यासाठी टोपणनाव प्रविष्ट करा",
"titleWithPolls": "चॅट वापरण्यासाठी टोपणनाव प्रविष्ट करा"
},
"privateNotice": "यांना खाजगी संदेश{{recipient}}",
"title": "गप्पा",
"titleWithPolls": "गप्पा",
"you": "आपण"
},
"chromeExtensionBanner": {

View File

@@ -46,9 +46,11 @@
"messagebox": "Skriv en melding",
"nickname": {
"popover": "Velg et kallenavn",
"title": ""
"title": "",
"titleWithPolls": ""
},
"title": "",
"titleWithPolls": "",
"messageTo": "Privat melding til {{recipient}}",
"fieldPlaceHolder": "Skriv inn din melding her"
},

View File

@@ -69,10 +69,12 @@
"noMessagesMessage": "Er zijn nog geen berichten in de vergadering. Begin hier een gesprek!",
"nickname": {
"popover": "Kies een bijnaam",
"title": "Voer een bijnaam in om chat te gebruiken"
"title": "Voer een bijnaam in om chat te gebruiken",
"titleWithPolls": "Voer een bijnaam in om chat te gebruiken"
},
"privateNotice": "Privébericht aan {{recipient}}",
"title": "Chat",
"titleWithPolls": "Chat",
"you": "u"
},
"chromeExtensionBanner": {

View File

@@ -71,12 +71,14 @@
"messageTo": "Messatge privat per {{recipient}}",
"nickname": {
"popover": "Causissètz un escais",
"title": "Picatz un escais-nom per utilizar la messatjariá"
"title": "Picatz un escais-nom per utilizar la messatjariá",
"titleWithPolls": "Picatz un escais-nom per utilizar la messatjariá"
},
"noMessagesMessage": "I a pas cap de messatge dins la conferéncia pel moment. Començat una conversacion aquí!",
"privateNotice": "Messatge privat per {{recipient}}",
"smileysPanel": "Panèl dEmoji",
"title": "Messatjariá",
"titleWithPolls": "Messatjariá",
"you": "vos"
},
"chromeExtensionBanner": {

View File

@@ -66,7 +66,8 @@
"noMessagesMessage": "Aktualnie brak wiadomości w tym spotkaniu. Rozpocznij konwersację!",
"nickname": {
"popover": "Wybierz swój nick",
"title": "Wpisz swoją nazwę, aby użyć rozmowy"
"title": "Wpisz swoją nazwę, aby użyć rozmowy",
"titleWithPolls": "Wpisz swoją nazwę, aby użyć rozmowy"
},
"privateNotice": "Prywatna wiadomość do {{recipient}}",
"message": "Wiadomość",
@@ -78,6 +79,7 @@
"polls": "Ankiety"
},
"title": "Rozmowa",
"titleWithPolls": "Rozmowa",
"you": "Ty"
},
"chromeExtensionBanner": {

View File

@@ -66,7 +66,8 @@
"noMessagesMessage": "Ainda não há mensagens na reunião. Comece aqui uma conversa!",
"nickname": {
"popover": "Escolha um apelido",
"title": "Introduza um apelido para usar no chat e nas sondagens"
"title": "Introduza um apelido para usar no chat e nas sondagens",
"titleWithPolls": "Introduza um apelido para usar no chat e nas sondagens"
},
"privateNotice": "Mensagem privada para {{recipient}}",
"message": "Mensagem",
@@ -78,6 +79,7 @@
"polls": "Sondagens"
},
"title": "Chat e Sondagens",
"titleWithPolls": "Chat e Sondagens",
"you": "você"
},
"chromeExtensionBanner": {
@@ -209,7 +211,8 @@
"dismiss": "Dispensar",
"displayNameRequired": "Olá! Qual é o seu nome?",
"done": "Feito",
"e2eeDescription": "A encriptação de ponta a ponta é actualmente EXPERIMENTAL. Tenha em mente que ligar a encriptação de ponta a ponta irá efectivamente desactivar os serviços fornecidos do lado do servidor, tais como: participação telefónica. Tenha também em mente que o encontro só funcionará para pessoas que se juntem a partir de browsers com suporte para \"insertable streams\".", "e2eeLabel": "Habilitar encriptação de ponta a ponta",
"e2eeDescription": "A encriptação de ponta a ponta é actualmente EXPERIMENTAL. Tenha em mente que ligar a encriptação de ponta a ponta irá efectivamente desactivar os serviços fornecidos do lado do servidor, tais como: participação telefónica. Tenha também em mente que o encontro só funcionará para pessoas que se juntem a partir de browsers com suporte para \"insertable streams\".",
"e2eeLabel": "Habilitar encriptação de ponta a ponta",
"e2eeWarning": "AVISO: Nem todos os participantes neste encontro parecem ter apoio para a encriptação de ponta a ponta. Se o permitir, eles não o poderão ver nem ouvir.",
"enterDisplayName": "Digite o seu nome aqui",
"embedMeeting": "Embutir reunião",
@@ -260,16 +263,21 @@
"muteParticipantBody": "Não poderá reativá-los, mas eles podem reativar-se a qualquer momento.",
"muteParticipantButton": "Silenciar",
"muteParticipantDialog": "Tem a certeza de que quer silenciar este participante? Não poderá reativá-los, mas eles podem reativar-se a qualquer momento.",
"muteParticipantsVideoDialog": "Tem a certeza de que quer desativar a câmara deste participante? Não poderá voltar a ativar a câmara, mas eles podem voltar a reativá-la a qualquer momento.",
"muteParticipantTitle": "Silenciar este participante?",
"muteParticipantsVideoButton": "Desativar a câmara",
"muteParticipantsVideoTitle": "Desativar a câmara deste participante?",
"muteParticipantsVideoBody": "Não poderá voltar a ligar a câmara, mas eles podem voltar a ligá-la a qualquer momento.",
"noDropboxToken": "Nenhum token do Dropbox válido",
"Ok": "OK",
"password": "Palavra-passe",
"passwordLabel": "A reunião foi encerrada por um participante. Por favor, introduza a $t(lockRoomPassword) para participar.",
"passwordNotSupported": "A definição na reunião $t(lockRoomPassword) não é suportada.",
"passwordNotSupportedTitle": "$t(lockRoomPasswordUppercase) não é suportada.",
"passwordRequired": "$t(lockRoomPasswordUppercase) necessário",
"permissionErrorTitle": "Permissão necessária",
"permissionCameraRequiredError": "É necessária a autorização da câmara para participar em conferências com vídeo. Por favor, conceda-a em Definições",
"permissionMicRequiredError": "É necessária a permissão do microfone para participar em conferências com áudio. Por favor, conceda-a em Definições",
"popupError": "O seu navegador está a bloquear janelas pop-up a partir deste site. Por favor, active os pop-ups nas definições de segurança do seu browser e tente novamente.",
"popupErrorTitle": "Pop-up bloqueado",
"readMore": "mais",
@@ -303,6 +311,13 @@
"sessTerminated": "Chamada terminada",
"sessionRestarted": "Chamada reiniciada pela ponte",
"Share": "Partilhar",
"shareAudio": "Continuar",
"shareAudioTitle" : "Como partilhar áudio",
"shareAudioWarningTitle": "Tem de parar a partilha de ecrã antes de partilhar áudio",
"shareAudioWarningH1": "Se quiser partilhar apenas áudio:",
"shareAudioWarningD1": "precisa de parar a partilha do ecrã antes de partilhar o seu áudio.",
"shareAudioWarningD2": "precisa de reiniciar a sua partilha de ecrã e verificar a opção \"partilhar áudio\".",
"shareMediaWarningGenericH2": "Se quiser partilhar o seu ecrã e áudio",
"shareVideoLinkError": "Por favor, forneça um link correcto do vídeo.",
"shareVideoTitle": "Partilhar vídeo",
"shareYourScreen": "Partilhe o seu ecrã",
@@ -310,6 +325,10 @@
"startLiveStreaming": "Iniciar a transmissão em direto",
"startRecording": "Iniciar gravação",
"startRemoteControlErrorMessage": "Ocorreu um erro ao tentar iniciar a sessão de controlo remoto!",
"shareScreenWarningTitle": "Tem de parar a partilha de áudio antes de partilhar o seu ecrã",
"shareScreenWarningH1": "Se quiser partilhar apenas o seu ecrã:",
"shareScreenWarningD1": "precisa de parar a partilha de áudio antes de partilhar o seu ecrã.",
"shareScreenWarningD2": "é necessário parar a partilha de áudio, iniciar a partilha de ecrã e verificar a opção \"partilhar áudio\".",
"stopLiveStreaming": "Parar a transmissão em direto",
"stopRecording": "Parar gravação",
"stopRecordingWarning": "Tem a certeza de que gostaria de parar a gravação?",
@@ -326,6 +345,9 @@
"userIdentifier": "Identificador do utilizador",
"userPassword": "Palavra-passe do utilizador",
"videoLink": "Link do vídeo",
"viewUpgradeOptions": "Ver opções de actualização",
"viewUpgradeOptionsContent": "Para obter acesso ilimitado a funcionalidades premium como gravação, transcrições, RTMP Streaming & mais, terá de actualizar o seu plano.",
"viewUpgradeOptionsTitle": "Descobriu uma característica premium!",
"WaitForHostMsg": "A conferência <b>{{room}}</b> ainda não começou. Se for o anfitrião, por favor autentique. Caso contrário, por favor aguarde que o anfitrião chegue.",
"WaitForHostMsgWOk": "A conferência <b>{{room}}</b> ainda não começou. Se for o anfitrião, por favor prima Ok para autenticar. Caso contrário, por favor aguarde que o anfitrião chegue.",
"WaitingForHostTitle": "À espera do anfitrião ...",
@@ -437,6 +459,7 @@
"support": "Suporte",
"supportMsg": "Se isso continuar acontecendo, chegar a"
},
"jitsiHome": "Logo de {{logo}}, redireciona para página inicial",
"keyboardShortcuts": {
"focusLocal": "Focar no seu vídeo",
"focusRemote": "Focar no vídeo de outro participante",
@@ -455,6 +478,8 @@
"videoMute": "Iniciar ou parar a sua câmara"
},
"liveStreaming": {
"limitNotificationDescriptionWeb": "Devido à grande procura, a sua transmissão será limitada a {{limit}} min. Para uma tentativa de streaming ilimitada tente <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
"limitNotificationDescriptionNative": "A sua transmissão será limitada a {{limit}} min. Para uma tentativa de streaming ilimitada tente {{app}}.",
"busy": "Estamos trabalhando para liberar os recursos de transmissão. Tente novamente em alguns minutos.",
"busyTitle": "Todas as transmissões estão atualmente ocupadas",
"changeSignIn": "Alternar contas.",
@@ -482,7 +507,9 @@
"signOut": "Sair",
"start": "Iniciar uma transmissão em direto",
"streamIdHelp": "O que é isso?",
"unavailableTitle": "Transmissão em direto indisponível"
"unavailableTitle": "Transmissão em direto indisponível",
"youtubeTerms": "Termos de serviços do YouTube",
"googlePrivacyPolicy": "Política de Privacidade do Google"
},
"localRecording": {
"clientState": {
@@ -515,14 +542,10 @@
},
"lockRoomPassword": "senha",
"lockRoomPasswordUppercase": "Senha",
"lonelyMeetingExperience": {
"youAreAlone": "Você é o único na reunião",
"button": "Convidar outros"
},
"me": "eu",
"notify": {
"connectedOneMember": "{{name}} entrou na reunião",
"connectedThreePlusMembers": "{{name}} e outros {{count}} entraram na reunião",
"connectedThreePlusMembers": "{{name}} e muitos outros entraram na reunião",
"connectedTwoMembers": "{{first}} e {{second}} entraram na reunião",
"disconnected": "desconectado",
"focus": "Foco da conferência",
@@ -700,6 +723,7 @@
"ringing": "Tocando..."
},
"profile": {
"avatar": "avatar",
"setDisplayNameLabel": "Definir seu nome de exibição",
"setEmailInput": "Digite e-mail",
"setEmailLabel": "Definir seu email de gravatar",
@@ -707,17 +731,22 @@
},
"raisedHand": "Gostaria de falar",
"recording": {
"limitNotificationDescriptionWeb": "Devido à grande procura, a sua gravação será limitada a {{limit}} min. For unlimited recordings try <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
"limitNotificationDescriptionNative": "Due to high demand your recording will be limited to {{limit}} min. Para gravações ilimitadas tente <3>{{app}}</3>.",
"authDropboxText": "Enviar para o Dropbox.",
"availableSpace": "Espaço disponível: {{spaceLeft}} MB (aproximadamente {{duration}} minutos de gravação)",
"beta": "BETA",
"busy": "Estamos trabalhando para liberar recursos de gravação. Tente novamente em alguns minutos.",
"busyTitle": "Todas as gravações estão atualmente ocupadas",
"copyLink": "Copiar Link",
"error": "A gravação falhou. Tente novamente.",
"errorFetchingLink": "Erro ao procurar link da gravação.",
"expandedOff": "Gravação finalizada",
"expandedOn": "A reunião está sendo gravada.",
"expandedPending": "Iniciando gravação...",
"failedToStart": "Falha ao iniciar a gravação",
"fileSharingdescription": "Compartilhar gravação com participantes da reunião",
"linkGenerated": "Gerámos um link para a sua gravação.",
"live": "DIRETO",
"loggedIn": "Conectado como {{userName}}",
"off": "Gravação parada",
@@ -727,11 +756,13 @@
"pending": "Preparando para gravar a reunião...",
"rec": "REC",
"serviceDescription": "Sua gravação será salva pelo serviço de gravação",
"serviceDescriptionCloud": "Gravação na nuvem",
"serviceName": "Serviço de gravação",
"signIn": "Entrar",
"signOut": "Sair",
"unavailable": "Oops! O {{serviceName}} está indisponível. Estamos trabalhando para resolver o problema. Por favor, tente mais tarde.",
"unavailableTitle": "Gravação indisponível"
"unavailableTitle": "Gravação indisponível",
"uploadToCloud": "Enviar para a nuvem"
},
"sectionList": {
"pullToRefresh": "Puxe para atualizar"
@@ -767,7 +798,7 @@
"participantJoined": "Entrar um participante",
"participantLeft": "Sair um participante",
"playSounds": "Reproduzir som quando",
"reactions": "Reações de reunião",
"reactions": "Expressarem uma reação",
"sameAsSystem": "O mesmo que o sistema ({{label}})",
"selectAudioOutput": "Saída de áudio",
"selectCamera": "Câmara",
@@ -780,14 +811,17 @@
"title": "Definições"
},
"settingsView": {
"advanced": "",
"advanced": "Avançado",
"alertOk": "OK",
"alertCancel": "Cancelar",
"alertTitle": "Atenção",
"alertURLText": "A URL digitada do servidor é inválida",
"buildInfoSection": "Informações de compilação",
"conferenceSection": "Conferência",
"disableCallIntegration": "",
"disableP2P": "",
"disableCallIntegration": "Desactivar a integração de chamadas nativas",
"disableP2P": "Desactivar o modo Peer-To-Peer",
"disableCrashReporting": "Desativar relatório de falhas",
"disableCrashReportingWarning": "Tem a certeza de que quer desativar o relatório de falhas? A configuração será aplicada depois de reiniciar a aplicação.",
"displayName": "Nome de exibição",
"email": "E-mail",
"header": "Configurações",
@@ -823,134 +857,146 @@
"title": "Sua chamada de vídeo foi interrompida, porque seu computador foi dormir."
},
"toolbar": {
"accessibilityLabel": {
"audioOnly": "Mudar para apenas áudio",
"accessibilityLabel": {
"audioOnly": "Mudar para apenas áudio",
"audioRoute": "Selecionar o dispositivo de som",
"boo": "Vaia",
"callQuality": "Gerir a qualidade do vídeo",
"cc": "Mudar legendas",
"chat": "Abrir / Fechar chat",
"clap": "Aplausos",
"document": "Mudar para documento partilhado",
"download": "Descarregar as nossas aplicações",
"embedMeeting": "Reunião incorporada",
"feedback": "Deixar comentários",
"fullScreen": "Mudar para ecrã completo",
"grantModerator": "Converter em moderador",
"hangup": "Sair da reunião",
"help": "Ajuda",
"invite": "Convidar pessoas",
"kick": "Remover participante",
"laugh": "Risos",
"like": "Aprovado",
"lobbyButton": "Ativar/desativar sala de espera",
"localRecording": "Mudar os controlos locais de gravação",
"lockRoom": "Mudar palavra-chave de reunião",
"moreActions": "Mais ações",
"moreActionsMenu": "Menu de mais ações",
"moreOptions": "Mostrar mais opções",
"mute": "Ativar / Desativar microfone",
"muteEveryone": "Silenciar a todos",
"muteEveryoneElse": "Silenciar todos os outros",
"muteEveryonesVideo": "Desativar a câmara de todos",
"muteEveryoneElsesVideo": "Desativar a câmara de todos os outros",
"participants": "Participantes",
"pip": "Mudar para o modo Picture-in-Picture",
"privateMessage": "Enviar mensagem privada",
"profile": "Editar o seu perfil",
"raiseHand": "Levantar / Baixar a mão",
"reactionsMenu": "Abrir / Fechar menu de reações",
"recording": "Mudar gravação",
"remoteMute": "Participante sem som",
"remoteVideoMute": "Desativar a câmara do participante",
"security": "Opções de segurança",
"Settings": "Mudar configurações",
"shareaudio": "Partilhar áudio",
"sharedvideo": "Mudar a partilha de vídeos do YouTube",
"shareRoom": "Convidar alguém",
"shareYourScreen": "Iniciar / Parar partilha de ecrã",
"shortcuts": "Mostrar / Esconder atalhos",
"show": "Mostrar no palco",
"silence": "Silêncio",
"speakerStats": "Mostrar / Esconder estatísticas dos participantes",
"surprised": "Surpreendido",
"tileView": "Mudar a vista em quadrícula",
"toggleCamera": "Mudar a câmara",
"toggleFilmstrip": "Mudar a película de filme",
"videomute": "Iniciar / Parar câmara",
"videoblur": "Mudar o desfoque de vídeo",
"selectBackground": "Selecionar plano de fundo",
"expand": "Expandir",
"collapse": "Colapsar"
},
"addPeople": "Adicione pessoas à sua chamada",
"audioSettings": "Definições de áudio",
"videoSettings": "Definições de vídeo",
"audioOnlyOff": "Desativar modo de largura de banda baixa",
"audioOnlyOn": "Ativar modo de largura de banda baixa",
"audioRoute": "Selecionar o dispositivo de som",
"authenticate": "Autenticar",
"boo": "Vaia",
"callQuality": "Gerir a qualidade do vídeo",
"cc": "Mudar legendas",
"chat": "Abrir / Fechar chat",
"document": "Mudar para documento partilhado",
"clap": "Aplausos",
"closeChat": "Fechar chat",
"closeReactionsMenu": "Fechar menu de reações",
"disableReactionSounds": "Pode desactivar os sons de reacção para esta reunião",
"documentClose": "Fechar documento partilhado",
"documentOpen": "Abrir documento partilhado",
"download": "Descarregar as nossas aplicações",
"embedMeeting": "Reunião incorporada",
"e2ee": "Criptografia ponta a ponta",
"embedMeeting": "Incorporar reunião",
"enterFullScreen": "Ver em ecrã completo",
"enterTileView": "Ver em quadrícula",
"exitFullScreen": "Sair de ecrã completo",
"exitTileView": "Sair de quadrícula",
"feedback": "Deixar comentários",
"fullScreen": "Mudar para ecrã completo",
"grantModerator": "Converter em moderador",
"hangup": "Sair da reunião",
"help": "Ajuda",
"invite": "Convidar pessoas",
"kick": "Remover participante",
"lobbyButton": "Ativar/desativar sala de espera",
"localRecording": "Mudar os controlos locais de gravação",
"lockRoom": "Mudar palavra-chave de reunião",
"laugh": "Risos",
"like": "Aprovado",
"lobbyButtonDisable": "Desativar sala de espera",
"lobbyButtonEnable": "Ativar sala de espera",
"login": "Iniciar sessão",
"logout": "Encerrar sessão",
"lowerYourHand": "Baixar a mão",
"moreActions": "Mais ações",
"moreActionsMenu": "Menu de mais ações",
"moreOptions": "Mostrar mais opções",
"moreOptions": "Mais opções",
"mute": "Ativar / Desativar microfone",
"muteEveryone": "Silenciar a todos",
"muteEveryoneElse": "Silenciar todos os outros",
"muteEveryone": "Silenciar todos",
"muteEveryonesVideo": "Desativar a câmara de todos",
"muteEveryoneElsesVideo": "Desativar a câmara de todos os outros",
"noAudioSignalTitle": "Não há nenhuma entrada vinda do seu microfone!",
"noAudioSignalDesc": "Se não o silenciou propositadamente a partir de configurações do sistema ou hardware, considere mudar de dispositivo.",
"noAudioSignalDescSuggestion": "Se não o silenciou propositadamente a partir das configurações do sistema ou hardware, considere mudar para o dispositivo sugerido.",
"noAudioSignalDialInDesc": "Também pode marcar usando:",
"noAudioSignalDialInLinkDesc": "Números de marcação",
"noisyAudioInputTitle": "Seu microfone parece estar barulhento!",
"noisyAudioInputDesc": "Parece que o seu microfone está a fazer barulho, por favor considere silenciar ou mudar de dispositivo.",
"openChat": "Abrir chat",
"openReactionsMenu": "Abrir menu de reações",
"participants": "Participantes",
"pip": "Mudar para o modo Picture-in-Picture",
"pip": "Entrar no modo Picture-in-Picture",
"privateMessage": "Enviar mensagem privada",
"profile": "Editar o seu perfil",
"raiseHand": "Levantar / Baixar a mão",
"recording": "Mudar gravação",
"remoteMute": "Participante sem som",
"remoteVideoMute": "Desativar a câmara do participante",
"raiseYourHand": "Levantar a mão",
"reactionBoo": "Enviar reação de vaia",
"reactionClap": "Enviar reação de aplausos",
"reactionLaugh": "Enviar reação de risos",
"reactionLike": "Enviar reação de aprovado",
"reactionSilence": "Enviar reação de silêncio",
"reactionSurprised": "Enviar reação de surpreendido",
"security": "Opções de segurança",
"Settings": "Mudar configurações",
"Settings": "Definições",
"shareaudio": "Partilhar áudio",
"sharedvideo": "Mudar a partilha de vídeos do YouTube",
"sharedvideo": "Partilhar vídeo",
"shareRoom": "Convidar alguém",
"shareYourScreen": "Iniciar / Parar partilha de ecrã",
"shortcuts": "Mostrar / Esconder atalhos",
"show": "Mostrar no palco",
"shortcuts": "Ver atalhos",
"silence": "Silêncio",
"speakerStats": "Mostrar / Esconder estatísticas dos participantes",
"tileView": "Mudar para vista em quadrícula",
"speakerStats": "Estatísticas dos participantes",
"startScreenSharing": "Iniciar partilha de ecrã",
"startSubtitles": "Iniciar legendas",
"stopAudioSharing": "Parar partilha de áudio",
"stopScreenSharing": "Parar partilha de ecrã",
"stopSubtitles": "Parar legendas",
"stopSharedVideo": "Parar vídeo do YouTube",
"surprised": "Surpreendido",
"talkWhileMutedPopup": "Está a tentar falar? Está com o microfone desativado.",
"tileViewToggle": "Mudar para vista em quadrícula",
"toggleCamera": "Mudar a câmara",
"toggleFilmstrip": "Mudar para película de filme",
"videomute": "Iniciar / Parar câmara",
"videoblur": "Mudar o desfoque de vídeo",
"selectBackground": "Selecionar plano de fundo",
"expand": "Expandir",
"collapse": "Colapsar"
},
"addPeople": "Adicione pessoas à sua chamada",
"audioSettings": "Definições de áudio",
"videoSettings": "Definições de vídeo",
"audioOnlyOff": "Desativar modo de largura de banda baixa",
"audioOnlyOn": "Ativar modo de largura de banda baixa",
"audioRoute": "Selecionar o dispositivo de som",
"authenticate": "Autenticar",
"callQuality": "Gerir a qualidade do vídeo",
"chat": "Abrir / Fechar chat",
"closeChat": "Fechar chat",
"closeReactionsMenu": "Fechar menu reações",
"disableReactionSounds": "Pode desactivar os sons de reacção para esta reunião",
"documentClose": "Fechar documento partilhado",
"documentOpen": "Abrir documento partilhado",
"download": "Descarregar as nossas aplicações",
"e2ee": "Criptografia ponta a ponta",
"embedMeeting": "Incorporar reunião",
"enterFullScreen": "Ver em ecrã completo",
"enterTileView": "Ver em quadrícula",
"exitFullScreen": "Sair de ecrã completo",
"exitTileView": "Sair de quadrícula",
"feedback": "Deixar comentários",
"hangup": "Sair da reunião",
"help": "Ajuda",
"invite": "Convidar pessoas",
"lobbyButtonDisable": "Desativar sala de espera",
"lobbyButtonEnable": "Ativar sala de espera",
"login": "Iniciar sessão",
"logout": "Encerrar sessão",
"lowerYourHand": "Baixar a mão",
"moreActions": "Mais ações",
"moreOptions": "Mais opções",
"mute": "Ativar / Desativar microfone",
"muteEveryone": "Silenciar todos",
"muteEveryonesVideo": "Desativar a câmara de todos",
"noAudioSignalTitle": "Não há nenhuma entrada vinda do seu microfone!",
"noAudioSignalDesc": "Se não o silenciou propositadamente a partir de configurações do sistema ou hardware, considere mudar de dispositivo.",
"noAudioSignalDescSuggestion": "Se não o silenciou propositadamente a partir das configurações do sistema ou hardware, considere mudar para o dispositivo sugerido.",
"noAudioSignalDialInDesc": "Também pode marcar usando:",
"noAudioSignalDialInLinkDesc": "Números de marcação",
"noisyAudioInputTitle": "Seu microfone parece estar barulhento!",
"noisyAudioInputDesc": "Parece que o seu microfone está a fazer barulho, por favor considere silenciar ou mudar de dispositivo.",
"openChat": "Abrir chat",
"participants": "Participantes",
"pip": "Entrar no modo Picture-in-Picture",
"privateMessage": "Enviar mensagem privada",
"profile": "Editar o seu perfil",
"raiseHand": "Levantar / Baixar a mão",
"raiseYourHand": "Levantar a mão",
"reactionBoo": "Enviar reação de boo",
"reactionClap": "Enviar reação de aplauso",
"reactionLaugh": "Enviar reação de riso",
"reactionLike": "Enviar reação positiva",
"reactionParty": "Enviar reação de lança-confetes",
"reactionSilence": "Enviar reação de silêncio",
"reactionSurprised": "Enviar reação de surpresa",
"security": "Opções de segurança",
"Settings": "Definições",
"shareaudio": "Partilhar áudio",
"sharedvideo": "Partilhar vídeo",
"shareRoom": "Convidar alguém",
"shortcuts": "Ver atalhos",
"silence": "Silêncio",
"speakerStats": "Estatísticas dos participantes",
"startScreenSharing": "Iniciar partilha de ecrã",
"startSubtitles": "Iniciar legendas",
"stopScreenSharing": "Parar partilha de ecrã",
"stopSubtitles": "Parar legendas",
"stopSharedVideo": "Parar vídeo do YouTube",
"talkWhileMutedPopup": "Está a tentar falar? Está com o microfone desativado.",
"tileViewToggle": "Mudar para vista em quadrícula",
"toggleCamera": "Mudar a câmara",
"videomute": "Iniciar / Parar câmara",
"selectBackground": "Selecionar plano de fundo"
"selectBackground": "Selecionar plano de fundo"
},
"transcribing": {
"ccButtonTooltip": "Iniciar/parar legendas",
@@ -965,30 +1011,31 @@
"tr": "TR"
},
"userMedia": {
"androidGrantPermissions": "Selecione <b><i>Permitir</i></b> quando seu navegador perguntar pelas permissões.",
"chromeGrantPermissions": "Selecione <b><i>Permitir</i></b> quando seu navegador perguntar pelas permissões.",
"edgeGrantPermissions": "Selecione <b><i>Sim</i></b> quando seu navegador perguntar pelas permissões.",
"electronGrantPermissions": "Dê as permissões para usar sua câmera e microfone",
"firefoxGrantPermissions": "Selecione <b><i>Compartilhar Dispositivos Selecionados</i></b> quando seu navegador perguntar pelas permissões.",
"iexplorerGrantPermissions": "Selecione <b><i>OK</i></b> quando seu navegador perguntar pelas permissões.",
"nwjsGrantPermissions": "Dê as permissões para usar sua câmera e microfone",
"operaGrantPermissions": "Selecione <b><i>Permitir</i></b> quando seu navegador perguntar pelas permissões.",
"react-nativeGrantPermissions": "Selecione <b><i>Permitir</i></b> quando seu navegador perguntar pelas permissões.",
"safariGrantPermissions": "Selecione <b><i>OK</i></b> quando seu navegador perguntar pelas permissões."
"androidGrantPermissions": "Selecione <b><i>Permitir</i></b> quando o seu navegador perguntar pelas permissões.",
"chromeGrantPermissions": "Selecione <b><i>Permitir</i></b> quando o seu navegador perguntar pelas permissões.",
"edgeGrantPermissions": "Selecione <b><i>Sim</i></b> quando o seu navegador perguntar pelas permissões.",
"electronGrantPermissions": "Dê as permissões para usar a sua câmara e microfone",
"firefoxGrantPermissions": "Selecione <b><i>Partilhar Dispositivos Selecionados</i></b> quando o seu navegador perguntar pelas permissões.",
"iexplorerGrantPermissions": "Selecione <b><i>OK</i></b> quando o seu navegador perguntar pelas permissões.",
"nwjsGrantPermissions": "Dê as permissões para usar a sua câmara e microfone",
"operaGrantPermissions": "Selecione <b><i>Permitir</i></b> quando o seu navegador perguntar pelas permissões.",
"react-nativeGrantPermissions": "Selecione <b><i>Permitir</i></b> quando o seu navegador perguntar pelas permissões.",
"safariGrantPermissions": "Selecione <b><i>OK</i></b> quando o seu navegador perguntar pelas permissões."
},
"volumeSlider": "Controlo de volume",
"videoSIPGW": {
"busy": "Estamos trabalhando para liberar recursos. Por favor, tente novamente em alguns minutos.",
"busy": "Estamos a trabalhar para liberar recursos. Por favor, tente novamente em alguns minutos.",
"busyTitle": "O serviço da sala está ocupado",
"errorAlreadyInvited": "{{displayName}} já convidado",
"errorInvite": "A conferência ainda não foi estabelecida. Por favor, tente mais tarde.",
"errorInviteFailed": "Estamos trabalhando para resolver o problema. Por favor, tente mais tarde.",
"errorInviteFailed": "Estamos a trabalhar para resolver o problema. Por favor, tente mais tarde.",
"errorInviteFailedTitle": "Convite para {{displayName}} falhou",
"errorInviteTitle": "Erro no convite da sala",
"pending": "{{displayName}} foi convidado"
},
"videoStatus": {
"audioOnly": "AUD",
"audioOnlyExpanded": "Você está em modo de banda baixa. Neste modo, se recebe somente áudio e compartilhamento de tela.",
"audioOnlyExpanded": "Está em modo de baixa largura de banda. Neste modo, receberá apenas partilha de áudio e ecrã.",
"callQuality": "Qualidade de vídeo",
"hd": "HD",
"hdTooltip": "Ver vídeo em alta definição",
@@ -998,8 +1045,6 @@
"ld": "LD",
"ldTooltip": "Ver vídeo em baixa definição",
"lowDefinition": "Baixa definição (LD)",
"onlyAudioAvailable": "Somente áudio disponível",
"onlyAudioSupported": "Suportamos somente áudio neste navegador.",
"sd": "SD",
"sdTooltip": "Ver vídeo em definição padrão",
"standardDefinition": "Definição padrão"
@@ -1016,39 +1061,65 @@
"moderator": "Moderador",
"mute": "Participante está sem som",
"muted": "Sem som",
"videomute": "O participante parou a câmara",
"videoMuted": "Câmara desativada",
"remoteControl": "Iniciar / Parar controlo remoto",
"show": "Mostrar no palco"
"show": "Mostrar no palco",
"videomute": "O participante parou a câmara"
},
"welcomepage": {
"addMeetingName": "AAdicionar nome da reunião",
"accessibilityLabel": {
"join": "Toque para entrar",
"roomname": "Digite o nome da sala"
},
"appDescription": "Vá em frente, converse por vídeo com toda a equipe. De fato, convide todos que você conhece. {{app}} é uma solução de videoconferência totalmente criptografada e 100% de código aberto que você pode usar todos os dias, a cada dia, gratuitamente — sem necessidade de conta.",
"appDescription": "Vá em frente, converse por vídeo com toda a equipa. Na verdade, convide todos os que conhece. {{app}} é uma solução de videoconferência totalmente criptografada e 100% de código aberto que você pode usar todos os dias, a cada dia, gratuitamente — sem necessidade de conta.",
"audioVideoSwitch": {
"audio": "Voz",
"video": "Vídeo"
},
"calendar": "Calendário",
"connectCalendarButton": "Conectar seu calendário",
"connectCalendarText": "Conecte seu calendário para ver todas as reuniões em {{app}}. Além disso, adicione reuniões de {{provider}} ao seu calendário e inicie-as com apenas um clique.",
"connectCalendarText": "Conecte o seu calendário para ver todas as reuniões em {{app}}. Além disso, adicione reuniões de {{provider}} ao seu calendário e inicie-as com apenas um clique.",
"enterRoomTitle": "Iniciar uma nova reunião",
"roomNameAllowedChars": "Nome da reunião não deve conter qualquer um destes caracteres: ?. &, :, ', \", %, #.",
"getHelp": "Obter ajuda",
"go": "IR",
"goSmall": "IR",
"join": "",
"headerTitle": "Jitsi Meet",
"headerSubtitle": "Reuniões com segurança e alta qualidade",
"info": "Informações",
"join": "CRIAR / ENTRAR",
"jitsiOnMobile": "Jitsi em dispositivos móveis descarregue as nossas aplicações e inicie uma reunião em qualquer lugar",
"mobileDownLoadLinkIos": "Descarregar aplicação móvel para iOS",
"mobileDownLoadLinkAndroid": "Descarregar aplicação móvel para Android",
"mobileDownLoadLinkFDroid": "Descarregar aplicação móvel para F-Droid",
"moderatedMessage": "Ou <a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">reserve um URL de reunião</a> com antecedência onde é o único moderador.",
"privacy": "Política de Privacidade",
"recentList": "Recente",
"recentListDelete": "Remover",
"recentListEmpty": "Sua lista recente está vazia. As reuniões que você realizar serão exibidas aqui.",
"reducedUIText": "Bem-vindo ao {{app}}!",
"roomNameAllowedChars": "Nome da reunião não deve conter qualquer um destes caracteres: ?. &, :, ', \", %, #.",
"roomname": "Digite o nome da sala",
"roomnameHint": "Digite o nome ou a URL da sala que você deseja entrar. Você pode digitar um nome, e apenas deixe para as pessoas que você quer se reunir digitem o mesmo nome.",
"roomnameHint": "Digite o nome ou URL da sala a que pretende entrar. Pode inventar um nome, basta informar as pessoas com quem se vai encontrar para que entrem com o mesmo nome.",
"sendFeedback": "Enviar comentários",
"startMeeting": "Iniciar reunião",
"terms": "Termos",
"title": "Videoconferências mais seguras, flexíveis e totalmente gratuitas"
"title": "Videoconferências mais seguras, flexíveis e totalmente gratuitas",
"logo":{
"calendar": "Logo do Calendário",
"microsoftLogo": "Logo da Microsoft",
"logoDeepLinking": "Logo do Jitsi Meet",
"desktopPreviewThumbnail": "Miniatura de Visualização do Desktop",
"googleLogo": "Logo do Google",
"policyLogo": "Logo da Política de Privacidade"
}
},
"lonelyMeetingExperience": {
"button": "Convidar outros",
"youAreAlone": "É o único na reunião"
},
"helpView": {
"header": "Centro de ajuda"
},
"lobby": {
"admit": "Aceitar",

View File

@@ -66,10 +66,12 @@
"noMessagesMessage": "Não há mensagens na reunião ainda. Inicie uma conversa aqui!",
"nickname": {
"popover": "Escolha um apelido",
"title": "Digite um apelido para usar o bate-papo"
"title": "Digite um apelido para usar o bate-papo",
"titleWithPolls": "Digite um apelido para usar o bate-papo"
},
"privateNotice": "Mensagem privada para {{recipient}}",
"title": "Bate-papo",
"titleWithPolls": "Bate-papo",
"you": "você",
"message": "Mensagem",
"messageAccessibleTitle": "{{user}} disse:",

View File

@@ -50,9 +50,11 @@
"messagebox": "Scrieți mesajul",
"nickname": {
"popover": "Alegeți un pseudonim",
"title": "Introduceți un pseudonim pentru a conversa"
"title": "Introduceți un pseudonim pentru a conversa",
"titleWithPolls": "Introduceți un pseudonim pentru a conversa"
},
"title": "Apel video",
"titleWithPolls": "Apel video",
"you": "",
"privateNotice": "",
"noMessagesMessage": "",

View File

@@ -67,11 +67,13 @@
"messagebox": "Введите сообщение",
"nickname": {
"popover": "Выберите имя",
"title": "Введите имя для использования чата"
"title": "Введите имя для использования чата",
"titleWithPolls": "Введите имя для использования чата"
},
"noMessagesMessage": "В конференции пока нет никаких сообщений. Начните разговор!",
"privateNotice": "Личное сообщение пользователю {{recipient}}",
"title": "Чат",
"titleWithPolls": "Чат",
"you": "вы"
},
"chromeExtensionBanner": {
@@ -452,6 +454,7 @@
"youtubeTerms": "Условия использования YouTube"
},
"lobby": {
"allow": "Разрешить",
"disableDialogContent": "В настоящее время включен режим лобби. Эта функция гарантирует, что нежелательные участники не смогут присоединиться к вашей встрече. Вы хотите его отключить?",
"disableDialogSubmit": "Отключить",
"emailField": "Введите ваш адрес электронной почты",
@@ -748,6 +751,7 @@
"moreOptions": "Меню доп. настроек",
"mute": "Вкл/Выкл звук",
"muteEveryone": "Выкл. микрофон у всех",
"participants": "Участники",
"pip": "Вкл/Выкл режим Картинка-в-картинке",
"privateMessage": "Отправить личное сообщение",
"profile": "Редактировать профиль",
@@ -805,6 +809,7 @@
"noisyAudioInputDesc": "Возможно, ваш микрофон создает шум. Вы можете выключить его или смените устройство.",
"noisyAudioInputTitle": "Похоже, ваш микрофон создает шум!",
"openChat": "Открыть чат",
"participants": "Участники",
"pip": "Вкл режим Картинка-в-картинке",
"privateMessage": "Отправить личное сообщение",
"profile": "Редактировать профиль",

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Perunu messàgiu ancora in sa riunione. Cumintza una tzarrada inoghe!",
"nickname": {
"popover": "Sèbera unu nòmine",
"title": "Inserta su nòmine pro impreare sa tzarrada"
"title": "Inserta su nòmine pro impreare sa tzarrada",
"titleWithPolls": "Inserta su nòmine pro impreare sa tzarrada"
},
"privateNotice": "Messàgiu privadu a {{recipient}}",
"title": "Tzarrada",
"titleWithPolls": "Tzarrada",
"you": "tue"
},
"chromeExtensionBanner": {

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "V tejto konferencii ešte nie je žiadna správa. Začnite tu vašu diskusiu!",
"nickname": {
"popover": "Zvoľte meno",
"title": "Zadajte vašu prezývku"
"title": "Zadajte vašu prezývku",
"titleWithPolls": "Zadajte vašu prezývku"
},
"privateNotice": "Súkromná správa pre {{recipient}}",
"title": "Chat",
"titleWithPolls": "Chat",
"you": "Vy"
},
"chromeExtensionBanner": {

View File

@@ -52,11 +52,13 @@
"messagebox": "Vnesite sporočilo",
"nickname": {
"popover": "Izberite svoje ime",
"title": "Vnesite ime, ki ga želite uporabljati na srečanju"
"title": "Vnesite ime, ki ga želite uporabljati na srečanju",
"titleWithPolls": "Vnesite ime, ki ga želite uporabljati na srečanju"
},
"noMessagesMessage": "There are no messages in the meeting yet. Start a conversation here!",
"privateNotice": "Zasebno sporočilo za uporabnika {{recipient}}",
"title": "Klepet",
"titleWithPolls": "Klepet",
"you": "vi"
},
"chromeExtensionBanner": {

View File

@@ -66,10 +66,12 @@
"noMessagesMessage": "Ende ska mesazhe te takimi. Filloni një bisedë këtu!",
"nickname": {
"popover": "Zgjidhni një nofkë",
"title": "Që të përdorni fjalosjen, jepni një nofkë"
"title": "Që të përdorni fjalosjen, jepni një nofkë",
"titleWithPolls": "Që të përdorni fjalosjen, jepni një nofkë"
},
"privateNotice": "Mesazh privat për {{recipient}}",
"title": "Fjalosje",
"titleWithPolls": "Fjalosje",
"you": "ju",
"message": "Mesazh",
"messageAccessibleTitle": "{{user}} thotë:",

View File

@@ -70,9 +70,11 @@
"messagebox": "Skriv ett meddelande",
"nickname": {
"popover": "Välj ett namn",
"title": "Skriv in ett namn för att börja använda chatten"
"title": "Skriv in ett namn för att börja använda chatten",
"titleWithPolls": "Skriv in ett namn för att börja använda chatten"
},
"title": "Chatt",
"titleWithPolls": "Chatt",
"you": "du",
"privateNotice": "Privat meddelande till {{recipient}}",
"noMessagesMessage": "Det finns ännu inga meddelanden i mötet. Påbörja en konversation!",

View File

@@ -70,10 +70,12 @@
"noMessagesMessage": "ఈ సమావేశంలో ఇంకా సందేశాలేమీ లేవు. ఇక్కడ ఒక సంభాషణను మొదలుపెట్టండి!",
"nickname": {
"popover": "ఒక మారుపేరు ఎంచుకోండి",
"title": "సంభాషణను మొదలుపెట్టడానికి ఒక మారుపేరును ఇవ్వండి"
"title": "సంభాషణను మొదలుపెట్టడానికి ఒక మారుపేరును ఇవ్వండి",
"titleWithPolls": "సంభాషణను మొదలుపెట్టడానికి ఒక మారుపేరును ఇవ్వండి"
},
"privateNotice": "{{recipient}}‌కి అంతరంగిక సందేశం",
"title": "సంభాషణ",
"titleWithPolls": "సంభాషణ",
"you": "మీరు"
},
"chromeExtensionBanner": {

View File

@@ -67,12 +67,13 @@
"noMessagesMessage": "Toplantıda henüz mesaj yok. Burada bir konuşma başlatın!",
"nickname": {
"popover": "Bir takma ad seçin",
"title": "Sohbette kullanmak için bir takma ad girin"
"title": "Sohbette kullanmak için bir takma ad girin",
"titleWithPolls": "Sohbette kullanmak için bir takma ad girin"
},
"privateNotice": "{{recipient}} için özel mesaj",
"privateNotice": "{{recipient}} için özel mesaj",
"title": "Sohbet",
"titleWithPolls": "Sohbet",
"you": "sen"
},
"connectingOverlay": {
"joiningRoom": "Toplantıya bağlanılıyor..."

View File

@@ -67,10 +67,12 @@
"noMessagesMessage": "У цій конференції відсутні повідомлення. Будь ласка, почніть розмову тут.",
"nickname": {
"popover": "Зазначте ім'я",
"title": "Зазначте ваше ім'я для чату"
"title": "Зазначте ваше ім'я для чату",
"titleWithPolls": "Зазначте ваше ім'я для чату"
},
"privateNotice": "Приватне повідомлення для {{recipient}}",
"title": "Чат",
"titleWithPolls": "Чат",
"you": "Ви"
},
"chromeExtensionBanner": {

View File

@@ -53,9 +53,11 @@
"messagebox": "Nhập nội dung tin nhắn",
"nickname": {
"popover": "Chọn tên",
"title": "Nhập tên của bạn để tán gẫu"
"title": "Nhập tên của bạn để tán gẫu",
"titleWithPolls": "Nhập tên của bạn để tán gẫu"
},
"title": "Tán gẫu",
"titleWithPolls": "Tán gẫu",
"you": "bạn"
},
"connectingOverlay": {

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "会议中还没有消息,在这里开始谈话吧!",
"nickname": {
"popover": "选择一个昵称",
"title": "输入一个昵称用于聊天"
"title": "输入一个昵称用于聊天",
"titleWithPolls": "输入一个昵称用于聊天"
},
"privateNotice": "与 {{recipient}} 的私人聊天",
"title": "话题",
"titleWithPolls": "话题",
"you": "您"
},
"chromeExtensionBanner": {

View File

@@ -66,10 +66,12 @@
"noMessagesMessage": "此會議尚無訊息。在此開始對話交談!",
"nickname": {
"popover": "選擇名稱",
"title": "輸入名稱來使用交談"
"title": "輸入名稱來使用交談",
"titleWithPolls": "輸入名稱來使用交談"
},
"privateNotice": "私人訊息傳送至 {{recipient}}",
"title": "對話",
"titleWithPolls": "對話",
"you": "您",
"message": "訊息",
"messageAccessibleTitle": "{{user}} 說:",

View File

@@ -66,7 +66,8 @@
"noMessagesMessage": "There are no messages in the meeting yet. Start a conversation here!",
"nickname": {
"popover": "Choose a nickname",
"title": "Enter a nickname to use chat and polls"
"title": "Enter a nickname to use chat",
"titleWithPolls": "Enter a nickname to use chat and polls"
},
"privateNotice": "Private message to {{recipient}}",
"message": "Message",
@@ -77,7 +78,8 @@
"chat": "Chat",
"polls": "Polls"
},
"title": "Chat and Polls",
"title": "Chat",
"titleWithPolls": "Chat and Polls",
"you": "you"
},
"chromeExtensionBanner": {
@@ -211,13 +213,15 @@
"done": "Done",
"e2eeDescription": "End-to-End Encryption is currently EXPERIMENTAL. Please keep in mind that turning on end-to-end encryption will effectively disable server-side provided services such as: phone participation. Also keep in mind that the meeting will only work for people joining from browsers with support for insertable streams.",
"e2eeLabel": "Enable End-to-End Encryption",
"e2eeDisabledDueToMaxModeDescription": "Cannot enable End-to-End Encryption due to large number of participants in the conference.",
"e2eeWarning": "WARNING: Not all participants in this meeting seem to have support for End-to-End encryption. If you enable it they won't be able to see nor hear you.",
"e2eeWillDisableDueToMaxModeDescription": "WARNING: End-to-End Encryption will be automatically disabled if more participants join the conference.",
"enterDisplayName": "Enter your name here",
"embedMeeting": "Embed meeting",
"error": "Error",
"gracefulShutdown": "Our service is currently down for maintenance. Please try again later.",
"grantModeratorDialog": "Are you sure you want to make this participant a moderator?",
"grantModeratorTitle": "Grant moderator",
"grantModeratorDialog": "Are you sure you want to grant moderator rights to {{participantName}}?",
"grantModeratorTitle": "Grant moderator rights",
"hideShareAudioHelper": "Don't show this dialog again",
"IamHost": "I am the host",
"incorrectRoomLockPassword": "Incorrect password",
@@ -247,15 +251,19 @@
"micPermissionDeniedError": "You have not granted permission to use your microphone. You can still join the conference but others won't hear you. Use the camera button in the address bar to fix this.",
"micTimeoutError": "Could not start audio source. Timeout occured!",
"micUnknownError": "Cannot use microphone for an unknown reason.",
"moderationAudioLabel": "Allow attendees to unmute themselves",
"moderationVideoLabel": "Allow attendees to start their video",
"muteEveryoneElseDialog": "Once muted, you won't be able to unmute them, but they can unmute themselves at any time.",
"muteEveryoneElseTitle": "Mute everyone except {{whom}}?",
"muteEveryoneDialog": "Are you sure you want to mute everyone? You won't be able to unmute them, but they can unmute themselves at any time.",
"muteEveryoneDialog": "The participants can unmute themselves at any time.",
"muteEveryoneDialogModerationOn": "The participants can send a request to speak at any time.",
"muteEveryoneTitle": "Mute everyone?",
"muteEveryoneElsesVideoDialog": "Once the camera is disabled, you won't be able to turn it back on, but they can turn it back on at any time.",
"muteEveryoneElsesVideoTitle": "Disable everyone's camera except {{whom}}?",
"muteEveryonesVideoDialog": "Are you sure you want to disable everyone's camera? You won't be able to turn it back on, but they can turn it back on at any time.",
"muteEveryoneElsesVideoTitle": "Stop everyone's video except {{whom}}?",
"muteEveryonesVideoDialog": "The participants can turn on their video at any time.",
"muteEveryonesVideoDialogModerationOn": "The participants can send a request to turn on their video at any time.",
"muteEveryonesVideoDialogOk": "Disable",
"muteEveryonesVideoTitle": "Disable everyone's camera?",
"muteEveryonesVideoTitle": "Stop everyone's video?",
"muteEveryoneSelf": "yourself",
"muteEveryoneStartMuted": "Everyone starts muted from now on",
"muteParticipantBody": "You won't be able to unmute them, but they can unmute themselves at any time.",
@@ -263,7 +271,7 @@
"muteParticipantDialog": "Are you sure you want to mute this participant? You won't be able to unmute them, but they can unmute themselves at any time.",
"muteParticipantsVideoDialog": "Are you sure you want to turn off this participant's camera? You won't be able to turn the camera back on, but they can turn it back on at any time.",
"muteParticipantTitle": "Mute this participant?",
"muteParticipantsVideoButton": "Disable camera",
"muteParticipantsVideoButton": "Stop camera",
"muteParticipantsVideoTitle": "Disable camera of this participant?",
"muteParticipantsVideoBody": "You won't be able to turn the camera back on, but they can turn it back on at any time.",
"noDropboxToken": "No valid Dropbox token",
@@ -327,6 +335,7 @@
"shareScreenWarningH1": "If you want to share just your screen:",
"shareScreenWarningD1": "you need to stop audio sharing before sharing your screen.",
"shareScreenWarningD2": "you need to stop audio sharing, start screen sharing and check the \"share audio\" option.",
"sharedVideoLinkPlaceholder": "YouTube link or direct video link",
"stopLiveStreaming": "Stop live stream",
"stopRecording": "Stop recording",
"stopRecordingWarning": "Are you sure you would like to stop the recording?",
@@ -542,29 +551,30 @@
"lockRoomPasswordUppercase": "Password",
"me": "me",
"notify": {
"allowAction": "Allow",
"allowedUnmute": "You can unmute your microphone, start your camera or share your screen.",
"connectedOneMember": "{{name}} joined the meeting",
"connectedThreePlusMembers": "{{name}} and many others joined the meeting",
"connectedTwoMembers": "{{first}} and {{second}} joined the meeting",
"disconnected": "disconnected",
"focus": "Conference focus",
"focusFail": "{{component}} not available - retry in {{ms}} sec",
"grantedTo": "Moderator rights granted to {{to}}!",
"hostAskedUnmute": "The host would like you to unmute",
"hostAskedUnmute": "The moderator would like you to speak",
"invitedOneMember": "{{name}} has been invited",
"invitedThreePlusMembers": "{{name}} and {{count}} others have been invited",
"invitedTwoMembers": "{{first}} and {{second}} have been invited",
"kickParticipant": "{{kicked}} was kicked by {{kicker}}",
"me": "Me",
"moderator": "Moderator rights granted!",
"moderator": "You're now a moderator",
"muted": "You have started the conversation muted.",
"mutedTitle": "You're muted!",
"mutedRemotelyTitle": "You have been muted by {{participantDisplayName}}!",
"mutedRemotelyTitle": "You've been muted by {{moderator}}",
"mutedRemotelyDescription": "You can always unmute when you're ready to speak. Mute back when you're done to keep noise away from the meeting.",
"videoMutedRemotelyTitle": "Your camera has been disabled by {{participantDisplayName}}!",
"videoMutedRemotelyTitle": "Your video has been turned off by {{moderator}}",
"videoMutedRemotelyDescription": "You can always turn it on again.",
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) removed by another participant",
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) set by another participant",
"raisedHand": "{{name}} would like to speak.",
"raisedHand": "Would like to speak.",
"screenShareNoAudio": " Share audio box was not checked in the window selection screen.",
"screenShareNoAudioTitle": "Couldn't share system audio!",
"somebody": "Somebody",
@@ -580,12 +590,12 @@
"oldElectronClientDescription1": "You appear to be using an old version of the Jitsi Meet client which has known security vulnerabilities. Please make sure you update to our ",
"oldElectronClientDescription2": "latest build",
"oldElectronClientDescription3": " now!",
"moderationInEffectDescription": "Please raise hand if you want to speak",
"moderationInEffectCSDescription": "Please raise hand if you want to share your video",
"moderationInEffectVideoDescription": "Please raise your hand if you want your video to be visible",
"moderationInEffectTitle": "The microphone is muted by the moderator",
"moderationInEffectCSTitle": "Content sharing is disabled by moderator",
"moderationInEffectVideoTitle": "The video is muted by the moderator",
"moderationInEffectDescription": "Please raise hand if you want to speak.",
"moderationInEffectCSDescription": "Please raise hand if you want to share your screen.",
"moderationInEffectVideoDescription": "Please raise your hand if you want to start your camera.",
"moderationInEffectTitle": "Your microphone is muted by the moderator",
"moderationInEffectCSTitle": "Screen sharing is blocked by the moderator",
"moderationInEffectVideoTitle": "Your camera is blocked by the moderator",
"moderationRequestFromModerator": "The host would like you to unmute",
"moderationRequestFromParticipant": "Wants to speak",
"moderationStartedTitle": "Moderation started",
@@ -605,16 +615,17 @@
},
"actions": {
"allow": "Allow attendees to:",
"audioModeration": "Unmute themselves",
"blockEveryoneMicCamera": "Block everyone's mic and camera",
"invite": "Invite Someone",
"askUnmute": "Ask to unmute",
"mute": "Mute",
"muteAll": "Mute all",
"muteEveryoneElse": "Mute everyone else",
"startModeration": "Unmute themselves or start video",
"stopEveryonesVideo": "Stop everyone's video",
"stopVideo": "Stop video",
"unblockEveryoneMicCamera": "Unblock everyone's mic and camera"
"unblockEveryoneMicCamera": "Unblock everyone's mic and camera",
"videoModeration": "Start their video"
}
},
"passwordSetRemotely": "Set by another participant",
@@ -687,6 +698,7 @@
"errorDialOutFailed": "Could not dial out. Call failed",
"errorDialOutStatus": "Error getting dial out status",
"errorMissingName": "Please enter your name to join the meeting",
"errorNoPermissions": "You need to enable microphone and camera access",
"errorStatusCode": "Error dialing out, status code: {{status}}",
"errorValidation": "Number validation failed",
"iWantToDialIn": "I want to dial in",
@@ -868,7 +880,7 @@
"embedMeeting": "Embed meeting",
"feedback": "Leave feedback",
"fullScreen": "Toggle full screen",
"grantModerator": "Grant Moderator",
"grantModerator": "Grant Moderator Rights",
"hangup": "Leave the meeting",
"help": "Help",
"invite": "Invite people",
@@ -1054,7 +1066,7 @@
"domuteOthers": "Mute everyone else",
"domuteVideoOfOthers": "Disable camera of everyone else",
"flip": "Flip",
"grantModerator": "Grant Moderator",
"grantModerator": "Grant Moderator Rights",
"kick": "Kick out",
"moderator": "Moderator",
"mute": "Participant is muted",

View File

@@ -15,6 +15,7 @@ import {
} from '../../react/features/base/conference';
import { overwriteConfig, getWhitelistedJSON } from '../../react/features/base/config';
import { toggleDialog } from '../../react/features/base/dialog/actions';
import { isSupportedBrowser } from '../../react/features/base/environment';
import { parseJWTFromURLParams } from '../../react/features/base/jwt';
import JitsiMeetJS, { JitsiRecordingConstants } from '../../react/features/base/lib-jitsi-meet';
import { MEDIA_TYPE } from '../../react/features/base/media';
@@ -39,6 +40,7 @@ import {
} from '../../react/features/device-selection/functions';
import { isEnabled as isDropboxEnabled } from '../../react/features/dropbox';
import { toggleE2EE } from '../../react/features/e2ee/actions';
import { setVolume } from '../../react/features/filmstrip';
import { invite } from '../../react/features/invite';
import {
selectParticipantInLargeVideo
@@ -174,6 +176,9 @@ function initCommands() {
sendAnalytics(createApiEvent('largevideo.participant.set'));
APP.store.dispatch(selectParticipantInLargeVideo(participantId));
},
'set-participant-volume': (participantId, volume) => {
APP.store.dispatch(setVolume(participantId, volume));
},
'subject': subject => {
sendAnalytics(createApiEvent('subject.changed'));
APP.store.dispatch(setSubject(subject));
@@ -688,6 +693,7 @@ class API {
this._enabled = true;
initCommands();
this.notifyBrowserSupport(isSupportedBrowser());
}
/**
@@ -1333,11 +1339,37 @@ class API {
*/
notifyError(error: Object) {
this._sendEvent({
name: 'error',
name: 'error-occurred',
error
});
}
/**
* Notify external application ( if API is enabled) that a toolbar button was clicked.
*
* @param {string} key - The key of the toolbar button.
* @returns {void}
*/
notifyToolbarButtonClicked(key: string) {
this._sendEvent({
name: 'toolbar-button-clicked',
key
});
}
/**
* Notify external application (if API is enabled) wether the used browser is supported or not.
*
* @param {boolean} supported - If browser is supported or not.
* @returns {void}
*/
notifyBrowserSupport(supported: boolean) {
this._sendEvent({
name: 'browser-support',
supported
});
}
/**
* Disposes the allocated resources.
*

View File

@@ -46,6 +46,7 @@ const commands = {
sendTones: 'send-tones',
setFollowMe: 'set-follow-me',
setLargeVideoParticipant: 'set-large-video-participant',
setParticipantVolume: 'set-participant-volume',
setTileView: 'set-tile-view',
setVideoQuality: 'set-video-quality',
startRecording: 'start-recording',
@@ -75,13 +76,14 @@ const events = {
'avatar-changed': 'avatarChanged',
'audio-availability-changed': 'audioAvailabilityChanged',
'audio-mute-status-changed': 'audioMuteStatusChanged',
'browser-support': 'browserSupport',
'camera-error': 'cameraError',
'chat-updated': 'chatUpdated',
'content-sharing-participants-changed': 'contentSharingParticipantsChanged',
'device-list-changed': 'deviceListChanged',
'display-name-change': 'displayNameChange',
'email-change': 'emailChange',
'error': 'error',
'error-occurred': 'errorOccurred',
'endpoint-text-message-received': 'endpointTextMessageReceived',
'feedback-submitted': 'feedbackSubmitted',
'feedback-prompt-displayed': 'feedbackPromptDisplayed',
@@ -111,7 +113,8 @@ const events = {
'dominant-speaker-changed': 'dominantSpeakerChanged',
'subject-change': 'subjectChange',
'suspend-detected': 'suspendDetected',
'tile-view-changed': 'tileViewChanged'
'tile-view-changed': 'tileViewChanged',
'toolbar-button-clicked': 'toolbarButtonClicked'
};
/**

15
package-lock.json generated
View File

@@ -2752,8 +2752,8 @@
}
},
"@jitsi/sdp-interop": {
"version": "github:jitsi/sdp-interop#98cd62cc00f92c8c2430e52ca746a86813658e83",
"from": "github:jitsi/sdp-interop#98cd62cc00f92c8c2430e52ca746a86813658e83",
"version": "github:jitsi/sdp-interop#4669790bb9020cc8f10c1d1f3823c26b08497547",
"from": "github:jitsi/sdp-interop#4669790bb9020cc8f10c1d1f3823c26b08497547",
"requires": {
"lodash.clonedeep": "4.5.0",
"sdp-transform": "2.14.1"
@@ -11117,11 +11117,11 @@
}
},
"lib-jitsi-meet": {
"version": "github:jitsi/lib-jitsi-meet#b0d27fa8daef615d45fe566a0385f66facfcf025",
"from": "github:jitsi/lib-jitsi-meet#b0d27fa8daef615d45fe566a0385f66facfcf025",
"version": "github:jitsi/lib-jitsi-meet#3b8baa9d3be2839510abaa954357d0b0ab023649",
"from": "github:jitsi/lib-jitsi-meet#3b8baa9d3be2839510abaa954357d0b0ab023649",
"requires": {
"@jitsi/js-utils": "1.0.2",
"@jitsi/sdp-interop": "github:jitsi/sdp-interop#98cd62cc00f92c8c2430e52ca746a86813658e83",
"@jitsi/sdp-interop": "github:jitsi/sdp-interop#4669790bb9020cc8f10c1d1f3823c26b08497547",
"@jitsi/sdp-simulcast": "0.4.0",
"async": "0.9.0",
"base64-js": "1.3.1",
@@ -15075,6 +15075,11 @@
"react-native-iphone-x-helper": "^1.3.1"
}
},
"react-native-performance": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/react-native-performance/-/react-native-performance-2.0.0.tgz",
"integrity": "sha512-jKM9Qg0SkL9D9ad377nxb1VV+OXJSyYyIrBHKmM6CABNxfrLVA5xkQMEibjmZQde7b0ndJOZoQAiObgJjjc4VQ=="
},
"react-native-sound": {
"version": "github:jitsi/react-native-sound#3fe5480fce935e888d5089d94a191c7c7e3aa190",
"from": "github:jitsi/react-native-sound#3fe5480fce935e888d5089d94a191c7c7e3aa190"

View File

@@ -47,6 +47,7 @@
"base64-js": "1.3.1",
"bc-css-flags": "3.0.0",
"clipboard-copy": "4.0.1",
"clsx": "1.1.1",
"dropbox": "10.7.0",
"focus-visible": "5.1.0",
"i18n-iso-countries": "6.8.0",
@@ -58,7 +59,7 @@
"jquery-i18next": "1.2.1",
"js-md5": "0.6.1",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#b0d27fa8daef615d45fe566a0385f66facfcf025",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#3b8baa9d3be2839510abaa954357d0b0ab023649",
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"lodash": "4.17.21",
"moment": "2.29.1",
@@ -83,6 +84,7 @@
"react-native-immersive": "2.0.0",
"react-native-keep-awake": "4.0.0",
"react-native-paper": "4.8.1",
"react-native-performance": "2.0.0",
"react-native-sound": "github:jitsi/react-native-sound#3fe5480fce935e888d5089d94a191c7c7e3aa190",
"react-native-splash-screen": "3.2.0",
"react-native-svg": "12.1.0",

View File

@@ -181,7 +181,7 @@ export function initAnalytics({ getState }: { getState: Function }, handlers: Ar
permanentProperties.appName = getAppName();
// Report if user is using websocket
permanentProperties.websocket = navigator.product !== 'ReactNative' && typeof config.websocket === 'string';
permanentProperties.websocket = typeof config.websocket === 'string';
// Report if user is using the external API
permanentProperties.externalApi = typeof API_ID === 'number';

View File

@@ -42,6 +42,7 @@ import '../recording/middleware';
import '../rejoin/middleware';
import '../room-lock/middleware';
import '../rtcstats/middleware';
import '../speaker-stats/middleware';
import '../subtitles/middleware';
import '../toolbox/middleware';
import '../transcribing/middleware';

View File

@@ -46,6 +46,7 @@ import '../reactions/reducer';
import '../recent-list/reducer';
import '../recording/reducer';
import '../settings/reducer';
import '../speaker-stats/reducer';
import '../subtitles/reducer';
import '../screen-share/reducer';
import '../toolbox/reducer';

View File

@@ -29,22 +29,40 @@ export const ENABLE_MODERATION = 'ENABLE_MODERATION';
/**
* The type of (redux) action which signals that A/V Moderation disable has been requested.
* The type of (redux) action which signals that Audio Moderation disable has been requested.
*
* {
* type: REQUEST_DISABLE_MODERATION
* type: REQUEST_DISABLE_AUDIO_MODERATION
* }
*/
export const REQUEST_DISABLE_MODERATION = 'REQUEST_DISABLE_MODERATION';
export const REQUEST_DISABLE_AUDIO_MODERATION = 'REQUEST_DISABLE_AUDIO_MODERATION';
/**
* The type of (redux) action which signals that A/V Moderation enable has been requested.
* The type of (redux) action which signals that Video Moderation disable has been requested.
*
* {
* type: REQUEST_ENABLE_MODERATION
* type: REQUEST_DISABLE_VIDEO_MODERATION
* }
*/
export const REQUEST_ENABLE_MODERATION = 'REQUEST_ENABLE_MODERATION';
export const REQUEST_DISABLE_VIDEO_MODERATION = 'REQUEST_DISABLE_VIDEO_MODERATION';
/**
* The type of (redux) action which signals that Audio Moderation enable has been requested.
*
* {
* type: REQUEST_ENABLE_AUDIO_MODERATION
* }
*/
export const REQUEST_ENABLE_AUDIO_MODERATION = 'REQUEST_ENABLE_AUDIO_MODERATION';
/**
* The type of (redux) action which signals that Video Moderation enable has been requested.
*
* {
* type: REQUEST_ENABLE_VIDEO_MODERATION
* }
*/
export const REQUEST_ENABLE_VIDEO_MODERATION = 'REQUEST_ENABLE_VIDEO_MODERATION';
/**
* The type of (redux) action which signals that the local participant had been approved.

View File

@@ -11,9 +11,12 @@ import {
LOCAL_PARTICIPANT_MODERATION_NOTIFICATION,
PARTICIPANT_APPROVED,
PARTICIPANT_PENDING_AUDIO,
REQUEST_DISABLE_MODERATION,
REQUEST_ENABLE_MODERATION
REQUEST_DISABLE_AUDIO_MODERATION,
REQUEST_ENABLE_AUDIO_MODERATION,
REQUEST_DISABLE_VIDEO_MODERATION,
REQUEST_ENABLE_VIDEO_MODERATION
} from './actionTypes';
import { isEnabledFromState } from './functions';
/**
* Action used by moderator to approve audio and video for a participant.
@@ -22,10 +25,15 @@ import {
* @returns {void}
*/
export const approveParticipant = (id: string) => (dispatch: Function, getState: Function) => {
const { conference } = getConferenceState(getState());
const state = getState();
const { conference } = getConferenceState(state);
conference.avModerationApprove(MEDIA_TYPE.AUDIO, id);
conference.avModerationApprove(MEDIA_TYPE.VIDEO, id);
if (isEnabledFromState(MEDIA_TYPE.AUDIO, state)) {
conference.avModerationApprove(MEDIA_TYPE.AUDIO, id);
}
if (isEnabledFromState(MEDIA_TYPE.VIDEO, state)) {
conference.avModerationApprove(MEDIA_TYPE.VIDEO, id);
}
};
/**
@@ -89,28 +97,54 @@ export const enableModeration = (mediaType: MediaType, actor: Object) => {
};
/**
* Requests disable of audio and video moderation.
* Requests disable of audio moderation.
*
* @returns {{
* type: REQUEST_DISABLE_MODERATED_AUDIO
* type: REQUEST_DISABLE_AUDIO_MODERATION
* }}
*/
export const requestDisableModeration = () => {
export const requestDisableAudioModeration = () => {
return {
type: REQUEST_DISABLE_MODERATION
type: REQUEST_DISABLE_AUDIO_MODERATION
};
};
/**
* Requests enabled audio & video moderation.
* Requests disable of video moderation.
*
* @returns {{
* type: REQUEST_ENABLE_MODERATED_AUDIO
* type: REQUEST_DISABLE_VIDEO_MODERATION
* }}
*/
export const requestEnableModeration = () => {
export const requestDisableVideoModeration = () => {
return {
type: REQUEST_ENABLE_MODERATION
type: REQUEST_DISABLE_VIDEO_MODERATION
};
};
/**
* Requests enable of audio moderation.
*
* @returns {{
* type: REQUEST_ENABLE_AUDIO_MODERATION
* }}
*/
export const requestEnableAudioModeration = () => {
return {
type: REQUEST_ENABLE_AUDIO_MODERATION
};
};
/**
* Requests enable of video moderation.
*
* @returns {{
* type: REQUEST_ENABLE_VIDEO_MODERATION
* }}
*/
export const requestEnableVideoModeration = () => {
return {
type: REQUEST_ENABLE_VIDEO_MODERATION
};
};

View File

@@ -1,38 +0,0 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import NotificationWithParticipants from '../../notifications/components/web/NotificationWithParticipants';
import {
approveParticipant,
dismissPendingAudioParticipant
} from '../actions';
import { getParticipantsAskingToAudioUnmute } from '../functions';
/**
* Component used to display a list of participants who asked to be unmuted.
* This is visible only to moderators.
*
* @returns {React$Element<'ul'> | null}
*/
export default function() {
const participants = useSelector(getParticipantsAskingToAudioUnmute);
const { t } = useTranslation();
return participants.length
? (
<>
<div className = 'title'>
{ t('raisedHand') }
</div>
<NotificationWithParticipants
approveButtonText = { t('notify.unmute') }
onApprove = { approveParticipant }
onReject = { dismissPendingAudioParticipant }
participants = { participants }
rejectButtonText = { t('dialog.dismiss') }
testIdPrefix = 'avModeration' />
</>
) : null;
}

View File

@@ -17,3 +17,15 @@ export const MEDIA_TYPE_TO_PENDING_STORE_KEY: {[key: MediaType]: string} = {
[MEDIA_TYPE.AUDIO]: 'pendingAudio',
[MEDIA_TYPE.VIDEO]: 'pendingVideo'
};
export const ASKED_TO_UNMUTE_SOUND_ID = 'ASKED_TO_UNMUTE_SOUND';
export const AUDIO_MODERATION_NOTIFICATION_ID = 'audio-moderation';
export const VIDEO_MODERATION_NOTIFICATION_ID = 'video-moderation';
export const CS_MODERATION_NOTIFICATION_ID = 'screensharing-moderation';
export const MODERATION_NOTIFICATIONS = {
[MEDIA_TYPE.AUDIO]: AUDIO_MODERATION_NOTIFICATION_ID,
[MEDIA_TYPE.VIDEO]: VIDEO_MODERATION_NOTIFICATION_ID,
[MEDIA_TYPE.PRESENTER]: CS_MODERATION_NOTIFICATION_ID
};

View File

@@ -1,12 +1,12 @@
// @flow
import { batch } from 'react-redux';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
import { getConferenceState } from '../base/conference';
import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
import { MEDIA_TYPE } from '../base/media';
import {
getLocalParticipant,
getParticipantDisplayName,
getRemoteParticipants,
isLocalParticipantModerator,
isParticipantModerator,
@@ -14,18 +14,19 @@ import {
raiseHand
} from '../base/participants';
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
import { playSound, registerSound, unregisterSound } from '../base/sounds';
import {
hideNotification,
NOTIFICATION_TIMEOUT,
showNotification
} from '../notifications';
import { muteLocal } from '../video-menu/actions.any';
import {
DISABLE_MODERATION,
ENABLE_MODERATION,
LOCAL_PARTICIPANT_MODERATION_NOTIFICATION,
REQUEST_DISABLE_MODERATION,
REQUEST_ENABLE_MODERATION
REQUEST_DISABLE_AUDIO_MODERATION,
REQUEST_DISABLE_VIDEO_MODERATION,
REQUEST_ENABLE_AUDIO_MODERATION,
REQUEST_ENABLE_VIDEO_MODERATION
} from './actionTypes';
import {
disableModeration,
@@ -36,38 +37,29 @@ import {
participantApproved,
participantPendingAudio
} from './actions';
import {
ASKED_TO_UNMUTE_SOUND_ID, AUDIO_MODERATION_NOTIFICATION_ID,
CS_MODERATION_NOTIFICATION_ID,
VIDEO_MODERATION_NOTIFICATION_ID
} from './constants';
import {
isEnabledFromState,
isParticipantApproved,
isParticipantPending
} from './functions';
const VIDEO_MODERATION_NOTIFICATION_ID = 'video-moderation';
const AUDIO_MODERATION_NOTIFICATION_ID = 'audio-moderation';
const CS_MODERATION_NOTIFICATION_ID = 'video-moderation';
import { ASKED_TO_UNMUTE_FILE } from './sounds';
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
const { actor, mediaType, type } = action;
const { type } = action;
const { conference } = getConferenceState(getState());
switch (type) {
case DISABLE_MODERATION:
case ENABLE_MODERATION: {
// Audio & video moderation are both enabled at the same time.
// Avoid displaying 2 different notifications.
if (mediaType === MEDIA_TYPE.VIDEO) {
const titleKey = type === ENABLE_MODERATION
? 'notify.moderationStartedTitle'
: 'notify.moderationStoppedTitle';
dispatch(showNotification({
descriptionKey: actor ? 'notify.moderationToggleDescription' : undefined,
descriptionArguments: actor ? {
participantDisplayName: getParticipantDisplayName(getState, actor.getId())
} : undefined,
titleKey
}, NOTIFICATION_TIMEOUT));
}
case APP_WILL_MOUNT: {
dispatch(registerSound(ASKED_TO_UNMUTE_SOUND_ID, ASKED_TO_UNMUTE_FILE));
break;
}
case APP_WILL_UNMOUNT: {
dispatch(unregisterSound(ASKED_TO_UNMUTE_SOUND_ID));
break;
}
case LOCAL_PARTICIPANT_MODERATION_NOTIFICATION: {
@@ -78,19 +70,16 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
switch (action.mediaType) {
case MEDIA_TYPE.AUDIO: {
titleKey = 'notify.moderationInEffectTitle';
descriptionKey = 'notify.moderationInEffectDescription';
uid = AUDIO_MODERATION_NOTIFICATION_ID;
break;
}
case MEDIA_TYPE.VIDEO: {
titleKey = 'notify.moderationInEffectVideoTitle';
descriptionKey = 'notify.moderationInEffectVideoDescription';
uid = VIDEO_MODERATION_NOTIFICATION_ID;
break;
}
case MEDIA_TYPE.PRESENTER: {
titleKey = 'notify.moderationInEffectCSTitle';
descriptionKey = 'notify.moderationInEffectCSDescription';
uid = CS_MODERATION_NOTIFICATION_ID;
break;
}
@@ -110,17 +99,19 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
break;
}
case REQUEST_DISABLE_MODERATION: {
const { conference } = getConferenceState(getState());
case REQUEST_DISABLE_AUDIO_MODERATION: {
conference.disableAVModeration(MEDIA_TYPE.AUDIO);
break;
}
case REQUEST_DISABLE_VIDEO_MODERATION: {
conference.disableAVModeration(MEDIA_TYPE.VIDEO);
break;
}
case REQUEST_ENABLE_MODERATION: {
const { conference } = getConferenceState(getState());
case REQUEST_ENABLE_AUDIO_MODERATION: {
conference.enableAVModeration(MEDIA_TYPE.AUDIO);
break;
}
case REQUEST_ENABLE_VIDEO_MODERATION: {
conference.enableAVModeration(MEDIA_TYPE.VIDEO);
break;
}
@@ -174,12 +165,14 @@ StateListenerRegistry.register(
// Audio & video moderation are both enabled at the same time.
// Avoid displaying 2 different notifications.
if (mediaType === MEDIA_TYPE.VIDEO) {
if (mediaType === MEDIA_TYPE.AUDIO) {
dispatch(showNotification({
titleKey: 'notify.unmute',
descriptionKey: 'notify.hostAskedUnmute',
sticky: true
titleKey: 'notify.hostAskedUnmute',
sticky: true,
customActionNameKey: 'notify.unmute',
customActionHandler: () => dispatch(muteLocal(false, MEDIA_TYPE.AUDIO))
}));
dispatch(playSound(ASKED_TO_UNMUTE_SOUND_ID));
}
});

View File

@@ -0,0 +1,6 @@
/**
* The name of the bundled audio file which will be played for the raise hand sound.
*
* @type {string}
*/
export const ASKED_TO_UNMUTE_FILE = 'asked-unmute.mp3';

View File

@@ -357,7 +357,7 @@ export function conferenceUniqueIdSet(conference: Object) {
* the local participant will (try to) join.
* @returns {Function}
*/
function _conferenceWillJoin(conference: Object) {
export function _conferenceWillJoin(conference: Object) {
return (dispatch: Dispatch<any>, getState: Function) => {
const localTracks
= getLocalTracks(getState()['features/base/tracks'])

View File

@@ -19,6 +19,7 @@ export default [
'apiLogLevels',
'avgRtpStatsN',
'backgroundAlpha',
'buttonsWithNotifyClick',
/**
* The display name of the CallKit call representing the conference/meeting
@@ -69,7 +70,9 @@ export default [
*/
'callUUID',
'conferenceInfo',
'channelLastN',
'connectionIndicators',
'constraints',
'brandingRoomAlias',
'debug',
@@ -82,7 +85,9 @@ export default [
'disableAGC',
'disableAP',
'disableAudioLevels',
'disableChatSmileys',
'disableDeepLinking',
'disabledSounds',
'disableFilmstripAutohiding',
'disableInitialGUM',
'disableH264',
@@ -91,16 +96,21 @@ export default [
'disableIncomingMessageSound',
'disableJoinLeaveSounds',
'disableLocalVideoFlip',
'disableModeratorIndicator',
'disableNS',
'disablePolls',
'disableProfile',
'disableReactions',
'disableRecordAudioNotification',
'disableRemoteControl',
'disableRemoteMute',
'disableResponsiveTiles',
'disableRtx',
'disableShortcuts',
'disableShowMoreStats',
'disableRemoveRaisedHandOnFocus',
'disableSpeakerStatsSearch',
'speakerStatsOrder',
'disableSimulcast',
'disableThirdPartyRequests',
'disableTileView',
@@ -108,6 +118,7 @@ export default [
'doNotStoreRoom',
'doNotFlipLocalVideo',
'dropbox',
'e2eeLabels',
'e2eping',
'enableDisplayNameInStats',
'enableEmailInStats',
@@ -117,11 +128,11 @@ export default [
'enableLayerSuspension',
'enableLipSync',
'enableOpusRed',
'enableReactions',
'enableRemb',
'enableSaveLogs',
'enableScreenshotCapture',
'enableTalkWhileMuted',
'enableUnifiedOnChrome',
'enableNoAudioDetection',
'enableNoisyMicDetection',
'enableTcc',

View File

@@ -49,6 +49,16 @@ export function getMeetingRegion(state: Object) {
return state['features/base/config']?.deploymentInfo?.region || '';
}
/**
* Selector used to get the disableRemoveRaisedHandOnFocus.
*
* @param {Object} state - The global state.
* @returns {boolean}
*/
export function getDisableRemoveRaisedHandOnFocus(state: Object) {
return state['features/base/config']?.disableRemoveRaisedHandOnFocus || false;
}
/**
* Selector used to get the endpoint used for fetching the recording.
*

View File

@@ -2,6 +2,7 @@
import _ from 'lodash';
import { CONFERENCE_INFO } from '../../conference/components/constants';
import { equals, ReducerRegistry } from '../redux';
import {
@@ -56,6 +57,17 @@ const INITIAL_RN_STATE = {
}
};
/**
* Mapping between old configs controlling the conference info headers visibility and the
* new configs. Needed in order to keep backwards compatibility.
*/
const CONFERENCE_HEADER_MAPPING = {
hideConferenceTimer: [ 'conference-timer' ],
hideConferenceSubject: [ 'subject' ],
hideParticipantsStats: [ 'participants-count' ],
hideRecordingLabel: [ 'recording', 'local-recording' ]
};
ReducerRegistry.register('features/base/config', (state = _getInitialState(), action) => {
switch (action.type) {
case UPDATE_CONFIG:
@@ -66,11 +78,11 @@ ReducerRegistry.register('features/base/config', (state = _getInitialState(), ac
error: undefined,
/**
* The URL of the location associated with/configured by this
* configuration.
*
* @type URL
*/
* The URL of the location associated with/configured by this
* configuration.
*
* @type URL
*/
locationURL: action.locationURL
};
@@ -84,11 +96,11 @@ ReducerRegistry.register('features/base/config', (state = _getInitialState(), ac
if (state.locationURL === action.locationURL) {
return {
/**
* The {@link Error} which prevented the loading of the
* configuration of the associated {@code locationURL}.
*
* @type Error
*/
* The {@link Error} which prevented the loading of the
* configuration of the associated {@code locationURL}.
*
* @type Error
*/
error: action.error
};
}
@@ -172,6 +184,27 @@ function _setConfig(state, { config }) {
return equals(state, newState) ? state : newState;
}
/**
* Processes the conferenceInfo object against the defaults.
*
* @param {Object} config - The old config.
* @returns {Object} The processed conferenceInfo object.
*/
function _getConferenceInfo(config) {
const { conferenceInfo } = config;
if (conferenceInfo) {
return {
alwaysVisible: conferenceInfo.alwaysVisible ?? [ ...CONFERENCE_INFO.alwaysVisible ],
autoHide: conferenceInfo.autoHide ?? [ ...CONFERENCE_INFO.autoHide ]
};
}
return {
...CONFERENCE_INFO
};
}
/**
* Constructs a new config {@code Object}, if necessary, out of a specific
* config {@code Object} which is in the latest format supported by jitsi-meet.
@@ -194,6 +227,58 @@ function _translateLegacyConfig(oldValue: Object) {
newValue.toolbarButtons = interfaceConfig.TOOLBAR_BUTTONS;
}
const filteredConferenceInfo = Object.keys(CONFERENCE_HEADER_MAPPING).filter(key => oldValue[key]);
if (filteredConferenceInfo.length) {
newValue.conferenceInfo = _getConferenceInfo(oldValue);
filteredConferenceInfo.forEach(key => {
// hideRecordingLabel does not mean not render it at all, but autoHide it
if (key === 'hideRecordingLabel') {
newValue.conferenceInfo.alwaysVisible
= newValue.conferenceInfo.alwaysVisible.filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c));
newValue.conferenceInfo.autoHide
= _.union(newValue.conferenceInfo.autoHide, CONFERENCE_HEADER_MAPPING[key]);
} else {
newValue.conferenceInfo.alwaysVisible
= newValue.conferenceInfo.alwaysVisible.filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c));
newValue.conferenceInfo.autoHide
= newValue.conferenceInfo.autoHide.filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c));
}
});
}
if (!oldValue.connectionIndicators
&& typeof interfaceConfig === 'object'
&& (interfaceConfig.hasOwnProperty('CONNECTION_INDICATOR_DISABLED')
|| interfaceConfig.hasOwnProperty('CONNECTION_INDICATOR_AUTO_HIDE_ENABLED')
|| interfaceConfig.hasOwnProperty('CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT'))) {
newValue.connectionIndicators = {
disabled: interfaceConfig.CONNECTION_INDICATOR_DISABLED,
autoHide: interfaceConfig.CONNECTION_INDICATOR_AUTO_HIDE_ENABLED,
autoHideTimeout: interfaceConfig.CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT
};
}
newValue.disabledSounds = newValue.disabledSounds || [];
if (oldValue.disableJoinLeaveSounds) {
newValue.disabledSounds.unshift('PARTICIPANT_LEFT_SOUND', 'PARTICIPANT_JOINED_SOUND');
}
if (oldValue.disableRecordAudioNotification) {
newValue.disabledSounds.unshift(
'RECORDING_ON_SOUND',
'RECORDING_OFF_SOUND',
'LIVE_STREAMING_ON_SOUND',
'LIVE_STREAMING_OFF_SOUND'
);
}
if (oldValue.disableIncomingMessageSound) {
newValue.disabledSounds.unshift('INCOMING_MSG_SOUND');
}
if (oldValue.stereo || oldValue.opusMaxAverageBitrate) {
newValue.audioQuality = {
opusMaxAverageBitrate: oldValue.audioQuality?.opusMaxAverageBitrate ?? oldValue.opusMaxAverageBitrate,
@@ -201,6 +286,12 @@ function _translateLegacyConfig(oldValue: Object) {
};
}
if (oldValue.disableModeratorIndicator === undefined
&& typeof interfaceConfig === 'object'
&& interfaceConfig.hasOwnProperty('DISABLE_FOCUS_INDICATOR')) {
newValue.disableModeratorIndicator = interfaceConfig.DISABLE_FOCUS_INDICATOR;
}
return newValue;
}

View File

@@ -54,4 +54,13 @@ export const CONNECTION_WILL_CONNECT = 'CONNECTION_WILL_CONNECT';
*/
export const SET_LOCATION_URL = 'SET_LOCATION_URL';
/**
* The type of (redux) action which tells whether connection info should be displayed
* on context menu.
*
* {
* type: SHOW_CONNECTION_INFO,
* showConnectionInfo: boolean
* }
*/
export const SHOW_CONNECTION_INFO = 'SHOW_CONNECTION_INFO';

Some files were not shown because too many files have changed in this diff Show More