mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-09-05 02:17:46 +00:00
Compare commits
18 Commits
release-42
...
saghul-pat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa801b6d09 | ||
|
|
701d34248b | ||
|
|
e72dae5c32 | ||
|
|
811ee40d99 | ||
|
|
76eabf1f29 | ||
|
|
01a8cc1478 | ||
|
|
047c9b43ea | ||
|
|
22d040ab76 | ||
|
|
4ac9ea258c | ||
|
|
6bd64ee552 | ||
|
|
7a1595f162 | ||
|
|
07cad2a98f | ||
|
|
6fbba52c6d | ||
|
|
311d1c67ba | ||
|
|
0aa54d8650 | ||
|
|
74e0e10928 | ||
|
|
4f169988a3 | ||
|
|
ec6ed6e8ec |
132
conference.js
132
conference.js
@@ -1,4 +1,4 @@
|
||||
/* global $, APP, JitsiMeetJS, config, interfaceConfig */
|
||||
/* global APP, JitsiMeetJS, config, interfaceConfig */
|
||||
|
||||
import EventEmitter from 'events';
|
||||
import Logger from 'jitsi-meet-logger';
|
||||
@@ -118,10 +118,7 @@ import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay
|
||||
import { suspendDetected } from './react/features/power-monitor';
|
||||
import {
|
||||
initPrejoin,
|
||||
isPrejoinPageEnabled,
|
||||
isPrejoinPageVisible,
|
||||
replacePrejoinAudioTrack,
|
||||
replacePrejoinVideoTrack
|
||||
isPrejoinPageEnabled
|
||||
} from './react/features/prejoin';
|
||||
import { createRnnoiseProcessorPromise } from './react/features/rnnoise';
|
||||
import { toggleScreenshotCaptureEffect } from './react/features/screenshot-capture';
|
||||
@@ -1409,18 +1406,6 @@ export default {
|
||||
useVideoStream(newStream) {
|
||||
return new Promise((resolve, reject) => {
|
||||
_replaceLocalVideoTrackQueue.enqueue(onFinish => {
|
||||
/**
|
||||
* When the prejoin page is visible there is no conference object
|
||||
* created. The prejoin tracks are managed separately,
|
||||
* so this updates the prejoin video track.
|
||||
*/
|
||||
if (isPrejoinPageVisible(APP.store.getState())) {
|
||||
return APP.store.dispatch(replacePrejoinVideoTrack(newStream))
|
||||
.then(resolve)
|
||||
.catch(reject)
|
||||
.then(onFinish);
|
||||
}
|
||||
|
||||
APP.store.dispatch(
|
||||
replaceLocalTrack(this.localVideo, newStream, room))
|
||||
.then(() => {
|
||||
@@ -1474,18 +1459,6 @@ export default {
|
||||
useAudioStream(newStream) {
|
||||
return new Promise((resolve, reject) => {
|
||||
_replaceLocalAudioTrackQueue.enqueue(onFinish => {
|
||||
/**
|
||||
* When the prejoin page is visible there is no conference object
|
||||
* created. The prejoin tracks are managed separately,
|
||||
* so this updates the prejoin audio stream.
|
||||
*/
|
||||
if (isPrejoinPageVisible(APP.store.getState())) {
|
||||
return APP.store.dispatch(replacePrejoinAudioTrack(newStream))
|
||||
.then(resolve)
|
||||
.catch(reject)
|
||||
.then(onFinish);
|
||||
}
|
||||
|
||||
APP.store.dispatch(
|
||||
replaceLocalTrack(this.localAudio, newStream, room))
|
||||
.then(() => {
|
||||
@@ -1669,8 +1642,6 @@ export default {
|
||||
* @private
|
||||
*/
|
||||
_createDesktopTrack(options = {}) {
|
||||
let externalInstallation = false;
|
||||
let DSExternalInstallationInProgress = false;
|
||||
const didHaveVideo = !this.isLocalVideoMuted();
|
||||
|
||||
const getDesktopStreamPromise = options.desktopStream
|
||||
@@ -1679,43 +1650,7 @@ export default {
|
||||
desktopSharingSourceDevice: options.desktopSharingSources
|
||||
? null : config._desktopSharingSourceDevice,
|
||||
desktopSharingSources: options.desktopSharingSources,
|
||||
devices: [ 'desktop' ],
|
||||
desktopSharingExtensionExternalInstallation: {
|
||||
interval: 500,
|
||||
checkAgain: () => DSExternalInstallationInProgress,
|
||||
listener: (status, url) => {
|
||||
switch (status) {
|
||||
case 'waitingForExtension': {
|
||||
DSExternalInstallationInProgress = true;
|
||||
externalInstallation = true;
|
||||
const listener = () => {
|
||||
// Wait a little bit more just to be sure that
|
||||
// we won't miss the extension installation
|
||||
setTimeout(() => {
|
||||
DSExternalInstallationInProgress = false;
|
||||
},
|
||||
500);
|
||||
APP.UI.removeListener(
|
||||
UIEvents.EXTERNAL_INSTALLATION_CANCELED,
|
||||
listener);
|
||||
};
|
||||
|
||||
APP.UI.addListener(
|
||||
UIEvents.EXTERNAL_INSTALLATION_CANCELED,
|
||||
listener);
|
||||
APP.UI.showExtensionExternalInstallationDialog(url);
|
||||
break;
|
||||
}
|
||||
case 'extensionFound':
|
||||
// Close the dialog.
|
||||
externalInstallation && $.prompt.close();
|
||||
break;
|
||||
default:
|
||||
|
||||
// Unknown status
|
||||
}
|
||||
}
|
||||
}
|
||||
devices: [ 'desktop' ]
|
||||
});
|
||||
|
||||
return getDesktopStreamPromise.then(desktopStreams => {
|
||||
@@ -1739,15 +1674,8 @@ export default {
|
||||
);
|
||||
}
|
||||
|
||||
// close external installation dialog on success.
|
||||
externalInstallation && $.prompt.close();
|
||||
|
||||
return desktopStreams;
|
||||
}, error => {
|
||||
DSExternalInstallationInProgress = false;
|
||||
|
||||
// close external installation dialog on success.
|
||||
externalInstallation && $.prompt.close();
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
@@ -1951,70 +1879,36 @@ export default {
|
||||
/**
|
||||
* Handles {@link JitsiTrackError} returned by the lib-jitsi-meet when
|
||||
* trying to create screensharing track. It will either do nothing if
|
||||
* the dialog was canceled on user's request or display inline installation
|
||||
* dialog and ask the user to install the extension, once the extension is
|
||||
* installed it will switch the conference to screensharing. The last option
|
||||
* is that an unrecoverable error dialog will be displayed.
|
||||
* the dialog was canceled on user's request or display an error if
|
||||
* screensharing couldn't be started.
|
||||
* @param {JitsiTrackError} error - The error returned by
|
||||
* {@link _createDesktopTrack} Promise.
|
||||
* @private
|
||||
*/
|
||||
_handleScreenSharingError(error) {
|
||||
if (error.name === JitsiTrackErrors.CHROME_EXTENSION_USER_CANCELED) {
|
||||
if (error.name === JitsiTrackErrors.SCREENSHARING_USER_CANCELED) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.error('failed to share local desktop', error);
|
||||
|
||||
if (error.name
|
||||
=== JitsiTrackErrors.CHROME_EXTENSION_USER_GESTURE_REQUIRED) {
|
||||
// If start with screen sharing the extension will fail to install
|
||||
// (if not found), because the request has been triggered by the
|
||||
// script. Show a dialog which asks user to click "install" and try
|
||||
// again switching to the screen sharing.
|
||||
APP.UI.showExtensionInlineInstallationDialog(
|
||||
() => {
|
||||
// eslint-disable-next-line no-empty-function
|
||||
this.toggleScreenSharing().catch(() => {});
|
||||
}
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Handling:
|
||||
// JitsiTrackErrors.PERMISSION_DENIED
|
||||
// JitsiTrackErrors.CHROME_EXTENSION_INSTALLATION_ERROR
|
||||
// JitsiTrackErrors.CONSTRAINT_FAILED
|
||||
// JitsiTrackErrors.GENERAL
|
||||
// JitsiTrackErrors.PERMISSION_DENIED
|
||||
// JitsiTrackErrors.SCREENSHARING_GENERIC_ERROR
|
||||
// and any other
|
||||
let descriptionKey;
|
||||
let titleKey;
|
||||
|
||||
if (error.name === JitsiTrackErrors.PERMISSION_DENIED) {
|
||||
|
||||
// in FF the only option for user is to deny access temporary or
|
||||
// permanently and we only receive permission_denied
|
||||
// we always show some info cause in case of permanently, no info
|
||||
// shown will be bad experience
|
||||
//
|
||||
// TODO: detect interval between requesting permissions and received
|
||||
// error, this way we can detect user interaction which will have
|
||||
// longer delay
|
||||
if (JitsiMeetJS.util.browser.isFirefox()) {
|
||||
descriptionKey
|
||||
= 'dialog.screenSharingFirefoxPermissionDeniedError';
|
||||
titleKey = 'dialog.screenSharingFirefoxPermissionDeniedTitle';
|
||||
} else {
|
||||
descriptionKey = 'dialog.screenSharingPermissionDeniedError';
|
||||
titleKey = 'dialog.screenSharingFailedToInstallTitle';
|
||||
}
|
||||
descriptionKey = 'dialog.screenSharingPermissionDeniedError';
|
||||
titleKey = 'dialog.screenSharingFailedTitle';
|
||||
} else if (error.name === JitsiTrackErrors.CONSTRAINT_FAILED) {
|
||||
descriptionKey = 'dialog.cameraConstraintFailedError';
|
||||
titleKey = 'deviceError.cameraError';
|
||||
} else {
|
||||
descriptionKey = 'dialog.screenSharingFailedToInstall';
|
||||
titleKey = 'dialog.screenSharingFailedToInstallTitle';
|
||||
} else if (error.name === JitsiTrackErrors.SCREENSHARING_GENERIC_ERROR) {
|
||||
descriptionKey = 'dialog.screenSharingFailed';
|
||||
titleKey = 'dialog.screenSharingFailedTitle';
|
||||
}
|
||||
|
||||
APP.UI.messageHandler.showError({
|
||||
|
||||
16
config.js
16
config.js
@@ -154,22 +154,6 @@ var config = {
|
||||
|
||||
// Desktop sharing
|
||||
|
||||
// The ID of the jidesha extension for Chrome.
|
||||
desktopSharingChromeExtId: null,
|
||||
|
||||
// Whether desktop sharing should be disabled on Chrome.
|
||||
// desktopSharingChromeDisabled: false,
|
||||
|
||||
// The media sources to use when using screen sharing with the Chrome
|
||||
// extension.
|
||||
desktopSharingChromeSources: [ 'screen', 'window', 'tab' ],
|
||||
|
||||
// Required version of Chrome extension
|
||||
desktopSharingChromeMinExtVersion: '0.1',
|
||||
|
||||
// Whether desktop sharing should be disabled on Firefox.
|
||||
// desktopSharingFirefoxDisabled: false,
|
||||
|
||||
// Optional desktop sharing frame rate options. Default value: min:5, max:5.
|
||||
// desktopSharingFrameRate: {
|
||||
// min: 5,
|
||||
|
||||
@@ -35,6 +35,10 @@
|
||||
cursor: initial;
|
||||
color: #fff;
|
||||
background-color: #a4b8d1;
|
||||
|
||||
&:hover {
|
||||
background-color: #a4b8d1;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
|
||||
@@ -47,13 +47,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.new-toolbox .toolbox-content .toolbox-icon.security-toolbar-button,
|
||||
.new-toolbox .toolbox-content .toolbox-icon.toggled.security-toolbar-button {
|
||||
background: rgba(241, 173, 51, 0.7);
|
||||
border: 1px solid rgba(255, 255, 255, 0.4);
|
||||
border-width: 0;
|
||||
|
||||
&:hover {
|
||||
background: rgba(241, 173, 51, 0.7);
|
||||
border: 1px solid rgba(255, 255, 255, 0.4);
|
||||
&:not(:hover) {
|
||||
background: unset;
|
||||
}
|
||||
}
|
||||
8
debian/jitsi-meet-web-config.postinst
vendored
8
debian/jitsi-meet-web-config.postinst
vendored
@@ -91,10 +91,14 @@ case "$1" in
|
||||
CERT_CRT="/etc/jitsi/meet/$JVB_HOSTNAME.crt"
|
||||
HOST="$( (hostname -s; echo localhost) | head -n 1)"
|
||||
DOMAIN="$( (hostname -d; echo localdomain) | head -n 1)"
|
||||
openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj \
|
||||
openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 -subj \
|
||||
"/O=$DOMAIN/OU=$HOST/CN=$JVB_HOSTNAME/emailAddress=webmaster@$HOST.$DOMAIN" \
|
||||
-keyout $CERT_KEY \
|
||||
-out $CERT_CRT
|
||||
-out $CERT_CRT \
|
||||
-reqexts SAN \
|
||||
-extensions SAN \
|
||||
-config <(cat /etc/ssl/openssl.cnf \
|
||||
<(printf '[SAN]\nsubjectAltName=DNS:localhost,DNS:$JVB_HOSTNAME,IP:$JVB_HOSTNAME'))
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Documentation
|
||||
|
||||
The Jitsi documentation has been moved to [The Handbook](https://jitsi.github.io/handbook/).
|
||||
The Jitsi documentation has been moved to [The Handbook](https://jitsi.github.io/handbook/). The repo is https://github.com/jitsi/handbook.
|
||||
|
||||
@@ -1,131 +1,23 @@
|
||||
/* eslint-disable no-unused-vars, no-var, max-len */
|
||||
/* eslint sort-keys: ["error", "asc", {"caseSensitive": false}] */
|
||||
|
||||
var interfaceConfig = {
|
||||
DEFAULT_BACKGROUND: '#474747',
|
||||
DEFAULT_LOGO_URL: '../images/watermark.png',
|
||||
|
||||
/**
|
||||
* Whether or not the blurred video background for large video should be
|
||||
* displayed on browsers that can support it.
|
||||
*/
|
||||
DISABLE_VIDEO_BACKGROUND: false,
|
||||
|
||||
INITIAL_TOOLBAR_TIMEOUT: 20000,
|
||||
TOOLBAR_TIMEOUT: 4000,
|
||||
TOOLBAR_ALWAYS_VISIBLE: false,
|
||||
DEFAULT_REMOTE_DISPLAY_NAME: 'Fellow Jitster',
|
||||
DEFAULT_LOCAL_DISPLAY_NAME: 'me',
|
||||
SHOW_JITSI_WATERMARK: true,
|
||||
JITSI_WATERMARK_LINK: 'https://jitsi.org',
|
||||
|
||||
// if watermark is disabled by default, it can be shown only for guests
|
||||
SHOW_WATERMARK_FOR_GUESTS: true,
|
||||
SHOW_BRAND_WATERMARK: false,
|
||||
BRAND_WATERMARK_LINK: '',
|
||||
SHOW_POWERED_BY: false,
|
||||
SHOW_DEEP_LINKING_IMAGE: false,
|
||||
GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true,
|
||||
DISPLAY_WELCOME_PAGE_CONTENT: true,
|
||||
DISPLAY_WELCOME_PAGE_TOOLBAR_ADDITIONAL_CONTENT: false,
|
||||
APP_NAME: 'Jitsi Meet',
|
||||
NATIVE_APP_NAME: 'Jitsi Meet',
|
||||
PROVIDER_NAME: 'Jitsi',
|
||||
LANG_DETECTION: true, // Allow i18n to detect the system language
|
||||
|
||||
/**
|
||||
* Hide the invite prompt in the header when alone in the meeting.
|
||||
*/
|
||||
HIDE_INVITE_MORE_HEADER: false,
|
||||
|
||||
/**
|
||||
* The name of the toolbar buttons to display in the toolbar. If present,
|
||||
* the button will display. Exceptions are "livestreaming" and "recording"
|
||||
* which also require being a moderator and some values in config.js to be
|
||||
* enabled. Also, the "profile" button will not display for user's with a
|
||||
* jwt.
|
||||
*/
|
||||
TOOLBAR_BUTTONS: [
|
||||
'microphone', 'camera', 'closedcaptions', 'desktop', 'fullscreen',
|
||||
'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
|
||||
'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
|
||||
'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
|
||||
'tileview', 'videobackgroundblur', 'download', 'help', 'mute-everyone', 'security'
|
||||
],
|
||||
|
||||
SETTINGS_SECTIONS: [ 'devices', 'language', 'moderator', 'profile', 'calendar' ],
|
||||
|
||||
// Determines how the video would fit the screen. 'both' would fit the whole
|
||||
// screen, 'height' would fit the original video height to the height of the
|
||||
// screen, 'width' would fit the original video width to the width of the
|
||||
// screen respecting ratio.
|
||||
VIDEO_LAYOUT_FIT: 'both',
|
||||
|
||||
/**
|
||||
* Whether to only show the filmstrip (and hide the toolbar).
|
||||
*/
|
||||
filmStripOnly: false,
|
||||
|
||||
/**
|
||||
* Whether to show thumbnails in filmstrip as a column instead of as a row.
|
||||
*/
|
||||
VERTICAL_FILMSTRIP: true,
|
||||
|
||||
// A html text to be shown to guests on the close page, false disables it
|
||||
CLOSE_PAGE_GUEST_HINT: false,
|
||||
SHOW_PROMOTIONAL_CLOSE_PAGE: false,
|
||||
FILM_STRIP_MAX_HEIGHT: 120,
|
||||
|
||||
// Enables feedback star animation.
|
||||
ENABLE_FEEDBACK_ANIMATION: false,
|
||||
DISABLE_FOCUS_INDICATOR: false,
|
||||
DISABLE_DOMINANT_SPEAKER_INDICATOR: false,
|
||||
|
||||
/**
|
||||
* Whether the speech to text transcription subtitles panel is disabled.
|
||||
* If {@code undefined}, defaults to {@code false}.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
DISABLE_TRANSCRIPTION_SUBTITLES: false,
|
||||
|
||||
/**
|
||||
* Whether the ringing sound in the call/ring overlay is disabled. If
|
||||
* {@code undefined}, defaults to {@code false}.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
DISABLE_RINGING: false,
|
||||
AUDIO_LEVEL_PRIMARY_COLOR: 'rgba(255,255,255,0.4)',
|
||||
AUDIO_LEVEL_SECONDARY_COLOR: 'rgba(255,255,255,0.2)',
|
||||
POLICY_LOGO: null,
|
||||
LOCAL_THUMBNAIL_RATIO: 16 / 9, // 16:9
|
||||
REMOTE_THUMBNAIL_RATIO: 1, // 1:1
|
||||
// Documentation reference for the live streaming feature.
|
||||
LIVE_STREAMING_HELP_LINK: 'https://jitsi.org/live',
|
||||
|
||||
/**
|
||||
* Whether the mobile app Jitsi Meet is to be promoted to participants
|
||||
* attempting to join a conference in a mobile Web browser. If
|
||||
* {@code undefined}, defaults to {@code true}.
|
||||
* A UX mode where the last screen share participant is automatically
|
||||
* pinned. Valid values are the string "remote-only" so remote participants
|
||||
* get pinned but not local, otherwise any truthy value for all participants,
|
||||
* and any falsy value to disable the feature.
|
||||
*
|
||||
* @type {boolean}
|
||||
* Note: this mode is experimental and subject to breakage.
|
||||
*/
|
||||
MOBILE_APP_PROMO: true,
|
||||
|
||||
/**
|
||||
* Maximum coeficient of the ratio of the large video to the visible area
|
||||
* after the large video is scaled to fit the window.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
MAXIMUM_ZOOMING_COEFFICIENT: 1.3,
|
||||
|
||||
/*
|
||||
* If indicated some of the error dialogs may point to the support URL for
|
||||
* help.
|
||||
*/
|
||||
SUPPORT_URL: 'https://community.jitsi.org/',
|
||||
AUTO_PIN_LATEST_SCREEN_SHARE: 'remote-only',
|
||||
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
|
||||
@@ -152,51 +44,112 @@ var interfaceConfig = {
|
||||
*/
|
||||
CONNECTION_INDICATOR_DISABLED: false,
|
||||
|
||||
/**
|
||||
* If true, hides the video quality label indicating the resolution status
|
||||
* of the current large video.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
VIDEO_QUALITY_LABEL_DISABLED: false,
|
||||
DEFAULT_BACKGROUND: '#474747',
|
||||
DEFAULT_LOCAL_DISPLAY_NAME: 'me',
|
||||
DEFAULT_LOGO_URL: 'images/watermark.png',
|
||||
DEFAULT_REMOTE_DISPLAY_NAME: 'Fellow Jitster',
|
||||
|
||||
/**
|
||||
* If true, will display recent list
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
RECENT_LIST_ENABLED: true,
|
||||
DISABLE_DOMINANT_SPEAKER_INDICATOR: false,
|
||||
|
||||
// Names of browsers which should show a warning stating the current browser
|
||||
// has a suboptimal experience. Browsers which are not listed as optimal or
|
||||
// unsupported are considered suboptimal. Valid values are:
|
||||
// chrome, chromium, edge, electron, firefox, nwjs, opera, safari
|
||||
OPTIMAL_BROWSERS: [ 'chrome', 'chromium', 'firefox', 'nwjs', 'electron', 'safari' ],
|
||||
|
||||
// Browsers, in addition to those which do not fully support WebRTC, that
|
||||
// are not supported and should show the unsupported browser page.
|
||||
UNSUPPORTED_BROWSERS: [],
|
||||
|
||||
/**
|
||||
* A UX mode where the last screen share participant is automatically
|
||||
* pinned. Valid values are the string "remote-only" so remote participants
|
||||
* get pinned but not local, otherwise any truthy value for all participants,
|
||||
* and any falsy value to disable the feature.
|
||||
*
|
||||
* Note: this mode is experimental and subject to breakage.
|
||||
*/
|
||||
AUTO_PIN_LATEST_SCREEN_SHARE: 'remote-only',
|
||||
|
||||
/**
|
||||
* If true, presence status: busy, calling, connected etc. is not displayed.
|
||||
*/
|
||||
DISABLE_PRESENCE_STATUS: false,
|
||||
DISABLE_FOCUS_INDICATOR: false,
|
||||
|
||||
/**
|
||||
* If true, notifications regarding joining/leaving are no longer displayed.
|
||||
*/
|
||||
DISABLE_JOIN_LEAVE_NOTIFICATIONS: false,
|
||||
|
||||
/**
|
||||
* If true, presence status: busy, calling, connected etc. is not displayed.
|
||||
*/
|
||||
DISABLE_PRESENCE_STATUS: false,
|
||||
|
||||
/**
|
||||
* Whether the ringing sound in the call/ring overlay is disabled. If
|
||||
* {@code undefined}, defaults to {@code false}.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
DISABLE_RINGING: false,
|
||||
|
||||
/**
|
||||
* Whether the speech to text transcription subtitles panel is disabled.
|
||||
* If {@code undefined}, defaults to {@code false}.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
DISABLE_TRANSCRIPTION_SUBTITLES: false,
|
||||
|
||||
/**
|
||||
* Whether or not the blurred video background for large video should be
|
||||
* displayed on browsers that can support it.
|
||||
*/
|
||||
DISABLE_VIDEO_BACKGROUND: false,
|
||||
|
||||
DISPLAY_WELCOME_PAGE_CONTENT: true,
|
||||
DISPLAY_WELCOME_PAGE_TOOLBAR_ADDITIONAL_CONTENT: false,
|
||||
|
||||
ENABLE_FEEDBACK_ANIMATION: false, // Enables feedback star animation.
|
||||
|
||||
FILM_STRIP_MAX_HEIGHT: 120,
|
||||
|
||||
/**
|
||||
* Whether to only show the filmstrip (and hide the toolbar).
|
||||
*/
|
||||
filmStripOnly: false,
|
||||
|
||||
GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true,
|
||||
|
||||
/**
|
||||
* Hide the invite prompt in the header when alone in the meeting.
|
||||
*/
|
||||
HIDE_INVITE_MORE_HEADER: false,
|
||||
|
||||
INITIAL_TOOLBAR_TIMEOUT: 20000,
|
||||
JITSI_WATERMARK_LINK: 'https://jitsi.org',
|
||||
|
||||
LANG_DETECTION: true, // Allow i18n to detect the system language
|
||||
LIVE_STREAMING_HELP_LINK: 'https://jitsi.org/live', // Documentation reference for the live streaming feature.
|
||||
LOCAL_THUMBNAIL_RATIO: 16 / 9, // 16:9
|
||||
|
||||
/**
|
||||
* Maximum coeficient of the ratio of the large video to the visible area
|
||||
* after the large video is scaled to fit the window.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
MAXIMUM_ZOOMING_COEFFICIENT: 1.3,
|
||||
|
||||
/**
|
||||
* Whether the mobile app Jitsi Meet is to be promoted to participants
|
||||
* attempting to join a conference in a mobile Web browser. If
|
||||
* {@code undefined}, defaults to {@code true}.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
MOBILE_APP_PROMO: true,
|
||||
|
||||
NATIVE_APP_NAME: 'Jitsi Meet',
|
||||
|
||||
// Names of browsers which should show a warning stating the current browser
|
||||
// has a suboptimal experience. Browsers which are not listed as optimal or
|
||||
// unsupported are considered suboptimal. Valid values are:
|
||||
// chrome, chromium, edge, electron, firefox, nwjs, opera, safari
|
||||
OPTIMAL_BROWSERS: [ 'chrome', 'chromium', 'firefox', 'nwjs', 'electron', 'safari' ],
|
||||
|
||||
POLICY_LOGO: null,
|
||||
PROVIDER_NAME: 'Jitsi',
|
||||
|
||||
/**
|
||||
* If true, will display recent list
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
RECENT_LIST_ENABLED: true,
|
||||
REMOTE_THUMBNAIL_RATIO: 1, // 1:1
|
||||
|
||||
SETTINGS_SECTIONS: [ 'devices', 'language', 'moderator', 'profile', 'calendar' ],
|
||||
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)
|
||||
@@ -204,6 +157,60 @@ var interfaceConfig = {
|
||||
*/
|
||||
SHOW_CHROME_EXTENSION_BANNER: false,
|
||||
|
||||
SHOW_DEEP_LINKING_IMAGE: false,
|
||||
SHOW_JITSI_WATERMARK: true,
|
||||
SHOW_POWERED_BY: false,
|
||||
SHOW_PROMOTIONAL_CLOSE_PAGE: false,
|
||||
SHOW_WATERMARK_FOR_GUESTS: true, // if watermark is disabled by default, it can be shown only for guests
|
||||
|
||||
/*
|
||||
* If indicated some of the error dialogs may point to the support URL for
|
||||
* help.
|
||||
*/
|
||||
SUPPORT_URL: 'https://community.jitsi.org/',
|
||||
|
||||
TOOLBAR_ALWAYS_VISIBLE: false,
|
||||
|
||||
/**
|
||||
* The name of the toolbar buttons to display in the toolbar. If present,
|
||||
* the button will display. Exceptions are "livestreaming" and "recording"
|
||||
* which also require being a moderator and some values in config.js to be
|
||||
* enabled. Also, the "profile" button will not display for user's with a
|
||||
* jwt.
|
||||
*/
|
||||
TOOLBAR_BUTTONS: [
|
||||
'microphone', 'camera', 'closedcaptions', 'desktop', 'fullscreen',
|
||||
'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
|
||||
'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
|
||||
'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
|
||||
'tileview', 'videobackgroundblur', 'download', 'help', 'mute-everyone', 'security'
|
||||
],
|
||||
|
||||
TOOLBAR_TIMEOUT: 4000,
|
||||
|
||||
// Browsers, in addition to those which do not fully support WebRTC, that
|
||||
// are not supported and should show the unsupported browser page.
|
||||
UNSUPPORTED_BROWSERS: [],
|
||||
|
||||
/**
|
||||
* Whether to show thumbnails in filmstrip as a column instead of as a row.
|
||||
*/
|
||||
VERTICAL_FILMSTRIP: true,
|
||||
|
||||
// Determines how the video would fit the screen. 'both' would fit the whole
|
||||
// screen, 'height' would fit the original video height to the height of the
|
||||
// screen, 'width' would fit the original video width to the width of the
|
||||
// screen respecting ratio.
|
||||
VIDEO_LAYOUT_FIT: 'both',
|
||||
|
||||
/**
|
||||
* If true, hides the video quality label indicating the resolution status
|
||||
* of the current large video.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
VIDEO_QUALITY_LABEL_DISABLED: false
|
||||
|
||||
/**
|
||||
* When enabled, the kick participant button will not be presented for users without a JWT
|
||||
*/
|
||||
@@ -258,12 +265,6 @@ var interfaceConfig = {
|
||||
INDICATOR_FONT_SIZES
|
||||
PHONE_NUMBER_REGEX
|
||||
*/
|
||||
|
||||
// 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'
|
||||
|
||||
// no configuration value should follow this line.
|
||||
};
|
||||
|
||||
/* eslint-enable no-unused-vars, no-var, max-len */
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"en": "Anglès",
|
||||
"af": "Afrikaans",
|
||||
"ar": "Àrab",
|
||||
"bg": "Búlgar",
|
||||
"ca": "Català",
|
||||
"cs": "Txec",
|
||||
@@ -10,25 +11,36 @@
|
||||
"enGB": "Anglès (Regne Unit)",
|
||||
"eo": "Esperanto",
|
||||
"es": "Espanyol",
|
||||
"esUS": "Espanyol (Amèrica llatina)",
|
||||
"esUS": "Espanyol (Amèrica Llatina)",
|
||||
"et": "Estonià",
|
||||
"eu": "Èuscar",
|
||||
"fi": "Finès",
|
||||
"fr": "Francès",
|
||||
"frCA": "Francès (Canadà)",
|
||||
"he": "Hebreu",
|
||||
"mr": "Marathi",
|
||||
"hr": "Croat",
|
||||
"hu": "Hongarès",
|
||||
"hy": "Armeni",
|
||||
"id": "Indonesi",
|
||||
"it": "Italià",
|
||||
"ja": "Japonès",
|
||||
"ko": "Coreà",
|
||||
"lt": "Lituà",
|
||||
"nl": "Neerlandès",
|
||||
"oc": "Occità",
|
||||
"pl": "Polonès",
|
||||
"ptBR": "Portuguès (Brasil)",
|
||||
"ru": "Rus",
|
||||
"ro": "Romanès",
|
||||
"sc": "Sard",
|
||||
"sk": "Eslovac",
|
||||
"sl": "Eslovè",
|
||||
"sv": "Suec",
|
||||
"th": "Tai",
|
||||
"tr": "Turc",
|
||||
"uk": "Ucraïnès",
|
||||
"vi": "Vietnamita",
|
||||
"zhCN": "Xinès (Xina)",
|
||||
"zhTW": "Xinès (Taiwan)",
|
||||
"et": "Estonià"
|
||||
"zhTW": "Xinès (Taiwan)"
|
||||
}
|
||||
|
||||
@@ -1,21 +1,36 @@
|
||||
{
|
||||
"addPeople": {
|
||||
"add": "Προσκάλεσε",
|
||||
"addContacts": "Προσκάλεσε τις επαφές σου",
|
||||
"copyInvite": "Αντίγραψε την πρόσκληση της συνάντησης",
|
||||
"copyLink": "Αντίγραψε το σύνδεσμο της συνάντησης",
|
||||
"copyStream": "Αντίγραψε το σύνδεσμο της ζωντανής μετάδοσης",
|
||||
"countryNotSupported": "Δεν υποστηρίζουμε αυτόν τον προορισμό ακόμα.",
|
||||
"countryReminder": "Κλήση εκτός ΗΠΑ; Παρακαλώ βεβαιωθείτε ότι ξεκινάτε με τον κωδικό της χώρας!",
|
||||
"defaultEmail": "Το προεπιλεγμένο Email σου",
|
||||
"disabled": "Δεν μπορείτε να προσκαλέσετε άτομα.",
|
||||
"failedToAdd": "Αποτυχία προσθήκης συμμετεχόντων",
|
||||
"footerText": "Η κλήση είναι απενεργοποιημένη.",
|
||||
"googleEmail": "Google Email",
|
||||
"inviteMoreHeader": "Είσαι ο μόναδικός συμμετέχων στη συνάντηση",
|
||||
"inviteMoreMailSubject": "Συμμετοχή στη συνάντηση {{appName}}",
|
||||
"inviteMorePrompt": "Πρόσκληση συμμετεχόντων",
|
||||
"linkCopied": "Ο σύνδεσμος αντιγράφηκε στο πρόχειρο",
|
||||
"loading": "Αναζήτηση για ανθρώπους και αριθμούς τηλεφώνου",
|
||||
"loadingNumber": "Ο αριθμός τηλεφώνου επικυρώνεται",
|
||||
"loadingPeople": "Γίνεται αναζήτηση για ανθρώπους που θα καλεστούν",
|
||||
"noResults": "Δε βρέθηκαν αποτελέσματα αναζήτησης",
|
||||
"outlookEmail": "Outlook Email",
|
||||
"noValidNumbers": "Παρακαλώ εισάγετε έναν αριθμό τηλεφώνου",
|
||||
"searchNumbers": "Προσθέστε αριθμούς τηλεφώνου",
|
||||
"searchPeople": "Αναζήτηση για ανθρώπους",
|
||||
"searchPeopleAndNumbers": "Αναζήτηση για ανθρώπους ή προσθήκη των αριθμών τηλεφώνου τους",
|
||||
"shareInvite": "Κοινή χρήση πρόσκλησης συνάντησης",
|
||||
"shareLink": "Κοινή χρήση συνδέσμου συνάντησης για πρόσκληση άλλων",
|
||||
"shareStream": "Κοινή χρήση του συνδέσμου ζωντανής μετάδοσης",
|
||||
"telephone": "Τηλέφωνο: {{number}}",
|
||||
"title": "Καλέστε ανθρώπους σε αυτή τη συνάντηση"
|
||||
"title": "Καλέστε ανθρώπους σε αυτή τη συνάντηση",
|
||||
"yahooEmail": "Yahoo Email"
|
||||
},
|
||||
"audioDevices": {
|
||||
"bluetooth": "Bluetooth",
|
||||
@@ -79,7 +94,7 @@
|
||||
"ERROR": "Σφάλμα",
|
||||
"FETCH_SESSION_ID": "Απόκτηση session-id...",
|
||||
"GET_SESSION_ID_ERROR": "Λήψη session-id σφάλματος: {{code}}",
|
||||
"GOT_SESSION_ID": "Απόκτηση session-id... Κάνει",
|
||||
"GOT_SESSION_ID": "Απόκτηση session-id... Έγινε",
|
||||
"LOW_BANDWIDTH": "Το βίντεο για το {{displayName}} έχει απενεργοποιηθεί για να εξοικονομήσετε εύρος ζώνης"
|
||||
},
|
||||
"connectionindicator": {
|
||||
@@ -98,9 +113,9 @@
|
||||
"more": "Εμφάνιση περισσότερων",
|
||||
"packetloss": "Απώλεια πακέτων:",
|
||||
"quality": {
|
||||
"good": "Καλά",
|
||||
"inactive": "Ανενεργά",
|
||||
"lost": "Χαμένα",
|
||||
"good": "Καλή",
|
||||
"inactive": "Ανενεργό",
|
||||
"lost": "Χαμένη",
|
||||
"nonoptimal": "Μέτρια",
|
||||
"poor": "Κακή"
|
||||
},
|
||||
@@ -123,8 +138,10 @@
|
||||
"description": "Δεν έγινε τίποτα; Προσπαθήσαμε να κάνουμε έναρξη σύσκεψης στο {{app}} desktop app. Προσπαθήστε ξανά ή ξεκινήστε το {{app}} web app.",
|
||||
"descriptionWithoutWeb": "Δεν έγινε τίποτα; Προσπαθήσαμε να κάνουμε έναρξη σύσκεψης στο {{app}} desktop app.",
|
||||
"downloadApp": "Κατεβάστε την εφαρμογή",
|
||||
"ifDoNotHaveApp": "If you don't have the app yet:",
|
||||
"ifHaveApp": "If you already have the app:",
|
||||
"joinInApp": "Join this meeting using the app",
|
||||
"launchWebButton": "Έναρξη στο web",
|
||||
"openApp": "Συνεχίστε στην εφαρμογή",
|
||||
"title": "Γίνεται έναρξη της συνάντησής σας στο {{app}}...",
|
||||
"tryAgainButton": "Προσπαθήστε ξανά στην επιφάνεια εργασίας"
|
||||
},
|
||||
@@ -146,6 +163,7 @@
|
||||
"accessibilityLabel": {
|
||||
"liveStreaming": "Ζωντανή ροή"
|
||||
},
|
||||
"add": "Add",
|
||||
"allow": "Επίτρεψε",
|
||||
"alreadySharedVideoMsg": "Ένας άλλος συμμετέχων κάνει ήδη κοινή προβολή βίντεο. Η διάσκεψη αυτή επιτρέπει μόνο ένα κοινόχρηστο βίντεο τη φορά.",
|
||||
"alreadySharedVideoTitle": "Μόνο ένα κοινόχρηστο βίντεο επιτρέπεται τη φορά",
|
||||
@@ -174,22 +192,20 @@
|
||||
"copy": "Αντιγραφή",
|
||||
"dismiss": "Απόρριψη",
|
||||
"displayNameRequired": "Γεια σου! Ποιο είναι το όνομα σου;",
|
||||
"done": "Κάνει",
|
||||
"done": "Έγινε",
|
||||
"e2eeDescription": "<p>Η από άκρη σε άκρη κρυπτογράφηση είναι σήμερα <strong>σε ΠΕΙΡΑΜΑΤΙΚΟ στάδιο</strong>. Παρακαλώ δείτε <a href='https://jitsi.org/blog/e2ee/' target='_blank'>αυτήν την ανάρτηση</a> για λεπτομέρειες.</p><br/><p>Παρακαλώ να έχετε κατά νου ότι η ενεργοποίηση της από άκρη σε άκρη κρυπτογράφησης θα απενεργοποιήσει από την πλευρά του διακομιστή υπηρεσίες όπως: καταγραφή, live streaming και συμμετοχή μέσω τηλεφώνου. Επίσης, να έχετε κατά νου ότι η συνάντηση θα λειτουργήσει μόνο για τους ανθρώπους που συνδέονται από φυλλομετρητές με υποστήριξη για insertable streams.</p>",
|
||||
"e2eeLabel": "Κλειδί",
|
||||
"e2eeNoKey": "None",
|
||||
"e2eeSet": "Set",
|
||||
"e2eeTitle": "Από άκρη σε άκρη κρυπτογράφηση",
|
||||
"e2eeToggleSet": "Set key",
|
||||
"e2eeWarning": "ΠΡΟΕΙΔΟΠΟΊΗΣΗ: Δε φαίνεται να έχουν όλοι οι συμμετέχοντες στη συνάντηση αυτή υποστήριξη για από άκρη σε άκρη κρυπτογράφηση. Αν την ενεργοποιήσετε, δεν θα μπορέσουν να σας δουν ούτε να σας ακούσουν.",
|
||||
"enterDisplayName": "Παρακαλώ εισάγετε το όνομά σας εδώ",
|
||||
"error": "Σφάλμα",
|
||||
"externalInstallationMsg": "Θα πρέπει να εγκαταστήσετε την επέκτασή μας για διαμοιρασμό επιφάνειας εργασίας.",
|
||||
"externalInstallationTitle": "Απαιτείται επέκταση",
|
||||
"goToStore": "Μετάβαση στο webstore",
|
||||
"gracefulShutdown": "Μας υπηρεσία είναι προς το παρόν εκτός λειτουργίας για συντήρηση. Παρακαλώ προσπαθήστε ξανά αργότερα.",
|
||||
"IamHost": "Είμαι ο οικοδεσπότης",
|
||||
"incorrectRoomLockPassword": "Εσφαλμένος κωδικός πρόσβασης",
|
||||
"incorrectPassword": "Λανθασμένο όνομα χρήστη ή κωδικός πρόσβασης",
|
||||
"inlineInstallationMsg": "Θα πρέπει να εγκαταστήσετε την επέκτασή μας για διαμοιρασμό επιφάνειας εργασίας.",
|
||||
"inlineInstallExtension": "Εγκαταστήστε τώρα",
|
||||
"internalError": "Ουπς! Κάτι πήγε στραβά. Παρουσιάστηκε το παρακάτω σφάλμα: {{error}}",
|
||||
"internalErrorTitle": "Εσωτερικό σφάλμα",
|
||||
"kickMessage": "Μπορείτε να επικοινωνήσετε με το {{participantDisplayName}} για περισσότερες λεπτομέρειες.",
|
||||
@@ -198,6 +214,7 @@
|
||||
"kickParticipantTitle": "Θέλετε να αποβάλετε αυτόν τον συμμετέχοντα;",
|
||||
"kickTitle": "Ωχ! Ο/Η {{participantDisplayName}} σας απέβαλε από τη διάσκεψη",
|
||||
"liveStreaming": "Ζωντανή ροή",
|
||||
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "Not possible while recording is active",
|
||||
"liveStreamingDisabledForGuestTooltip": "Οι επισκέπτες δεν μπορούν να ξεκινήσουν τη ζωντανή ροή",
|
||||
"liveStreamingDisabledTooltip": "Έναρξη ζωντανής ροής απενεργοποιημένη",
|
||||
"lockMessage": "Αποτυχία κλειδώματος της διάσκεψης.",
|
||||
@@ -231,6 +248,7 @@
|
||||
"popupError": "Ο φυλλομετρητής σας μπλοκάρει τα pop-up windows από αυτό το site. Παρακαλούμε ενεργοποιήστε τα pop-ups στις ρυθμίσεις ασφαλείας του προγράμματος περιήγησής σας και προσπαθήστε ξανά.",
|
||||
"popupErrorTitle": "Pop-up μπλοκαρίστηκε",
|
||||
"recording": "Γίνεται εγγραφή",
|
||||
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Not possible while a live stream is active",
|
||||
"recordingDisabledForGuestTooltip": "Οι επισκέπτες δεν μπορούν να ξεκινήσουν τις ηχογραφήσεις.",
|
||||
"recordingDisabledTooltip": "Έναρξη εγγραφής απενεργοποιημένη.",
|
||||
"rejoinNow": "Επανασύνδεση τώρα",
|
||||
@@ -251,8 +269,6 @@
|
||||
"screenSharingAudio": "Διαμοιρασμός ήχου",
|
||||
"screenSharingFailedToInstall": "Ουπς! Η εγκατάσταση της επέκταση κοινής χρήσης οθόνης απέτυχε.",
|
||||
"screenSharingFailedToInstallTitle": "Η εγκατάσταση της επέκταση κοινής χρήσης οθόνης απέτυχε",
|
||||
"screenSharingFirefoxPermissionDeniedError": "Κάτι πήγε στραβά ενώ προσπαθούσατε να μοιραστείτε την οθόνη σας. Παρακαλούμε βεβαιωθείτε ότι μας έχετε δώσει την άδεια να το πράξουμε.",
|
||||
"screenSharingFirefoxPermissionDeniedTitle": "Ουπς! Δεν ήμασταν σε θέση να ξεκινήσουμε την κοινή χρήση οθόνης!",
|
||||
"screenSharingPermissionDeniedError": "Ουπς! Κάτι πήγε στραβά με τα δικαιώματα της επέκτασης κοινής χρήσης οθόνης. Παρακαλώ ξαναφορτώστε και προσπαθήστε ξανά.",
|
||||
"sendPrivateMessage": "Πρόσφατα λάβατε ένα προσωπικό μήνυμα. Σκοπεύετε να απαντήσετε σε αυτό ιδιωτικά ή θέλετε να στείλετε το μήνυμά σας στην ομάδα;",
|
||||
"sendPrivateMessageCancel": "Στείλτε στην ομάδα",
|
||||
@@ -390,6 +406,8 @@
|
||||
"failedToStart": "Η ζωντανή ροή απέτυχε να ξεκινήσει",
|
||||
"getStreamKeyManually": "Δεν ήμασταν σε θέση να φέρουμε κάποια ζωντανή ροή. Προσπαθήστε να πάρετε το κλειδί της ζωντανής ροής από το YouTube.",
|
||||
"invalidStreamKey": "Το κλειδί της ζωντανής ροής μπορεί να είναι εσφαλμένο.",
|
||||
"limitNotificationDescriptionNative": "Your streaming will be limited to {{limit}} min. For unlimited streaming try {{app}}.",
|
||||
"limitNotificationDescriptionWeb": "Due to high demand your streaming will be limited to {{limit}} min. For unlimited streaming try <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"off": "Η ζωντανή ροή σταμάτησε",
|
||||
"offBy": "Ο/Η {{name}} σταμάτησε τη ζωντανή ροή",
|
||||
"on": "Ζωντανή ροή",
|
||||
@@ -476,6 +494,40 @@
|
||||
"passwordSetRemotely": "ορίστηκε από άλλον συμμετέχοντα",
|
||||
"passwordDigitsOnly": "Έως {{number}} ψηφία",
|
||||
"poweredby": "με τη δύναμη του",
|
||||
"prejoin": {
|
||||
"audioAndVideoError": "Σφάλμα ήχου και βίντεο:",
|
||||
"audioOnlyError": "Σφάλμα ήχου:",
|
||||
"audioTrackError": "Δεν ήταν δυνατή η δημιουργία κομματιού ήχου.",
|
||||
"callMe": "Κάλεσέ με",
|
||||
"callMeAtNumber": "Κάλεσέ με σε αυτό το νούμερο:",
|
||||
"configuringDevices": "Γίνεται παραμετροποίηση συσκευών...",
|
||||
"connectedWithAudioQ": "Είστε συνδεδεμένοι με ήχο;",
|
||||
"copyAndShare": "Αντιγραφή και κοινή χρήση συνδέσμου συνάντησης",
|
||||
"dialInMeeting": "Κλήση στη συνάντηση",
|
||||
"dialInPin": "Κλήση στη συνάντηση και εισαγωγή κωδικού PIN:",
|
||||
"dialing": "Γίνεται κλήση",
|
||||
"doNotShow": "Να μην εμφανιστεί αυτό ξανά",
|
||||
"errorDialOut": "Η κλήση δεν ήταν δυνατή",
|
||||
"errorDialOutDisconnected": "Η κλήση δεν ήταν δυνατή. Έγινε αποσύνδεση",
|
||||
"errorDialOutFailed": "Η κλήση δεν ήταν δυνατή. Η κλήση απέτυχε",
|
||||
"errorDialOutStatus": "Σφάλμα λήψης κατάστασης κλήσης",
|
||||
"errorStatusCode": "Σφάλμα κλήσης, κωδικός κατάστασης: {{status}}",
|
||||
"errorValidation": "Η επικύρωση του αριθμού απέτυχε",
|
||||
"iWantToDialIn": "Θέλω να κάνω κλήση",
|
||||
"joinAudioByPhone": "Συμμετοχή με ήχο τηλεφώνου",
|
||||
"joinMeeting": "Συμμετοχή στη συνάντηση",
|
||||
"joinWithoutAudio": "Συμμετοχή χωρίς ήχο",
|
||||
"initiated": "Η κλήση ξεκίνησε",
|
||||
"linkCopied": "Ο σύνδεσμος αντιγράφηκε στο πρόχειρο",
|
||||
"lookGood": "Ακούγεται ότι το μικρόφωνο σας λειτουργεί άψογα",
|
||||
"or": "ή",
|
||||
"calling": "Γίνεται κλήση",
|
||||
"startWithPhone": "Έναρξη με ήχο τηλεφώνου",
|
||||
"screenSharingError": "Σφάλμα διαμοιρασμού οθόνης:",
|
||||
"videoOnlyError": "Σφάλμα βίντεο:",
|
||||
"videoTrackError": "Δεν ήταν δυνατή η δημιουργία κομματιού βίντεο.",
|
||||
"viewAllNumbers": "προβολή όλων των αριθμών"
|
||||
},
|
||||
"presenceStatus": {
|
||||
"busy": "Απασχολημένος",
|
||||
"calling": "Γίνεται κλήση...",
|
||||
@@ -498,6 +550,8 @@
|
||||
},
|
||||
"raisedHand": "Θα ήθελα να μιλήσω",
|
||||
"recording": {
|
||||
"limitNotificationDescriptionWeb": "Λόγω υψηλής ζήτησης η εγγραφή σας θα περιριστεί σε {{limit}} λεπτά. Για απεριόριστες εγγραφές, δοκιμάστε το <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"limitNotificationDescriptionNative": "Λόγω υψηλής ζήτησης η εγγραφή σας θα περιριστεί σε {{limit}} λεπτά. Για απεριόριστες εγγραφές, δοκιμάστε <3>{{app}}</3>.",
|
||||
"authDropboxText": "Ανεβάστε στο Dropbox",
|
||||
"availableSpace": "Διαθέσιμος χώρος: {{spaceLeft}} MB (περίπου {{duration}} λεπτά εγγραφής)",
|
||||
"beta": "BETA",
|
||||
@@ -527,6 +581,11 @@
|
||||
"sectionList": {
|
||||
"pullToRefresh": "Τραβήξτε για να ανανεώσετε"
|
||||
},
|
||||
"security": {
|
||||
"about": "Έχετε τη δυνατότητα να προσθέσετε κωδικό στη συνάντησή σας. Οι συμμετέχοντες θα πρέπει να τον εισάγουν για να τους δοθεί πρόσβαση στη συνάντηση.",
|
||||
"insecureRoomNameWarning": "Το όνομα του διαδρόμου δεν είναι ασφαλές. Ανεπιθύμητοι συμμετέχοντες μπορεί να συμμετάσχουν στη συνάντησή σας. Σκεφτείτε το να ασφαλίσετε τη συνάντηση σας χρησιμοποιώντας το κουμπί Ασφάλεια.",
|
||||
"securityOptions": "Επιλογές ασφαλείας"
|
||||
},
|
||||
"settings": {
|
||||
"calendar": {
|
||||
"about": "H σύνδεση ημερολογίου του {{appName}} χρησιμοποιείται για την ασφαλή πρόσβαση του ημερολογίου σας, ώστε να μπορεί να διαβάσει τις επερχόμενες εκδηλώσεις.",
|
||||
@@ -585,7 +644,7 @@
|
||||
"name": "Όνομα",
|
||||
"seconds": "{{count}}δ",
|
||||
"speakerStats": "Στατιστικά ομιλητή",
|
||||
"speakerTime": "Ώρα ομιλητή"
|
||||
"speakerTime": "Χρόνος ομιλητή"
|
||||
},
|
||||
"startupoverlay": {
|
||||
"policyText": " ",
|
||||
@@ -612,6 +671,7 @@
|
||||
"help": "Βοήθεια",
|
||||
"invite": "Πρόσκληση συμμετεχόντων",
|
||||
"kick": "Αποβολή συμμετέχοντα",
|
||||
"lobbyButton": "Ενεργοποίηση/απενεργοποίηση λειτουργίας διαδρόμου",
|
||||
"localRecording": "Εναλλαγή ελέγχων τοπικής καταγραφής",
|
||||
"lockRoom": "Εναλλαγή κωδικού πρόσβασης συνάντησης",
|
||||
"moreActions": "Εναλλαγή μενού περισσότερων ενεργειών",
|
||||
@@ -625,6 +685,7 @@
|
||||
"raiseHand": "Εναλλαγή σηκώματος χεριού",
|
||||
"recording": "Εναλλαγή καταγραφής",
|
||||
"remoteMute": "Σίγαση συμμετέχοντα",
|
||||
"security": "Επιλογές ασφαλείας",
|
||||
"Settings": "Εναλλαγή ρυθμίσεων",
|
||||
"sharedvideo": "Εναλλαγή κοινής χρήσης βίντεο στο Youtube",
|
||||
"shareRoom": "Προσκαλέστε κάποιον",
|
||||
@@ -658,6 +719,8 @@
|
||||
"hangup": "Αποσύνδεση",
|
||||
"help": "Βοήθεια",
|
||||
"invite": "Πρόσκληση συμμετεχόντων",
|
||||
"lobbyButtonDisable": "Απενεργοποίηση λειτουργίας διαδρόμου",
|
||||
"lobbyButtonEnable": "Ενεργοποίηση λειτουργίας διαδρόμου",
|
||||
"login": "Είσοδος",
|
||||
"logout": "Αποσύνδεση",
|
||||
"lowerYourHand": "Κατεβάστε το χέρι σας",
|
||||
@@ -678,6 +741,7 @@
|
||||
"profile": "Επεξεργαστείτε το προφίλ σας",
|
||||
"raiseHand": "Σηκώστε / κατεβάστε το χέρι σας",
|
||||
"raiseYourHand": "Σηκώστε το χέρι σας",
|
||||
"security": "Επιλογές ασφαλείας",
|
||||
"Settings": "Ρυθμίσεις",
|
||||
"sharedvideo": "Μοιραστείτε βίντεο στο YouTube",
|
||||
"shareRoom": "Προσκαλέστε κάποιον",
|
||||
@@ -743,9 +807,6 @@
|
||||
"lowDefinition": "Χαμηλής ευκρίνειας",
|
||||
"onlyAudioAvailable": "Μόνο ο ήχος είναι διαθέσιμος",
|
||||
"onlyAudioSupported": "Υποστηρίζουμε μόνο ήχο σε αυτό το πρόγραμμα περιήγησης.",
|
||||
"p2pEnabled": "Λειτουργία Peer to Peer Ενεργοποιημένη",
|
||||
"p2pVideoQualityDescription": "Σε λειτουργία peer-to-peer, η ποιότητα του εισερχόμενου βίντεο μπορεί μόνο να εναλλάσσεται μεταξύ της υψηλής και μόνο ήχου. Οι υπόλοιπες ρυθμίσεις δεν θα ενεργοποιηθούν μέχρι να τερματιστεί η λειτουργία peer to peer.",
|
||||
"recHighDefinitionOnly": "Να προτιμηθεί υψηλή ευκρίνεια.",
|
||||
"sd": "SD",
|
||||
"sdTooltip": "Προβολή βίντεο τυπικής ανάλυσης",
|
||||
"standardDefinition": "Τυπική ανάλυση"
|
||||
@@ -800,32 +861,31 @@
|
||||
"helpView": {
|
||||
"header": "Κέντρο βοήθειας"
|
||||
},
|
||||
"prejoin": {
|
||||
"audioAndVideoError": "Σφάλμα ήχου και βίντεο:",
|
||||
"audioOnlyError": "Σφάλμα ήχου:",
|
||||
"audioTrackError": "Δεν ήταν δυνατό να δημιουργηθεί το κομμάτι ήχου.",
|
||||
"callMe": "Κάλεσέ με",
|
||||
"callMeAtNumber": "Κάλεσε με σε αυτό το νούμερο:",
|
||||
"configuringDevices": "Διαμόρφωση συσκευών",
|
||||
"connectedWithAudioQ": "Είστε συνδεδεμένοι με ήχο;",
|
||||
"copyAndShare": "Αντιγραφή & διαμοιρασμός συνδέσμου συνάντησης",
|
||||
"dialInMeeting": "Καλέστε στη συνάντηση",
|
||||
"dialInPin": "Καλέστε στη συνάντηση και εισάγετε κωδικό PIN:",
|
||||
"dialing": "Γίνεται κλήση",
|
||||
"doNotShow": "Να μην εμφανιστεί αυτό ξανά",
|
||||
"iWantToDialIn": "Θέλω να καλέσω",
|
||||
"joinAudioByPhone": "Σύνδεση με ήχο τηλεφώνου",
|
||||
"joinMeeting": "Σύνδεση στη συνάντηση",
|
||||
"joinWithoutAudio": "Σύνδεση χωρίς ήχο",
|
||||
"initiated": "Η κλήση ξεκίνησε",
|
||||
"linkCopied": "Ο σύνδεσμος αντιγράφηκε στο πρόχειρο",
|
||||
"lookGood": "Ακούγεται ότι το μικρόφωνό σας δουλεύει σωστά",
|
||||
"or": "ή",
|
||||
"calling": "Γίνεται κλήση...",
|
||||
"startWithPhone": "Έναρξη με ήχο τηλεφώνου",
|
||||
"screenSharingError": "Σφάλμα διαμοιρασμού οθόνης:",
|
||||
"videoOnlyError": "Σφάλμα βίντεο:",
|
||||
"videoTrackError": "Δεν μπορεί να δημιουργηθεί το βίντεο",
|
||||
"viewAllNumbers": "προβολή όλων των αριθμών"
|
||||
"lobby": {
|
||||
"allow": "Επίτρεψε",
|
||||
"backToKnockModeButton": "Χωρίς κωδικό, ζητήστε πρόσβαση αντί αυτού",
|
||||
"dialogTitle": "Λειτουργία διαδρόμου",
|
||||
"disableDialogContent": "Η λειτουργία διαδρόμου είναι ενεργοποιημένη. Αυτή η λειτουργία εξασφαλιζει ότι οι ανεπιθύμητοι συμμετέχοντες δεν μπορούν να προστεθούν στη συνάντηση. Θέλετε να την απαεργοποιήσετε;",
|
||||
"disableDialogSubmit": "Απενεργοποίηση",
|
||||
"emailField": "Εισάγετε τη διεύθυνση email σας",
|
||||
"enableDialogPasswordField": "Ορισμός κωδικού (προαιρετικός)",
|
||||
"enableDialogSubmit": "Ενεργοποίηση",
|
||||
"enableDialogText": "Η ενεργοποίηση λειτουργίας διαδρόμου σας επιτρέπει να προστατεύσετε τη συνάντηση σας, επιτρέποντας την είσοδο μόνο μετά από επίσημη έγκριση από έναν διαχειριστή.",
|
||||
"enterPasswordButton": "Εισαγωγή κωδικού συνάντησής",
|
||||
"enterPasswordTitle": "Εισάγετε κωδικό για να προστεθείτε στη συνομιλία",
|
||||
"invalidPassword": "Εσφαλμένος κωδικός",
|
||||
"joiningMessage": "Θα προστεθείτε στη συνάντηση μόλις κάποιος αποδεχτεί το αίτημά σας",
|
||||
"joinWithPasswordMessage": "Γίνεται προσπάθεια εισόδου με κωδικό, παρακαλώ περιμένετε...",
|
||||
"joinRejectedMessage": "Το αίτημα εισόδου σας απορρίφθηκε από έναν διαχειριστή.",
|
||||
"joinTitle": "Προσθήκη σε συνάντηση",
|
||||
"joiningTitle": "Γίνεται αίτηση εισόδου σε συνάντηση...",
|
||||
"joiningWithPasswordTitle": "Γίνεται είσοδος με κωδικό...",
|
||||
"knockButton": "Αίτημα εισόδου",
|
||||
"knockTitle": "Κάποιος θέλει να προστεθεί στη συνάντηση",
|
||||
"nameField": "Εισάγετε το όνομά σας",
|
||||
"passwordField": "Εισάγετε τον κωδικό συνάντησης",
|
||||
"passwordJoinButton": "Είσοδος",
|
||||
"reject": "Απόρριψη",
|
||||
"toggleLabel": "Ενεργοποίηση διαδρόμου"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
"FETCH_SESSION_ID": "Obtention d’un identifiant de session…",
|
||||
"GET_SESSION_ID_ERROR": "Obtenir une erreur d’identifiant de session : {{code}}",
|
||||
"GOT_SESSION_ID": "Obtention d’un identifiant de session… Terminée",
|
||||
"LOW_BANDWIDTH": "La vidéo de {{displayName}} a été désactivée pour économiser de la ba de passante"
|
||||
"LOW_BANDWIDTH": "La vidéo de {{displayName}} a été désactivée pour économiser de la bande passante"
|
||||
},
|
||||
"connectionindicator": {
|
||||
"address": "Adresse :",
|
||||
|
||||
@@ -202,15 +202,10 @@
|
||||
"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.",
|
||||
"enterDisplayName": "Please enter your name here",
|
||||
"error": "Error",
|
||||
"externalInstallationMsg": "You need to install our desktop sharing extension.",
|
||||
"externalInstallationTitle": "Extension required",
|
||||
"goToStore": "Go to the webstore",
|
||||
"gracefulShutdown": "Our service is currently down for maintenance. Please try again later.",
|
||||
"IamHost": "I am the host",
|
||||
"incorrectRoomLockPassword": "Incorrect password",
|
||||
"incorrectPassword": "Incorrect username or password",
|
||||
"inlineInstallationMsg": "You need to install our desktop sharing extension.",
|
||||
"inlineInstallExtension": "Install now",
|
||||
"internalError": "Oops! Something went wrong. The following error occurred: {{error}}",
|
||||
"internalErrorTitle": "Internal error",
|
||||
"kickMessage": "You can contact {{participantDisplayName}} for more details.",
|
||||
@@ -272,11 +267,9 @@
|
||||
"reservationErrorMsg": "Error code: {{code}}, message: {{msg}}",
|
||||
"retry": "Retry",
|
||||
"screenSharingAudio": "Share audio",
|
||||
"screenSharingFailedToInstall": "Oops! Your screen sharing extension failed to install.",
|
||||
"screenSharingFailedToInstallTitle": "Screen sharing extension failed to install",
|
||||
"screenSharingFirefoxPermissionDeniedError": "Something went wrong while we were trying to share your screen. Please make sure that you have given us permission to do so.",
|
||||
"screenSharingFirefoxPermissionDeniedTitle": "Oops! We weren’t able to start screen sharing!",
|
||||
"screenSharingPermissionDeniedError": "Oops! Something went wrong with your screen sharing extension permissions. Please reload and try again.",
|
||||
"screenSharingFailed": "Oops! Something went wrong, we weren’t able to start screen sharing!",
|
||||
"screenSharingFailedTitle": "Screen sharing failed!",
|
||||
"screenSharingPermissionDeniedError": "Oops! Something went wrong with your screen sharing permissions. Please reload and try again.",
|
||||
"sendPrivateMessage": "You recently received a private message. Did you intend to reply to that privately, or you want to send your message to the group?",
|
||||
"sendPrivateMessageCancel": "Send to the group",
|
||||
"sendPrivateMessageOk": "Send privately",
|
||||
|
||||
@@ -553,82 +553,6 @@ UI.getLargeVideo = function() {
|
||||
return VideoLayout.getLargeVideo();
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows "Please go to chrome webstore to install the desktop sharing extension"
|
||||
* 2 button dialog with buttons - cancel and go to web store.
|
||||
* @param url {string} the url of the extension.
|
||||
*/
|
||||
UI.showExtensionExternalInstallationDialog = function(url) {
|
||||
let openedWindow = null;
|
||||
|
||||
const submitFunction = function(e, v) {
|
||||
if (v) {
|
||||
e.preventDefault();
|
||||
if (openedWindow === null || openedWindow.closed) {
|
||||
openedWindow
|
||||
= window.open(
|
||||
url,
|
||||
'extension_store_window',
|
||||
'resizable,scrollbars=yes,status=1');
|
||||
} else {
|
||||
openedWindow.focus();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const closeFunction = function(e, v) {
|
||||
if (openedWindow) {
|
||||
// Ideally we would close the popup, but this does not seem to work
|
||||
// on Chrome. Leaving it uncommented in case it could work
|
||||
// in some version.
|
||||
openedWindow.close();
|
||||
openedWindow = null;
|
||||
}
|
||||
if (!v) {
|
||||
eventEmitter.emit(UIEvents.EXTERNAL_INSTALLATION_CANCELED);
|
||||
}
|
||||
};
|
||||
|
||||
messageHandler.openTwoButtonDialog({
|
||||
titleKey: 'dialog.externalInstallationTitle',
|
||||
msgKey: 'dialog.externalInstallationMsg',
|
||||
leftButtonKey: 'dialog.goToStore',
|
||||
submitFunction,
|
||||
loadedFunction: $.noop,
|
||||
closeFunction
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows a dialog which asks user to install the extension. This one is
|
||||
* displayed after installation is triggered from the script, but fails because
|
||||
* it must be initiated by user gesture.
|
||||
* @param callback {function} function to be executed after user clicks
|
||||
* the install button - it should make another attempt to install the extension.
|
||||
*/
|
||||
UI.showExtensionInlineInstallationDialog = function(callback) {
|
||||
const submitFunction = function(e, v) {
|
||||
if (v) {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
const closeFunction = function(e, v) {
|
||||
if (!v) {
|
||||
eventEmitter.emit(UIEvents.EXTERNAL_INSTALLATION_CANCELED);
|
||||
}
|
||||
};
|
||||
|
||||
messageHandler.openTwoButtonDialog({
|
||||
titleKey: 'dialog.externalInstallationTitle',
|
||||
msgKey: 'dialog.inlineInstallationMsg',
|
||||
leftButtonKey: 'dialog.inlineInstallExtension',
|
||||
submitFunction,
|
||||
loadedFunction: $.noop,
|
||||
closeFunction
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Show shared video.
|
||||
* @param {string} id the id of the sender of the command
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -10965,8 +10965,8 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "github:jitsi/lib-jitsi-meet#b5f85a4758570dfd3ffccf6b4ddfcbf88edc33ac",
|
||||
"from": "github:jitsi/lib-jitsi-meet#b5f85a4758570dfd3ffccf6b4ddfcbf88edc33ac",
|
||||
"version": "github:jitsi/lib-jitsi-meet#1c5e2446358b22599486f84866df945d93e9485b",
|
||||
"from": "github:jitsi/lib-jitsi-meet#1c5e2446358b22599486f84866df945d93e9485b",
|
||||
"requires": {
|
||||
"@jitsi/sdp-interop": "1.0.3",
|
||||
"@jitsi/sdp-simulcast": "0.3.0",
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"js-md5": "0.6.1",
|
||||
"js-utils": "github:jitsi/js-utils#cf11996bd866fdb47326c59a5d3bc24be17282d4",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#b5f85a4758570dfd3ffccf6b4ddfcbf88edc33ac",
|
||||
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#1c5e2446358b22599486f84866df945d93e9485b",
|
||||
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
|
||||
"lodash": "4.17.13",
|
||||
"moment": "2.19.4",
|
||||
|
||||
@@ -42,7 +42,7 @@ export const JITSI_CONFERENCE_URL_KEY = Symbol('url');
|
||||
* @type {object}
|
||||
*/
|
||||
export const VIDEO_QUALITY_LEVELS = {
|
||||
HIGH: 1080,
|
||||
HIGH: 720,
|
||||
STANDARD: 360,
|
||||
LOW: 180
|
||||
};
|
||||
|
||||
@@ -72,11 +72,6 @@ export default [
|
||||
'debug',
|
||||
'debugAudioLevels',
|
||||
'defaultLanguage',
|
||||
'desktopSharingChromeDisabled',
|
||||
'desktopSharingChromeExtId',
|
||||
'desktopSharingChromeMinExtVersion',
|
||||
'desktopSharingChromeSources',
|
||||
'desktopSharingFirefoxDisabled',
|
||||
'desktopSharingFrameRate',
|
||||
'desktopSharingSources',
|
||||
'disable1On1Mode',
|
||||
|
||||
@@ -42,6 +42,7 @@ export default [
|
||||
'RECENT_LIST_ENABLED',
|
||||
'REMOTE_THUMBNAIL_RATIO',
|
||||
'SETTINGS_SECTIONS',
|
||||
'SHOW_CHROME_EXTENSION_BANNER',
|
||||
'SHOW_DEEP_LINKING_IMAGE',
|
||||
'SHOW_POWERED_BY',
|
||||
'SUPPORT_URL',
|
||||
|
||||
@@ -234,7 +234,7 @@ export function getVideoDeviceIds(state: Object) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there are devices of a specific type.
|
||||
* Returns true if there are devices of a specific type or on native platform.
|
||||
*
|
||||
* @param {Object} state - The state of the application.
|
||||
* @param {string} type - The type of device: VideoOutput | audioOutput | audioInput.
|
||||
@@ -242,6 +242,10 @@ export function getVideoDeviceIds(state: Object) {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function hasAvailableDevices(state: Object, type: string) {
|
||||
if (state['features/base/devices'] === undefined) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return state['features/base/devices'].availableDevices[type].length > 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@ export { default as IconInfo } from './info.svg';
|
||||
export { default as IconInviteMore } from './user-plus.svg';
|
||||
export { default as IconKick } from './kick.svg';
|
||||
export { default as IconLiveStreaming } from './public.svg';
|
||||
export { default as IconLockPassword } from './lock.svg';
|
||||
export { default as IconMeetingLocked } from './meeting-locked.svg';
|
||||
export { default as IconMeetingUnlocked } from './meeting-unlocked.svg';
|
||||
export { default as IconMenu } from './menu.svg';
|
||||
@@ -75,6 +74,8 @@ export { default as IconReply } from './reply.svg';
|
||||
export { default as IconRestore } from './restore.svg';
|
||||
export { default as IconRoomLock } from './security.svg';
|
||||
export { default as IconRoomUnlock } from './security-locked.svg';
|
||||
export { default as IconSecurityOff } from './security-off.svg';
|
||||
export { default as IconSecurityOn } from './security-on.svg';
|
||||
export { default as IconSearch } from './search.svg';
|
||||
export { default as IconSettings } from './settings.svg';
|
||||
export { default as IconSignalLevel0 } from './signal_cellular_0.svg';
|
||||
@@ -87,7 +88,6 @@ export { default as IconShareVideo } from './shared-video.svg';
|
||||
export { default as IconSwitchCamera } from './switch-camera.svg';
|
||||
export { default as IconTileView } from './tiles-many.svg';
|
||||
export { default as IconToggleRecording } from './camera-take-picture.svg';
|
||||
export { default as IconUnlockPassword } from './unlock.svg';
|
||||
export { default as IconVideoQualityAudioOnly } from './AUD.svg';
|
||||
export { default as IconVideoQualityHD } from './HD.svg';
|
||||
export { default as IconVideoQualityLD } from './LD.svg';
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 10H7H17H19V20H5V10ZM19 8H17V7C17 4.23858 14.7614 2 12 2C9.23858 2 7 4.23858 7 7V8H5C3.89543 8 3 8.89543 3 10V20C3 21.1046 3.89543 22 5 22H19C20.1046 22 21 21.1046 21 20V10C21 8.89543 20.1046 8 19 8ZM12.9686 15.7502C13.5837 15.4091 14 14.7532 14 14C14 12.8954 13.1046 12 12 12C10.8954 12 10 12.8954 10 14C10 14.7532 10.4163 15.4091 11.0314 15.7502C11.0109 15.8301 11 15.9138 11 16V17C11 17.5523 11.4477 18 12 18C12.5523 18 13 17.5523 13 17V16C13 15.9138 12.9891 15.8301 12.9686 15.7502ZM12 4C13.6569 4 15 5.34315 15 7V8H9V7C9 5.34315 10.3431 4 12 4Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 720 B |
14
react/features/base/icons/svg/security-off.svg
Normal file
14
react/features/base/icons/svg/security-off.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.87597 3.00772L3 3.11722V4V13.6745C3 16.088 4.24334 18.3313 6.29001 19.6105L11.47 22.848L12 23.1792L12.53 22.848L17.71 19.6105C19.7567 18.3313 21 16.088 21 13.6745V4V3.11722L20.124 3.00772L12.124 2.00772L12 1.99222L11.876 2.00772L3.87597 3.00772Z" fill="url(#paint0_linear)" stroke="white" stroke-width="2"/>
|
||||
<path d="M20 4V13.6745C20 15.7433 18.9343 17.6661 17.18 18.7625L12 22V3L20 4Z" fill="url(#paint1_linear)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="11.8143" y1="4.14215" x2="11.8143" y2="23" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FFB800"/>
|
||||
<stop offset="1" stop-color="#CF4B00"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear" x1="11.8143" y1="4.14215" x2="11.8143" y2="23" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FF8A00"/>
|
||||
<stop offset="1" stop-color="#A03B03"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 948 B |
15
react/features/base/icons/svg/security-on.svg
Normal file
15
react/features/base/icons/svg/security-on.svg
Normal file
@@ -0,0 +1,15 @@
|
||||
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.87597 3.00772L3 3.11722V4V13.6745C3 16.088 4.24334 18.3313 6.29001 19.6105L11.47 22.848L12 23.1792L12.53 22.848L17.71 19.6105C19.7567 18.3313 21 16.088 21 13.6745V4V3.11722L20.124 3.00772L12.124 2.00772L12 1.99222L11.876 2.00772L3.87597 3.00772Z" fill="url(#paint0_linear)" stroke="white" stroke-width="2"/>
|
||||
<path d="M20 4V13.6745C20 15.7433 18.9343 17.6661 17.18 18.7625L12 22V3L20 4Z" fill="url(#paint1_linear)"/>
|
||||
<path d="M9 11.4382L10.6848 13L15 9" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="11.8143" y1="4.14215" x2="11.8143" y2="23" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#76CF9C"/>
|
||||
<stop offset="1" stop-color="#279255"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear" x1="11.8143" y1="4.14215" x2="11.8143" y2="23" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#31B76A"/>
|
||||
<stop offset="1" stop-color="#18663A"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 8V7C7 4.23858 9.23858 2 12 2C14.0608 2 15.8304 3.24676 16.5957 5.02716L14.7583 5.81698C14.2882 4.72339 13.2108 4 12 4C10.3431 4 9 5.34315 9 7V8H12H16.8374H16.8818H19C20.1046 8 21 8.89543 21 10V20C21 21.1046 20.1046 22 19 22H5C3.89543 22 3 21.1046 3 20V10C3 8.89543 3.89543 8 5 8H7ZM5 20V10H19V20H5ZM12.9686 15.7502C13.5837 15.4091 14 14.7532 14 14C14 12.8954 13.1046 12 12 12C10.8954 12 10 12.8954 10 14C10 14.7532 10.4163 15.4091 11.0314 15.7502C11.0109 15.8301 11 15.9138 11 16V17C11 17.5523 11.4477 18 12 18C12.5523 18 13 17.5523 13 17V16C13 15.9138 12.9891 15.8301 12.9686 15.7502Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 757 B |
@@ -4,6 +4,17 @@ import { toState } from '../redux';
|
||||
|
||||
import { VIDEO_MUTISM_AUTHORITY } from './constants';
|
||||
|
||||
/**
|
||||
* Determines whether audio is currently muted.
|
||||
*
|
||||
* @param {Function|Object} stateful - The redux store, state, or
|
||||
* {@code getState} function.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isAudioMuted(stateful: Function | Object) {
|
||||
return Boolean(toState(stateful)['features/base/media'].audio.muted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether video is currently muted by the audio-only authority.
|
||||
*
|
||||
|
||||
@@ -42,6 +42,11 @@ type Props = {
|
||||
*/
|
||||
_readyToDisplayJitsiWatermark: boolean,
|
||||
|
||||
/**
|
||||
* Returns true if welcome page is visible at the moment.
|
||||
*/
|
||||
_welcomePageIsVisible: boolean,
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
@@ -162,11 +167,13 @@ class Watermarks extends Component<Props, State> {
|
||||
} = this.state;
|
||||
const {
|
||||
_isGuest,
|
||||
_readyToDisplayJitsiWatermark
|
||||
_readyToDisplayJitsiWatermark,
|
||||
_welcomePageIsVisible
|
||||
} = this.props;
|
||||
|
||||
return _readyToDisplayJitsiWatermark
|
||||
&& (showJitsiWatermark || (_isGuest && showJitsiWatermarkForGuests));
|
||||
return (_readyToDisplayJitsiWatermark
|
||||
&& (showJitsiWatermark || (_isGuest && showJitsiWatermarkForGuests)))
|
||||
|| _welcomePageIsVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,6 +280,7 @@ class Watermarks extends Component<Props, State> {
|
||||
function _mapStateToProps(state) {
|
||||
const { isGuest } = state['features/base/jwt'];
|
||||
const { customizationReady, logoClickUrl, logoImageUrl } = state['features/dynamic-branding'];
|
||||
const { room } = state['features/base/conference'];
|
||||
|
||||
return {
|
||||
/**
|
||||
@@ -285,7 +293,8 @@ function _mapStateToProps(state) {
|
||||
_customLogoLink: logoClickUrl,
|
||||
_customLogoUrl: logoImageUrl,
|
||||
_isGuest: isGuest,
|
||||
_readyToDisplayJitsiWatermark: customizationReady
|
||||
_readyToDisplayJitsiWatermark: customizationReady,
|
||||
_welcomePageIsVisible: !room
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ export * from './functions.any';
|
||||
* @returns {void}
|
||||
*/
|
||||
export function getCurrentCameraDeviceId(state: Object) {
|
||||
return state['features/base/settings'].cameraDeviceId;
|
||||
return getDeviceIdByType(state, 'isVideoTrack');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -19,7 +19,7 @@ export function getCurrentCameraDeviceId(state: Object) {
|
||||
* @returns {void}
|
||||
*/
|
||||
export function getCurrentMicDeviceId(state: Object) {
|
||||
return state['features/base/settings'].micDeviceId;
|
||||
return getDeviceIdByType(state, 'isAudioTrack');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,6 +32,22 @@ export function getCurrentOutputDeviceId(state: Object) {
|
||||
return state['features/base/settings'].audioOutputDeviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the deviceId for the corresponding local track type.
|
||||
*
|
||||
* @param {Object} state - The state of the application.
|
||||
* @param {string} isType - Can be 'isVideoTrack' | 'isAudioTrack'.
|
||||
* @returns {string}
|
||||
*/
|
||||
function getDeviceIdByType(state: Object, isType: string) {
|
||||
const [ deviceId ] = state['features/base/tracks']
|
||||
.map(t => t.jitsiTrack)
|
||||
.filter(t => t && t.isLocal() && t[isType]())
|
||||
.map(t => t.getDeviceId());
|
||||
|
||||
return deviceId || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the saved display name.
|
||||
*
|
||||
|
||||
@@ -267,56 +267,70 @@ export function toggleScreensharing() {
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function replaceLocalTrack(oldTrack, newTrack, conference) {
|
||||
return (dispatch, getState) => {
|
||||
return async (dispatch, getState) => {
|
||||
conference
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
|| (conference = getState()['features/base/conference'].conference);
|
||||
|
||||
return conference.replaceTrack(oldTrack, newTrack)
|
||||
if (conference) {
|
||||
await conference.replaceTrack(oldTrack, newTrack);
|
||||
}
|
||||
|
||||
return dispatch(replaceStoredTracks(oldTrack, newTrack));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces a stored track with another.
|
||||
*
|
||||
* @param {JitsiLocalTrack|null} oldTrack - The track to dispose.
|
||||
* @param {JitsiLocalTrack|null} newTrack - The track to use instead.
|
||||
* @returns {Function}
|
||||
*/
|
||||
function replaceStoredTracks(oldTrack, newTrack) {
|
||||
return dispatch => {
|
||||
// We call dispose after doing the replace because dispose will
|
||||
// try and do a new o/a after the track removes itself. Doing it
|
||||
// after means the JitsiLocalTrack.conference is already
|
||||
// cleared, so it won't try and do the o/a.
|
||||
const disposePromise
|
||||
= oldTrack
|
||||
? dispatch(_disposeAndRemoveTracks([ oldTrack ]))
|
||||
: Promise.resolve();
|
||||
|
||||
return disposePromise
|
||||
.then(() => {
|
||||
// We call dispose after doing the replace because dispose will
|
||||
// try and do a new o/a after the track removes itself. Doing it
|
||||
// after means the JitsiLocalTrack.conference is already
|
||||
// cleared, so it won't try and do the o/a.
|
||||
const disposePromise
|
||||
= oldTrack
|
||||
? dispatch(_disposeAndRemoveTracks([ oldTrack ]))
|
||||
: Promise.resolve();
|
||||
if (newTrack) {
|
||||
// The mute state of the new track should be
|
||||
// reflected in the app's mute state. For example,
|
||||
// if the app is currently muted and changing to a
|
||||
// new track that is not muted, the app's mute
|
||||
// state should be falsey. As such, emit a mute
|
||||
// event here to set up the app to reflect the
|
||||
// track's mute state. If this is not done, the
|
||||
// current mute state of the app will be reflected
|
||||
// on the track, not vice-versa.
|
||||
const setMuted
|
||||
= newTrack.isVideoTrack()
|
||||
? setVideoMuted
|
||||
: setAudioMuted;
|
||||
const isMuted = newTrack.isMuted();
|
||||
|
||||
return disposePromise
|
||||
.then(() => {
|
||||
if (newTrack) {
|
||||
// The mute state of the new track should be
|
||||
// reflected in the app's mute state. For example,
|
||||
// if the app is currently muted and changing to a
|
||||
// new track that is not muted, the app's mute
|
||||
// state should be falsey. As such, emit a mute
|
||||
// event here to set up the app to reflect the
|
||||
// track's mute state. If this is not done, the
|
||||
// current mute state of the app will be reflected
|
||||
// on the track, not vice-versa.
|
||||
const setMuted
|
||||
= newTrack.isVideoTrack()
|
||||
? setVideoMuted
|
||||
: setAudioMuted;
|
||||
const isMuted = newTrack.isMuted();
|
||||
sendAnalytics(createTrackMutedEvent(
|
||||
newTrack.getType(),
|
||||
'track.replaced',
|
||||
isMuted));
|
||||
logger.log(`Replace ${newTrack.getType()} track - ${
|
||||
isMuted ? 'muted' : 'unmuted'}`);
|
||||
|
||||
sendAnalytics(createTrackMutedEvent(
|
||||
newTrack.getType(),
|
||||
'track.replaced',
|
||||
isMuted));
|
||||
logger.log(`Replace ${newTrack.getType()} track - ${
|
||||
isMuted ? 'muted' : 'unmuted'}`);
|
||||
|
||||
return dispatch(setMuted(isMuted));
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
if (newTrack) {
|
||||
return dispatch(_addTracks([ newTrack ]));
|
||||
}
|
||||
});
|
||||
return dispatch(setMuted(isMuted));
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
if (newTrack) {
|
||||
return dispatch(_addTracks([ newTrack ]));
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -104,8 +104,6 @@ export function createLocalTracksF(options = {}, firePermissionPromptIsShownEven
|
||||
{
|
||||
cameraDeviceId,
|
||||
constraints,
|
||||
desktopSharingExtensionExternalInstallation:
|
||||
options.desktopSharingExtensionExternalInstallation,
|
||||
desktopSharingFrameRate,
|
||||
desktopSharingSourceDevice:
|
||||
options.desktopSharingSourceDevice,
|
||||
@@ -200,6 +198,18 @@ export function getLocalVideoType(tracks) {
|
||||
return presenterTrack ? MEDIA_TYPE.PRESENTER : MEDIA_TYPE.VIDEO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stored local video track.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function getLocalJitsiVideoTrack(state) {
|
||||
const track = getLocalVideoTrack(state['features/base/tracks']);
|
||||
|
||||
return track?.jitsiTrack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns track of specified media type for specified participant id.
|
||||
*
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
import UIEvents from '../../../../service/UI/UIEvents';
|
||||
import { hideNotification } from '../../notifications';
|
||||
import { isPrejoinPageVisible } from '../../prejoin/functions';
|
||||
import { getAvailableDevices } from '../devices/actions';
|
||||
import {
|
||||
CAMERA_FACING_MODE,
|
||||
MEDIA_TYPE,
|
||||
@@ -15,6 +17,7 @@ import {
|
||||
import { MiddlewareRegistry } from '../redux';
|
||||
|
||||
import {
|
||||
TRACK_ADDED,
|
||||
TOGGLE_SCREENSHARING,
|
||||
TRACK_NO_DATA_FROM_SOURCE,
|
||||
TRACK_REMOVED,
|
||||
@@ -44,6 +47,15 @@ declare var APP: Object;
|
||||
*/
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
switch (action.type) {
|
||||
case TRACK_ADDED: {
|
||||
// The devices list needs to be refreshed when no initial video permissions
|
||||
// were granted and a local video track is added by umuting the video.
|
||||
if (action.track.local) {
|
||||
store.dispatch(getAvailableDevices());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case TRACK_NO_DATA_FROM_SOURCE: {
|
||||
const result = next(action);
|
||||
|
||||
@@ -281,7 +293,7 @@ function _setMuted(store, { ensureTrack, authority, muted }, mediaType: MEDIA_TY
|
||||
// anymore, unless it is muted by audioOnly.
|
||||
jitsiTrack && (jitsiTrack.videoType !== 'desktop' || isAudioOnly)
|
||||
&& setTrackMuted(jitsiTrack, muted);
|
||||
} else if (!muted && ensureTrack && typeof APP === 'undefined') {
|
||||
} else if (!muted && ensureTrack && (typeof APP === 'undefined' || isPrejoinPageVisible(store.getState()))) {
|
||||
// FIXME: This only runs on mobile now because web has its own way of
|
||||
// creating local tracks. Adjust the check once they are unified.
|
||||
store.dispatch(createLocalTracksA({ devices: [ mediaType ] }));
|
||||
|
||||
@@ -18,7 +18,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
if (action.type === UPDATE_DEVICE_LIST) {
|
||||
const state = store.getState();
|
||||
const { popupDialogData } = state['features/device-selection'];
|
||||
const { availableDevices } = state['features/base/devices'];
|
||||
const { availableDevices } = state['features/base/devices'] || {};
|
||||
|
||||
if (popupDialogData) {
|
||||
popupDialogData.transport.sendEvent({
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/**
|
||||
* Action type to add a video track to the store.
|
||||
*/
|
||||
export const ADD_PREJOIN_VIDEO_TRACK = 'ADD_PREJOIN_VIDEO_TRACK';
|
||||
|
||||
/**
|
||||
* Action type to add an audio track to the store.
|
||||
*/
|
||||
export const ADD_PREJOIN_AUDIO_TRACK = 'ADD_PREJOIN_AUDIO_TRACK';
|
||||
|
||||
/**
|
||||
* Action type to add a content sharing track to the store.
|
||||
*/
|
||||
export const ADD_PREJOIN_CONTENT_SHARING_TRACK
|
||||
= 'ADD_PREJOIN_CONTENT_SHARING_TRACK';
|
||||
|
||||
/**
|
||||
* Action type to signal the start of the conference.
|
||||
@@ -68,13 +53,3 @@ export const SET_PREJOIN_DEVICE_ERRORS = 'SET_PREJOIN_DEVICE_ERRORS';
|
||||
* Action type to set the visibility of the prejoin page.
|
||||
*/
|
||||
export const SET_PREJOIN_PAGE_VISIBILITY = 'SET_PREJOIN_PAGE_VISIBILITY';
|
||||
|
||||
/**
|
||||
* Action type to mute/unmute the video while on prejoin page.
|
||||
*/
|
||||
export const SET_PREJOIN_VIDEO_DISABLED = 'SET_PREJOIN_VIDEO_DISABLED';
|
||||
|
||||
/**
|
||||
* Action type to mute/unmute the video while on prejoin page.
|
||||
*/
|
||||
export const SET_PREJOIN_VIDEO_MUTED = 'SET_PREJOIN_VIDEO_MUTED';
|
||||
|
||||
@@ -5,14 +5,17 @@ import uuid from 'uuid';
|
||||
import { getRoomName } from '../base/conference';
|
||||
import { getDialOutStatusUrl, getDialOutUrl } from '../base/config/functions';
|
||||
import { createLocalTrack } from '../base/lib-jitsi-meet';
|
||||
import {
|
||||
getLocalAudioTrack,
|
||||
getLocalVideoTrack,
|
||||
trackAdded,
|
||||
replaceLocalTrack
|
||||
} from '../base/tracks';
|
||||
import { openURLInBrowser } from '../base/util';
|
||||
import { executeDialOutRequest, executeDialOutStatusRequest, getDialInfoPageURL } from '../invite/functions';
|
||||
import { showErrorNotification } from '../notifications';
|
||||
|
||||
import {
|
||||
ADD_PREJOIN_AUDIO_TRACK,
|
||||
ADD_PREJOIN_CONTENT_SHARING_TRACK,
|
||||
ADD_PREJOIN_VIDEO_TRACK,
|
||||
PREJOIN_START_CONFERENCE,
|
||||
SET_DEVICE_STATUS,
|
||||
SET_DIALOUT_COUNTRY,
|
||||
@@ -20,19 +23,13 @@ import {
|
||||
SET_DIALOUT_STATUS,
|
||||
SET_SKIP_PREJOIN,
|
||||
SET_JOIN_BY_PHONE_DIALOG_VISIBLITY,
|
||||
SET_PREJOIN_AUDIO_DISABLED,
|
||||
SET_PREJOIN_AUDIO_MUTED,
|
||||
SET_PREJOIN_DEVICE_ERRORS,
|
||||
SET_PREJOIN_PAGE_VISIBILITY,
|
||||
SET_PREJOIN_VIDEO_DISABLED,
|
||||
SET_PREJOIN_VIDEO_MUTED
|
||||
SET_PREJOIN_PAGE_VISIBILITY
|
||||
} from './actionTypes';
|
||||
import {
|
||||
getFullDialOutNumber,
|
||||
getAudioTrack,
|
||||
getDialOutConferenceUrl,
|
||||
getDialOutCountry,
|
||||
getVideoTrack,
|
||||
isJoinByPhoneDialogVisible
|
||||
} from './functions';
|
||||
import logger from './logger';
|
||||
@@ -60,45 +57,6 @@ const STATUS_REQ_FREQUENCY = 2000;
|
||||
*/
|
||||
const STATUS_REQ_CAP = 45;
|
||||
|
||||
/**
|
||||
* Action used to add an audio track to the store.
|
||||
*
|
||||
* @param {Object} value - The track to be added.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function addPrejoinAudioTrack(value: Object) {
|
||||
return {
|
||||
type: ADD_PREJOIN_AUDIO_TRACK,
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Action used to add a video track to the store.
|
||||
*
|
||||
* @param {Object} value - The track to be added.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function addPrejoinVideoTrack(value: Object) {
|
||||
return {
|
||||
type: ADD_PREJOIN_VIDEO_TRACK,
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Action used to add a content sharing track to the store.
|
||||
*
|
||||
* @param {Object} value - The track to be added.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function addPrejoinContentSharingTrack(value: Object) {
|
||||
return {
|
||||
type: ADD_PREJOIN_CONTENT_SHARING_TRACK,
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Polls for status change after dial out.
|
||||
* Changes dialog message based on response, closes the dialog if there is an error,
|
||||
@@ -232,27 +190,10 @@ export function dialOut(onSuccess: Function, onFail: Function) {
|
||||
*/
|
||||
export function initPrejoin(tracks: Object[], errors: Object) {
|
||||
return async function(dispatch: Function) {
|
||||
const audioTrack = tracks.find(t => t.isAudioTrack());
|
||||
const videoTrack = tracks.find(t => t.isVideoTrack());
|
||||
|
||||
dispatch(setPrejoinDeviceErrors(errors));
|
||||
|
||||
if (audioTrack) {
|
||||
dispatch(addPrejoinAudioTrack(audioTrack));
|
||||
} else {
|
||||
dispatch(setAudioDisabled());
|
||||
}
|
||||
|
||||
if (videoTrack) {
|
||||
if (videoTrack.videoType === 'desktop') {
|
||||
dispatch(addPrejoinContentSharingTrack(videoTrack));
|
||||
dispatch(setPrejoinVideoDisabled(true));
|
||||
} else {
|
||||
dispatch(addPrejoinVideoTrack(videoTrack));
|
||||
}
|
||||
} else {
|
||||
dispatch(setPrejoinVideoDisabled(true));
|
||||
}
|
||||
tracks.forEach(track => dispatch(trackAdded(track)));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -275,12 +216,12 @@ export function joinConference() {
|
||||
*/
|
||||
export function joinConferenceWithoutAudio() {
|
||||
return async function(dispatch: Function, getState: Function) {
|
||||
const audioTrack = getAudioTrack(getState());
|
||||
const tracks = getState()['features/base/tracks'];
|
||||
const audioTrack = getLocalAudioTrack(tracks)?.jitsiTrack;
|
||||
|
||||
if (audioTrack) {
|
||||
await dispatch(replacePrejoinAudioTrack(null));
|
||||
await dispatch(replaceLocalTrack(audioTrack, null));
|
||||
}
|
||||
dispatch(setAudioDisabled());
|
||||
dispatch(joinConference());
|
||||
};
|
||||
}
|
||||
@@ -301,21 +242,6 @@ export function openDialInPage() {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the existing audio track with a new one.
|
||||
*
|
||||
* @param {Object} track - The new track.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function replacePrejoinAudioTrack(track: Object) {
|
||||
return async (dispatch: Function, getState: Function) => {
|
||||
const oldTrack = getAudioTrack(getState());
|
||||
|
||||
oldTrack && await oldTrack.dispose();
|
||||
dispatch(addPrejoinAudioTrack(track));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new audio track based on a device id and replaces the current one.
|
||||
*
|
||||
@@ -323,11 +249,13 @@ export function replacePrejoinAudioTrack(track: Object) {
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function replaceAudioTrackById(deviceId: string) {
|
||||
return async (dispatch: Function) => {
|
||||
return async (dispatch: Function, getState: Function) => {
|
||||
try {
|
||||
const track = await createLocalTrack('audio', deviceId);
|
||||
const tracks = getState()['features/base/tracks'];
|
||||
const newTrack = await createLocalTrack('audio', deviceId);
|
||||
const oldTrack = getLocalAudioTrack(tracks)?.jitsiTrack;
|
||||
|
||||
dispatch(replacePrejoinAudioTrack(track));
|
||||
dispatch(replaceLocalTrack(oldTrack, newTrack));
|
||||
} catch (err) {
|
||||
dispatch(setDeviceStatusWarning('prejoin.audioTrackError'));
|
||||
logger.log('Error replacing audio track', err);
|
||||
@@ -335,21 +263,6 @@ export function replaceAudioTrackById(deviceId: string) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the existing video track with a new one.
|
||||
*
|
||||
* @param {Object} track - The new track.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function replacePrejoinVideoTrack(track: Object) {
|
||||
return async (dispatch: Function, getState: Function) => {
|
||||
const oldTrack = getVideoTrack(getState());
|
||||
|
||||
oldTrack && await oldTrack.dispose();
|
||||
dispatch(addPrejoinVideoTrack(track));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new video track based on a device id and replaces the current one.
|
||||
*
|
||||
@@ -357,11 +270,13 @@ export function replacePrejoinVideoTrack(track: Object) {
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function replaceVideoTrackById(deviceId: Object) {
|
||||
return async (dispatch: Function) => {
|
||||
return async (dispatch: Function, getState: Function) => {
|
||||
try {
|
||||
const track = await createLocalTrack('video', deviceId);
|
||||
const tracks = getState()['features/base/tracks'];
|
||||
const newTrack = await createLocalTrack('video', deviceId);
|
||||
const oldTrack = getLocalVideoTrack(tracks)?.jitsiTrack;
|
||||
|
||||
dispatch(replacePrejoinVideoTrack(track));
|
||||
dispatch(replaceLocalTrack(oldTrack, newTrack));
|
||||
} catch (err) {
|
||||
dispatch(setDeviceStatusWarning('prejoin.videoTrackError'));
|
||||
logger.log('Error replacing video track', err);
|
||||
@@ -369,58 +284,6 @@ export function replaceVideoTrackById(deviceId: Object) {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Action used to mark audio muted.
|
||||
*
|
||||
* @param {boolean} value - True for muted.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function setPrejoinAudioMuted(value: boolean) {
|
||||
return {
|
||||
type: SET_PREJOIN_AUDIO_MUTED,
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Action used to mark video disabled.
|
||||
*
|
||||
* @param {boolean} value - True for muted.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function setPrejoinVideoDisabled(value: boolean) {
|
||||
return {
|
||||
type: SET_PREJOIN_VIDEO_DISABLED,
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Action used to mark video muted.
|
||||
*
|
||||
* @param {boolean} value - True for muted.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function setPrejoinVideoMuted(value: boolean) {
|
||||
return {
|
||||
type: SET_PREJOIN_VIDEO_MUTED,
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Action used to mark audio as disabled.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function setAudioDisabled() {
|
||||
return {
|
||||
type: SET_PREJOIN_AUDIO_DISABLED
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the device status as OK with the corresponding text.
|
||||
*
|
||||
|
||||
@@ -6,9 +6,11 @@ import React, { Component } from 'react';
|
||||
import { getRoomName } from '../../base/conference';
|
||||
import { translate } from '../../base/i18n';
|
||||
import { Icon, IconPhone, IconVolumeOff } from '../../base/icons';
|
||||
import { isVideoMutedByUser } from '../../base/media';
|
||||
import { ActionButton, InputField, PreMeetingScreen } from '../../base/premeeting';
|
||||
import { connect } from '../../base/redux';
|
||||
import { getDisplayName, updateSettings } from '../../base/settings';
|
||||
import { getLocalJitsiVideoTrack } from '../../base/tracks';
|
||||
import {
|
||||
joinConference as joinConferenceAction,
|
||||
joinConferenceWithoutAudio as joinConferenceWithoutAudioAction,
|
||||
@@ -16,11 +18,9 @@ import {
|
||||
setJoinByPhoneDialogVisiblity as setJoinByPhoneDialogVisiblityAction
|
||||
} from '../actions';
|
||||
import {
|
||||
getActiveVideoTrack,
|
||||
isJoinByPhoneButtonVisible,
|
||||
isDeviceStatusVisible,
|
||||
isJoinByPhoneDialogVisible,
|
||||
isPrejoinVideoMuted
|
||||
isJoinByPhoneDialogVisible
|
||||
} from '../functions';
|
||||
|
||||
import JoinByPhoneDialog from './dialogs/JoinByPhoneDialog';
|
||||
@@ -315,8 +315,8 @@ function mapStateToProps(state): Object {
|
||||
roomName: getRoomName(state),
|
||||
showDialog: isJoinByPhoneDialogVisible(state),
|
||||
hasJoinByPhoneButton: isJoinByPhoneButtonVisible(state),
|
||||
showCameraPreview: !isPrejoinVideoMuted(state),
|
||||
videoTrack: getActiveVideoTrack(state)
|
||||
showCameraPreview: !isVideoMutedByUser(state),
|
||||
videoTrack: getLocalJitsiVideoTrack(state)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -2,25 +2,7 @@
|
||||
|
||||
import { getRoomName } from '../base/conference';
|
||||
import { getDialOutStatusUrl, getDialOutUrl } from '../base/config/functions';
|
||||
|
||||
/**
|
||||
* Mutes or unmutes a track.
|
||||
*
|
||||
* @param {Object} track - The track to be configured.
|
||||
* @param {boolean} shouldMute - If it should mute or not.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
function applyMuteOptionsToTrack(track, shouldMute) {
|
||||
if (track.isMuted() === shouldMute) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (shouldMute) {
|
||||
return track.mute();
|
||||
}
|
||||
|
||||
return track.unmute();
|
||||
}
|
||||
import { isAudioMuted, isVideoMutedByUser } from '../base/media';
|
||||
|
||||
/**
|
||||
* Selector for the visibility of the 'join by phone' button.
|
||||
@@ -39,73 +21,8 @@ export function isJoinByPhoneButtonVisible(state: Object): boolean {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isDeviceStatusVisible(state: Object): boolean {
|
||||
return !((isAudioDisabled(state) && isPrejoinVideoDisabled(state))
|
||||
|| (isPrejoinAudioMuted(state) && isPrejoinVideoMuted(state)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector for getting the active video/content sharing track.
|
||||
*
|
||||
* @param {Object} state - The state of the app.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function getActiveVideoTrack(state: Object): Object {
|
||||
const track = getVideoTrack(state) || getContentSharingTrack(state);
|
||||
|
||||
if (track && track.isActive()) {
|
||||
return track;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list with all the prejoin tracks configured according to
|
||||
* user's preferences.
|
||||
*
|
||||
* @param {Object} state - The state of the app.
|
||||
* @returns {Promise<Object[]>}
|
||||
*/
|
||||
export async function getAllPrejoinConfiguredTracks(state: Object): Promise<Object[]> {
|
||||
const tracks = [];
|
||||
const audioTrack = getAudioTrack(state);
|
||||
const videoTrack = getVideoTrack(state);
|
||||
const csTrack = getContentSharingTrack(state);
|
||||
|
||||
if (csTrack) {
|
||||
tracks.push(csTrack);
|
||||
} else if (videoTrack) {
|
||||
await applyMuteOptionsToTrack(videoTrack, isPrejoinVideoMuted(state));
|
||||
tracks.push(videoTrack);
|
||||
}
|
||||
|
||||
if (audioTrack) {
|
||||
await applyMuteOptionsToTrack(audioTrack, isPrejoinAudioMuted(state));
|
||||
isPrejoinAudioMuted(state) && audioTrack.mute();
|
||||
tracks.push(audioTrack);
|
||||
}
|
||||
|
||||
return tracks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector for getting the prejoin audio track.
|
||||
*
|
||||
* @param {Object} state - The state of the app.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function getAudioTrack(state: Object): Object {
|
||||
return state['features/prejoin']?.audioTrack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector for getting the prejoin content sharing track.
|
||||
*
|
||||
* @param {Object} state - The state of the app.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function getContentSharingTrack(state: Object): Object {
|
||||
return state['features/prejoin']?.contentSharingTrack;
|
||||
return !(isAudioMuted(state) && isVideoMutedByUser(state))
|
||||
&& !state['features/base/config'].startSilent;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,36 +98,6 @@ export function getFullDialOutNumber(state: Object): string {
|
||||
return `+${country.dialCode}${dialOutNumber}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector for getting the prejoin video track.
|
||||
*
|
||||
* @param {Object} state - The state of the app.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function getVideoTrack(state: Object): Object {
|
||||
return state['features/prejoin']?.videoTrack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector for getting the mute status of the prejoin audio.
|
||||
*
|
||||
* @param {Object} state - The state of the app.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isPrejoinAudioMuted(state: Object): boolean {
|
||||
return state['features/prejoin']?.audioMuted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector for getting the mute status of the prejoin video.
|
||||
*
|
||||
* @param {Object} state - The state of the app.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isPrejoinVideoMuted(state: Object): boolean {
|
||||
return state['features/prejoin']?.videoMuted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector for getting the error if any while creating streams.
|
||||
*
|
||||
@@ -221,26 +108,6 @@ export function getRawError(state: Object): string {
|
||||
return state['features/prejoin']?.rawError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector for getting state of the prejoin audio.
|
||||
*
|
||||
* @param {Object} state - The state of the app.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isAudioDisabled(state: Object): Object {
|
||||
return state['features/prejoin']?.audioDisabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector for getting state of the prejoin video.
|
||||
*
|
||||
* @param {Object} state - The state of the app.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isPrejoinVideoDisabled(state: Object): Object {
|
||||
return state['features/prejoin']?.videoDisabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector for getting the visiblity state for the 'JoinByPhoneDialog'.
|
||||
*
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
// @flow
|
||||
|
||||
import { SET_AUDIO_MUTED, SET_VIDEO_MUTED } from '../base/media';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import { updateSettings } from '../base/settings';
|
||||
|
||||
import {
|
||||
ADD_PREJOIN_AUDIO_TRACK,
|
||||
ADD_PREJOIN_VIDEO_TRACK,
|
||||
PREJOIN_START_CONFERENCE
|
||||
} from './actionTypes';
|
||||
import { setPrejoinAudioMuted, setPrejoinVideoMuted } from './actions';
|
||||
import { getAllPrejoinConfiguredTracks } from './functions';
|
||||
import { PREJOIN_START_CONFERENCE } from './actionTypes';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
@@ -22,62 +15,22 @@ declare var APP: Object;
|
||||
*/
|
||||
MiddlewareRegistry.register(store => next => async action => {
|
||||
switch (action.type) {
|
||||
case ADD_PREJOIN_AUDIO_TRACK: {
|
||||
const { value: audioTrack } = action;
|
||||
|
||||
if (audioTrack) {
|
||||
store.dispatch(
|
||||
updateSettings({
|
||||
micDeviceId: audioTrack.getDeviceId()
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ADD_PREJOIN_VIDEO_TRACK: {
|
||||
const { value: videoTrack } = action;
|
||||
|
||||
if (videoTrack) {
|
||||
store.dispatch(
|
||||
updateSettings({
|
||||
cameraDeviceId: videoTrack.getDeviceId()
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PREJOIN_START_CONFERENCE: {
|
||||
const { getState, dispatch } = store;
|
||||
const state = getState();
|
||||
const { userSelectedSkipPrejoin } = state['features/prejoin'];
|
||||
const tracks = state['features/base/tracks'];
|
||||
|
||||
userSelectedSkipPrejoin && dispatch(updateSettings({
|
||||
userSelectedSkipPrejoin
|
||||
}));
|
||||
|
||||
|
||||
const tracks = await getAllPrejoinConfiguredTracks(state);
|
||||
|
||||
APP.conference.prejoinStart(tracks);
|
||||
APP.conference.prejoinStart(tracks.map(t => t.jitsiTrack));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SET_AUDIO_MUTED: {
|
||||
store.dispatch(setPrejoinAudioMuted(Boolean(action.muted)));
|
||||
break;
|
||||
}
|
||||
|
||||
case SET_VIDEO_MUTED: {
|
||||
store.dispatch(setPrejoinVideoMuted(Boolean(action.muted)));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return next(action);
|
||||
});
|
||||
|
||||
@@ -1,28 +1,17 @@
|
||||
import { ReducerRegistry } from '../base/redux';
|
||||
|
||||
import {
|
||||
ADD_PREJOIN_AUDIO_TRACK,
|
||||
ADD_PREJOIN_CONTENT_SHARING_TRACK,
|
||||
ADD_PREJOIN_VIDEO_TRACK,
|
||||
SET_DEVICE_STATUS,
|
||||
SET_DIALOUT_NUMBER,
|
||||
SET_DIALOUT_COUNTRY,
|
||||
SET_DIALOUT_STATUS,
|
||||
SET_JOIN_BY_PHONE_DIALOG_VISIBLITY,
|
||||
SET_SKIP_PREJOIN,
|
||||
SET_PREJOIN_AUDIO_DISABLED,
|
||||
SET_PREJOIN_AUDIO_MUTED,
|
||||
SET_PREJOIN_DEVICE_ERRORS,
|
||||
SET_PREJOIN_PAGE_VISIBILITY,
|
||||
SET_PREJOIN_VIDEO_DISABLED,
|
||||
SET_PREJOIN_VIDEO_MUTED
|
||||
SET_PREJOIN_PAGE_VISIBILITY
|
||||
} from './actionTypes';
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
audioDisabled: false,
|
||||
audioMuted: false,
|
||||
audioTrack: null,
|
||||
contentSharingTrack: null,
|
||||
country: '',
|
||||
deviceStatusText: 'prejoin.configuringDevices',
|
||||
deviceStatusType: 'ok',
|
||||
@@ -37,10 +26,7 @@ const DEFAULT_STATE = {
|
||||
rawError: '',
|
||||
showPrejoin: true,
|
||||
showJoinByPhoneDialog: false,
|
||||
userSelectedSkipPrejoin: false,
|
||||
videoTrack: null,
|
||||
videoDisabled: false,
|
||||
videoMuted: false
|
||||
userSelectedSkipPrejoin: false
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -49,26 +35,6 @@ const DEFAULT_STATE = {
|
||||
ReducerRegistry.register(
|
||||
'features/prejoin', (state = DEFAULT_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case ADD_PREJOIN_AUDIO_TRACK: {
|
||||
return {
|
||||
...state,
|
||||
audioTrack: action.value
|
||||
};
|
||||
}
|
||||
|
||||
case ADD_PREJOIN_CONTENT_SHARING_TRACK: {
|
||||
return {
|
||||
...state,
|
||||
contentSharingTrack: action.value
|
||||
};
|
||||
}
|
||||
|
||||
case ADD_PREJOIN_VIDEO_TRACK: {
|
||||
return {
|
||||
...state,
|
||||
videoTrack: action.value
|
||||
};
|
||||
}
|
||||
|
||||
case SET_SKIP_PREJOIN: {
|
||||
return {
|
||||
@@ -83,25 +49,6 @@ ReducerRegistry.register(
|
||||
showPrejoin: action.value
|
||||
};
|
||||
|
||||
case SET_PREJOIN_VIDEO_DISABLED: {
|
||||
return {
|
||||
...state,
|
||||
videoDisabled: action.value
|
||||
};
|
||||
}
|
||||
|
||||
case SET_PREJOIN_VIDEO_MUTED:
|
||||
return {
|
||||
...state,
|
||||
videoMuted: action.value
|
||||
};
|
||||
|
||||
case SET_PREJOIN_AUDIO_MUTED:
|
||||
return {
|
||||
...state,
|
||||
audioMuted: action.value
|
||||
};
|
||||
|
||||
case SET_PREJOIN_DEVICE_ERRORS: {
|
||||
const status = getStatusFromErrors(action.value);
|
||||
|
||||
@@ -119,13 +66,6 @@ ReducerRegistry.register(
|
||||
};
|
||||
}
|
||||
|
||||
case SET_PREJOIN_AUDIO_DISABLED: {
|
||||
return {
|
||||
...state,
|
||||
audioDisabled: true
|
||||
};
|
||||
}
|
||||
|
||||
case SET_DIALOUT_NUMBER: {
|
||||
return {
|
||||
...state,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { createToolbarEvent, sendAnalytics } from '../../../analytics';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { IconLockPassword, IconUnlockPassword } from '../../../base/icons';
|
||||
import { IconSecurityOff, IconSecurityOn } from '../../../base/icons';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox';
|
||||
import { openSecurityDialog } from '../../actions';
|
||||
@@ -28,9 +28,9 @@ type Props = AbstractButtonProps & {
|
||||
*/
|
||||
class SecurityDialogButton extends AbstractButton<Props, *> {
|
||||
accessibilityLabel = 'toolbar.accessibilityLabel.security';
|
||||
icon = IconUnlockPassword;
|
||||
icon = IconSecurityOff;
|
||||
label = 'toolbar.security';
|
||||
toggledIcon = IconLockPassword;
|
||||
toggledIcon = IconSecurityOn;
|
||||
tooltip = 'toolbar.security';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import { createToolbarEvent, sendAnalytics } from '../../analytics';
|
||||
import { isLocalParticipantModerator } from '../../base/participants';
|
||||
import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox';
|
||||
import { toggleRequestingSubtitles } from '../actions';
|
||||
|
||||
@@ -83,9 +84,8 @@ export class AbstractClosedCaptionButton
|
||||
*/
|
||||
export function _abstractMapStateToProps(state: Object, ownProps: Object) {
|
||||
const { _requestingSubtitles } = state['features/subtitles'];
|
||||
const { isGuest = true } = state['features/base/jwt'];
|
||||
const { transcribingEnabled } = state['features/base/config'];
|
||||
const { visible = Boolean(transcribingEnabled && !isGuest) } = ownProps;
|
||||
const { visible = Boolean(transcribingEnabled && isLocalParticipantModerator(state)) } = ownProps;
|
||||
|
||||
return {
|
||||
_requestingSubtitles,
|
||||
|
||||
@@ -12,11 +12,6 @@ import { connect } from '../../base/redux';
|
||||
import { AbstractAudioMuteButton } from '../../base/toolbox';
|
||||
import type { AbstractButtonProps } from '../../base/toolbox';
|
||||
import { isLocalTrackMuted } from '../../base/tracks';
|
||||
import {
|
||||
isPrejoinAudioMuted,
|
||||
isAudioDisabled,
|
||||
isPrejoinPageVisible
|
||||
} from '../../prejoin/functions';
|
||||
import { muteLocal } from '../../remote-video-menu/actions';
|
||||
|
||||
declare var APP: Object;
|
||||
@@ -154,18 +149,8 @@ class AudioMuteButton extends AbstractAudioMuteButton<Props, *> {
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state): Object {
|
||||
let _audioMuted;
|
||||
let _disabled;
|
||||
|
||||
if (isPrejoinPageVisible(state)) {
|
||||
_audioMuted = isPrejoinAudioMuted(state);
|
||||
_disabled = state['features/base/config'].startSilent;
|
||||
} else {
|
||||
const tracks = state['features/base/tracks'];
|
||||
|
||||
_audioMuted = isLocalTrackMuted(tracks, MEDIA_TYPE.AUDIO);
|
||||
_disabled = state['features/base/config'].startSilent || isAudioDisabled(state);
|
||||
}
|
||||
const _audioMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.AUDIO);
|
||||
const _disabled = state['features/base/config'].startSilent;
|
||||
|
||||
return {
|
||||
_audioMuted,
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
sendAnalytics
|
||||
} from '../../analytics';
|
||||
import { setAudioOnly } from '../../base/audio-only';
|
||||
import { hasAvailableDevices } from '../../base/devices';
|
||||
import { translate } from '../../base/i18n';
|
||||
import {
|
||||
VIDEO_MUTISM_AUTHORITY,
|
||||
@@ -18,11 +19,6 @@ import { connect } from '../../base/redux';
|
||||
import { AbstractVideoMuteButton } from '../../base/toolbox';
|
||||
import type { AbstractButtonProps } from '../../base/toolbox';
|
||||
import { getLocalVideoType, isLocalVideoTrackMuted } from '../../base/tracks';
|
||||
import {
|
||||
isPrejoinPageVisible,
|
||||
isPrejoinVideoDisabled,
|
||||
isPrejoinVideoMuted
|
||||
} from '../../prejoin/functions';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
@@ -191,19 +187,12 @@ class VideoMuteButton extends AbstractVideoMuteButton<Props, *> {
|
||||
function _mapStateToProps(state): Object {
|
||||
const { enabled: audioOnly } = state['features/base/audio-only'];
|
||||
const tracks = state['features/base/tracks'];
|
||||
let _videoMuted = isLocalVideoTrackMuted(tracks);
|
||||
let _videoDisabled = false;
|
||||
|
||||
if (isPrejoinPageVisible(state)) {
|
||||
_videoMuted = isPrejoinVideoMuted(state);
|
||||
_videoDisabled = isPrejoinVideoDisabled(state);
|
||||
}
|
||||
|
||||
return {
|
||||
_audioOnly: Boolean(audioOnly),
|
||||
_videoDisabled,
|
||||
_videoDisabled: !hasAvailableDevices(state, 'videoInput'),
|
||||
_videoMediaType: getLocalVideoType(tracks),
|
||||
_videoMuted
|
||||
_videoMuted: isLocalVideoTrackMuted(tracks)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { IconArrowDown } from '../../../base/icons';
|
||||
import JitsiMeetJS from '../../../base/lib-jitsi-meet/_';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { ToolboxButtonWithIcon } from '../../../base/toolbox';
|
||||
import { getLocalJitsiVideoTrack } from '../../../base/tracks';
|
||||
import { getMediaPermissionPromptVisibility } from '../../../overlay';
|
||||
import { toggleVideoSettings, VideoSettingsPopup } from '../../../settings';
|
||||
import { isVideoSettingsButtonDisabled } from '../../functions';
|
||||
@@ -24,6 +25,11 @@ type Props = {
|
||||
*/
|
||||
permissionPromptVisibility: boolean,
|
||||
|
||||
/**
|
||||
* Whether there is a video track or not.
|
||||
*/
|
||||
hasVideoTrack: boolean,
|
||||
|
||||
/**
|
||||
* If the button should be disabled
|
||||
*/
|
||||
@@ -66,6 +72,17 @@ class VideoSettingsButton extends Component<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the settings icon is disabled.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isIconDisabled() {
|
||||
const { hasVideoTrack, isDisabled } = this.props;
|
||||
|
||||
return (!this.state.hasPermissions || isDisabled) && !hasVideoTrack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates device permissions.
|
||||
*
|
||||
@@ -116,14 +133,13 @@ class VideoSettingsButton extends Component<Props, State> {
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
const { isDisabled, onVideoOptionsClick, visible } = this.props;
|
||||
const iconDisabled = !this.state.hasPermissions || isDisabled;
|
||||
const { onVideoOptionsClick, visible } = this.props;
|
||||
|
||||
return visible ? (
|
||||
<VideoSettingsPopup>
|
||||
<ToolboxButtonWithIcon
|
||||
icon = { IconArrowDown }
|
||||
iconDisabled = { iconDisabled }
|
||||
iconDisabled = { this._isIconDisabled() }
|
||||
onIconClick = { onVideoOptionsClick }>
|
||||
<VideoMuteButton />
|
||||
</ToolboxButtonWithIcon>
|
||||
@@ -140,6 +156,7 @@ class VideoSettingsButton extends Component<Props, State> {
|
||||
*/
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
hasVideoTrack: Boolean(getLocalJitsiVideoTrack(state)),
|
||||
isDisabled: isVideoSettingsButtonDisabled(state),
|
||||
permissionPromptVisibility: getMediaPermissionPromptVisibility(state)
|
||||
};
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import { hasAvailableDevices } from '../base/devices';
|
||||
import {
|
||||
isAudioDisabled,
|
||||
isPrejoinPageVisible,
|
||||
isPrejoinVideoDisabled
|
||||
} from '../prejoin';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
@@ -60,12 +55,9 @@ export function isToolboxVisible(state: Object) {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isAudioSettingsButtonDisabled(state: Object) {
|
||||
const devicesMissing = !hasAvailableDevices(state, 'audioInput')
|
||||
&& !hasAvailableDevices(state, 'audioOutput');
|
||||
|
||||
return isPrejoinPageVisible(state)
|
||||
? devicesMissing || isAudioDisabled(state)
|
||||
: devicesMissing;
|
||||
return (!hasAvailableDevices(state, 'audioInput')
|
||||
&& !hasAvailableDevices(state, 'audioOutput'))
|
||||
|| state['features/base/config'].startSilent;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,9 +67,5 @@ export function isAudioSettingsButtonDisabled(state: Object) {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isVideoSettingsButtonDisabled(state: Object) {
|
||||
const devicesMissing = !hasAvailableDevices(state, 'videoInput');
|
||||
|
||||
return isPrejoinPageVisible(state)
|
||||
? devicesMissing || isPrejoinVideoDisabled(state)
|
||||
: devicesMissing;
|
||||
return !hasAvailableDevices(state, 'videoInput');
|
||||
}
|
||||
|
||||
@@ -33,6 +33,13 @@ log("debug",
|
||||
tostring(host), tostring(token_util.appId), tostring(token_util.appSecret),
|
||||
tostring(token_util.allowEmptyToken));
|
||||
|
||||
-- option to disable room modification (sending muc config form) for guest that do not provide token
|
||||
local require_token_for_moderation;
|
||||
local function load_config()
|
||||
require_token_for_moderation = module:get_option_boolean("token_verification_require_token_for_moderation");
|
||||
end
|
||||
load_config();
|
||||
|
||||
local function verify_user(session, stanza)
|
||||
log("debug", "Session token: %s, session room: %s",
|
||||
tostring(session.auth_token),
|
||||
@@ -70,3 +77,30 @@ module:hook("muc-occupant-pre-join", function(event)
|
||||
log("debug", "pre join: %s %s", tostring(room), tostring(stanza));
|
||||
return verify_user(origin, stanza);
|
||||
end);
|
||||
|
||||
for event_name, method in pairs {
|
||||
-- Normal room interactions
|
||||
["iq-set/bare/http://jabber.org/protocol/muc#owner:query"] = "handle_owner_query_set_to_room" ;
|
||||
-- Host room
|
||||
["iq-set/host/http://jabber.org/protocol/muc#owner:query"] = "handle_owner_query_set_to_room" ;
|
||||
} do
|
||||
module:hook(event_name, function (event)
|
||||
local session, stanza = event.origin, event.stanza;
|
||||
|
||||
-- if we do not require token we pass it through(default behaviour)
|
||||
-- or the request is coming from admin (focus)
|
||||
if not require_token_for_moderation or is_admin(stanza.attr.from) then
|
||||
return;
|
||||
end
|
||||
|
||||
if not session.auth_token then
|
||||
session.send(
|
||||
st.error_reply(
|
||||
stanza, "cancel", "not-allowed", "Room modification disabled for guests"));
|
||||
return true;
|
||||
end
|
||||
|
||||
end, -1); -- the default prosody hook is on -2
|
||||
end
|
||||
|
||||
module:hook_global('config-reloaded', load_config);
|
||||
|
||||
@@ -53,12 +53,6 @@ export default {
|
||||
*/
|
||||
LOCAL_FLIPX_CHANGED: 'UI.local_flipx_changed',
|
||||
|
||||
/**
|
||||
* Notifies that the button "Cancel" is pressed on the dialog for
|
||||
* external extension installation.
|
||||
*/
|
||||
EXTERNAL_INSTALLATION_CANCELED: 'UI.external_installation_canceled',
|
||||
|
||||
/**
|
||||
* Notifies that the side toolbar container has been toggled. The actual
|
||||
* event must contain the identifier of the container that has been toggled
|
||||
|
||||
Reference in New Issue
Block a user