mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-01-16 19:50:18 +00:00
Compare commits
1 Commits
fix/preven
...
replace-sa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d490b29b7a |
@@ -16,10 +16,6 @@ android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
packagingOptions {
|
||||
exclude 'lib/*/libhermes*.so'
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'org.jitsi.meet'
|
||||
versionCode vcode
|
||||
@@ -78,7 +74,7 @@ dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.2'
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-beta-5'
|
||||
|
||||
if (!rootProject.ext.libreBuild) {
|
||||
implementation 'com.google.android.gms:play-services-auth:16.0.1'
|
||||
@@ -86,7 +82,6 @@ dependencies {
|
||||
// Firebase
|
||||
// - Crashlytics
|
||||
// - Dynamic Links
|
||||
implementation 'com.google.firebase:firebase-analytics:17.5.0'
|
||||
implementation 'com.google.firebase:firebase-crashlytics:17.2.1'
|
||||
implementation 'com.google.firebase:firebase-dynamic-links:19.1.0'
|
||||
}
|
||||
|
||||
6
android/app/proguard-rules.pro
vendored
6
android/app/proguard-rules.pro
vendored
@@ -85,4 +85,8 @@
|
||||
# ^^^ We added the above when we switched minifyEnabled on.
|
||||
|
||||
# Rule to avoid build errors related to SVGs.
|
||||
-keep public class com.horcrux.svg.** {*;}
|
||||
-keep public class com.horcrux.svg.** {*;}
|
||||
|
||||
# Hermes
|
||||
-keep class com.facebook.hermes.unicode.** { *; }
|
||||
|
||||
|
||||
@@ -9,44 +9,18 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.0.1'
|
||||
classpath 'com.android.tools.build:gradle:3.3.2'
|
||||
classpath 'com.google.gms:google-services:4.3.3'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.3.0'
|
||||
}
|
||||
}
|
||||
|
||||
ext {
|
||||
buildToolsVersion = "29.0.3"
|
||||
compileSdkVersion = 29
|
||||
minSdkVersion = 23
|
||||
targetSdkVersion = 29
|
||||
supportLibVersion = "28.0.0"
|
||||
|
||||
// The Maven artifact groupdId of the third-party react-native modules which
|
||||
// Jitsi Meet SDK for Android depends on and which are not available in
|
||||
// third-party Maven repositories so we have to deploy to a Maven repository
|
||||
// of ours.
|
||||
moduleGroupId = 'com.facebook.react'
|
||||
|
||||
// Maven repo where artifacts will be published
|
||||
mavenRepo = System.env.MVN_REPO ?: ""
|
||||
mavenUser = System.env.MVN_USER ?: ""
|
||||
mavenPassword = System.env.MVN_PASSWORD ?: ""
|
||||
|
||||
// Libre build
|
||||
libreBuild = (System.env.LIBRE_BUILD ?: "false").toBoolean()
|
||||
|
||||
googleServicesEnabled = project.file('app/google-services.json').exists() && !libreBuild
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
// React Native (JS, Obj-C sources, Android binaries) is installed from npm.
|
||||
maven { url "$rootDir/../node_modules/react-native/android" }
|
||||
// Android JSC is installed from npm.
|
||||
maven { url("$rootDir/../node_modules/jsc-android/dist") }
|
||||
}
|
||||
|
||||
// Make sure we use the react-native version in node_modules and not the one
|
||||
@@ -161,6 +135,30 @@ allprojects {
|
||||
}
|
||||
}
|
||||
|
||||
ext {
|
||||
buildToolsVersion = "29.0.3"
|
||||
compileSdkVersion = 29
|
||||
minSdkVersion = 23
|
||||
targetSdkVersion = 29
|
||||
supportLibVersion = "28.0.0"
|
||||
|
||||
// The Maven artifact groupdId of the third-party react-native modules which
|
||||
// Jitsi Meet SDK for Android depends on and which are not available in
|
||||
// third-party Maven repositories so we have to deploy to a Maven repository
|
||||
// of ours.
|
||||
moduleGroupId = 'com.facebook.react'
|
||||
|
||||
// Maven repo where artifacts will be published
|
||||
mavenRepo = System.env.MVN_REPO ?: ""
|
||||
mavenUser = System.env.MVN_USER ?: ""
|
||||
mavenPassword = System.env.MVN_PASSWORD ?: ""
|
||||
|
||||
// Libre build
|
||||
libreBuild = (System.env.LIBRE_BUILD ?: "false").toBoolean()
|
||||
|
||||
googleServicesEnabled = project.file('app/google-services.json').exists() && !libreBuild
|
||||
}
|
||||
|
||||
// Force the version of the Android build tools we have chosen on all
|
||||
// subprojects. The forcing was introduced for react-native and the third-party
|
||||
// modules that we utilize such as react-native-background-timer.
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
# Default value: -Xmx10248m -XX:MaxPermSize=256m
|
||||
|
||||
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
@@ -21,5 +20,5 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryErro
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
appVersion=20.5.0
|
||||
sdkVersion=2.11.0
|
||||
appVersion=20.4.0
|
||||
sdkVersion=2.10.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#Wed Sep 23 11:48:00 EEST 2020
|
||||
#Fri Mar 08 13:36:51 CET 2019
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
|
||||
|
||||
@@ -10,7 +10,7 @@ MVN_HTTP=0
|
||||
DEFAULT_SDK_VERSION=$(grep sdkVersion ${THIS_DIR}/../gradle.properties | cut -d"=" -f2)
|
||||
SDK_VERSION=${OVERRIDE_SDK_VERSION:-${DEFAULT_SDK_VERSION}}
|
||||
RN_VERSION=$(jq -r '.version' ${THIS_DIR}/../../node_modules/react-native/package.json)
|
||||
JSC_VERSION="r"$(jq -r '.dependencies."jsc-android"' ${THIS_DIR}/../../node_modules/react-native/package.json | cut -d . -f 1 | cut -c 2-)
|
||||
HERMES_VERSION=$(jq -r '.dependencies."hermes-engine"' ${THIS_DIR}/../../node_modules/react-native/package.json | cut -c 2-)
|
||||
DO_GIT_TAG=${GIT_TAG:-0}
|
||||
|
||||
if [[ $THE_MVN_REPO == http* ]]; then
|
||||
@@ -38,17 +38,19 @@ if [[ $MVN_HTTP == 1 ]]; then
|
||||
-DgeneratePom=false \
|
||||
-DpomFile=react-native-${RN_VERSION}.pom || true
|
||||
popd
|
||||
# Push JSC
|
||||
echo "Pushing JSC ${JSC_VERSION} to the Maven repo"
|
||||
pushd ${THIS_DIR}/../../node_modules/jsc-android/dist/org/webkit/android-jsc/${JSC_VERSION}
|
||||
# Push Hermes
|
||||
echo "Pushing Hermes ${HERMES_VERSION} to the Maven repo"
|
||||
pushd ${THIS_DIR}/../../node_modules/hermes-engine/android/
|
||||
mvn \
|
||||
deploy:deploy-file \
|
||||
-Durl=${MVN_REPO} \
|
||||
-DrepositoryId=${MVN_REPO_ID} \
|
||||
-Dfile=android-jsc-${JSC_VERSION}.aar \
|
||||
-Dfile=hermes-release.aar \
|
||||
-Dpackaging=aar \
|
||||
-DgeneratePom=false \
|
||||
-DpomFile=android-jsc-${JSC_VERSION}.pom || true
|
||||
-DgroupId=com.facebook \
|
||||
-DartifactId=hermes \
|
||||
-Dversion=${HERMES_VERSION} \
|
||||
-DgeneratePom=true || true
|
||||
popd
|
||||
else
|
||||
# Push React Native, if necessary
|
||||
@@ -65,17 +67,19 @@ else
|
||||
popd
|
||||
fi
|
||||
|
||||
# Push JSC, if necessary
|
||||
if [[ ! -d ${MVN_REPO}/org/webkit/android-jsc/${JSC_VERSION} ]]; then
|
||||
echo "Pushing JSC ${JSC_VERSION} to the Maven repo"
|
||||
pushd ${THIS_DIR}/../../node_modules/jsc-android/dist/org/webkit/android-jsc/${JSC_VERSION}
|
||||
# Push Hermes, if necessary
|
||||
if [[ ! -d ${MVN_REPO}/com/facebook/hermes/${HERMES_VERSION} ]]; then
|
||||
echo "Pushing Hermes ${HERMES_VERSION} to the Maven repo"
|
||||
pushd ${THIS_DIR}/../../node_modules/hermes-engine/android/
|
||||
mvn \
|
||||
deploy:deploy-file \
|
||||
-Durl=${MVN_REPO} \
|
||||
-Dfile=android-jsc-${JSC_VERSION}.aar \
|
||||
-Dfile=hermes-release.aar \
|
||||
-Dpackaging=aar \
|
||||
-DgeneratePom=false \
|
||||
-DpomFile=android-jsc-${JSC_VERSION}.pom
|
||||
-DgroupId=com.facebook \
|
||||
-DartifactId=hermes \
|
||||
-Dversion=${HERMES_VERSION} \
|
||||
-DgeneratePom=true
|
||||
popd
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
@@ -33,6 +35,10 @@ android {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
pickFirst '**/libc++_shared.so'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -44,8 +50,11 @@ dependencies {
|
||||
|
||||
//noinspection GradleDynamicVersion
|
||||
api 'com.facebook.react:react-native:+'
|
||||
//noinspection GradleDynamicVersion
|
||||
implementation 'org.webkit:android-jsc:+'
|
||||
|
||||
// Hermes JS engine
|
||||
def hermesPath = "../../node_modules/hermes-engine/android/"
|
||||
debugImplementation files(hermesPath + "hermes-debug.aar")
|
||||
releaseImplementation files(hermesPath + "hermes-release.aar")
|
||||
|
||||
implementation 'com.dropbox.core:dropbox-core-sdk:3.0.8'
|
||||
implementation 'com.jakewharton.timber:timber:4.7.1'
|
||||
@@ -144,7 +153,7 @@ android.libraryVariants.all { def variant ->
|
||||
mergeResourcesTask.dependsOn(currentBundleTask)
|
||||
|
||||
mergeAssetsTask.doLast {
|
||||
def assetsDir = mergeAssetsTask.outputDir.get()
|
||||
def assetsDir = mergeAssetsTask.outputDir
|
||||
|
||||
// Bundle sounds
|
||||
//
|
||||
@@ -178,7 +187,7 @@ android.libraryVariants.all { def variant ->
|
||||
if (currentBundleTask.enabled) {
|
||||
copy {
|
||||
from(resourcesDir)
|
||||
into(mergeResourcesTask.outputDir.get())
|
||||
into(mergeResourcesTask.outputDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,6 +227,14 @@ publishing {
|
||||
dependency.appendNode('artifactId', artifactId)
|
||||
dependency.appendNode('version', it.moduleVersion)
|
||||
}
|
||||
|
||||
// Add Hermes dependency.
|
||||
def hermesPkg = new File("$rootDir/../node_modules/hermes-engine/package.json")
|
||||
def hermesVersion = new JsonSlurper().parseText(hermesPkg.text).version
|
||||
def hermesDependency = dependencies.appendNode('dependency')
|
||||
hermesDependency.appendNode('groupId', "com.facebook")
|
||||
hermesDependency.appendNode('artifactId', "hermes")
|
||||
hermesDependency.appendNode('version', hermesVersion)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.app.Activity;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.facebook.hermes.reactexecutor.HermesExecutorFactory;
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
@@ -27,7 +28,6 @@ import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.common.LifecycleState;
|
||||
import com.facebook.react.devsupport.DevInternalSettings;
|
||||
import com.facebook.react.jscexecutor.JSCExecutorFactory;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
@@ -35,7 +35,6 @@ import com.facebook.soloader.SoLoader;
|
||||
import com.oney.WebRTCModule.RTCVideoViewManager;
|
||||
import com.oney.WebRTCModule.WebRTCModule;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
import org.webrtc.SoftwareVideoDecoderFactory;
|
||||
import org.webrtc.SoftwareVideoEncoderFactory;
|
||||
import org.webrtc.audio.AudioDeviceModule;
|
||||
@@ -217,9 +216,8 @@ class ReactInstanceManagerHolder {
|
||||
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
|
||||
}
|
||||
|
||||
// Keep on using JSC, the jury is out on Hermes.
|
||||
JSCExecutorFactory jsFactory
|
||||
= new JSCExecutorFactory("", "");
|
||||
// Use the Hermes JavaScript engine.
|
||||
HermesExecutorFactory jsFactory = new HermesExecutorFactory();
|
||||
|
||||
reactInstanceManager
|
||||
= ReactInstanceManager.builder()
|
||||
|
||||
10
app.js
10
app.js
@@ -6,11 +6,6 @@ import 'jQuery-Impromptu';
|
||||
|
||||
import 'olm';
|
||||
|
||||
// We need to setup the jitsi-local-storage as early as possible so that we can start using it.
|
||||
// NOTE: If jitsi-local-storage is used before the initial setup is performed this will break the use case when we use
|
||||
// the local storage from the parent page when the localStorage is disabled. Also the setup is relying that
|
||||
// window.location is not changed and still has all URL parameters.
|
||||
import './react/features/base/jitsi-local-storage/setup';
|
||||
import conference from './conference';
|
||||
import API from './modules/API';
|
||||
import UI from './modules/UI/UI';
|
||||
@@ -20,10 +15,7 @@ import translation from './modules/translation/translation';
|
||||
|
||||
// Initialize Olm as early as possible.
|
||||
if (window.Olm) {
|
||||
window.Olm.init().catch(e => {
|
||||
console.error('Failed to initialize Olm, E2EE will be disabled', e);
|
||||
delete window.Olm;
|
||||
});
|
||||
window.Olm.init();
|
||||
}
|
||||
|
||||
window.APP = {
|
||||
|
||||
@@ -108,7 +108,6 @@ import {
|
||||
getBackendSafePath,
|
||||
getJitsiMeetGlobalNS
|
||||
} from './react/features/base/util';
|
||||
import { downloadJSON } from './react/features/base/util/downloadJSON';
|
||||
import { showDesktopPicker } from './react/features/desktop-picker';
|
||||
import { appendSuffix } from './react/features/display-name';
|
||||
import {
|
||||
@@ -1222,8 +1221,19 @@ export default {
|
||||
// this can be called from console and will not have reference to this
|
||||
// that's why we reference the global var
|
||||
const logs = APP.connection.getLogs();
|
||||
const data = encodeURIComponent(JSON.stringify(logs, null, ' '));
|
||||
|
||||
downloadJSON(logs, filename);
|
||||
const elem = document.createElement('a');
|
||||
|
||||
elem.download = filename;
|
||||
elem.href = `data:application/json;charset=utf-8,\n${data}`;
|
||||
elem.dataset.downloadurl
|
||||
= [ 'text/json', elem.download, elem.href ].join(':');
|
||||
elem.dispatchEvent(new MouseEvent('click', {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
11
config.js
11
config.js
@@ -14,6 +14,9 @@ var config = {
|
||||
// Domain for authenticated users. Defaults to <domain>.
|
||||
// authdomain: 'jitsi-meet.example.com',
|
||||
|
||||
// Jirecon recording component domain.
|
||||
// jirecon: 'jirecon.jitsi-meet.example.com',
|
||||
|
||||
// Call control component (Jigasi).
|
||||
// call_control: 'callcontrol.jitsi-meet.example.com',
|
||||
|
||||
@@ -64,11 +67,6 @@ var config = {
|
||||
// adjusted to 2.5 Mbps. This takes a value between 0 and 1 which determines
|
||||
// the probability for this to be enabled.
|
||||
// capScreenshareBitrate: 1 // 0 to disable
|
||||
|
||||
// Enable callstats only for a percentage of users.
|
||||
// This takes a value between 0 and 100 which determines the probability for
|
||||
// the callstats to be enabled.
|
||||
// callStatsThreshold: 5 // enable callstats for 5% of the users.
|
||||
},
|
||||
|
||||
// Disables ICE/UDP by filtering out local and remote UDP candidates in
|
||||
@@ -337,7 +335,6 @@ var config = {
|
||||
// 'datachannel'), undefined (treat it as 'datachannel') and false (don't
|
||||
// open any channel).
|
||||
// openBridgeChannel: true,
|
||||
openBridgeChannel: 'websocket',
|
||||
|
||||
|
||||
// UI
|
||||
@@ -638,6 +635,8 @@ var config = {
|
||||
// List of undocumented settings used in jitsi-meet
|
||||
/**
|
||||
_immediateReloadThreshold
|
||||
autoRecord
|
||||
autoRecordToken
|
||||
debug
|
||||
debugAudioLevels
|
||||
deploymentInfo
|
||||
|
||||
@@ -45,8 +45,10 @@
|
||||
@extend .connection-info__icon;
|
||||
}
|
||||
|
||||
.connection-actions {
|
||||
.showmore {
|
||||
display: block;
|
||||
margin: 10px auto;
|
||||
text-align: center;
|
||||
width: 90px;
|
||||
}
|
||||
}
|
||||
|
||||
8
debian/jitsi-meet-prosody.postrm
vendored
8
debian/jitsi-meet-prosody.postrm
vendored
@@ -45,12 +45,8 @@ case "$1" in
|
||||
rm -rf /var/lib/prosody/$JICOFO_AUTH_DOMAIN.*
|
||||
rm -rf /var/lib/prosody/$JVB_HOSTNAME.*
|
||||
|
||||
# clean created users, replace '.' with '%2e', replace '-' with '%2d'
|
||||
rm -rf /var/lib/prosody/`echo $JICOFO_AUTH_DOMAIN | sed -e "s/\./%2e/g"| sed -e "s/-/%2d/g"`
|
||||
|
||||
# clean the prosody cert from the trust store
|
||||
rm -rf /usr/local/share/ca-certificates/$JICOFO_AUTH_DOMAIN.*
|
||||
update-ca-certificates -f
|
||||
# clean created users
|
||||
rm -rf /var/lib/prosody/`echo $JICOFO_AUTH_DOMAIN | sed -e "s/\./%2e/g"`
|
||||
fi
|
||||
|
||||
# Clear the debconf variable
|
||||
|
||||
50
debian/jitsi-meet-turnserver.postinst
vendored
50
debian/jitsi-meet-turnserver.postinst
vendored
@@ -36,6 +36,26 @@ case "$1" in
|
||||
NGINX_CONFIG="/etc/nginx/sites-available/$JVB_HOSTNAME.conf"
|
||||
JITSI_MEET_CONFIG="/etc/jitsi/meet/$JVB_HOSTNAME-config.js"
|
||||
|
||||
NGINX_SITES_ENABLED="/etc/nginx/sites-enabled/"
|
||||
NGINX_CONFIG_ENABLED="${NGINX_SITES_ENABLED}${JVB_HOSTNAME}.conf"
|
||||
NGINX_MULTIPLEXING="true"
|
||||
for site in ${NGINX_SITES_ENABLED}*; do
|
||||
# if it is not a file continue
|
||||
[ -f "${site}" ] || continue
|
||||
# if it is our config skip
|
||||
[ "${site}" != "${NGINX_CONFIG_ENABLED}" ] || continue
|
||||
# check whether other enabled hosts has listen 443
|
||||
if cat ${site} | grep -v "^[[:space:]]*#" | grep listen | grep -q "^.*[[:space:]:]443[;[:space:]].*" ; then
|
||||
# nothing to do
|
||||
echo "------------------------------------------------"
|
||||
echo ""
|
||||
echo "turnserver is listening on tcp 5349 as other nginx sites use port 443"
|
||||
echo ""
|
||||
echo "------------------------------------------------"
|
||||
NGINX_MULTIPLEXING="false"
|
||||
fi
|
||||
done
|
||||
|
||||
# if there was a turn config backup it so we can configure
|
||||
# we cannot recognize at the moment is this a user config or default config when installing coturn
|
||||
if [[ -f $TURN_CONFIG ]] && ! grep -q "jitsi-meet coturn config" "$TURN_CONFIG" ; then
|
||||
@@ -113,9 +133,19 @@ denied-peer-ip=240.0.0.0-255.255.255.255" >> $TURN_CONFIG
|
||||
TURN_SECRET="$RET"
|
||||
|
||||
# no turn config exists, lt's copy template and fill it in
|
||||
PUBLIC_IP=$(dig -4 +short myip.opendns.com a @resolver1.opendns.com) || true
|
||||
if [ -z "$PUBLIC_IP" ] ; then
|
||||
PUBLIC_IP="127.0.0.1"
|
||||
echo "------------------------------------------------"
|
||||
echo "Warning! Could not resolve your external ip address! Error:^"
|
||||
echo "Your turn server will not work till you edit your $TURN_CONFIG config file."
|
||||
echo "You need to set your external ip address in external-ip and restart coturn service."
|
||||
echo "------------------------------------------------"
|
||||
fi
|
||||
cp /usr/share/jitsi-meet-turnserver/turnserver.conf $TURN_CONFIG
|
||||
sed -i "s/jitsi-meet.example.com/$JVB_HOSTNAME/g" $TURN_CONFIG
|
||||
sed -i "s/__turnSecret__/$TURN_SECRET/g" $TURN_CONFIG
|
||||
sed -i "s/__external_ip_address__/$PUBLIC_IP/g" $TURN_CONFIG
|
||||
|
||||
# SSL for nginx
|
||||
db_get jitsi-meet/cert-choice
|
||||
@@ -140,14 +170,18 @@ denied-peer-ip=240.0.0.0-255.255.255.255" >> $TURN_CONFIG
|
||||
invoke-rc.d coturn restart || true
|
||||
|
||||
NGINX_STREAM_CONFIG="/etc/nginx/modules-enabled/60-jitsi-meet.conf"
|
||||
if [ -f $NGINX_STREAM_CONFIG ] ; then
|
||||
echo "------------------------------------------------"
|
||||
echo ""
|
||||
echo "You have multiplexing enabled, it is recommended to disable it and migrate to using websockets for the bridge channel."
|
||||
echo "The support for sctp data channels is deprecated and will be dropped at some point."
|
||||
echo "How to do it at: https://jitsi.org/multiplexing-to-bridge-ws-howto"
|
||||
echo ""
|
||||
echo "------------------------------------------------"
|
||||
if [ $NGINX_MULTIPLEXING = "true" ] && [ ! -f $NGINX_STREAM_CONFIG ] && [ -f $NGINX_CONFIG ] ; then
|
||||
ln -s /usr/share/jitsi-meet-turnserver/jitsi-meet.conf $NGINX_STREAM_CONFIG
|
||||
sed -i "s/listen 443 ssl/listen 4444 ssl http2/g" $NGINX_CONFIG
|
||||
sed -i "s/listen \[\:\:\]\:443 ssl/listen \[\:\:\]\:4444 ssl http2/g" $NGINX_CONFIG
|
||||
invoke-rc.d nginx reload || true
|
||||
else
|
||||
PROSODY_HOST_CONFIG="/etc/prosody/conf.avail/$JVB_HOSTNAME.cfg.lua"
|
||||
if [ -f $PROSODY_HOST_CONFIG ] ; then
|
||||
# If we are not multiplexing we need to change the port in prosody config
|
||||
sed -i 's/"443"/"5349"/g' $PROSODY_HOST_CONFIG
|
||||
invoke-rc.d prosody restart || true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Enable turn server in config.js
|
||||
|
||||
2
debian/jitsi-meet-turnserver.postrm
vendored
2
debian/jitsi-meet-turnserver.postrm
vendored
@@ -24,6 +24,7 @@ set -e
|
||||
|
||||
case "$1" in
|
||||
remove)
|
||||
rm -rf /etc/nginx/modules-enabled/60-jitsi-meet.conf
|
||||
if [ -x "/etc/init.d/nginx" ]; then
|
||||
invoke-rc.d nginx reload || true
|
||||
fi
|
||||
@@ -32,6 +33,7 @@ case "$1" in
|
||||
fi
|
||||
;;
|
||||
purge)
|
||||
rm -rf /etc/nginx/modules-enabled/60-jitsi-meet.conf
|
||||
rm -rf /etc/turnserver.conf
|
||||
if [ -x "/etc/init.d/nginx" ]; then
|
||||
invoke-rc.d nginx reload || true
|
||||
|
||||
@@ -8,7 +8,7 @@ turncredentials_secret = "__turnSecret__";
|
||||
turncredentials = {
|
||||
{ type = "stun", host = "jitmeet.example.com", port = "3478" },
|
||||
{ type = "turn", host = "jitmeet.example.com", port = "3478", transport = "udp" },
|
||||
{ type = "turns", host = "jitmeet.example.com", port = "5349", transport = "tcp" }
|
||||
{ type = "turns", host = "jitmeet.example.com", port = "443", transport = "tcp" }
|
||||
};
|
||||
|
||||
cross_domain_bosh = false;
|
||||
|
||||
@@ -12,6 +12,7 @@ no-tcp-relay
|
||||
no-tcp
|
||||
listening-port=3478
|
||||
tls-listening-port=5349
|
||||
external-ip=__external_ip_address__
|
||||
no-tlsv1
|
||||
no-tlsv1_1
|
||||
# https://ssl-config.mozilla.org/#server=haproxy&version=2.1&config=intermediate&openssl=1.1.0g&guideline=5.4
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
# this is jitsi-meet nginx module configuration
|
||||
# this forward all http traffic to the nginx virtual host port
|
||||
# and the rest to the turn server
|
||||
#
|
||||
# Multiplexing based on ALPN is DEPRECATED. ALPN does not play well with websockets on some browsers and reverse proxies.
|
||||
# To migrate away from using it read: https://jitsi.org/multiplexing-to-bridge-ws-howto
|
||||
# This file will be removed at some point and if deployment is still using it, will break.
|
||||
#
|
||||
|
||||
stream {
|
||||
upstream web {
|
||||
server 127.0.0.1:4444;
|
||||
|
||||
@@ -87,15 +87,6 @@ server {
|
||||
tcp_nodelay on;
|
||||
}
|
||||
|
||||
# colibri (JVB) websockets for jvb1
|
||||
location ~ ^/colibri-ws/default-id/(.*) {
|
||||
proxy_pass http://127.0.0.1:9090/colibri-ws/default-id/$1$is_args$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
tcp_nodelay on;
|
||||
}
|
||||
|
||||
location ~ ^/([^/?&:'"]+)$ {
|
||||
try_files $uri @root_path;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,8 @@ require_relative '../node_modules/@react-native-community/cli-platform-ios/nativ
|
||||
target 'jitsi-meet' do
|
||||
project 'app/app.xcodeproj'
|
||||
|
||||
pod 'Firebase/Analytics', '~> 6.33.0'
|
||||
pod 'Firebase/Crashlytics', '~> 6.33.0'
|
||||
pod 'Firebase/DynamicLinks', '~> 6.33.0'
|
||||
pod 'Firebase/Crashlytics', '~> 6.24.0'
|
||||
pod 'Firebase/DynamicLinks', '~> 6.24.0'
|
||||
end
|
||||
|
||||
target 'JitsiMeet' do
|
||||
|
||||
157
ios/Podfile.lock
157
ios/Podfile.lock
@@ -20,49 +20,42 @@ PODS:
|
||||
- React-Core (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- ReactCommon/turbomodule/core (= 0.61.5-jitsi.1)
|
||||
- Firebase/Analytics (6.33.0):
|
||||
- Firebase/Core
|
||||
- Firebase/Core (6.33.0):
|
||||
- Firebase/CoreOnly (6.24.0):
|
||||
- FirebaseCore (= 6.7.0)
|
||||
- Firebase/Crashlytics (6.24.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseAnalytics (= 6.8.3)
|
||||
- Firebase/CoreOnly (6.33.0):
|
||||
- FirebaseCore (= 6.10.3)
|
||||
- Firebase/Crashlytics (6.33.0):
|
||||
- FirebaseCrashlytics (~> 4.1.0)
|
||||
- Firebase/DynamicLinks (6.24.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseCrashlytics (~> 4.6.1)
|
||||
- Firebase/DynamicLinks (6.33.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseDynamicLinks (~> 4.3.1)
|
||||
- FirebaseAnalytics (6.8.3):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- FirebaseInstallations (~> 1.6)
|
||||
- GoogleAppMeasurement (= 6.8.3)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.7)
|
||||
- GoogleUtilities/MethodSwizzler (~> 6.7)
|
||||
- GoogleUtilities/Network (~> 6.7)
|
||||
- "GoogleUtilities/NSData+zlib (~> 6.7)"
|
||||
- nanopb (~> 1.30906.0)
|
||||
- FirebaseCore (6.10.3):
|
||||
- FirebaseCoreDiagnostics (~> 1.6)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/Logger (~> 6.7)
|
||||
- FirebaseCoreDiagnostics (1.7.0):
|
||||
- GoogleDataTransport (~> 7.4)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/Logger (~> 6.7)
|
||||
- nanopb (~> 1.30906.0)
|
||||
- FirebaseCrashlytics (4.6.1):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- FirebaseInstallations (~> 1.6)
|
||||
- GoogleDataTransport (~> 7.2)
|
||||
- nanopb (~> 1.30906.0)
|
||||
- FirebaseDynamicLinks (~> 4.0.8)
|
||||
- FirebaseAnalyticsInterop (1.5.0)
|
||||
- FirebaseCore (6.7.0):
|
||||
- FirebaseCoreDiagnostics (~> 1.3)
|
||||
- FirebaseCoreDiagnosticsInterop (~> 1.2)
|
||||
- GoogleUtilities/Environment (~> 6.5)
|
||||
- GoogleUtilities/Logger (~> 6.5)
|
||||
- FirebaseCoreDiagnostics (1.3.0):
|
||||
- FirebaseCoreDiagnosticsInterop (~> 1.2)
|
||||
- GoogleDataTransportCCTSupport (~> 3.1)
|
||||
- GoogleUtilities/Environment (~> 6.5)
|
||||
- GoogleUtilities/Logger (~> 6.5)
|
||||
- nanopb (~> 1.30905.0)
|
||||
- FirebaseCoreDiagnosticsInterop (1.2.0)
|
||||
- FirebaseCrashlytics (4.1.1):
|
||||
- FirebaseAnalyticsInterop (~> 1.2)
|
||||
- FirebaseCore (~> 6.6)
|
||||
- FirebaseInstallations (~> 1.1)
|
||||
- GoogleDataTransport (~> 6.1)
|
||||
- GoogleDataTransportCCTSupport (~> 3.1)
|
||||
- nanopb (~> 1.30905.0)
|
||||
- PromisesObjC (~> 1.2)
|
||||
- FirebaseDynamicLinks (4.3.1):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- FirebaseInstallations (1.7.0):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/UserDefaults (~> 6.7)
|
||||
- FirebaseDynamicLinks (4.0.8):
|
||||
- FirebaseAnalyticsInterop (~> 1.3)
|
||||
- FirebaseCore (~> 6.2)
|
||||
- FirebaseInstallations (1.2.0):
|
||||
- FirebaseCore (~> 6.6)
|
||||
- GoogleUtilities/Environment (~> 6.6)
|
||||
- GoogleUtilities/UserDefaults (~> 6.6)
|
||||
- PromisesObjC (~> 1.2)
|
||||
- Folly (2018.10.22.00):
|
||||
- boost-for-react-native
|
||||
@@ -74,36 +67,19 @@ PODS:
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- glog (0.3.5)
|
||||
- GoogleAppMeasurement (6.8.3):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.7)
|
||||
- GoogleUtilities/MethodSwizzler (~> 6.7)
|
||||
- GoogleUtilities/Network (~> 6.7)
|
||||
- "GoogleUtilities/NSData+zlib (~> 6.7)"
|
||||
- nanopb (~> 1.30906.0)
|
||||
- GoogleDataTransport (7.4.0):
|
||||
- nanopb (~> 1.30906.0)
|
||||
- GoogleDataTransport (6.1.0)
|
||||
- GoogleDataTransportCCTSupport (3.1.0):
|
||||
- GoogleDataTransport (~> 6.1)
|
||||
- nanopb (~> 1.30905.0)
|
||||
- GoogleSignIn (5.0.1):
|
||||
- AppAuth (~> 1.2)
|
||||
- GTMAppAuth (~> 1.0)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
- GoogleUtilities/AppDelegateSwizzler (6.7.2):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Environment (6.7.2):
|
||||
- GoogleUtilities/Environment (6.6.0):
|
||||
- PromisesObjC (~> 1.2)
|
||||
- GoogleUtilities/Logger (6.7.2):
|
||||
- GoogleUtilities/Logger (6.6.0):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/MethodSwizzler (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (6.7.2)"
|
||||
- GoogleUtilities/Reachability (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/UserDefaults (6.7.2):
|
||||
- GoogleUtilities/UserDefaults (6.6.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GTMAppAuth (1.0.0):
|
||||
- AppAuth/Core (~> 1.0)
|
||||
@@ -113,13 +89,13 @@ PODS:
|
||||
- GTMSessionFetcher/Core (1.2.2)
|
||||
- GTMSessionFetcher/Full (1.2.2):
|
||||
- GTMSessionFetcher/Core (= 1.2.2)
|
||||
- nanopb (1.30906.0):
|
||||
- nanopb/decode (= 1.30906.0)
|
||||
- nanopb/encode (= 1.30906.0)
|
||||
- nanopb/decode (1.30906.0)
|
||||
- nanopb/encode (1.30906.0)
|
||||
- nanopb (1.30905.0):
|
||||
- nanopb/decode (= 1.30905.0)
|
||||
- nanopb/encode (= 1.30905.0)
|
||||
- nanopb/decode (1.30905.0)
|
||||
- nanopb/encode (1.30905.0)
|
||||
- ObjectiveDropboxOfficial (3.9.4)
|
||||
- PromisesObjC (1.2.10)
|
||||
- PromisesObjC (1.2.8)
|
||||
- RCTRequired (0.61.5-jitsi.1)
|
||||
- RCTTypeSafety (0.61.5-jitsi.1):
|
||||
- FBLazyVector (= 0.61.5-jitsi.1)
|
||||
@@ -293,7 +269,7 @@ PODS:
|
||||
- React
|
||||
- react-native-webrtc (1.84.0):
|
||||
- React
|
||||
- react-native-webview (10.9.0):
|
||||
- react-native-webview (7.4.1):
|
||||
- React
|
||||
- React-RCTActionSheet (0.61.5-jitsi.1):
|
||||
- React-Core/RCTActionSheetHeaders (= 0.61.5-jitsi.1)
|
||||
@@ -374,9 +350,8 @@ DEPENDENCIES:
|
||||
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector/`)
|
||||
- FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec/`)
|
||||
- Firebase/Analytics (~> 6.33.0)
|
||||
- Firebase/Crashlytics (~> 6.33.0)
|
||||
- Firebase/DynamicLinks (~> 6.33.0)
|
||||
- Firebase/Crashlytics (~> 6.24.0)
|
||||
- Firebase/DynamicLinks (~> 6.24.0)
|
||||
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
|
||||
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
||||
- ObjectiveDropboxOfficial (~> 3.9.4)
|
||||
@@ -422,14 +397,15 @@ SPEC REPOS:
|
||||
- boost-for-react-native
|
||||
- CocoaLumberjack
|
||||
- Firebase
|
||||
- FirebaseAnalytics
|
||||
- FirebaseAnalyticsInterop
|
||||
- FirebaseCore
|
||||
- FirebaseCoreDiagnostics
|
||||
- FirebaseCoreDiagnosticsInterop
|
||||
- FirebaseCrashlytics
|
||||
- FirebaseDynamicLinks
|
||||
- FirebaseInstallations
|
||||
- GoogleAppMeasurement
|
||||
- GoogleDataTransport
|
||||
- GoogleDataTransportCCTSupport
|
||||
- GoogleSignIn
|
||||
- GoogleUtilities
|
||||
- GTMAppAuth
|
||||
@@ -525,24 +501,25 @@ SPEC CHECKSUMS:
|
||||
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
|
||||
FBLazyVector: 4a5251159a3ed05dc11cc8b74cf937869935814b
|
||||
FBReactNativeSpec: 6fa602a20993212cc9877a81838578ffb0008bc9
|
||||
Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5
|
||||
FirebaseAnalytics: 5dd088bd2e67bb9d13dbf792d1164ceaf3052193
|
||||
FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd
|
||||
FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1
|
||||
FirebaseCrashlytics: 5777d3462fb8c3ab9e80a2473bd7d667a2e8411c
|
||||
FirebaseDynamicLinks: 6eac37d86910382eafb6315d952cc44c9e176094
|
||||
FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2
|
||||
Firebase: b28e55c60efd98963cd9011fe2fac5a10c2ba124
|
||||
FirebaseAnalyticsInterop: 3f86269c38ae41f47afeb43ebf32a001f58fcdae
|
||||
FirebaseCore: e610482f64097b0e9f056cd97bc6b33dfabcbb6a
|
||||
FirebaseCoreDiagnostics: 4a773a47bd83bbd5a9b1ccf1ce7caa8b2d535e67
|
||||
FirebaseCoreDiagnosticsInterop: 296e2c5f5314500a850ad0b83e9e7c10b011a850
|
||||
FirebaseCrashlytics: a87cce5746d3335995bd18b1b60d073cd05a6920
|
||||
FirebaseDynamicLinks: 417dc6dbb6013233c77558290d73296f429656a6
|
||||
FirebaseInstallations: 2119fb3e46b0a88bfdbf12562f855ee3252462fa
|
||||
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
|
||||
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
|
||||
GoogleAppMeasurement: 966e88df9d19c15715137bb2ddaf52373f111436
|
||||
GoogleDataTransport: b7f406340a291370045a270c599e53c6fa6ec20f
|
||||
GoogleDataTransport: f6f8eba931df03ebd2232ff4645aa85f8f47b5ab
|
||||
GoogleDataTransportCCTSupport: d70a561f7d236af529fee598835caad5e25f6d3d
|
||||
GoogleSignIn: 3a51b9bb8e48b635fd7f4272cee06ca260345b86
|
||||
GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
|
||||
GoogleUtilities: 39530bc0ad980530298e9c4af8549e991fd033b1
|
||||
GTMAppAuth: 4deac854479704f348309e7b66189e604cf5e01e
|
||||
GTMSessionFetcher: 61bb0f61a4cb560030f1222021178008a5727a23
|
||||
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
|
||||
nanopb: c43f40fadfe79e8b8db116583945847910cbabc9
|
||||
ObjectiveDropboxOfficial: a5afefc83f6467c42c45f2253f583f2ad1ffc701
|
||||
PromisesObjC: b14b1c6b68e306650688599de8a45e49fae81151
|
||||
PromisesObjC: c119f3cd559f50b7ae681fa59dc1acd19173b7e6
|
||||
RCTRequired: f63dd90a89a60602acdd44c42e5d2645ca60ab79
|
||||
RCTTypeSafety: 24a3c6d55684046ed550b1d0ef083a9bf71c8bd4
|
||||
React: 71c5a51135f291c3b32c0b558e167b858ae50e84
|
||||
@@ -557,7 +534,7 @@ SPEC CHECKSUMS:
|
||||
react-native-keep-awake: eba3137546b10003361b37c761f6c429b59814ae
|
||||
react-native-netinfo: 8d8db463bcc5db66a8ac5c48a7d86beb3b92f61a
|
||||
react-native-webrtc: 9268ae9a2bc9730796b0968d012327e92c392adf
|
||||
react-native-webview: 6ee7868ca8eba635dbf7963986d1ab7959da0391
|
||||
react-native-webview: 4dbc1d2a4a6b9c5e9e723c62651917aa2b5e579e
|
||||
React-RCTActionSheet: b72ddbfbe15b44ce691d128e4b582f4bb9abb540
|
||||
React-RCTAnimation: cfaefba5024499d336b76ab850e6bd33b232b5e3
|
||||
React-RCTBlob: c427e643bef82999deeab97489ba43298ecfbe24
|
||||
@@ -576,6 +553,6 @@ SPEC CHECKSUMS:
|
||||
RNWatch: a5320c959c75e72845c07985f3e935e58998f1d3
|
||||
Yoga: 7b4209fda2441f99d54dd6cf4c82b094409bb68f
|
||||
|
||||
PODFILE CHECKSUM: 224e84629bf45ae487c4ebc66faf33ec8304fb67
|
||||
PODFILE CHECKSUM: 7255ec38ea51a8bc10a7a582248b4eb4bbbff80c
|
||||
|
||||
COCOAPODS: 1.9.3
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>20.5.0</string>
|
||||
<string>20.4.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
@@ -66,10 +66,10 @@
|
||||
<string>See your scheduled meetings in the app.</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Participate in meetings with video.</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string></string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Participate in meetings with voice.</string>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>Local network is used for establishing Peer-to-Peer connections.</string>
|
||||
<key>NSUserActivityTypes</key>
|
||||
<array>
|
||||
<string>org.jitsi.JitsiMeet.ios.conference</string>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>20.5.0</string>
|
||||
<string>20.4.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>20.5.0</string>
|
||||
<string>20.4.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>CLKComplicationPrincipalClass</key>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.11.0</string>
|
||||
<string>2.10.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
"ru": "Russisch",
|
||||
"sk": "Slowakisch",
|
||||
"sl": "Slowenisch",
|
||||
"sr": "Serbish",
|
||||
"sv": "Schwedisch",
|
||||
"tr": "Türkisch",
|
||||
"vi": "Vietnamesisch",
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
"ru": "Russian",
|
||||
"sk": "",
|
||||
"sl": "Slovenian",
|
||||
"sr": "Serbian",
|
||||
"sv": "Swedish",
|
||||
"tr": "Turkish",
|
||||
"vi": "Vietnamese",
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
"ru": "Ruski",
|
||||
"sk": "Slovački",
|
||||
"sl": "Slovenski",
|
||||
"sr": "Srpski",
|
||||
"sv": "Švedski",
|
||||
"tr": "Turski",
|
||||
"vi": "Vijetnamski",
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
"pl": "Польский",
|
||||
"ptBR": "Португальский (Бразилия)",
|
||||
"ru": "Русский",
|
||||
"sr": "Сербский",
|
||||
"sv": "Шведский",
|
||||
"tr": "Турецкий",
|
||||
"vi": "Вьетнамский",
|
||||
|
||||
@@ -1,39 +1,34 @@
|
||||
{
|
||||
"en": "Енглески",
|
||||
"af": "Африкански",
|
||||
"az": "Азербејџански",
|
||||
"bg": "Бугарски",
|
||||
"cs": "Чешки",
|
||||
"de": "Њемачки",
|
||||
"el": "Грчки",
|
||||
"eo": "Есперанто",
|
||||
"es": "Шпански",
|
||||
"fr": "Француски",
|
||||
"hy": "Јерменски",
|
||||
"it": "Италијански",
|
||||
"ja": "Јапански",
|
||||
"ko": "Корејски",
|
||||
"nb": "Норвешки Бокал",
|
||||
"oc": "Окцитански",
|
||||
"pl": "Пољски",
|
||||
"ptBR": "Португалски (Бразил)",
|
||||
"ru": "Руски",
|
||||
"sk": "Словачки",
|
||||
"sl": "Словенски",
|
||||
"sr": "Српски",
|
||||
"sv": "Шведски",
|
||||
"tr": "Турски",
|
||||
"vi": "Вијетнамски",
|
||||
"zhCN": "Кинески (Кина)",
|
||||
"zhTW": "Кинески (Тајван)",
|
||||
"nl": "Холандски",
|
||||
"hu": "Мађарски",
|
||||
"hr": "Хрватски",
|
||||
"frCA": "Француски (Канада)",
|
||||
"fi": "Фински",
|
||||
"et": "Естонски",
|
||||
"esUS": "Шпански (Латинска Америка)",
|
||||
"enGB": "Енглески (Велика Британија)",
|
||||
"da": "Дански",
|
||||
"ca": "Каталонски"
|
||||
"en": "",
|
||||
"af": "",
|
||||
"bg": "",
|
||||
"ca": "",
|
||||
"cs": "",
|
||||
"da": "",
|
||||
"de": "",
|
||||
"el": "",
|
||||
"enGB": "",
|
||||
"eo": "",
|
||||
"es": "",
|
||||
"esUS": "",
|
||||
"et": "",
|
||||
"fi": "",
|
||||
"fr": "",
|
||||
"frCA": "",
|
||||
"hr": "",
|
||||
"hu": "",
|
||||
"hy": "",
|
||||
"it": "",
|
||||
"ja": "",
|
||||
"ko": "",
|
||||
"nl": "",
|
||||
"oc": "",
|
||||
"pl": "",
|
||||
"ptBR": "",
|
||||
"ru": "",
|
||||
"sv": "",
|
||||
"tr": "",
|
||||
"vi": "",
|
||||
"zhCN": "",
|
||||
"zhTW": ""
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
"sc": "Sardinian",
|
||||
"sk": "Slovak",
|
||||
"sl": "Slovenian",
|
||||
"sr": "Serbian",
|
||||
"sv": "Swedish",
|
||||
"th": "Thailand",
|
||||
"tr": "Turkish",
|
||||
|
||||
@@ -234,7 +234,7 @@
|
||||
"micPermissionDeniedError": "Die Berechtigung zur Verwendung des Mikrofons wurde nicht erteilt. Sie können trotzdem an der Konferenz teilnehmen, aber die anderen Teilnehmer können Sie nicht hören. Verwenden Sie die Kamera-Schaltfläche in der Adressleiste, um die Berechtigungen zu erteilen.",
|
||||
"micUnknownError": "Das Mikrofon kann aus einem unbekannten Grund nicht verwendet werden.",
|
||||
"muteEveryoneElseDialog": "Einmal stummgeschaltet, können Sie deren Stummschaltung nicht mehr beenden, aber sie können ihre Stummschaltung jederzeit selbst beenden.",
|
||||
"muteEveryoneElseTitle": "Alle außer {{whom}} stummschalten?",
|
||||
"muteEveryoneElseTitle": "Alle außer {{whom}} stummschaten?",
|
||||
"muteEveryoneDialog": "Wollen Sie wirklich alle stummschalten? Sie können deren Stummschaltung nicht mehr beenden, aber sie können ihre Stummschaltung jederzeit selbst beenden.",
|
||||
"muteEveryoneTitle": "Alle stummschalten?",
|
||||
"muteEveryoneSelf": "sich selbst",
|
||||
|
||||
@@ -139,9 +139,6 @@
|
||||
"description": "Rien ne s'est passé ? Nous avons essayé de lancer votre réunion dans l'application de bureau {{app}}. Essayez à nouveau ou lancez-la dans l'application web {{app}}.",
|
||||
"descriptionWithoutWeb": "Rien ne s'est passé ? Nous avons essayé de démarrer votre réunion dans l'application bureau {{app}}.",
|
||||
"downloadApp": "Télécharger l'application",
|
||||
"ifDoNotHaveApp": "Si vous n'avez pas encore l'application:",
|
||||
"ifHaveApp": "Si vous avez déjà installé l'application:",
|
||||
"joinInApp": "Rejoindre la réunion en utilisant l'application",
|
||||
"launchWebButton": "Lancer dans le navigateur",
|
||||
"openApp": "Continuer vers l'application",
|
||||
"title": "Lancement de votre réunion dans {{app}} en cours...",
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
"kickParticipantButton": "Verwijderen",
|
||||
"kickParticipantDialog": "Weet u zeker dat u deze deelnemer wilt verwijderen?",
|
||||
"kickParticipantTitle": "Deze deelnemer verwijderen?",
|
||||
"kickTitle": "Oei! {{participantDisplayName}} heeft u uit de vergadering verwijderd",
|
||||
"kickTitle": "Oei! {{ParticipantDisplayName}} heeft u uit de vergadering verwijderd",
|
||||
"liveStreaming": "Livestreamen",
|
||||
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "Niet mogelijk tijdens opnemen",
|
||||
"liveStreamingDisabledForGuestTooltip": "Gasten kunnen geen livestream starten.",
|
||||
|
||||
@@ -1,77 +1,62 @@
|
||||
{
|
||||
"addPeople": {
|
||||
"add": "Pozvať",
|
||||
"addContacts": "Pozvať kontakty",
|
||||
"copyInvite": "Skopírovať pozvánku",
|
||||
"copyLink": "Skopírovať odkaz na konferenciu",
|
||||
"copyStream": "Skopírovať odkaz na živé vysielanie",
|
||||
"countryNotSupported": "Zatiaľ nepodporujeme túto krajinu.",
|
||||
"countryReminder": "Medzinárodný hovor? Prosím skontrolujte, či telefónne číslo začína smerovým číslo krajiny.",
|
||||
"defaultEmail": "Predvolený email",
|
||||
"disabled": "Nemôžete pozvať ďalších ľudí.",
|
||||
"disabled": "Nemôžete pozvať ďalších účastníkov.",
|
||||
"failedToAdd": "Nepodarilo sa pridať účastníka.",
|
||||
"footerText": "Odchádzajúce hovory sú zablokované.",
|
||||
"googleEmail": "Google email",
|
||||
"inviteMoreHeader": "Ste sám v tejto konferencii",
|
||||
"inviteMoreMailSubject": "Pozvánka do konferencie {{appName}}",
|
||||
"inviteMorePrompt": "Pozvať ľudí",
|
||||
"linkCopied": "Odkaz skopírovaný do schránky",
|
||||
"loading": "Hľadanie ľudí a telefónnych čísiel",
|
||||
"loading": "Hľadanie účastníkov a telefónnych čísiel",
|
||||
"loadingNumber": "Kontrola telefónneho čísla",
|
||||
"loadingPeople": "Hľadanie ľudí na pozvanie",
|
||||
"loadingPeople": "Hľadanie účastníkov na pozvanie",
|
||||
"noResults": "Žiadne výsledky hľadania",
|
||||
"noValidNumbers": "Prosím zadajte telefónne číslo",
|
||||
"outlookEmail": "Outlook email",
|
||||
"searchNumbers": "Zadajte telefónne čísla",
|
||||
"searchPeople": "Hľadanie ľudí",
|
||||
"searchPeopleAndNumbers": "Hľadať ľudí alebo pridať ich telefónne čísla",
|
||||
"shareInvite": "Zdieľať pozvánku do konferencie",
|
||||
"shareLink": "Zdieľať odkaz na pozvanie",
|
||||
"shareStream": "Zdieľať odkaz na živé vysielanie",
|
||||
"searchPeople": "Hľadanie účastníkov",
|
||||
"searchPeopleAndNumbers": "Hľadanie účastníkov alebo pridávanie telefónny čísel",
|
||||
"telephone": "Telefón: {{number}}",
|
||||
"title": "Pozvať ľudí do tejto konferencie",
|
||||
"yahooEmail": "Yahoo email"
|
||||
"title": "Pozvať účastníkov do tejto konferencie"
|
||||
},
|
||||
"audioDevices": {
|
||||
"bluetooth": "Bluetooth",
|
||||
"headphones": "Slúchadlá",
|
||||
"headphones": "Sluchátka",
|
||||
"phone": "Telefón",
|
||||
"speaker": "Reproduktor",
|
||||
"speaker": "Rečník",
|
||||
"none": "Žiadne zvukové zariadenia"
|
||||
},
|
||||
"audioOnly": {
|
||||
"audioOnly": "Iba zvuk"
|
||||
},
|
||||
"calendarSync": {
|
||||
"addMeetingURL": "Pridať odkaz na konferenciu",
|
||||
"addMeetingURL": "Pridať odkaz na stretnutie",
|
||||
"confirmAddLink": "Chcete pridal Jitsi odkaz do tejto udalosti?",
|
||||
"error": {
|
||||
"appConfiguration": "Integrácia s kalendárom nie je správne nastavená.",
|
||||
"generic": "Stala sa chyba. Skontrolujte nastavenia kalendára a skúste obnoviť kalendár.",
|
||||
"notSignedIn": "Stala sa chyba počas autentifikácie pre zobrazenie kaledárových udalosti. Skontrolujte nastavenia kalendára a skúste sa znovu prihlásiť."
|
||||
"generic": "Stala sa chyba. Skontrolujte si nastavenia kalendáru a skúste aktualizovať kalendár. ",
|
||||
"notSignedIn": "Stala sa chyba počas autentifikácie pre zobrazovanie kaledárových udalosti. Skontrolujte si nastavenia kalendáru a skúste sa znovu prihlásiť."
|
||||
},
|
||||
"join": "Zúčastniť sa",
|
||||
"joinTooltip": "Zúčastniť sa konferencie",
|
||||
"nextMeeting": "nasledujúca konferencia",
|
||||
"noEvents": "Nie sú naplánované žiadne ďalšie udalosti.",
|
||||
"ongoingMeeting": "prebiehajúca konferencia",
|
||||
"joinTooltip": "Zúčastniť sa stretnutia",
|
||||
"nextMeeting": "nasledujúce stretnutie",
|
||||
"noEvents": "Niesú naplánované žiadne ďalšie udalosti.",
|
||||
"ongoingMeeting": "prebiehajúce stretnutie",
|
||||
"permissionButton": "Otvoriť nastavenia",
|
||||
"permissionMessage": "Aplikácia potrebuje kalendárové oprávnenie pre zobranie termínov a stretnutí.",
|
||||
"refresh": "Obnoviť kalendár",
|
||||
"permissionMessage": "Aplikácia potrebuje kalendárové oprávnenie pre zobranie termínov a stretnutí ",
|
||||
"refresh": "Aktualizovať kalendár",
|
||||
"today": "Dnes"
|
||||
},
|
||||
"chat": {
|
||||
"error": "Chyba: vaša správa \"{{originalText}}\" nebola poslaná. Dôvod: {{error}}",
|
||||
"fieldPlaceHolder": "Zadajte sem vašu správu",
|
||||
"messagebox": "Napíšte správu",
|
||||
"messageTo": "Súkromná správa pre {{recipient}}",
|
||||
"noMessagesMessage": "V tejto konferencii ešte nie je žiadna správa. Začnite tu vašu diskusiu!",
|
||||
"messageTo": "Správa pre {{recipient}}",
|
||||
"noMessagesMessage": "V tejto konferencií ešte nie je žiadna správa. Začnite tu vašu diskusiu!",
|
||||
"nickname": {
|
||||
"popover": "Zvoľte meno",
|
||||
"title": "Zadajte vašu prezývku"
|
||||
"title": "Zadajte sem vašu prezývku"
|
||||
},
|
||||
"privateNotice": "Súkromná správa pre {{recipient}}",
|
||||
"title": "Chat",
|
||||
"title": "Písanie",
|
||||
"you": "Vy"
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
@@ -80,54 +65,54 @@
|
||||
"dontShowAgain": "Upozornenie viac nezobrazovať"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
"joiningRoom": "Pripájanie do konferencie..."
|
||||
"joiningRoom": "Vytvára sa spojenie do vašej konferencie…"
|
||||
},
|
||||
"connection": {
|
||||
"ATTACHED": "Priložený",
|
||||
"AUTHENTICATING": "Overovanie",
|
||||
"AUTHENTICATING": "Overujem",
|
||||
"AUTHFAIL": "Overenie zlyhalo",
|
||||
"CONNECTED": "Pripojený",
|
||||
"CONNECTING": "Pripájanie",
|
||||
"CONNECTING": "Pripájam",
|
||||
"CONNFAIL": "Spojenie zlyhalo",
|
||||
"DISCONNECTED": "Odpojený",
|
||||
"DISCONNECTING": "Odpájanie",
|
||||
"DISCONNECTING": "Odpájam",
|
||||
"ERROR": "Chyba",
|
||||
"FETCH_SESSION_ID": "Získavanie session-id...",
|
||||
"GET_SESSION_ID_ERROR": "Chyba pri získavaní session-id: {{code}}",
|
||||
"GOT_SESSION_ID": "Získavanie session-id... Hotovo",
|
||||
"RECONNECTING": "Chyba siete. Skúšam sa znova pripojiť ...",
|
||||
"LOW_BANDWIDTH": "Video pre {{displayName}} bolo vypnuté, aby sa ušetrila prenosová kapacita"
|
||||
},
|
||||
"connectionindicator": {
|
||||
"address": "Adresa:",
|
||||
"bandwidth": "Dátový tok:",
|
||||
"bitrate": "Prenos. rýchlosť:",
|
||||
"bridgeCount": "Počet serverov: ",
|
||||
"bandwidth": "Predpokladaný dat. tok:",
|
||||
"bitrate": "Prenos. rýchlosť",
|
||||
"bridgeCount": "Počet serverov:",
|
||||
"connectedTo": "Spojenie s:",
|
||||
"e2e_rtt": "E2E RTT:",
|
||||
"framerate": "Rýchlosť snímkovania:",
|
||||
"less": "Zobraziť menej",
|
||||
"localaddress": "Lokálna adresa:",
|
||||
"localaddress_plural": "Lokálne adresy:",
|
||||
"localport": "Lokálny port:",
|
||||
"localport_plural": "Lokálne porty:",
|
||||
"maxEnabledResolution": "send max",
|
||||
"more": "Zobraziť viac",
|
||||
"packetloss": "Strata paketov:",
|
||||
"less": "Zobraz menej",
|
||||
"localaddress_0": "Lokálna adresa:",
|
||||
"localaddress_1": "Lokálne adresy:",
|
||||
"localaddress_2": "",
|
||||
"localport_0": "Lokálny port:",
|
||||
"localport_1": "Lokálne porty:",
|
||||
"localport_2": "",
|
||||
"more": "Zobraz viac",
|
||||
"packetloss": "Strata packetov:",
|
||||
"quality": {
|
||||
"good": "Dobré",
|
||||
"inactive": "Neaktívne",
|
||||
"lost": "Stratené",
|
||||
"nonoptimal": "Neoptimálne",
|
||||
"nonoptimal": "Nie je optimálne",
|
||||
"poor": "Slabé"
|
||||
},
|
||||
"remoteaddress": "Vzdialená adresa:",
|
||||
"remoteaddress_plural": "Vzdialené adresy:",
|
||||
"remoteport": "Vzdialený port:",
|
||||
"remoteport_plural": "Vzdialené porty:",
|
||||
"remoteaddress_0": "Vzdialená adresa:",
|
||||
"remoteaddress_1": "Vzdialené adresy:",
|
||||
"remoteaddress_2": "",
|
||||
"remoteport_0": "Vzdialený port:",
|
||||
"remoteport_1": "Vzdialené porty:",
|
||||
"remoteport_2": "",
|
||||
"resolution": "Rozlíšenie:",
|
||||
"status": "Spojenie:",
|
||||
"transport": "Prenos:",
|
||||
"transport_plural": "Prenosy:"
|
||||
"transport": "Prenos:"
|
||||
},
|
||||
"dateUtils": {
|
||||
"earlier": "Skôr",
|
||||
@@ -136,18 +121,16 @@
|
||||
},
|
||||
"deepLinking": {
|
||||
"appNotInstalled": "Potrebujete aplikáciu {{app}}, aby ste sa mohli pripojiť do tejto konferencie na vašom telefóne.",
|
||||
"description": "Nič sa nestalo? Snažili sme sa otvoriť konferenciu v {{app}}. Skúste to znovu, alebo sa pripojte na konferenciu v {{app}} cez web.",
|
||||
"descriptionWithoutWeb": "Nič sa nestalo? Snažili sme sa spustiť konferenciu v desktopovej aplikácií {{app}}.",
|
||||
"description": "Nič sa nestalo? Snažili sme sa otvoriť konferenciu v {{app}}. Skúste to znovu, alebo sa pripojte na konferenciu v {{app}} cez Web.",
|
||||
"descriptionWithoutWeb": "Nič sa nestalo? Snažili sme sa spustiť váš rozhovor v desktopovej aplikácií {{app}}.",
|
||||
"downloadApp": "Stiahnutie aplikácie",
|
||||
"ifDoNotHaveApp": "Ak nemáte aplikáciu:",
|
||||
"ifHaveApp": "Ak máte aplikáciu:",
|
||||
"joinInApp": "Vstúpiť do konferencie cez aplikáciu",
|
||||
"launchWebButton": "Otvoriť na webe",
|
||||
"openApp": "Pokračovať na aplikáciu",
|
||||
"title": "Konferencia sa otvára v {{app}}...",
|
||||
"tryAgainButton": "Skúsiť znova s natívnou aplikáciou"
|
||||
},
|
||||
"defaultLink": "napr. {{url}}",
|
||||
"defaultNickname": "napr. Ján Kováč",
|
||||
"defaultNickname": "napr. Jane Pink",
|
||||
"deviceError": {
|
||||
"cameraError": "Chyba pri prístupe ku kamere",
|
||||
"cameraPermission": "Aplikácia nemá oprávnenie pristupovať ku kamere",
|
||||
@@ -157,84 +140,79 @@
|
||||
"deviceSelection": {
|
||||
"noPermission": "Oprávnenie nie je poskytnuté",
|
||||
"previewUnavailable": "Náhľad nie je dostupný",
|
||||
"selectADevice": "Vybrať zariadenie",
|
||||
"selectADevice": "Vyberte zvukové zariadenie",
|
||||
"testAudio": "Vyskúšať zvuk"
|
||||
},
|
||||
"dialog": {
|
||||
"accessibilityLabel": {
|
||||
"liveStreaming": "Živé vysielanie"
|
||||
},
|
||||
"add": "Pridať",
|
||||
"allow": "Povoliť",
|
||||
"alreadySharedVideoMsg": "Iný účastník už zdieľa video. Pri tejto konferencií môže zdieľať video iba jeden účastník.",
|
||||
"alreadySharedVideoTitle": "Je možné zdieľať iba jedno video",
|
||||
"alreadySharedVideoMsg": "Iný účastník už poskytuje video. Pri tejto konferencií môže poskytovať súčasne iba jeden účastník.",
|
||||
"alreadySharedVideoTitle": "Naraz sa dá poskytovať iba jedno video",
|
||||
"applicationWindow": "Okno aplikácie",
|
||||
"Back": "Späť",
|
||||
"cameraConstraintFailedError": "Vaša kamera nespĺňa potrebné požiadavky.",
|
||||
"cameraNotFoundError": "Kamera nebola nájdená.",
|
||||
"cameraNotSendingData": "Kamera nie je dostupná. Skontrolujte či iná aplikácia používa kameru, vyberte inú kameru v nastaveniach alebo znovu spustite aplikáciu.",
|
||||
"cameraNotSendingData": "Kamera nie je dostupná. Skontrolujte či iná aplikácia používa kameru, vyberte inú kameru v nastaveniach ale znovu spustite aplikáciu.",
|
||||
"cameraNotSendingDataTitle": "Prístup na kameru nie je možný.",
|
||||
"cameraPermissionDeniedError": "Nebolo udelené oprávnenie používať kameru. Napriek tomu sa môže zúčastniť na konferencií, ale ostatní účastníci vás nebudu vidieť. Pre pridelenie oprávnenia môžete použiť ikonu kamery na adresnej lište.",
|
||||
"cameraPermissionDeniedError": "Nebolo udelené oprávnenie používať kameru. Napriek tomu sa môže zúčastniť na konferencií, ale ostatný účastníci vás nebudu vidieť. Pre pridelenie oprávnenia môžete použiť ikonu kamery na adresnej lište.",
|
||||
"cameraUnknownError": "Z neznámeho dôvodu sa kamera nedá použiť.",
|
||||
"cameraUnsupportedResolutionError": "Kamera nepodporuje požadované rozlíšenie.",
|
||||
"cameraUnsupportedResolutionError": "Táto kamera nepodporuje požadované rozlíšenie.",
|
||||
"Cancel": "Zrušiť",
|
||||
"close": "Zatvoriť",
|
||||
"conferenceDisconnectMsg": "Skontrolujte prípadne vaše sieťové pripojenie. Pripájam znovu o {{seconds}} sekúnd...",
|
||||
"conferenceDisconnectTitle": "Vaše spojenie bolo prerušené.",
|
||||
"conferenceReloadMsg": "Snažíme sa to napraviť. Pripájam znovu o {{seconds}} sekund...",
|
||||
"conferenceReloadTitle": "Spojenie sa prerušilo.",
|
||||
"conferenceReloadTitle": "Žiaľ niečo sa nepodarilo.",
|
||||
"confirm": "Potvrdiť",
|
||||
"confirmNo": "Nie",
|
||||
"confirmYes": "Áno",
|
||||
"connectError": "Niečo je zle a nemôžem sa pripojiť do konferencie.",
|
||||
"connectErrorWithMsg": "Niečo je zle a nemôžem sa pripojiť do konferencie. Správa: {{msg}}",
|
||||
"connectError": "Oops! Niečo je zle a nemôžem sa pripojiť do konferencie.",
|
||||
"connectErrorWithMsg": "Oops! Niečo je zle a nemôžem sa pripojiť do konferencie. Správa: {{msg}}",
|
||||
"connecting": "Pripájam",
|
||||
"contactSupport": "Spojiť sa s podporou",
|
||||
"copy": "Kopírovať",
|
||||
"dismiss": "Zavrieť",
|
||||
"displayNameRequired": "Ahoj! Ako sa voláš?",
|
||||
"done": "Hotovo",
|
||||
"e2eeDescription": "Koncové šifrovanie (End-to-End Encryption, E2EE) je momentálne EXPERIMENTÁLNE. Zapnutie koncového šifrovania znemožní použitie serverových služieb ako: nahrávanie, živé vysielanie a účasť cez telefón. Do konferencie je možné vstúpiť len s prehliadačom, ktorý podporuje vložiteľné prúdy (insertable streams).",
|
||||
"e2eeLabel": "E2EE kľúč",
|
||||
"e2eeNoKey": "žiadny",
|
||||
"e2eeToggleSet": "Nastaviť kľúč",
|
||||
"e2eeSet": "Nastaviť",
|
||||
"e2eeWarning": "VAROVANIE: NIektorí účastníci nemajú podporu pre koncové šifrovanie. Ak ho zapnete, nebudú Vás vidieť ani počuť.",
|
||||
"enterDisplayName": "Prosím zadajte sem vaše meno",
|
||||
"error": "Chyba",
|
||||
"gracefulShutdown": "Služba je momentálne vypnutá pre údržbu. Skúste to neskor.",
|
||||
"grantModeratorDialog": "Chcete naozaj tohoto účastníka urobiť moderatorom?",
|
||||
"grantModeratorTitle": "Urobiť moderatorom",
|
||||
"externalInstallationMsg": "Zlyhanie pri inštalácií rozšírenia pre zdieľanie prac. plochy",
|
||||
"externalInstallationTitle": "Potrebné rozšírenie:",
|
||||
"goToStore": "",
|
||||
"gracefulShutdown": "Naša služba je momentálne vypnutá pre údržbu. Skúste to neskor.",
|
||||
"IamHost": "Ja som hostiteľ",
|
||||
"incorrectRoomLockPassword": "Nesprávne heslo",
|
||||
"incorrectPassword": "Používateľské meno alebo heslo je nesprávne",
|
||||
"inlineInstallationMsg": "Musí byť nainštalované rozšírenie pre zdieľanie pracovnej prochy.",
|
||||
"inlineInstallExtension": "Teraz inštalovať",
|
||||
"internalError": "Ups! Niečo nefunguje. Vyskytla sa nasledujúca chyba: {{error}}",
|
||||
"internalErrorTitle": "Interná chyba",
|
||||
"kickMessage": "Pre podrobnosti sa môžete spojiť s {{participantDisplayName}}.",
|
||||
"kickParticipantButton": "Odstrániť",
|
||||
"kickParticipantDialog": "Skutočne chcete odstrániť tohto účastnika?",
|
||||
"kickParticipantTitle": "Odstrániť účastníka?",
|
||||
"kickTitle": "{{participantDisplayName}} vás odstránil z konferencie.",
|
||||
"kickTitle": "Ouch! {{participantDisplayName}} vás odstránil zo stretnutia.",
|
||||
"liveStreaming": "Živé vysielanie",
|
||||
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "Nie je možné keď je aktívne nahrávanie",
|
||||
"liveStreamingDisabledForGuestTooltip": "Hostia nemôžu začať živé vysielanie.",
|
||||
"liveStreamingDisabledTooltip": "Spustenie živého vysielania je zakázané.",
|
||||
"liveStreamingDisabledTooltip": "Štartovanie živého vysielania je vypnuté.",
|
||||
"lockMessage": "Zlyhanie pri pokuse o zabezpečenie konferencie.",
|
||||
"lockRoom": "Pridať $t(lockRoomPassword)",
|
||||
"lockRoom": "Pridať stretnutie $t(lockRoomPasswordUppercase)",
|
||||
"lockTitle": "Zabezpečenie zlyhalo",
|
||||
"logoutQuestion": "Ste si istý, že sa chcete odhlásiť a skončiť konferenciu?",
|
||||
"logoutTitle": "Odhlásiť",
|
||||
"maxUsersLimitReached": "Bol dosiahnutý maximálny počet účastníkov. Konferencia je plná. Spojte sa prosím s organizátorom konferencie, alebo to skúste neskôr.",
|
||||
"maxUsersLimitReached": "Bol dosiahnutý maximálny počet účastníkov. Konferencia je plná. Spojte sa prosím s organizátorom stretnutia, alebo to skúste neskôr.",
|
||||
"maxUsersLimitReachedTitle": "Dosiahnutý maximálny počet účastníkov",
|
||||
"micConstraintFailedError": "Váš mikrofón nespĺňa potrebné požiadavky.",
|
||||
"micNotFoundError": "Mikrofón nebol nájdený.",
|
||||
"micNotSendingData": "Choďte do nastavení vašeho počítača, aby ste odblokovali stlmenie vášho mikrofónu a upravte jeho úroveň.",
|
||||
"micNotSendingDataTitle": "Mikrofón je stlmený vašimi systémovými nastaveniami.",
|
||||
"micPermissionDeniedError": "Nebolo udelené oprávnenie používať mikrofón. Napriek tomu sa môže zúčastniť na konferencií, ale ostatní účastníci vás nebudú počuť. Pre pridelenie oprávnenia môžete použiť ikonu kamery na adresnej lište.",
|
||||
"micPermissionDeniedError": "Nebolo udelené oprávnenie používať mikrofón. Napriek tomu sa môže zúčastniť na konferencií, ale ostatný účastníci vás nebudú počuť. Pre pridelenie oprávnenia môžete použiť ikonu kamery na adresnej lište.",
|
||||
"micUnknownError": "Mikrofón sa nedá použiť z neznámeho dôvodu.",
|
||||
"muteEveryoneElseDialog": "Keď všetkým vypnete mikrofóny, nedokážete ich späť zapnúť. Účastníci si ale môžu zapnúť mikrofóny sami.",
|
||||
"muteEveryoneElseDialog": "Keď všetkým vypnete mikrofón, nedokážete spať zapnuť mikrofóny. Účastníci si ale môžu zapnúť mikrofóny sami.",
|
||||
"muteEveryoneElseTitle": "Vypnúť mikrofón všetkým okrem {{whom}}?",
|
||||
"muteEveryoneDialog": "Chcete naozaj všetkým vypnúť mikrofón. Keď všetkým vypnete mikrofóny, nedokážete ich späť zapnúť. Účastníci si ale môžu zapnúť mikrofóny sami.",
|
||||
"muteEveryoneDialog": "Chcete naozaj všetkým vypnúť mikrofón. Keď všetkým vypnete mikrofón, nedokážete spať zapnúť mikrofóny. Účastníci si ale môžu zapnúť mikrofóny sami.",
|
||||
"muteEveryoneTitle": "Všetkým vypnúť mikrofón?",
|
||||
"muteEveryoneSelf": "seba samého",
|
||||
"muteEveryoneStartMuted": "Všetci odteraz začínajú s vypnutým mikrofónom",
|
||||
@@ -244,34 +222,33 @@
|
||||
"muteParticipantTitle": "Vypnúť účastníkovi mikrofón?",
|
||||
"Ok": "Ok",
|
||||
"passwordLabel": "$t(lockRoomPasswordUppercase)",
|
||||
"passwordNotSupported": "$t(lockRoomPasswordUppercase) nie je podporované.",
|
||||
"passwordNotSupported": "Nastavovanie $t(lockRoomPassword) nie je podporované.",
|
||||
"passwordNotSupportedTitle": "$t(lockRoomPasswordUppercase) nie je podporované",
|
||||
"passwordRequired": "Prihlásenie",
|
||||
"popupError": "Váš prehliadač blokuje vyskakovacie okná tejto stránky. Prosím aktivujte vyskakovacie okná v bezpečnostných nastaveniach vašeho prehliadača a skúste znovu.",
|
||||
"passwordRequired": "$t(lockRoomPasswordUppercase) je potrebné",
|
||||
"popupError": "Váš prehliadať blokuje vyskakovacie okná tejto stránky. Prosím aktivujte vyskakovacie okná v bezpečnostných nastaveniach vašeho prehliadača a skúste znovu.",
|
||||
"popupErrorTitle": "Vyskakovacie okná sú zablokované",
|
||||
"readMore": "viac",
|
||||
"recording": "Nahrávanie",
|
||||
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Nie je možné keď je aktívny živý prenos",
|
||||
"recordingDisabledForGuestTooltip": "Hostia nemôžu začať nahrávanie.",
|
||||
"recordingDisabledTooltip": "Spustenie nahrávania je zakázané.",
|
||||
"rejoinNow": "Pripojiť hneď",
|
||||
"recordingDisabledTooltip": "Štartovanie nahrávania je vypnuté.",
|
||||
"rejoinNow": "Teraz sa znovu pridať.",
|
||||
"remoteControlAllowedMessage": "{{user}} prijal požiadavku o vzdialené ovládanie.",
|
||||
"remoteControlDeniedMessage": "{{user}} odmietol požiadavku o vzdialené ovládanie.",
|
||||
"remoteControlDeniedMessage": "{{user}} odmietol prijal požiadavku o vzdialené ovládanie.",
|
||||
"remoteControlErrorMessage": "Stala sa chyba počas žiadania o vzdialené ovládanie od {{user}}",
|
||||
"remoteControlRequestMessage": "Povolíte {{user}} ovládať vášu pracovnú plochu?",
|
||||
"remoteControlShareScreenWarning": "Pozor, keď povolíte požiadavku budete zdielať vašu obrazovku!",
|
||||
"remoteControlStopMessage": "Vzdialené ovládanie bolo ukončené.",
|
||||
"remoteControlTitle": "Vzdialené ovládanie",
|
||||
"Remove": "Odstrániť",
|
||||
"removePassword": "$t(lockRoomPasswordUppercase) odstránené",
|
||||
"removeSharedVideoMsg": "Naozaj chcete odstrániť zdieľané video?",
|
||||
"removeSharedVideoTitle": "Odstrániť zdieľané video",
|
||||
"removePassword": "$t(lockRoomPassword) odstránené",
|
||||
"removeSharedVideoMsg": "Ste si istý že chcete odstrániť zdielané video?",
|
||||
"removeSharedVideoTitle": "Odstrániť zdielané video",
|
||||
"reservationError": "Systémová chyba rezervácie",
|
||||
"reservationErrorMsg": "Chyba: {{code}}, správa: {{msg}}",
|
||||
"retry": "Skúsiť znovu",
|
||||
"screenSharingAudio": "Zdieľať zvuk",
|
||||
"screenSharingFailed": "Nie je možné spustiť zdieľanie obrazovky!",
|
||||
"screenSharingFailedTitle": "Zdieľanie obrazovky zlyhalo!",
|
||||
"screenSharingFailedToInstall": "Ups! Nepodarilo sa nainštalovať rozšírenie pre zdieľanie obrazovky.",
|
||||
"screenSharingFailedToInstallTitle": "Chyba v inštalácii rozšírenie pre zdieľanie obrazovky",
|
||||
"screenSharingFirefoxPermissionDeniedError": "Niečo sa nepodarilo pri pokuse o zdielanie obrazovky. Skontrolujte prosím či ste dali oprávnenie v prehliadači.",
|
||||
"screenSharingFirefoxPermissionDeniedTitle": "Nepodarilo sa zdielať obrazovku",
|
||||
"screenSharingPermissionDeniedError": "Ups! Niečo sa nepodarilo pri žiadaní o oprávnenie zdielať obrazovku. Prosím aktualizovať a skúsiť znovu.",
|
||||
"sendPrivateMessage": "Dostali ste súkromnú správu. Chceli ste na ňu odpovedať súkromne, alebo chcete poslať správu skupine?",
|
||||
"sendPrivateMessageCancel": "Poslať skupine",
|
||||
@@ -281,26 +258,26 @@
|
||||
"sessTerminated": "Volanie ukončené",
|
||||
"Share": "Zdieľať",
|
||||
"shareVideoLinkError": "Prosím, zadajte správny Youtube odkaz.",
|
||||
"shareVideoTitle": "Zdieľať video",
|
||||
"shareVideoTitle": "Zdielať video",
|
||||
"shareYourScreen": "Zdielať obrazovku",
|
||||
"shareYourScreenDisabled": "Zdieľanie obrazovky vypnuté.",
|
||||
"shareYourScreenDisabledForGuest": "Hostia nemôžu zdielať obrazovku.",
|
||||
"startLiveStreaming": "Spustiť živý prenos",
|
||||
"startLiveStreaming": "Spustiť priamy prenos",
|
||||
"startRecording": "Začať záznam",
|
||||
"startRemoteControlErrorMessage": "Chyba pri pokuse o začatie vzdialeného ovládania!",
|
||||
"stopLiveStreaming": "Zastaviť živý prenos",
|
||||
"startRemoteControlErrorMessage": "Chyba pri pokuse o začatie vzdialeného riadenia!",
|
||||
"stopLiveStreaming": "Prerušiť priamy prenos",
|
||||
"stopRecording": "Zastaviť záznam",
|
||||
"stopRecordingWarning": "Chcete zastaviť záznam?",
|
||||
"stopStreamingWarning": "Chcete zastaviť priamy prenos?",
|
||||
"streamKey": "Kľúč živého vysielania",
|
||||
"stopStreamingWarning": "Chcete prerušiť priamy prenos",
|
||||
"streamKey": "Klúč živého vysielania",
|
||||
"Submit": "OK",
|
||||
"thankYou": "Ďakujeme za používanie {{appName}}!",
|
||||
"thankYou": "Ďakujeme vám za používanie {{appName}}!",
|
||||
"token": "token",
|
||||
"tokenAuthFailed": "Prepáčte, nie ste oprávnený zúčastniť tejto sa konferencie.",
|
||||
"tokenAuthFailedTitle": "Overenie zlyhalo",
|
||||
"transcribing": "",
|
||||
"unlockRoom": "Odstrániť $t(lockRoomPassword)",
|
||||
"userPassword": "heslo",
|
||||
"unlockRoom": "Odstrániť stretnutie $t(lockRoomPassword)",
|
||||
"userPassword": "užívateľské heslo",
|
||||
"WaitForHostMsg": "Konferencia <b>{{room}}</b> sa ešte nezačala. Autorizujte sa prosím ak ste hostiteľ. V opačnom prípade čakajte na hostiteľa.",
|
||||
"WaitForHostMsgWOk": "Konferencia <b>{{room}}</b> sa ešte nezačala. Ak ste hostiteľ autorizujte sa stlačením Ok. V opačnom prípade čakajte na hostiteľa.",
|
||||
"WaitingForHost": "Čakám na hostiteľa ...",
|
||||
@@ -311,10 +288,7 @@
|
||||
"statusMessage": "je teraz {{status}}"
|
||||
},
|
||||
"documentSharing": {
|
||||
"title": "Zdieľaný dokument"
|
||||
},
|
||||
"e2ee": {
|
||||
"labelToolTip": "Zvuková a obrazová komunikácia je koncovo šifrovaná"
|
||||
"title": "Zdielaný dokument"
|
||||
},
|
||||
"feedback": {
|
||||
"average": "Priemerný",
|
||||
@@ -334,8 +308,8 @@
|
||||
},
|
||||
"info": {
|
||||
"accessibilityLabel": "Zobraziť informácie",
|
||||
"addPassword": "Nastaviť $t(lockRoomPassword)",
|
||||
"cancelPassword": "Zrušiť $t(lockRoomPassword)",
|
||||
"addPassword": "$t(lockRoomPassword) pridať",
|
||||
"cancelPassword": "$t(lockRoomPassword) zmazať",
|
||||
"conferenceURL": "Odkaz:",
|
||||
"country": "Krajina",
|
||||
"dialANumber": "Aby ste sa zúčastnili stretnutia, zavolajte jedno z týchto čísel a zadajte pin.",
|
||||
@@ -348,9 +322,9 @@
|
||||
"inviteLiveStream": "Kliknite túto linku {{url}}, pre zobrazenie živého vysielania z tohto stretnutia.",
|
||||
"invitePhone": "Keď sa chcete pripojiť cez telefón, klikni na: {{number}},,{{conferenceID}}#\n",
|
||||
"invitePhoneAlternatives": "Hľadáte iné pripojovacie číslo? Pripojovacie čísla pre konferenciu: {{{url}}\n\n\n\nTaktiež pokiaľ sa telefonicky pripájate cez konferenčný celomiestnostný telefón pripojte sa bez prenosu zvuku {{silentUrl}}",
|
||||
"inviteURLFirstPartGeneral": "Ste pozvaný do konferencie.",
|
||||
"inviteURLFirstPartPersonal": "{{name}} vás pozýva do konferencie.\n",
|
||||
"inviteURLSecondPart": "\nVstúpiť do konferencie:\n{{url}}\n",
|
||||
"inviteURLFirstPartGeneral": "Ste pozývaný pripojiť sa na stretnutie.",
|
||||
"inviteURLFirstPartPersonal": "{{name}} vás pozýva na stretnutie.",
|
||||
"inviteURLSecondPart": "\n Zúčastniť sa stretnutia:\n{{url}}\n",
|
||||
"liveStreamURL": "Živý prenos:",
|
||||
"moreNumbers": "Ďalšie telefónne čísla",
|
||||
"noNumbers": "Žiadne pripojovacie telefónne čísla.",
|
||||
@@ -394,8 +368,6 @@
|
||||
"videoQuality": "Nastavenie kvality volania"
|
||||
},
|
||||
"liveStreaming": {
|
||||
"limitNotificationDescriptionWeb": "Živé vysielanie je obmedzené na {{limit}} minút. Pre neobmedzené vysielanie skúste <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"limitNotificationDescriptionNative": "Živé vysielanie je obmedzené na {{limit}} minút. Pre neobmedzené vysielanie skúste {{app}}.",
|
||||
"busy": "Chystajú sa zdroje pre vysielanie. Skúste znova za pár minút.",
|
||||
"busyTitle": "Všetky vysielacie inštancie sú obsadené",
|
||||
"changeSignIn": "Prepnúť konto",
|
||||
@@ -403,19 +375,19 @@
|
||||
"chooseCTA": "Vyberte vysielaciu možnosť. Ste prihlásený ako {{email}}",
|
||||
"enterStreamKey": "Zadajte meno/heslo pre YouTube vysielanie.",
|
||||
"error": "Živé vysielanie zlyhalo. Prosím skúste to znovu.",
|
||||
"errorAPI": "Došlo k chybe pri prístupe k vašemu YouTube vysielaniu. Prosím skúste sa znovu prihlásiť.",
|
||||
"errorAPI": "Došlo chybe pri prístupe k vašemu YouTube vysielaniu. Prosím skúste sa znovu prihlásiť.",
|
||||
"errorLiveStreamNotEnabled": "Živé vysielanie pre {{email}} nie je aktivované. Aktivujte živé vysielanie, alebo sa prihláste pomocou konta s aktivovaným živým vysielaním.",
|
||||
"expandedOff": "Živé vysielanie bolo zastavené",
|
||||
"expandedOn": "Stretnutie je momentálne vysielané na YouTube.",
|
||||
"expandedPending": "Spúšťa živé vysielanie...",
|
||||
"failedToStart": "Nepodarilo sa spustiť živé vysielanie",
|
||||
"failedToStart": "Nepodarilo sa naštartovať živé vysielanie",
|
||||
"getStreamKeyManually": "Nepodarilo sa získať žiadne živé vysielania. Skúste získať kľúč pre živé vysielanie z YouTube.",
|
||||
"invalidStreamKey": "Kľúč pre živé vysielanie je nesprávny.",
|
||||
"off": "Živé vysielanie ukončené",
|
||||
"offBy": "{{name}} ukončil živé vysielanie",
|
||||
"on": "Živé vysielanie",
|
||||
"onBy": "{{name}} začal živé vysielanie",
|
||||
"pending": "Spúšťa sa živé vysielanie...",
|
||||
"pending": "Štartuje sa živé vysielanie...",
|
||||
"serviceName": "Služba pre živé vysielanie",
|
||||
"signedInAs": "Ste prihlásený ako:",
|
||||
"signIn": "Prihlásiť sa pomocou Google",
|
||||
@@ -423,9 +395,7 @@
|
||||
"signOut": "Odhlásiť",
|
||||
"start": "Začať živé vysielanie",
|
||||
"streamIdHelp": "Čo je to?",
|
||||
"unavailableTitle": "Živé vysielanie nie je k dispozícií",
|
||||
"youtubeTerms": "Podmienky poskytovania služby YouTube",
|
||||
"googlePrivacyPolicy": "Pravidlá ochrany súkromia Google"
|
||||
"unavailableTitle": "Živé vysielanie nie je k dispozícií"
|
||||
},
|
||||
"localRecording": {
|
||||
"clientState": {
|
||||
@@ -433,19 +403,19 @@
|
||||
"on": "Zapnutý",
|
||||
"unknown": "Neznámy"
|
||||
},
|
||||
"dialogTitle": "Ovládacie prvky lokálneho nahrávania",
|
||||
"dialogTitle": "Lokálne ovládacie prvky nahrávania",
|
||||
"duration": "Dĺžka",
|
||||
"durationNA": "neznáma",
|
||||
"encoding": "Kódovanie",
|
||||
"label": "",
|
||||
"labelToolTip": "Lokálne nahrávanie je aktivovaný",
|
||||
"labelToolTip": "Lokálny nahrávanie je aktivovaný",
|
||||
"localRecording": "Lokálne nahrávanie",
|
||||
"me": "Ja",
|
||||
"messages": {
|
||||
"engaged": "Lokálne nahrávanie je spustené",
|
||||
"finished": "Nahrávanie sedenia {{token}} je ukončené. Prosím pošlite nahratý súbor moderátorovi.",
|
||||
"finishedModerator": "Nahrávanie sedenia {{token}} je ukončené. Bola uložená nahrávka lokálnej stopy. Poproste ostatných účastníkov, aby vám poslali ich nahrávky.",
|
||||
"notModerator": "Nie ste moderátor. Nemôže začať, alebo skončiť lokálne nahrávanie."
|
||||
"notModerator": "Nieste moderátor. Nemôže začať, alebo skončiť lokálne nahrávanie."
|
||||
},
|
||||
"moderator": "Moderátor",
|
||||
"no": "Nie",
|
||||
@@ -468,17 +438,17 @@
|
||||
"focusFail": "{{component}} je nedostupný - skúste znova za {{ms}} sek",
|
||||
"grantedTo": "Práva moderátora boli udelené {{to}}!",
|
||||
"invitedOneMember": "{{displayName}} bol pozvaný",
|
||||
"invitedThreePlusMembers": "{{name}} a {{count}} ďalší boli pozvaní",
|
||||
"invitedTwoMembers": "{{first}} a {{second}} boli pozvaní",
|
||||
"kickParticipant": "{{kicked}} bol odstránený účastníkom {{kicker}}",
|
||||
"invitedThreePlusMembers": "{{name}} a {{count}} ďalší boli pozvaný",
|
||||
"invitedTwoMembers": "{{first}} a {{second}} boli pozvaný",
|
||||
"kickParticipant": "Pre ďalšie podrobnosti sa môže obrátiť na {{participantDisplayName}}",
|
||||
"me": "Ja",
|
||||
"moderator": "Boli vám udelené práva moderátora!",
|
||||
"muted": "Začali ste rozhovor s vypnutým mikrofónom.",
|
||||
"mutedTitle": "Boli ste stíšený!",
|
||||
"mutedRemotelyTitle": "{{participantDisplayName}} vám vypol mikrofón",
|
||||
"mutedRemotelyTitle": "{{participantDisplayName}} vás stíšil",
|
||||
"mutedRemotelyDescription": "Kedykoľvek môžete stíšenie zrušiť, keď ste prichystaný rozprávať. Keď skončite môžete sa znova stíšiť, aby ste znížili hluk na stretnutí.",
|
||||
"passwordRemovedRemotely": "Iný účastník odstránil $t(lockRoomPassword)",
|
||||
"passwordSetRemotely": "Iný účastník nastavil $t(lockRoomPassword)",
|
||||
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) bolo odstránené iným účastníkom",
|
||||
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) bolo nastavené iným účastníkom",
|
||||
"raisedHand": "{{name}} chce hovoriť",
|
||||
"somebody": "Niekto",
|
||||
"startSilentTitle": "Pripojili ste sa bez zvukového výstupu!",
|
||||
@@ -488,49 +458,11 @@
|
||||
"unmute": "Zapnúť mikrofón",
|
||||
"newDeviceCameraTitle": "Bola zistená nová kamera",
|
||||
"newDeviceAudioTitle": "Bolo zistené nové audio zariadenie",
|
||||
"newDeviceAction": "Použiť",
|
||||
"OldElectronAPPTitle": "Bezpečnostná hrozba!",
|
||||
"oldElectronClientDescription1": "Používate starú verziu klienta Jitsi Meet, ktorá má známe zraniteľnosti. Aktualizujte na ",
|
||||
"oldElectronClientDescription2": "najnovšiu verziu",
|
||||
"oldElectronClientDescription3": " teraz!"
|
||||
"newDeviceAction": "Použiť"
|
||||
},
|
||||
"passwordSetRemotely": "nastavené iným účastníkom",
|
||||
"passwordDigitsOnly": "až {{number}} číslic",
|
||||
"poweredby": "založené na",
|
||||
"prejoin": {
|
||||
"audioAndVideoError": "Chyba zvuku a videa:",
|
||||
"audioOnlyError": "Chyba zvuku:",
|
||||
"audioTrackError": "Nemôžem vytvoriť zvukovú stopu.",
|
||||
"callMe": "Zavolať mi",
|
||||
"callMeAtNumber": "Zavolajte mi na toto číslo:",
|
||||
"configuringDevices": "Konfigurácia zariedení...",
|
||||
"connectedWithAudioQ": "Ste pripojení so zvukom?",
|
||||
"copyAndShare": "Kopírovať a zdieľať odkaz",
|
||||
"dialInMeeting": "Volanie dnu do konferencie",
|
||||
"dialInPin": "Volajte dnu do konferencie a zadajte PIN kód:",
|
||||
"dialing": "Vytáčanie",
|
||||
"doNotShow": "Viac nezobrazovať",
|
||||
"errorDialOut": "Nemôžem volať von",
|
||||
"errorDialOutDisconnected": "Nemôžem volať von. Odpojené",
|
||||
"errorDialOutFailed": "Nemôžem volať von. Volanie zlyhalo",
|
||||
"errorDialOutStatus": "Chyba pri získavaní stavu volania",
|
||||
"errorStatusCode": "Chyba volania von, kód: {{status}}",
|
||||
"errorValidation": "Overenie čísla zlyhalo",
|
||||
"iWantToDialIn": "Chcem volať dnu",
|
||||
"joinAudioByPhone": "Vstúpiť so zvukom cez telefón",
|
||||
"joinMeeting": "Vstúpiť do konferencie",
|
||||
"joinWithoutAudio": "Vstúpiť bez zvuku",
|
||||
"initiated": "Hovor začatý",
|
||||
"linkCopied": "Odkaz skopírovaný do schránky",
|
||||
"lookGood": "Váš mikrofón funguje správne",
|
||||
"or": "alebo",
|
||||
"calling": "Volanie",
|
||||
"startWithPhone": "Začať so zvukom cez telefón",
|
||||
"screenSharingError": "Chyba pri zdieľaní obrazovky:",
|
||||
"videoOnlyError": "Chyba videa:",
|
||||
"videoTrackError": "Nemôžem vytvoriť video stopu.",
|
||||
"viewAllNumbers": "zobraziť všetky čísla"
|
||||
},
|
||||
"presenceStatus": {
|
||||
"busy": "Obsadený",
|
||||
"calling": "Je volaný",
|
||||
@@ -553,8 +485,6 @@
|
||||
},
|
||||
"raisedHand": "Chcel by som hovoriť",
|
||||
"recording": {
|
||||
"limitNotificationDescriptionWeb": "Nahrávanie je obmedzené na {{limit}} minút. Pre neobmedzené nahrávanie skúste <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"limitNotificationDescriptionNative": "Nahrávanie je obmedzené na {{limit}} minút. Pre neobmedzené nahrávanie skúste <3>{{app}}</3>.",
|
||||
"authDropboxText": "Nahrať na Dropbox",
|
||||
"availableSpace": "Dostupná kapacita {{spaceLeft}} MB (ca. {{duration}} minút nahrávania)",
|
||||
"beta": "BETA",
|
||||
@@ -584,12 +514,6 @@
|
||||
"sectionList": {
|
||||
"pullToRefresh": "Potiahnuť pre aktualizáciu"
|
||||
},
|
||||
"security": {
|
||||
"about": "Môžete nastaviť $t(lockRoomPassword) pre konferenciu. Účastníci budú musieť zadať $t(lockRoomPassword), aby mohli vstúpiť.",
|
||||
"aboutReadOnly": "Moderátor može nastaviť $t(lockRoomPassword) pre konferenciu. Účastníci budú musieť zadať $t(lockRoomPassword), aby mohli vstúpiť.",
|
||||
"insecureRoomNameWarning": "Názov konferencie nie je bezpečný. Môžu do nej vstúpiť neželaní účastníci. Zvážte zabezpečenie konferencie tlačidlom.",
|
||||
"securityOptions": "Nastavenie zabezpečenia"
|
||||
},
|
||||
"settings": {
|
||||
"calendar": {
|
||||
"about": "Používa sa kalendárová integrácia {{appName}} pre zabezpečený prístup ku vašemu kalendáru.",
|
||||
@@ -602,7 +526,6 @@
|
||||
"followMe": "Všetci sledujú mňa",
|
||||
"language": "Jazyk",
|
||||
"loggedIn": "Prihlásený ako {{name}}",
|
||||
"microphones": "Mikrofóny",
|
||||
"moderator": "Moderátor",
|
||||
"more": "Viac",
|
||||
"name": "Meno",
|
||||
@@ -610,7 +533,6 @@
|
||||
"selectAudioOutput": "Zvukový výstup",
|
||||
"selectCamera": "Kamera",
|
||||
"selectMic": "Mikrofón",
|
||||
"speakers": "Reproduktory",
|
||||
"startAudioMuted": "Pri pripojení všetkým stlmiť zvuk",
|
||||
"startVideoMuted": "Pri pripojení všetkým vypnúť video",
|
||||
"title": "Nastavenia"
|
||||
@@ -618,15 +540,12 @@
|
||||
"settingsView": {
|
||||
"advanced": "Rozšírené",
|
||||
"alertOk": "OK",
|
||||
"alertCancel": "Zrušiť",
|
||||
"alertTitle": "Upozornenie",
|
||||
"alertURLText": "Zadaná serverová URL je neplatná",
|
||||
"alertURLText": "Zadaná serverový URL je neplatná",
|
||||
"buildInfoSection": "informácie o kompilácií",
|
||||
"conferenceSection": "Konferencia",
|
||||
"disableCallIntegration": "Deaktivovať integráciu s natívnymi volaniami",
|
||||
"disableP2P": "Deaktivovať mód s koncovými zariadeniami",
|
||||
"disableCrashReporting": "Vypnúť oznamovanie pádov",
|
||||
"disableCrashReportingWarning": "Naozak chcete vypnúť oznamovanie pádov? Nastavenie bude aktívne po reštartovaní aplikácie.",
|
||||
"displayName": "Ukázať",
|
||||
"email": "E-mail",
|
||||
"header": "Nastavenia",
|
||||
@@ -643,10 +562,10 @@
|
||||
},
|
||||
"speaker": "Rečník",
|
||||
"speakerStats": {
|
||||
"hours": "{{count}}h",
|
||||
"minutes": "{{count}}m",
|
||||
"hours": "",
|
||||
"minutes": "",
|
||||
"name": "Meno",
|
||||
"seconds": "{{count}}s",
|
||||
"seconds": "",
|
||||
"speakerStats": "Štatistiky rečníka",
|
||||
"speakerTime": "Čas rečníka"
|
||||
},
|
||||
@@ -657,7 +576,7 @@
|
||||
"suspendedoverlay": {
|
||||
"rejoinKeyTitle": "Znovu pripojiť",
|
||||
"text": "Stlačte tlačidlo <i>Znovu pripojiť</i> na opätovné spojenie.",
|
||||
"title": "Konferencia sa prerušila lebo váš počítač bol uspaný."
|
||||
"title": "Konferencia sa prerušila lebo váš počítač bol uspaní."
|
||||
},
|
||||
"toolbar": {
|
||||
"accessibilityLabel": {
|
||||
@@ -668,17 +587,14 @@
|
||||
"chat": "Zapnúť/vypnúť textovú diskusiu",
|
||||
"document": "Zatvoriť zdielaný dokument",
|
||||
"download": "Stiahnuť našu aplikáciu",
|
||||
"e2ee": "Koncové šifrovanie",
|
||||
"feedback": "Zanechať spätnú väzbu",
|
||||
"fullScreen": "Zapnúť/vypnúť zobrazenie na celú obrazovku",
|
||||
"grantModerator": "Urobiť moderátorom",
|
||||
"hangup": "Ukončiť volanie",
|
||||
"help": "Pomoc",
|
||||
"invite": "Pozvať účastníka",
|
||||
"kick": "Odstrániť účastníka",
|
||||
"lobbyButton": "Zapnúť/vypnúť čakáreň",
|
||||
"localRecording": "Zapnúť/vypnúť ovládanie lokálneho nahrávania",
|
||||
"lockRoom": "Zapnúť/vypnúť heslo",
|
||||
"lockRoom": "Zapnúť/vypnúť heslo pre stretnutie",
|
||||
"moreActions": "Menu „Ďalšie akcie“ zapnúť/vypnúť",
|
||||
"moreActionsMenu": "Menu „Ďalšie akcie“",
|
||||
"moreOptions": "Zobraz viac možností",
|
||||
@@ -690,7 +606,6 @@
|
||||
"raiseHand": "„Ohlásiť sa“ zapnúť/vypnúť",
|
||||
"recording": "Nahrávanie zapnúť/vypnúť",
|
||||
"remoteMute": "Účastníka stlmiť",
|
||||
"security": "Nastavenie zabezpečenia",
|
||||
"Settings": "Nastavenia zapnúť/vypnúť",
|
||||
"sharedvideo": "Zdieľanie YouTube videa zapnúť/vypnúť",
|
||||
"shareRoom": "Pozvať osobu",
|
||||
@@ -700,7 +615,6 @@
|
||||
"speakerStats": "Štatistiky rečníka zobraziť/skryť",
|
||||
"tileView": "Prepnúť dlaždicové zobrazenie",
|
||||
"toggleCamera": "Zmeniť kameru",
|
||||
"toggleFilmstrip": "Zapnúť/vypnúť video náhľady",
|
||||
"videomute": "„Video odpojiť“ zapnúť/vypnúť",
|
||||
"videoblur": "Rozmazanie pozadia zapnúť/vypnúť"
|
||||
},
|
||||
@@ -708,24 +622,21 @@
|
||||
"audioOnlyOff": "Mód „Iba zvuk“ deaktivovať",
|
||||
"audioOnlyOn": "Mód „Iba zvuk“ aktivovať",
|
||||
"audioRoute": "Vybrať zvukové zariadenie",
|
||||
"authenticate": "Autentifikácia",
|
||||
"authenticate": "Overiť",
|
||||
"callQuality": "Spravovať kvalitu videa",
|
||||
"chat": "Otvoriť / Zatvoriť chat",
|
||||
"closeChat": "Chat zatvoriť",
|
||||
"documentClose": "Zatvoriť zdieľaný dokument",
|
||||
"documentOpen": "Otvoriť zdieľaný dokument",
|
||||
"documentClose": "Zdielaný dokument zatvoriť",
|
||||
"documentOpen": "Zdielaný dokument otvoriť",
|
||||
"download": "Stiahnuť našu aplikáciu",
|
||||
"e2ee": "Koncové šifrovanie",
|
||||
"enterFullScreen": "Zobraziť na celú obrazovku",
|
||||
"enterTileView": "Dlaždicové zobrazenie",
|
||||
"enterTileView": "Kachličkové zobrazenie",
|
||||
"exitFullScreen": "Opustiť celú obrazovku",
|
||||
"exitTileView": "Zrušiť dlaždicové zobrazenie",
|
||||
"exitTileView": "Kachličkové zobrazenie vypnúť",
|
||||
"feedback": "Nechať spätnú väzbu",
|
||||
"hangup": "Odísť",
|
||||
"help": "Pomoc",
|
||||
"invite": "Pozvať ľudí",
|
||||
"lobbyButtonDisable": "Vypnúť čakáreň",
|
||||
"lobbyButtonEnable": "Zapnúť čakáreň",
|
||||
"invite": "Pozvať účastníkov",
|
||||
"login": "Prihlásiť",
|
||||
"logout": "Odhlásiť",
|
||||
"lowerYourHand": "Dať dole ruku",
|
||||
@@ -734,10 +645,10 @@
|
||||
"mute": "Vypnúť / Zapnúť mikrofón",
|
||||
"muteEveryone": "Všetkých stlmiť",
|
||||
"noAudioSignalTitle": "Neprichádza žiaden vstup z vašeho mikrofónu!",
|
||||
"noAudioSignalDesc": "Pokiaľ ste zámerne nestlmili váš mikrofón v systémových nastaveniach alebo hardvéri, pouvažujte nad prepnutím zariadenia.",
|
||||
"noAudioSignalDescSuggestion": "Pokiaľ ste zámerne nestlmili váš mikrofón v systémových nastaveniach alebo hardvéri, pouvažujte nad prepnutím na odporúčané zariadenie.",
|
||||
"noAudioSignalDesc": "Pokiaľ ste zámerne nestlmili váš mikrofón v systémových nastavenia alebo hardvery, pouvažujte nad prepnutím zariadenia.",
|
||||
"noAudioSignalDescSuggestion": "Pokiaľ ste zámerne nestlmili váš mikrofón v systémových nastavenia alebo hardvery, pouvažujte nad prepnutím na odporúčané zariadenie.",
|
||||
"noAudioSignalDialInDesc": "Môže zavolať pomocou:",
|
||||
"noAudioSignalDialInLinkDesc": "Pripojovacie telefónne čísla",
|
||||
"noAudioSignalDialInLinkDesc" : "Pripojovacie telefónne čísla",
|
||||
"noisyAudioInputTitle": "Váš mikrofón vyzerá byť zašumený!",
|
||||
"noisyAudioInputDesc": "Vyzerá, že váš mikrofón je zašumený, skúste ho vypnuť, alebo zmeňte zariadenie.",
|
||||
"openChat": "Otvoriť chat",
|
||||
@@ -746,7 +657,6 @@
|
||||
"profile": "Úprava profilu",
|
||||
"raiseHand": "Prihlásiť / Odhlásiť sa o slovo",
|
||||
"raiseYourHand": "Prihlásiť sa o slovo",
|
||||
"security": "Nastavenie zabezpečenia",
|
||||
"Settings": "Nastavenia",
|
||||
"sharedvideo": "Zdielať YouTube video",
|
||||
"shareRoom": "Pozvať niekoho",
|
||||
@@ -774,7 +684,7 @@
|
||||
"pending": "Pripravuje sa prepisovanie stretnutia...",
|
||||
"start": "Začni zobrazovať titulky",
|
||||
"stop": "Skonči zobrazovať titulky",
|
||||
"tr": "TR"
|
||||
"tr": ""
|
||||
},
|
||||
"userMedia": {
|
||||
"androidGrantPermissions": "Vyberte <b><i>Povoliť</i></b> keď sa prehliadač bude pýtať na povolenie.",
|
||||
@@ -789,14 +699,14 @@
|
||||
"safariGrantPermissions": "Vyberte <b><i>OK</i></b> keď sa prehliadač bude pýtať na povolenie."
|
||||
},
|
||||
"videoSIPGW": {
|
||||
"busy": "Všetky zdroje sú obsadené, skúste znovu o pár minút.",
|
||||
"busyTitle": "Služba je obsadená",
|
||||
"errorAlreadyInvited": "{{displayName}} už bol pozvaný",
|
||||
"errorInvite": "Konferencia sa ešte nezačala, skúste neskôr.",
|
||||
"errorInviteFailed": "Skúste znovu neskôr.",
|
||||
"errorInviteFailedTitle": "Pozývanie {{displayName}} zlyhalo",
|
||||
"errorInviteTitle": "Chyba pozývania",
|
||||
"pending": "{{displayName}} bol pozvaný"
|
||||
"busy": "",
|
||||
"busyTitle": "",
|
||||
"errorAlreadyInvited": "",
|
||||
"errorInvite": "",
|
||||
"errorInviteFailed": "",
|
||||
"errorInviteFailedTitle": "",
|
||||
"errorInviteTitle": "",
|
||||
"pending": ""
|
||||
},
|
||||
"videoStatus": {
|
||||
"audioOnly": "AUD",
|
||||
@@ -818,10 +728,8 @@
|
||||
},
|
||||
"videothumbnail": {
|
||||
"domute": "Vypnúť mikrofón",
|
||||
"domuteOthers": "Vypnúť mikrofóny ostatným",
|
||||
"flip": "Prevrátiť",
|
||||
"grantModerator": "Urobiť moderátorom",
|
||||
"kick": "Odstrániť",
|
||||
"kick": "Vyhodiť",
|
||||
"moderator": "Moderátor",
|
||||
"mute": "Účastník s vypnutým mikrofónom",
|
||||
"muted": "Vypnutý mikrofón",
|
||||
@@ -843,62 +751,20 @@
|
||||
"connectCalendarButton": "Pripojte váš kalendár",
|
||||
"connectCalendarText": "",
|
||||
"enterRoomTitle": "Začať nové stretnutie",
|
||||
"getHelp": "Získať pomoc",
|
||||
"roomNameAllowedChars": "Meno stretnutia by nemalo obsahovať žiaden z týchto znakov: ?, &, :, ', \", %, #.",
|
||||
"go": "Začať",
|
||||
"goSmall": "Začať",
|
||||
"info": "Info",
|
||||
"join": "Pripojiť",
|
||||
"moderatedMessage": "Alebo si <a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">rezervujte vopred URL</a> pre konferenciu, kde budete jediný moderátor.",
|
||||
"info": "Info",
|
||||
"privacy": "Súkromie",
|
||||
"recentList": "Posledné",
|
||||
"recentListDelete": "Vymazať",
|
||||
"recentListEmpty": "Váš zoznam posledných hovorov je prázdny. Spojte sa s kolegami z Vášho tímu a potom tu nájdete všetky vaše stretnutia.",
|
||||
"reducedUIText": "Vitajte v {{app}}!",
|
||||
"roomNameAllowedChars": "Názov miestnosti by nemal obsahovať žiaden z týchto znakov: ?, &, :, ', \", %, #.",
|
||||
"reducedUIText": "Vítajte v {{app}}!",
|
||||
"roomname": "Zadajte názov miestnosti",
|
||||
"roomnameHint": "Zadajte názov alebo URL odkaz miestnosti ku ktorej sa chcete pripojiť. Názov si môžete vymyslieť - dajte ho vedieť ostatným účastníkom konferencie, ktorí ho sem zadajú.",
|
||||
"roomnameHint": "Zadajte názov alebo URL odkaz miestnosti ku ktorej sa chcete pripojiť. Pokial ste miestnosť vytvorili, uistite sa, že ostatný účastníci schôdzky zadajú rovnaké meno ako vy.",
|
||||
"sendFeedback": "Odoslať spätnú väzbu",
|
||||
"terms": "Podmienky používania",
|
||||
"title": "Zabezpečené, plnohodnotné a úplne bezplatné videokonferencie"
|
||||
},
|
||||
"lonelyMeetingExperience": {
|
||||
"button": "Pozvať ďalších",
|
||||
"youAreAlone": "Ste sám v tejto konferencii"
|
||||
},
|
||||
"helpView": {
|
||||
"header": "Centrum pomoci"
|
||||
},
|
||||
"lobby": {
|
||||
"knockingParticipantList": "Zoznam čakajúcich účastníkov",
|
||||
"allow": "Povoliť",
|
||||
"backToKnockModeButton": "Žiadne heslo, požiadať o vstup",
|
||||
"dialogTitle": "Čakáreň",
|
||||
"disableDialogContent": "Čakáreň je zapnutá. Táto funkcia zabezpečuje, že do konferencie nemôžu vstúpiť neželaní účastníci. Chcete ju vypnúť?",
|
||||
"disableDialogSubmit": "Vypnúť",
|
||||
"emailField": "Zadajte vašu e-mailovú adresu",
|
||||
"enableDialogPasswordField": "Nastaviť heslo (voliteľné)",
|
||||
"enableDialogSubmit": "Zapnúť",
|
||||
"enableDialogText": "Čakáreň umožňuje zabezpečiť konferenciu tým, že účastníci môžu do konferencie vstúpiť len po schválení moderátorom.",
|
||||
"enterPasswordButton": "Zadať heslo do konferencie",
|
||||
"enterPasswordTitle": "Zadajte heslo pre vstup do konferencie",
|
||||
"invalidPassword": "Nesprávne heslo",
|
||||
"joiningMessage": "Vstúpite do konferencie, keď niekto schváli vašu žiadosť",
|
||||
"joinWithPasswordMessage": "Vstupujem s heslom...",
|
||||
"joinRejectedMessage": "Vaša žiadosť bola zamietnutá moderátorom.",
|
||||
"joinTitle": "Vstup do konferencie",
|
||||
"joiningTitle": "Žiadam o vstup do konferencie...",
|
||||
"joiningWithPasswordTitle": "Vstupujem s heslom...",
|
||||
"knockButton": "Požiadať o vstup",
|
||||
"knockTitle": "Niekto žiada o vstup do konferencie",
|
||||
"nameField": "Zadajte vaše meno",
|
||||
"notificationLobbyAccessDenied": "Žiadosť {{targetParticipantName}} o vstup bola zamietnutá účastníkom {{originParticipantName}}",
|
||||
"notificationLobbyAccessGranted": "Žiadosť {{targetParticipantName}} o vstup bola povolená účastníkom {{originParticipantName}}",
|
||||
"notificationLobbyDisabled": "Účastník {{originParticipantName}} vypol čakáreň",
|
||||
"notificationLobbyEnabled": "Účastník {{originParticipantName}} zapol čakáreň",
|
||||
"notificationTitle": "Čakáreň",
|
||||
"passwordField": "Zadajte heslo do konferencie",
|
||||
"passwordJoinButton": "Vstúpiť",
|
||||
"reject": "Odmietnuť",
|
||||
"toggleLabel": "Zapnúť čakáreň"
|
||||
}
|
||||
}
|
||||
|
||||
1520
lang/main-sr.json
1520
lang/main-sr.json
File diff suppressed because it is too large
Load Diff
@@ -579,7 +579,7 @@
|
||||
},
|
||||
|
||||
"security": {
|
||||
"about": "Toplantınıza bir parola ekleyebilirsiniz. Katılımcıların toplantıya katılmasına izin verilmeden önce parolayı girmeleri gerekecektir.",
|
||||
"about": "Toplantınıza bir şifre ekleyebilirsiniz. Katılımcıların toplantıya katılmasına izin verilmeden önce şifreyi girmeleri gerekecektir.",
|
||||
"insecureRoomNameWarning": "Toplantı odası güvenli değil. Konferansınıza istenmeyen katılımcılar katılabilir.",
|
||||
"securityOptions": "Güvenlik Seçenekleri"
|
||||
},
|
||||
@@ -819,7 +819,7 @@
|
||||
"join": "Katılmak için dokunun",
|
||||
"roomname": "Oda adı girin"
|
||||
},
|
||||
"appDescription": "Durma ve tüm ekiple görüntülü sohbet et. Hatta tanıdığın herkesi davet et. {{app}} tüm gün, her gün ücretsiz olarak ve hesap gerektirmeden kullanabileceğiniz tamamen şifrelenmiş, % 100 özgür bir video konferans çözümüdür.",
|
||||
"appDescription": "Durma ve tüm ekiple görüntülü sohbet et. Hatta tanıdığın herkesi davet et. {{app}} tüm gün, her gün ücretsiz olarak kullanabileceğiniz, hesap gerektirmeden kullanbilieceğiniz tamamen şifrelenmiş, % 100 özgür bir video konferans çözümüdür.",
|
||||
"audioVideoSwitch": {
|
||||
"audio": "Ses",
|
||||
"video": "Görüntü"
|
||||
@@ -865,27 +865,27 @@
|
||||
|
||||
"lobby": {
|
||||
"allow": "İzin ver",
|
||||
"backToKnockModeButton": "Parola yok, bunun yerine katılmayı isteyin",
|
||||
"backToKnockModeButton": "Şifre yok, bunun yerine katılmayı isteyin",
|
||||
"dialogTitle": "Lobi modu",
|
||||
"disableDialogContent": "Lobi modu şu anda etkin. Bu özellik, istenmeyen katılımcıların toplantınıza katılamamasını sağlar. Devre dışı bırakmak istiyor musunuz?",
|
||||
"disableDialogSubmit": "Devre Dışı",
|
||||
"emailField": "E-posta adresinizi giriniz",
|
||||
"enableDialogPasswordField": "Parola belirleyin (isteğe bağlı)",
|
||||
"enableDialogPasswordField": "Şifre belirleyin (isteğe bağlı)",
|
||||
"enableDialogSubmit": "Etkin",
|
||||
"enableDialogText": "Lobi modu, toplantınızı yalnızca kişilerin bir moderatör tarafından resmi olarak onaylandıktan sonra girmelerine izin vererek korumanıza izin verir.",
|
||||
"enterPasswordButton": "Toplantı parolasını girin",
|
||||
"enterPasswordTitle": "Toplantıya katılmak için parola girin",
|
||||
"invalidPassword": "Geçersiz parola",
|
||||
"enterPasswordButton": "Toplantı şifresini girin",
|
||||
"enterPasswordTitle": "Toplantıya katılmak için şifre girin",
|
||||
"invalidPassword": "Geçersiz şifre",
|
||||
"joiningMessage": "Birisi isteğinizi kabul eder etmez toplantıya katılacaksınız",
|
||||
"joinWithPasswordMessage": "Parola ile katılmaya çalışıyorsunuz lütfen bekleyin...",
|
||||
"joinWithPasswordMessage": "Şifre ile katılmaya çalışıyorsunuz lütfen bekleyin...",
|
||||
"joinRejectedMessage": "Katılma isteğiniz bir moderatör tarafından reddedildi.",
|
||||
"joinTitle": "Toplantıya katıl",
|
||||
"joiningTitle": "Toplantıya katılma isteniyor...",
|
||||
"joiningWithPasswordTitle": "Parola ile katılıyor...",
|
||||
"joiningWithPasswordTitle": "Şifre ile katılıyor...",
|
||||
"knockButton": "Katılmak için sor",
|
||||
"knockTitle": "Birisi toplantıya katılmak istiyor",
|
||||
"nameField": "Adınızı giriniz",
|
||||
"passwordField": "Toplantı parolasını giriniz",
|
||||
"passwordField": "Toplantı şifresini giriniz",
|
||||
"passwordJoinButton": "Katıl",
|
||||
"reject": "Reddet",
|
||||
"toggleLabel": "Lobiyi etkinleştir"
|
||||
|
||||
@@ -99,7 +99,6 @@
|
||||
},
|
||||
"connectionindicator": {
|
||||
"address": "Address:",
|
||||
"audio_ssrc": "Audio SSRC:",
|
||||
"bandwidth": "Estimated bandwidth:",
|
||||
"bitrate": "Bitrate:",
|
||||
"bridgeCount": "Server count: ",
|
||||
@@ -127,12 +126,9 @@
|
||||
"remoteport": "Remote port:",
|
||||
"remoteport_plural": "Remote ports:",
|
||||
"resolution": "Resolution:",
|
||||
"savelogs": "Save logs",
|
||||
"participant_id": "Participant id:",
|
||||
"status": "Connection:",
|
||||
"transport": "Transport:",
|
||||
"transport_plural": "Transports:",
|
||||
"video_ssrc": "Video SSRC:"
|
||||
"transport_plural": "Transports:"
|
||||
},
|
||||
"dateUtils": {
|
||||
"earlier": "Earlier",
|
||||
|
||||
@@ -15,18 +15,13 @@ import {
|
||||
} from '../../react/features/base/conference';
|
||||
import { parseJWTFromURLParams } from '../../react/features/base/jwt';
|
||||
import { JitsiRecordingConstants } from '../../react/features/base/lib-jitsi-meet';
|
||||
import { pinParticipant } from '../../react/features/base/participants';
|
||||
import {
|
||||
processExternalDeviceRequest
|
||||
} from '../../react/features/device-selection/functions';
|
||||
import { isEnabled as isDropboxEnabled } from '../../react/features/dropbox';
|
||||
import { toggleE2EE } from '../../react/features/e2ee/actions';
|
||||
import { invite } from '../../react/features/invite';
|
||||
import {
|
||||
captureLargeVideoScreenshot,
|
||||
resizeLargeVideo,
|
||||
selectParticipantInLargeVideo
|
||||
} from '../../react/features/large-video/actions';
|
||||
import { selectParticipantInLargeVideo } from '../../react/features/large-video/actions';
|
||||
import { toggleLobbyMode } from '../../react/features/lobby/actions.web';
|
||||
import { RECORDING_TYPES } from '../../react/features/recording/constants';
|
||||
import { getActiveSession } from '../../react/features/recording/functions';
|
||||
@@ -121,19 +116,9 @@ function initCommands() {
|
||||
));
|
||||
}
|
||||
},
|
||||
'pin-participant': id => {
|
||||
logger.debug('Pin participant command received');
|
||||
sendAnalytics(createApiEvent('participant.pinned'));
|
||||
APP.store.dispatch(pinParticipant(id));
|
||||
},
|
||||
'proxy-connection-event': event => {
|
||||
APP.conference.onProxyConnectionEvent(event);
|
||||
},
|
||||
'resize-large-video': (width, height) => {
|
||||
logger.debug('Resize large video command received');
|
||||
sendAnalytics(createApiEvent('largevideo.resized'));
|
||||
APP.store.dispatch(resizeLargeVideo(width, height));
|
||||
},
|
||||
'send-tones': (options = {}) => {
|
||||
const { duration, tones, pause } = options;
|
||||
|
||||
@@ -349,21 +334,6 @@ function initCommands() {
|
||||
const { name } = request;
|
||||
|
||||
switch (name) {
|
||||
case 'capture-largevideo-screenshot' :
|
||||
APP.store.dispatch(captureLargeVideoScreenshot())
|
||||
.then(dataURL => {
|
||||
let error;
|
||||
|
||||
if (!dataURL) {
|
||||
error = new Error('No large video found!');
|
||||
}
|
||||
|
||||
callback({
|
||||
error,
|
||||
dataURL
|
||||
});
|
||||
});
|
||||
break;
|
||||
case 'invite': {
|
||||
const { invitees } = request;
|
||||
|
||||
@@ -1026,19 +996,6 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that the localStorage has changed.
|
||||
*
|
||||
* @param {string} localStorageContent - The new localStorageContent.
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyLocalStorageChanged(localStorageContent: string) {
|
||||
this._sendEvent({
|
||||
name: 'local-storage-changed',
|
||||
localStorageContent
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the allocated resources.
|
||||
*
|
||||
|
||||
52
modules/API/external/external_api.js
vendored
52
modules/API/external/external_api.js
vendored
@@ -1,4 +1,3 @@
|
||||
import { jitsiLocalStorage } from '@jitsi/js-utils/jitsi-local-storage';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
import { urlObjectToString } from '../../../react/features/base/util/uri';
|
||||
@@ -36,8 +35,6 @@ const commands = {
|
||||
hangup: 'video-hangup',
|
||||
muteEveryone: 'mute-everyone',
|
||||
password: 'password',
|
||||
pinParticipant: 'pin-participant',
|
||||
resizeLargeVideo: 'resize-large-video',
|
||||
sendEndpointTextMessage: 'send-endpoint-text-message',
|
||||
sendTones: 'send-tones',
|
||||
setLargeVideoParticipant: 'set-large-video-participant',
|
||||
@@ -269,7 +266,6 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
userInfo,
|
||||
e2eeKey
|
||||
} = parseArguments(args);
|
||||
const localStorageContent = jitsiLocalStorage.getItem('jitsiLocalStorage');
|
||||
|
||||
this._parentNode = parentNode;
|
||||
this._url = generateURL(domain, {
|
||||
@@ -279,10 +275,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
noSSL,
|
||||
roomName,
|
||||
devices,
|
||||
userInfo,
|
||||
appData: {
|
||||
localStorageContent
|
||||
}
|
||||
userInfo
|
||||
});
|
||||
this._createIFrame(height, width, onload);
|
||||
this._transport = new Transport({
|
||||
@@ -444,12 +437,10 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
const parsedWidth = parseSizeParam(width);
|
||||
|
||||
if (parsedHeight !== undefined) {
|
||||
this._height = height;
|
||||
this._frame.style.height = parsedHeight;
|
||||
}
|
||||
|
||||
if (parsedWidth !== undefined) {
|
||||
this._width = width;
|
||||
this._frame.style.width = parsedWidth;
|
||||
}
|
||||
}
|
||||
@@ -531,11 +522,6 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
case 'video-quality-changed':
|
||||
this._videoQuality = data.videoQuality;
|
||||
break;
|
||||
case 'local-storage-changed':
|
||||
jitsiLocalStorage.setItem('jitsiLocalStorage', data.localStorageContent);
|
||||
|
||||
// Since this is internal event we don't need to emit it to the consumer of the API.
|
||||
return true;
|
||||
}
|
||||
|
||||
const eventName = events[name];
|
||||
@@ -647,18 +633,6 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures the screenshot of the large video.
|
||||
*
|
||||
* @returns {Promise<string>} - Resolves with a base64 encoded image data of the screenshot
|
||||
* if large video is detected, an error otherwise.
|
||||
*/
|
||||
captureLargeVideoScreenshot() {
|
||||
return this._transport.sendRequest({
|
||||
name: 'capture-largevideo-screenshot'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the listeners and removes the Jitsi Meet frame.
|
||||
*
|
||||
@@ -930,17 +904,6 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Pins a participant's video on to the stage view.
|
||||
*
|
||||
* @param {string} participantId - Participant id (JID) of the participant
|
||||
* that needs to be pinned on the stage view.
|
||||
* @returns {void}
|
||||
*/
|
||||
pinParticipant(participantId) {
|
||||
this.executeCommand('pinParticipant', participantId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes event listener.
|
||||
*
|
||||
@@ -967,19 +930,6 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
eventList.forEach(event => this.removeEventListener(event));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes the large video container as per the dimensions provided.
|
||||
*
|
||||
* @param {number} width - Width that needs to be applied on the large video container.
|
||||
* @param {number} height - Height that needs to be applied on the large video container.
|
||||
* @returns {void}
|
||||
*/
|
||||
resizeLargeVideo(width, height) {
|
||||
if (width <= this._width && height <= this._height) {
|
||||
this.executeCommand('resizeLargeVideo', width, height);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes an event along to the local conference participant to establish
|
||||
* or update a direct peer connection. This is currently used for developing
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
*/
|
||||
const UIUtil = {
|
||||
|
||||
/**
|
||||
* Returns the available video width.
|
||||
*/
|
||||
getAvailableVideoWidth() {
|
||||
return window.innerWidth;
|
||||
},
|
||||
|
||||
/**
|
||||
* Escapes the given text.
|
||||
*/
|
||||
|
||||
@@ -15,12 +15,13 @@ import { VIDEO_TYPE } from '../../../react/features/base/media';
|
||||
import { CHAT_SIZE } from '../../../react/features/chat';
|
||||
import {
|
||||
updateKnownLargeVideoResolution
|
||||
} from '../../../react/features/large-video/actions';
|
||||
} from '../../../react/features/large-video';
|
||||
import { PresenceLabel } from '../../../react/features/presence-status';
|
||||
/* eslint-enable no-unused-vars */
|
||||
import UIEvents from '../../../service/UI/UIEvents';
|
||||
import { createDeferred } from '../../util/helpers';
|
||||
import AudioLevels from '../audio_levels/AudioLevels';
|
||||
import UIUtil from '../util/UIUtil';
|
||||
|
||||
import { VideoContainer, VIDEO_CONTAINER_TYPE } from './VideoContainer';
|
||||
|
||||
@@ -67,30 +68,7 @@ export default class LargeVideoManager {
|
||||
// use the same video container to handle desktop tracks
|
||||
this.addContainer(DESKTOP_CONTAINER_TYPE, this.videoContainer);
|
||||
|
||||
/**
|
||||
* The preferred width passed as an argument to {@link updateContainerSize}.
|
||||
*
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.preferredWidth = undefined;
|
||||
|
||||
/**
|
||||
* The preferred height passed as an argument to {@link updateContainerSize}.
|
||||
*
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.preferredHeight = undefined;
|
||||
|
||||
/**
|
||||
* The calculated width that will be used for the large video.
|
||||
* @type {number}
|
||||
*/
|
||||
this.width = 0;
|
||||
|
||||
/**
|
||||
* The calculated height that will be used for the large video.
|
||||
* @type {number}
|
||||
*/
|
||||
this.height = 0;
|
||||
|
||||
/**
|
||||
@@ -345,32 +323,20 @@ export default class LargeVideoManager {
|
||||
/**
|
||||
* Update container size.
|
||||
*/
|
||||
updateContainerSize(width, height) {
|
||||
if (typeof width === 'number') {
|
||||
this.preferredWidth = width;
|
||||
}
|
||||
if (typeof height === 'number') {
|
||||
this.preferredHeight = height;
|
||||
}
|
||||
|
||||
let widthToUse = this.preferredWidth || window.innerWidth;
|
||||
updateContainerSize() {
|
||||
let widthToUse = UIUtil.getAvailableVideoWidth();
|
||||
const { isOpen } = APP.store.getState()['features/chat'];
|
||||
|
||||
/**
|
||||
* If chat state is open, we re-compute the container width by subtracting the default width of
|
||||
* the chat. We re-compute the width again after the chat window is closed. This is needed when
|
||||
* custom styling is configured on the large video container through the iFrame API.
|
||||
*/
|
||||
if (isOpen && !this.resizedForChat) {
|
||||
if (isOpen) {
|
||||
/**
|
||||
* If chat state is open, we re-compute the container width
|
||||
* by subtracting the default width of the chat.
|
||||
*/
|
||||
widthToUse -= CHAT_SIZE;
|
||||
this.resizedForChat = true;
|
||||
} else if (this.resizedForChat) {
|
||||
this.resizedForChat = false;
|
||||
widthToUse += CHAT_SIZE;
|
||||
}
|
||||
|
||||
this.width = widthToUse;
|
||||
this.height = this.preferredHeight || window.innerHeight;
|
||||
this.height = window.innerHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -373,6 +373,7 @@ export default class RemoteVideo extends SmallVideo {
|
||||
|
||||
if (stream === this.videoStream) {
|
||||
this.videoStream = null;
|
||||
this.videoType = undefined;
|
||||
}
|
||||
|
||||
this.updateView();
|
||||
@@ -483,6 +484,7 @@ export default class RemoteVideo extends SmallVideo {
|
||||
|
||||
if (isVideo) {
|
||||
this.videoStream = stream;
|
||||
this.videoType = stream.videoType;
|
||||
} else {
|
||||
this.audioStream = stream;
|
||||
}
|
||||
|
||||
@@ -243,10 +243,6 @@ export default class SmallVideo {
|
||||
* or hidden
|
||||
*/
|
||||
setScreenSharing(isScreenSharing) {
|
||||
if (isScreenSharing === this.isScreenSharing) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isScreenSharing = isScreenSharing;
|
||||
this.updateView();
|
||||
this.updateStatusBar();
|
||||
|
||||
@@ -489,7 +489,7 @@ const VideoLayout = {
|
||||
onVideoTypeChanged(id, newVideoType) {
|
||||
const remoteVideo = remoteVideos[id];
|
||||
|
||||
if (!remoteVideo) {
|
||||
if (!remoteVideo || remoteVideo.videoType === newVideoType) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ export default {
|
||||
})
|
||||
.catch(err => {
|
||||
audioTrackError = err;
|
||||
showError && APP.store.dispatch(notifyMicError(err));
|
||||
showError && APP.store.disptach(notifyMicError(err));
|
||||
|
||||
return [];
|
||||
}));
|
||||
|
||||
787
package-lock.json
generated
787
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@@ -32,7 +32,7 @@
|
||||
"@atlaskit/theme": "7.0.2",
|
||||
"@atlaskit/toggle": "5.0.14",
|
||||
"@atlaskit/tooltip": "12.1.13",
|
||||
"@jitsi/js-utils": "1.0.2",
|
||||
"@jitsi/js-utils": "1.0.1",
|
||||
"@microsoft/microsoft-graph-client": "1.1.0",
|
||||
"@react-native-community/async-storage": "1.3.4",
|
||||
"@react-native-community/google-signin": "3.0.1",
|
||||
@@ -56,14 +56,13 @@
|
||||
"jquery-i18next": "1.2.1",
|
||||
"js-md5": "0.6.1",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#0cffc064e644ad87ff381cc6c4df1c1a9f2c73ff",
|
||||
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#43e7c853b834dc7ced0f81ee5f4b130444d85e95",
|
||||
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
|
||||
"lodash": "4.17.19",
|
||||
"moment": "2.19.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
"olm": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz",
|
||||
"pixelmatch": "5.1.0",
|
||||
"punycode": "2.1.1",
|
||||
"react": "16.9",
|
||||
"react-dom": "16.9",
|
||||
"react-emoji-render": "1.2.4",
|
||||
@@ -71,7 +70,7 @@
|
||||
"react-linkify": "1.0.0-alpha",
|
||||
"react-native": "github:jitsi/react-native#efd2aff5661d75a230e36406b698cfe0ee545be2",
|
||||
"react-native-background-timer": "2.4.0",
|
||||
"react-native-calendar-events": "github:jitsi/react-native-calendar-events#df48ecdc4e1e90c5352f803ddbab1fa7269b74a7",
|
||||
"react-native-calendar-events": "github:jitsi/react-native-calendar-events#928a80e2ffef0d7e84936d7e7e0acc4f53ee8470",
|
||||
"react-native-callstats": "3.61.0",
|
||||
"react-native-collapsible": "1.5.1",
|
||||
"react-native-default-preference": "1.4.2",
|
||||
@@ -84,7 +83,7 @@
|
||||
"react-native-swipeout": "2.3.6",
|
||||
"react-native-watch-connectivity": "0.4.3",
|
||||
"react-native-webrtc": "1.84.0",
|
||||
"react-native-webview": "10.9.0",
|
||||
"react-native-webview": "7.4.1",
|
||||
"react-native-youtube-iframe": "1.2.3",
|
||||
"react-redux": "7.1.0",
|
||||
"react-textarea-autosize": "7.1.0",
|
||||
@@ -93,7 +92,6 @@
|
||||
"redux-thunk": "2.2.0",
|
||||
"rnnoise-wasm": "github:jitsi/rnnoise-wasm.git#566a16885897704d6e6d67a1d5ac5d39781db2af",
|
||||
"rtcstats": "github:jitsi/rtcstats#v6.2.0",
|
||||
"stackblur-canvas": "2.3.0",
|
||||
"styled-components": "3.4.9",
|
||||
"util": "0.12.1",
|
||||
"uuid": "3.1.0",
|
||||
|
||||
@@ -57,15 +57,12 @@ export function resetAnalytics() {
|
||||
* @param {Store} store - The redux store in which the specified {@code action} is being dispatched.
|
||||
* @returns {Promise} Resolves with the handlers that have been successfully loaded.
|
||||
*/
|
||||
export async function createHandlers({ getState }: { getState: Function }) {
|
||||
export function createHandlers({ getState }: { getState: Function }) {
|
||||
getJitsiMeetGlobalNS().analyticsHandlers = [];
|
||||
window.analyticsHandlers = []; // Legacy support.
|
||||
|
||||
if (!isAnalyticsEnabled(getState)) {
|
||||
// Avoid all analytics processing if there are no handlers, since no event would be sent.
|
||||
analytics.dispose();
|
||||
|
||||
return [];
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
const state = getState();
|
||||
@@ -103,47 +100,43 @@ export async function createHandlers({ getState }: { getState: Function }) {
|
||||
};
|
||||
const handlers = [];
|
||||
|
||||
if (amplitudeAPPKey) {
|
||||
try {
|
||||
const amplitude = new AmplitudeHandler(handlerConstructorOptions);
|
||||
try {
|
||||
const amplitude = new AmplitudeHandler(handlerConstructorOptions);
|
||||
|
||||
analytics.amplitudeIdentityProps = amplitude.getIdentityProps();
|
||||
analytics.amplitudeIdentityProps = amplitude.getIdentityProps();
|
||||
|
||||
handlers.push(amplitude);
|
||||
} catch (e) {
|
||||
logger.error('Failed to initialize Amplitude handler', e);
|
||||
}
|
||||
}
|
||||
handlers.push(amplitude);
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (e) {}
|
||||
|
||||
if (matomoEndpoint && matomoSiteID) {
|
||||
try {
|
||||
const matomo = new MatomoHandler(handlerConstructorOptions);
|
||||
try {
|
||||
const matomo = new MatomoHandler(handlerConstructorOptions);
|
||||
|
||||
handlers.push(matomo);
|
||||
} catch (e) {
|
||||
logger.error('Failed to initialize Matomo handler', e);
|
||||
}
|
||||
}
|
||||
handlers.push(matomo);
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (e) {}
|
||||
|
||||
if (Array.isArray(scriptURLs) && scriptURLs.length > 0) {
|
||||
let externalHandlers;
|
||||
return (
|
||||
_loadHandlers(scriptURLs, handlerConstructorOptions)
|
||||
.then(externalHandlers => {
|
||||
handlers.push(...externalHandlers);
|
||||
if (handlers.length === 0) {
|
||||
// Throwing an error in order to dispose the analytics in the catch clause due to the lack of any
|
||||
// analytics handlers.
|
||||
throw new Error('No analytics handlers created!');
|
||||
}
|
||||
|
||||
try {
|
||||
externalHandlers = await _loadHandlers(scriptURLs, handlerConstructorOptions);
|
||||
handlers.push(...externalHandlers);
|
||||
} catch (e) {
|
||||
logger.error('Failed to initialize external analytics handlers', e);
|
||||
}
|
||||
}
|
||||
return handlers;
|
||||
})
|
||||
.catch(e => {
|
||||
analytics.dispose();
|
||||
if (handlers.length !== 0) {
|
||||
logger.error(e);
|
||||
}
|
||||
|
||||
// Avoid all analytics processing if there are no handlers, since no event would be sent.
|
||||
if (handlers.length === 0) {
|
||||
analytics.dispose();
|
||||
}
|
||||
return [];
|
||||
}));
|
||||
|
||||
logger.info(`Initialized ${handlers.length} analytics handlers`);
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -235,7 +228,7 @@ function _inIframe() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to load the scripts for the external analytics handlers and creates them.
|
||||
* Tries to load the scripts for the analytics handlers and creates them.
|
||||
*
|
||||
* @param {Array} scriptURLs - The array of script urls to load.
|
||||
* @param {Object} handlerConstructorOptions - The default options to pass when creating handlers.
|
||||
@@ -286,7 +279,7 @@ function _loadHandlers(scriptURLs = [], handlerConstructorOptions) {
|
||||
logger.warn(`Error creating analytics handler: ${error}`);
|
||||
}
|
||||
}
|
||||
logger.debug(`Loaded ${handlers.length} external analytics handlers`);
|
||||
logger.debug(`Loaded ${handlers.length} analytics handlers`);
|
||||
|
||||
return handlers;
|
||||
});
|
||||
|
||||
@@ -72,11 +72,6 @@ export default class AmplitudeHandler extends AbstractHandler {
|
||||
* @returns {Object}
|
||||
*/
|
||||
getIdentityProps() {
|
||||
// TODO: Remove when web and native Aplitude implementations are unified.
|
||||
if (navigator.product === 'ReactNative') {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
sessionId: amplitude.getInstance(this._amplitudeOptions).getSessionId(),
|
||||
deviceId: amplitude.getInstance(this._amplitudeOptions).options.deviceId,
|
||||
|
||||
@@ -294,8 +294,6 @@ export function maybeRedirectToWelcomePage(options: Object = {}) {
|
||||
if (enableClosePage) {
|
||||
if (isVpaasMeeting(getState())) {
|
||||
redirectToStaticPage('/');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const { isGuest, jwt } = getState()['features/base/jwt'];
|
||||
|
||||
@@ -15,6 +15,8 @@ export default [
|
||||
'abTesting',
|
||||
'analytics.disabled',
|
||||
'audioLevelsInterval',
|
||||
'autoRecord',
|
||||
'autoRecordToken',
|
||||
'apiLogLevels',
|
||||
'avgRtpStatsN',
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import { getLogger } from '../logging/functions';
|
||||
|
||||
export default getLogger('features/base/jitsi-local-storage');
|
||||
@@ -1,45 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import { jitsiLocalStorage } from '@jitsi/js-utils/jitsi-local-storage';
|
||||
|
||||
import { parseURLParams } from '../util/parseURLParams';
|
||||
|
||||
import logger from './logger';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
/**
|
||||
* Handles changes of the fake local storage.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function onFakeLocalStorageChanged() {
|
||||
APP.API.notifyLocalStorageChanged(jitsiLocalStorage.serialize());
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs initial setup of the jitsiLocalStorage.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function setupJitsiLocalStorage() {
|
||||
if (jitsiLocalStorage.isLocalStorageDisabled()) {
|
||||
const urlParams = parseURLParams(window.location);
|
||||
|
||||
try {
|
||||
const localStorageContent = JSON.parse(urlParams['appData.localStorageContent']);
|
||||
|
||||
if (typeof localStorageContent === 'object') {
|
||||
Object.keys(localStorageContent).forEach(key => {
|
||||
jitsiLocalStorage.setItem(key, localStorageContent[key]);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Can\'t parse localStorageContent.', error);
|
||||
}
|
||||
|
||||
jitsiLocalStorage.on('changed', onFakeLocalStorageChanged);
|
||||
}
|
||||
}
|
||||
|
||||
setupJitsiLocalStorage();
|
||||
@@ -1,6 +1,5 @@
|
||||
/* @flow */
|
||||
|
||||
import { jitsiLocalStorage } from '@jitsi/js-utils';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { isOnline } from '../net-info/selectors';
|
||||
@@ -52,8 +51,7 @@ export function initLib() {
|
||||
try {
|
||||
JitsiMeetJS.init({
|
||||
enableAnalyticsLogging: isAnalyticsEnabled(getState),
|
||||
...config,
|
||||
externalStorage: jitsiLocalStorage.isLocalStorageDisabled() ? jitsiLocalStorage : undefined
|
||||
...config
|
||||
});
|
||||
JitsiMeetJS.setNetworkInfo({
|
||||
isOnline: isOnline(state)
|
||||
|
||||
@@ -18,7 +18,7 @@ const { JavaScriptSandbox } = NativeModules;
|
||||
*/
|
||||
export async function loadConfig(url: string): Promise<Object> {
|
||||
try {
|
||||
const configTxt = await loadScript(url, 10 * 1000 /* Timeout in ms */, true /* skipeval */);
|
||||
const configTxt = await loadScript(url, 2.5 * 1000 /* Timeout in ms */, true /* skipeval */);
|
||||
const configJson = await JavaScriptSandbox.evaluate(`${configTxt}\nJSON.stringify(config);`);
|
||||
const config = JSON.parse(configJson);
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// @flow
|
||||
|
||||
import punycode from 'punycode';
|
||||
import React, { Component } from 'react';
|
||||
import ReactLinkify from 'react-linkify';
|
||||
import { Text } from 'react-native';
|
||||
@@ -69,7 +68,7 @@ export default class Linkify extends Component<Props> {
|
||||
key = { key }
|
||||
style = { this.props.linkStyle }
|
||||
url = { decoratedHref }>
|
||||
{ punycode.toASCII(decoratedText) }
|
||||
{decoratedText}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// @flow
|
||||
|
||||
import punycode from 'punycode';
|
||||
import React, { Component } from 'react';
|
||||
import ReactLinkify from 'react-linkify';
|
||||
|
||||
@@ -45,7 +44,7 @@ export default class Linkify extends Component<Props> {
|
||||
key = { key }
|
||||
rel = 'noopener noreferrer'
|
||||
target = '_blank'>
|
||||
{ punycode.toASCII(decoratedText) }
|
||||
{decoratedText}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,19 +24,35 @@ const _RIGHT_WATERMARK_STYLE = {
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The link used to navigate to on logo click.
|
||||
* The user selected url used to navigate to on logo click.
|
||||
*/
|
||||
_logoLink: string,
|
||||
_customLogoLink: string,
|
||||
|
||||
/**
|
||||
* The url for the logo.
|
||||
* The url of the user selected logo.
|
||||
*/
|
||||
_logoUrl: string,
|
||||
_customLogoUrl: string,
|
||||
|
||||
/**
|
||||
* If the Jitsi watermark should be displayed or not.
|
||||
* Whether or not the current user is logged in through a JWT.
|
||||
*/
|
||||
_showJitsiWatermark: boolean,
|
||||
_isGuest: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the current meeting is a vpaas one.
|
||||
*/
|
||||
_isVpaas: boolean,
|
||||
|
||||
/**
|
||||
* Flag used to signal that the logo can be displayed.
|
||||
* It becomes true after the user customization options are fetched.
|
||||
*/
|
||||
_readyToDisplayJitsiWatermark: boolean,
|
||||
|
||||
/**
|
||||
* Returns true if welcome page is visible at the moment.
|
||||
*/
|
||||
_welcomePageIsVisible: boolean,
|
||||
|
||||
/**
|
||||
* The default value for the Jitsi logo URL.
|
||||
@@ -59,11 +75,27 @@ type State = {
|
||||
*/
|
||||
brandWatermarkLink: string,
|
||||
|
||||
/**
|
||||
* The url to open when clicking the Jitsi watermark.
|
||||
*/
|
||||
jitsiWatermarkLink: string,
|
||||
|
||||
/**
|
||||
* Whether or not the brand watermark should be displayed.
|
||||
*/
|
||||
showBrandWatermark: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the Jitsi watermark should be displayed.
|
||||
*/
|
||||
showJitsiWatermark: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the Jitsi watermark should be displayed for users not
|
||||
* logged in through a JWT.
|
||||
*/
|
||||
showJitsiWatermarkForGuests: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the show the "powered by Jitsi.org" link.
|
||||
*/
|
||||
@@ -85,17 +117,29 @@ class Watermarks extends Component<Props, State> {
|
||||
super(props);
|
||||
|
||||
let showBrandWatermark;
|
||||
let showJitsiWatermark;
|
||||
let showJitsiWatermarkForGuests;
|
||||
|
||||
if (interfaceConfig.filmStripOnly) {
|
||||
showBrandWatermark = false;
|
||||
showJitsiWatermark = false;
|
||||
showJitsiWatermarkForGuests = false;
|
||||
} else {
|
||||
showBrandWatermark = interfaceConfig.SHOW_BRAND_WATERMARK;
|
||||
showJitsiWatermark = interfaceConfig.SHOW_JITSI_WATERMARK;
|
||||
showJitsiWatermarkForGuests
|
||||
= interfaceConfig.SHOW_WATERMARK_FOR_GUESTS;
|
||||
}
|
||||
|
||||
this.state = {
|
||||
brandWatermarkLink:
|
||||
showBrandWatermark ? interfaceConfig.BRAND_WATERMARK_LINK : '',
|
||||
jitsiWatermarkLink:
|
||||
showJitsiWatermark || showJitsiWatermarkForGuests
|
||||
? interfaceConfig.JITSI_WATERMARK_LINK : '',
|
||||
showBrandWatermark,
|
||||
showJitsiWatermark,
|
||||
showJitsiWatermarkForGuests,
|
||||
showPoweredBy: interfaceConfig.SHOW_POWERED_BY
|
||||
};
|
||||
}
|
||||
@@ -122,6 +166,55 @@ class Watermarks extends Component<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the watermark is ready to be displayed.
|
||||
*
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_canDisplayJitsiWatermark() {
|
||||
const {
|
||||
showJitsiWatermark,
|
||||
showJitsiWatermarkForGuests
|
||||
} = this.state;
|
||||
const {
|
||||
_isGuest,
|
||||
_readyToDisplayJitsiWatermark,
|
||||
_welcomePageIsVisible
|
||||
} = this.props;
|
||||
|
||||
return (_readyToDisplayJitsiWatermark
|
||||
&& (showJitsiWatermark || (_isGuest && showJitsiWatermarkForGuests)))
|
||||
|| _welcomePageIsVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the background image style.
|
||||
*
|
||||
* @private
|
||||
* @returns {string}
|
||||
*/
|
||||
_getBackgroundImageStyle() {
|
||||
const {
|
||||
_customLogoUrl,
|
||||
_isVpaas,
|
||||
defaultJitsiLogoURL
|
||||
} = this.props;
|
||||
let style = 'none';
|
||||
|
||||
if (_isVpaas) {
|
||||
if (_customLogoUrl) {
|
||||
style = `url(${_customLogoUrl})`;
|
||||
}
|
||||
} else {
|
||||
style = `url(${_customLogoUrl
|
||||
|| defaultJitsiLogoURL
|
||||
|| interfaceConfig.DEFAULT_LOGO_URL})`;
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a brand watermark if it is enabled.
|
||||
*
|
||||
@@ -161,28 +254,33 @@ class Watermarks extends Component<Props, State> {
|
||||
* @returns {ReactElement|null}
|
||||
*/
|
||||
_renderJitsiWatermark() {
|
||||
const {
|
||||
_logoLink,
|
||||
_logoUrl,
|
||||
_showJitsiWatermark
|
||||
} = this.props;
|
||||
let reactElement = null;
|
||||
|
||||
if (_showJitsiWatermark) {
|
||||
if (this._canDisplayJitsiWatermark()) {
|
||||
const backgroundImage = this._getBackgroundImageStyle();
|
||||
const link = this.props._customLogoLink || this.state.jitsiWatermarkLink;
|
||||
const additionalStyles = {};
|
||||
|
||||
if (backgroundImage === 'none') {
|
||||
additionalStyles.height = 0;
|
||||
additionalStyles.width = 0;
|
||||
}
|
||||
|
||||
const style = {
|
||||
backgroundImage: `url(${_logoUrl})`,
|
||||
backgroundImage,
|
||||
maxWidth: 140,
|
||||
maxHeight: 70
|
||||
maxHeight: 70,
|
||||
...additionalStyles
|
||||
};
|
||||
|
||||
reactElement = (<div
|
||||
className = 'watermark leftwatermark'
|
||||
style = { style } />);
|
||||
|
||||
if (_logoLink) {
|
||||
if (link) {
|
||||
reactElement = (
|
||||
<a
|
||||
href = { _logoLink }
|
||||
href = { link }
|
||||
target = '_new'>
|
||||
{ reactElement }
|
||||
</a>
|
||||
@@ -221,52 +319,27 @@ class Watermarks extends Component<Props, State> {
|
||||
* Maps parts of Redux store to component prop types.
|
||||
*
|
||||
* @param {Object} state - Snapshot of Redux store.
|
||||
* @param {Object} ownProps - Component's own props.
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state, ownProps) {
|
||||
function _mapStateToProps(state) {
|
||||
const { isGuest } = state['features/base/jwt'];
|
||||
const {
|
||||
customizationReady,
|
||||
customizationFailed,
|
||||
defaultBranding,
|
||||
useDynamicBrandingData,
|
||||
logoClickUrl,
|
||||
logoImageUrl
|
||||
} = state['features/dynamic-branding'];
|
||||
const isValidRoom = state['features/base/conference'].room;
|
||||
const {
|
||||
DEFAULT_LOGO_URL,
|
||||
JITSI_WATERMARK_LINK,
|
||||
SHOW_JITSI_WATERMARK,
|
||||
SHOW_JITSI_WATERMARK_FOR_GUESTS,
|
||||
filmStripOnly
|
||||
} = interfaceConfig;
|
||||
let _showJitsiWatermark = (!filmStripOnly
|
||||
&& (customizationReady && !customizationFailed)
|
||||
&& (SHOW_JITSI_WATERMARK || (isGuest && SHOW_JITSI_WATERMARK_FOR_GUESTS)))
|
||||
|| !isValidRoom;
|
||||
let _logoUrl = logoImageUrl;
|
||||
let _logoLink = logoClickUrl;
|
||||
|
||||
if (useDynamicBrandingData) {
|
||||
if (isVpaasMeeting(state)) {
|
||||
// don't show logo if request fails or no logo set for vpaas meetings
|
||||
_showJitsiWatermark = !customizationFailed && Boolean(logoImageUrl);
|
||||
} else if (defaultBranding) {
|
||||
_logoUrl = DEFAULT_LOGO_URL;
|
||||
_logoLink = JITSI_WATERMARK_LINK;
|
||||
}
|
||||
} else {
|
||||
// When there is no custom branding data use defaults
|
||||
_logoUrl = ownProps.defaultJitsiLogoURL || DEFAULT_LOGO_URL;
|
||||
_logoLink = JITSI_WATERMARK_LINK;
|
||||
}
|
||||
const { customizationReady, logoClickUrl, logoImageUrl } = state['features/dynamic-branding'];
|
||||
const { room } = state['features/base/conference'];
|
||||
|
||||
return {
|
||||
_logoLink,
|
||||
_logoUrl,
|
||||
_showJitsiWatermark
|
||||
/**
|
||||
* The indicator which determines whether the local participant is a
|
||||
* guest in the conference.
|
||||
*
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
_customLogoLink: logoClickUrl,
|
||||
_customLogoUrl: logoImageUrl,
|
||||
_isGuest: isGuest,
|
||||
_isVpaas: isVpaasMeeting(state),
|
||||
_readyToDisplayJitsiWatermark: customizationReady,
|
||||
_welcomePageIsVisible: !room
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -153,10 +153,12 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
const isVideoTrack = jitsiTrack.type !== MEDIA_TYPE.AUDIO;
|
||||
|
||||
if (isVideoTrack) {
|
||||
// Do not change the video mute state for local presenter tracks.
|
||||
if (jitsiTrack.type === MEDIA_TYPE.PRESENTER) {
|
||||
APP.conference.mutePresenter(muted);
|
||||
} else if (jitsiTrack.isLocal()) {
|
||||
}
|
||||
|
||||
// Make sure we change the video mute state only for camera tracks.
|
||||
if (jitsiTrack.isLocal() && jitsiTrack.videoType !== 'desktop') {
|
||||
APP.conference.setVideoMuteStatus(muted);
|
||||
} else {
|
||||
APP.UI.setVideoMuted(participantID, muted);
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
// @flow
|
||||
|
||||
/**
|
||||
* Downloads a JSON object.
|
||||
*
|
||||
* @param {Object} json - The JSON object to download.
|
||||
* @param {string} filename - The filename to give to the downloaded file.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function downloadJSON(json: Object, filename: string) {
|
||||
const data = encodeURIComponent(JSON.stringify(json, null, ' '));
|
||||
|
||||
const elem = document.createElement('a');
|
||||
|
||||
elem.download = filename;
|
||||
elem.href = `data:application/json;charset=utf-8,\n${data}`;
|
||||
elem.dataset.downloadurl = [ 'text/json', elem.download, elem.href ].join(':');
|
||||
elem.dispatchEvent(new MouseEvent('click', {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
}));
|
||||
}
|
||||
@@ -546,7 +546,7 @@ export function urlObjectToString(o: Object): ?string {
|
||||
|
||||
let { hash } = url;
|
||||
|
||||
for (const urlPrefix of [ 'config', 'interfaceConfig', 'devices', 'userInfo', 'appData' ]) {
|
||||
for (const urlPrefix of [ 'config', 'interfaceConfig', 'devices', 'userInfo' ]) {
|
||||
const urlParamsArray
|
||||
= _objectToURLParamsArray(
|
||||
o[`${urlPrefix}Overwrite`]
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import getRoomName from '../base/config/getRoomName';
|
||||
import { downloadJSON } from '../base/util/downloadJSON';
|
||||
|
||||
|
||||
/**
|
||||
* Create an action for saving the conference logs.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function saveLogs() {
|
||||
return (dispatch, getState) => {
|
||||
|
||||
const logs = getState()['features/base/connection'].connection.getLogs();
|
||||
const roomName = getRoomName() || '';
|
||||
|
||||
downloadJSON(logs, `meetlog-${roomName}.json`);
|
||||
};
|
||||
}
|
||||
@@ -1,17 +1,12 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { Icon, IconConnectionActive, IconConnectionInactive } from '../../../base/icons';
|
||||
import { JitsiParticipantConnectionStatus } from '../../../base/lib-jitsi-meet';
|
||||
import { MEDIA_TYPE } from '../../../base/media';
|
||||
import { Popover } from '../../../base/popover';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { getTrackByMediaTypeAndParticipant } from '../../../base/tracks';
|
||||
import { ConnectionStatsTable } from '../../../connection-stats';
|
||||
import { saveLogs } from '../../actions';
|
||||
import AbstractConnectionIndicator, {
|
||||
INDICATOR_DISPLAY_THRESHOLD,
|
||||
type Props as AbstractProps,
|
||||
@@ -67,22 +62,12 @@ type Props = AbstractProps & {
|
||||
*/
|
||||
alwaysVisible: boolean,
|
||||
|
||||
/**
|
||||
* The audio SSRC of this client.
|
||||
*/
|
||||
audioSsrc: number,
|
||||
|
||||
/**
|
||||
* The current condition of the user's connection, matching one of the
|
||||
* enumerated values in the library.
|
||||
*/
|
||||
connectionStatus: string,
|
||||
|
||||
/**
|
||||
* The Redux dispatch function.
|
||||
*/
|
||||
dispatch: Dispatch<any>,
|
||||
|
||||
/**
|
||||
* Whether or not clicking the indicator should display a popover for more
|
||||
* details.
|
||||
@@ -108,17 +93,7 @@ type Props = AbstractProps & {
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: Function,
|
||||
|
||||
/**
|
||||
* The video SSRC of this client.
|
||||
*/
|
||||
videoSsrc: number,
|
||||
|
||||
/**
|
||||
* Invoked to save the conference logs.
|
||||
*/
|
||||
_onSaveLogs: Function
|
||||
t: Function
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -378,7 +353,6 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
|
||||
|
||||
return (
|
||||
<ConnectionStatsTable
|
||||
audioSsrc = { this.props.audioSsrc }
|
||||
bandwidth = { bandwidth }
|
||||
bitrate = { bitrate }
|
||||
bridgeCount = { bridgeCount }
|
||||
@@ -388,67 +362,15 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
|
||||
framerate = { framerate }
|
||||
isLocalVideo = { this.props.isLocalVideo }
|
||||
maxEnabledResolution = { maxEnabledResolution }
|
||||
onSaveLogs = { this.props._onSaveLogs }
|
||||
onShowMore = { this._onToggleShowMore }
|
||||
packetLoss = { packetLoss }
|
||||
participantId = { this.props.participantId }
|
||||
region = { region }
|
||||
resolution = { resolution }
|
||||
serverRegion = { serverRegion }
|
||||
shouldShowMore = { this.state.showMoreStats }
|
||||
transport = { transport }
|
||||
videoSsrc = { this.props.videoSsrc } />
|
||||
transport = { transport } />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Maps redux actions to the props of the component.
|
||||
*
|
||||
* @param {Function} dispatch - The redux action {@code dispatch} function.
|
||||
* @returns {{
|
||||
* _onSaveLogs: Function,
|
||||
* }}
|
||||
* @private
|
||||
*/
|
||||
export function _mapDispatchToProps(dispatch: Dispatch<any>) {
|
||||
return {
|
||||
/**
|
||||
* Saves the conference logs.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
_onSaveLogs() {
|
||||
dispatch(saveLogs());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Maps part of the Redux state to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @param {Props} ownProps - The own props of the component.
|
||||
* @returns {Props}
|
||||
*/
|
||||
export function _mapStateToProps(state: Object, ownProps: Props) {
|
||||
|
||||
const conference = state['features/base/conference'].conference;
|
||||
|
||||
if (conference) {
|
||||
const firstVideoTrack = getTrackByMediaTypeAndParticipant(
|
||||
state['features/base/tracks'], MEDIA_TYPE.VIDEO, ownProps.participantId);
|
||||
const firstAudioTrack = getTrackByMediaTypeAndParticipant(
|
||||
state['features/base/tracks'], MEDIA_TYPE.AUDIO, ownProps.participantId);
|
||||
|
||||
return {
|
||||
audioSsrc: firstAudioTrack ? conference.getSsrcByTrack(firstAudioTrack.jitsiTrack) : undefined,
|
||||
videoSsrc: firstVideoTrack ? conference.getSsrcByTrack(firstVideoTrack.jitsiTrack) : undefined
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
export default translate(connect(_mapStateToProps, _mapDispatchToProps)(ConnectionIndicator));
|
||||
export default translate(ConnectionIndicator);
|
||||
|
||||
@@ -10,11 +10,6 @@ import { translate } from '../../base/i18n';
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The audio SSRC of this client.
|
||||
*/
|
||||
audioSsrc: number,
|
||||
|
||||
/**
|
||||
* Statistics related to bandwidth.
|
||||
* {{
|
||||
@@ -54,11 +49,6 @@ type Props = {
|
||||
*/
|
||||
e2eRtt: number,
|
||||
|
||||
/**
|
||||
* The endpoint id of this client.
|
||||
*/
|
||||
participantId: string,
|
||||
|
||||
/**
|
||||
* Statistics related to frame rates for each ssrc.
|
||||
* {{
|
||||
@@ -78,11 +68,6 @@ type Props = {
|
||||
*/
|
||||
maxEnabledResolution: number,
|
||||
|
||||
/**
|
||||
* Callback to invoke when the user clicks on the download logs link.
|
||||
*/
|
||||
onSaveLogs: Function,
|
||||
|
||||
/**
|
||||
* Callback to invoke when the show additional stats link is clicked.
|
||||
*/
|
||||
@@ -129,11 +114,6 @@ type Props = {
|
||||
*/
|
||||
t: Function,
|
||||
|
||||
/**
|
||||
* The video SSRC of this client.
|
||||
*/
|
||||
videoSsrc: number,
|
||||
|
||||
/**
|
||||
* Statistics related to transports.
|
||||
*/
|
||||
@@ -158,11 +138,9 @@ class ConnectionStatsTable extends Component<Props> {
|
||||
return (
|
||||
<div className = 'connection-info'>
|
||||
{ this._renderStatistics() }
|
||||
<div className = 'connection-actions'>
|
||||
{ isLocalVideo ? this._renderSaveLogs() : null}
|
||||
{ this._renderShowMoreLink() }
|
||||
</div>
|
||||
{ this.props.shouldShowMore ? this._renderAdditionalStats() : null }
|
||||
{ isLocalVideo ? this._renderShowMoreLink() : null }
|
||||
{ isLocalVideo && this.props.shouldShowMore
|
||||
? this._renderAdditionalStats() : null }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -175,17 +153,12 @@ class ConnectionStatsTable extends Component<Props> {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderAdditionalStats() {
|
||||
const { isLocalVideo } = this.props;
|
||||
|
||||
return (
|
||||
<table className = 'connection-info__container'>
|
||||
<tbody>
|
||||
{ isLocalVideo ? this._renderBandwidth() : null }
|
||||
{ isLocalVideo ? this._renderTransport() : null }
|
||||
{ isLocalVideo ? this._renderRegion() : null }
|
||||
{ this._renderAudioSsrc() }
|
||||
{ this._renderVideoSsrc() }
|
||||
{ this._renderParticipantId() }
|
||||
{ this._renderBandwidth() }
|
||||
{ this._renderTransport() }
|
||||
{ this._renderRegion() }
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
@@ -251,66 +224,6 @@ class ConnectionStatsTable extends Component<Props> {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a table row as a ReactElement for displaying the audio ssrc.
|
||||
* This will typically be something like "Audio SSRC: 12345".
|
||||
*
|
||||
* @returns {JSX.Element}
|
||||
* @private
|
||||
*/
|
||||
_renderAudioSsrc() {
|
||||
const { audioSsrc, t } = this.props;
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<span>{ t('connectionindicator.audio_ssrc') }</span>
|
||||
</td>
|
||||
<td>{ audioSsrc || 'N/A' }</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a table row as a ReactElement for displaying the video ssrc.
|
||||
* This will typically be something like "Video SSRC: 12345".
|
||||
*
|
||||
* @returns {JSX.Element}
|
||||
* @private
|
||||
*/
|
||||
_renderVideoSsrc() {
|
||||
const { videoSsrc, t } = this.props;
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<span>{ t('connectionindicator.video_ssrc') }</span>
|
||||
</td>
|
||||
<td>{ videoSsrc || 'N/A' }</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a table row as a ReactElement for displaying the endpoint id.
|
||||
* This will typically be something like "Endpoint id: 1e8fbg".
|
||||
*
|
||||
* @returns {JSX.Element}
|
||||
* @private
|
||||
*/
|
||||
_renderParticipantId() {
|
||||
const { participantId, t } = this.props;
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<span>{ t('connectionindicator.participant_id') }</span>
|
||||
</td>
|
||||
<td>{ participantId || 'N/A' }</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a a table row as a ReactElement for displaying codec, if present.
|
||||
* This will typically be something like "Codecs (A/V): Opus, vp8".
|
||||
@@ -542,26 +455,6 @@ class ConnectionStatsTable extends Component<Props> {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ReactElement for display a link to save the logs.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderSaveLogs() {
|
||||
return (
|
||||
<span>
|
||||
<a
|
||||
className = 'savelogs link'
|
||||
onClick = { this.props.onSaveLogs } >
|
||||
{ this.props.t('connectionindicator.savelogs') }
|
||||
</a>
|
||||
<span> | </span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a ReactElement for display a link to toggle showing additional
|
||||
* statistics.
|
||||
|
||||
@@ -3,11 +3,6 @@
|
||||
*/
|
||||
export const SET_DYNAMIC_BRANDING_DATA = 'SET_DYNAMIC_BRANDING_DATA';
|
||||
|
||||
/**
|
||||
* Action used to signal the customization failed.
|
||||
*/
|
||||
export const SET_DYNAMIC_BRANDING_FAILED = 'SET_DYNAMIC_BRANDING_FAILED';
|
||||
|
||||
/**
|
||||
* Action used to signal the branding elements are ready to be displayed
|
||||
*/
|
||||
|
||||
@@ -4,11 +4,7 @@ import { getLogger } from 'jitsi-meet-logger';
|
||||
|
||||
import { doGetJSON } from '../base/util';
|
||||
|
||||
import {
|
||||
SET_DYNAMIC_BRANDING_DATA,
|
||||
SET_DYNAMIC_BRANDING_FAILED,
|
||||
SET_DYNAMIC_BRANDING_READY
|
||||
} from './actionTypes';
|
||||
import { SET_DYNAMIC_BRANDING_DATA, SET_DYNAMIC_BRANDING_READY } from './actionTypes';
|
||||
import { extractFqnFromPath } from './functions';
|
||||
|
||||
const logger = getLogger(__filename);
|
||||
@@ -36,8 +32,6 @@ export function fetchCustomBrandingData() {
|
||||
return dispatch(setDynamicBrandingData(res));
|
||||
} catch (err) {
|
||||
logger.error('Error fetching branding data', err);
|
||||
|
||||
return dispatch(setDynamicBrandingFailed());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,14 +63,3 @@ function setDynamicBrandingReady() {
|
||||
type: SET_DYNAMIC_BRANDING_READY
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Action used to signal the branding request failed.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
function setDynamicBrandingFailed() {
|
||||
return {
|
||||
type: SET_DYNAMIC_BRANDING_FAILED
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
|
||||
import { ReducerRegistry } from '../base/redux';
|
||||
|
||||
import {
|
||||
SET_DYNAMIC_BRANDING_DATA,
|
||||
SET_DYNAMIC_BRANDING_FAILED,
|
||||
SET_DYNAMIC_BRANDING_READY
|
||||
} from './actionTypes';
|
||||
import { SET_DYNAMIC_BRANDING_DATA, SET_DYNAMIC_BRANDING_READY } from './actionTypes';
|
||||
|
||||
/**
|
||||
* The name of the redux store/state property which is the root of the redux
|
||||
@@ -15,80 +11,12 @@ import {
|
||||
const STORE_NAME = 'features/dynamic-branding';
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
/**
|
||||
* The custom background color for the LargeVideo.
|
||||
*
|
||||
* @public
|
||||
* @type {string}
|
||||
*/
|
||||
backgroundColor: '',
|
||||
|
||||
/**
|
||||
* The custom background image used on the LargeVideo.
|
||||
*
|
||||
* @public
|
||||
* @type {string}
|
||||
*/
|
||||
backgroundImageUrl: '',
|
||||
|
||||
/**
|
||||
* Flag indicating that the logo (JitsiWatermark) can be displayed.
|
||||
* This is used in order to avoid image flickering.
|
||||
*
|
||||
* @public
|
||||
* @type {boolean}
|
||||
*/
|
||||
customizationReady: false,
|
||||
|
||||
/**
|
||||
* Flag indicating that the dynamic branding data request has failed.
|
||||
* When the request fails there is no logo (JitsiWatermark) displayed.
|
||||
*
|
||||
* @public
|
||||
* @type {boolean}
|
||||
*/
|
||||
customizationFailed: false,
|
||||
|
||||
/**
|
||||
* Flag indicating that the dynamic branding has not been modified and should use
|
||||
* the default options.
|
||||
*
|
||||
* @public
|
||||
* @type {boolean}
|
||||
*/
|
||||
defaultBranding: true,
|
||||
|
||||
/**
|
||||
* The custom invite domain.
|
||||
*
|
||||
* @public
|
||||
* @type {string}
|
||||
*/
|
||||
inviteDomain: '',
|
||||
|
||||
/**
|
||||
* The custom url used when the user clicks the logo.
|
||||
*
|
||||
* @public
|
||||
* @type {string}
|
||||
*/
|
||||
logoClickUrl: '',
|
||||
|
||||
/**
|
||||
* The custom logo (JitisWatermark).
|
||||
*
|
||||
* @public
|
||||
* @type {string}
|
||||
*/
|
||||
logoImageUrl: '',
|
||||
|
||||
/**
|
||||
* Flag used to signal if the app should use a custom logo or not
|
||||
*
|
||||
* @public
|
||||
* @type {boolean}
|
||||
*/
|
||||
useDynamicBrandingData: false
|
||||
logoImageUrl: ''
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -97,33 +25,15 @@ const DEFAULT_STATE = {
|
||||
ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case SET_DYNAMIC_BRANDING_DATA: {
|
||||
const {
|
||||
backgroundColor,
|
||||
backgroundImageUrl,
|
||||
defaultBranding,
|
||||
inviteDomain,
|
||||
logoClickUrl,
|
||||
logoImageUrl
|
||||
} = action.value;
|
||||
const { backgroundColor, backgroundImageUrl, inviteDomain, logoClickUrl, logoImageUrl } = action.value;
|
||||
|
||||
return {
|
||||
backgroundColor,
|
||||
backgroundImageUrl,
|
||||
defaultBranding,
|
||||
inviteDomain,
|
||||
logoClickUrl,
|
||||
logoImageUrl,
|
||||
customizationFailed: false,
|
||||
customizationReady: true,
|
||||
useDynamicBrandingData: true
|
||||
};
|
||||
}
|
||||
case SET_DYNAMIC_BRANDING_FAILED: {
|
||||
return {
|
||||
...state,
|
||||
customizationReady: true,
|
||||
customizationFailed: true,
|
||||
useDynamicBrandingData: true
|
||||
customizationReady: true
|
||||
};
|
||||
}
|
||||
case SET_DYNAMIC_BRANDING_READY:
|
||||
@@ -131,6 +41,7 @@ ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
||||
...state,
|
||||
customizationReady: true
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
return state;
|
||||
|
||||
@@ -10,7 +10,6 @@ import { translate } from '../../../../base/i18n';
|
||||
import { JitsiRecordingConstants } from '../../../../base/lib-jitsi-meet';
|
||||
import { getLocalParticipant } from '../../../../base/participants';
|
||||
import { connect } from '../../../../base/redux';
|
||||
import { isVpaasMeeting } from '../../../../billing-counter/functions';
|
||||
import EmbedMeetingTrigger from '../../../../embed-meeting/components/EmbedMeetingTrigger';
|
||||
import { getActiveSession } from '../../../../recording';
|
||||
import { updateDialInNumbers } from '../../../actions';
|
||||
@@ -37,11 +36,6 @@ type Props = {
|
||||
*/
|
||||
_dialIn: Object,
|
||||
|
||||
/**
|
||||
* Whether or not embed meeting should be visible.
|
||||
*/
|
||||
_embedMeetingVisible: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not invite contacts should be visible.
|
||||
*/
|
||||
@@ -86,7 +80,6 @@ type Props = {
|
||||
function AddPeopleDialog({
|
||||
_conferenceName,
|
||||
_dialIn,
|
||||
_embedMeetingVisible,
|
||||
_inviteContactsVisible,
|
||||
_inviteUrl,
|
||||
_liveStreamViewURL,
|
||||
@@ -159,7 +152,7 @@ function AddPeopleDialog({
|
||||
<InviteByEmailSection
|
||||
inviteSubject = { inviteSubject }
|
||||
inviteText = { invite } />
|
||||
{ _embedMeetingVisible && <EmbedMeetingTrigger /> }
|
||||
<EmbedMeetingTrigger />
|
||||
<div className = 'invite-more-dialog separator' />
|
||||
{
|
||||
_liveStreamViewURL
|
||||
@@ -198,7 +191,6 @@ function mapStateToProps(state) {
|
||||
return {
|
||||
_conferenceName: getRoomName(state),
|
||||
_dialIn: state['features/invite'],
|
||||
_embedMeetingVisible: !isVpaasMeeting(state),
|
||||
_inviteContactsVisible: interfaceConfig.ENABLE_DIAL_OUT && !hideInviteContacts,
|
||||
_inviteUrl: getInviteURL(state),
|
||||
_liveStreamViewURL:
|
||||
|
||||
@@ -17,6 +17,8 @@ import {
|
||||
UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION
|
||||
} from './actionTypes';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
/**
|
||||
* Signals conference to select a participant.
|
||||
*
|
||||
@@ -48,7 +50,7 @@ export function selectParticipant() {
|
||||
|
||||
/**
|
||||
* Action to select the participant to be displayed in LargeVideo based on the
|
||||
* participant id provided. If a participant id is not provided, the LargeVideo
|
||||
* participant id provided. If a partcipant id is not provided, the LargeVideo
|
||||
* participant will be selected based on a variety of factors: If there is a
|
||||
* dominant or pinned speaker, or if there are remote tracks, etc.
|
||||
*
|
||||
@@ -1,3 +0,0 @@
|
||||
// @flow
|
||||
|
||||
export * from './actions.any';
|
||||
@@ -1,75 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
|
||||
import { MEDIA_TYPE } from '../base/media';
|
||||
import { getTrackByMediaTypeAndParticipant } from '../base/tracks';
|
||||
|
||||
export * from './actions.any';
|
||||
|
||||
/**
|
||||
* Captures a screenshot of the video displayed on the large video.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function captureLargeVideoScreenshot() {
|
||||
return (dispatch: Dispatch<any>, getState: Function): Promise<string> => {
|
||||
const state = getState();
|
||||
const largeVideo = state['features/large-video'];
|
||||
|
||||
if (!largeVideo) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
const tracks = state['features/base/tracks'];
|
||||
const { jitsiTrack } = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, largeVideo.participantId);
|
||||
const videoStream = jitsiTrack.getOriginalStream();
|
||||
|
||||
// Get the video element for the large video, cast HTMLElement to HTMLVideoElement to make flow happy.
|
||||
/* eslint-disable-next-line no-extra-parens*/
|
||||
const videoElement = ((document.getElementById('largeVideo'): any): HTMLVideoElement);
|
||||
|
||||
if (!videoElement) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// Create a HTML canvas and draw video on to the canvas.
|
||||
const [ track ] = videoStream.getVideoTracks();
|
||||
const { height, width } = track.getSettings() ?? track.getConstraints();
|
||||
const canvasElement = document.createElement('canvas');
|
||||
const ctx = canvasElement.getContext('2d');
|
||||
|
||||
canvasElement.style.display = 'none';
|
||||
canvasElement.height = parseInt(height, 10);
|
||||
canvasElement.width = parseInt(width, 10);
|
||||
ctx.drawImage(videoElement, 0, 0);
|
||||
const dataURL = canvasElement.toDataURL('image/png', 1.0);
|
||||
|
||||
// Cleanup.
|
||||
ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);
|
||||
canvasElement.remove();
|
||||
|
||||
return Promise.resolve(dataURL);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes the large video container based on the dimensions provided.
|
||||
*
|
||||
* @param {number} width - Width that needs to be applied on the large video container.
|
||||
* @param {number} height - Height that needs to be applied on the large video container.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function resizeLargeVideo(width: number, height: number) {
|
||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||
const state = getState();
|
||||
const largeVideo = state['features/large-video'];
|
||||
|
||||
if (largeVideo) {
|
||||
const largeVideoContainer = VideoLayout.getLargeVideo();
|
||||
|
||||
largeVideoContainer.updateContainerSize(width, height);
|
||||
largeVideoContainer.resize();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import { CONFERENCE_FAILED, CONFERENCE_JOINED } from '../base/conference';
|
||||
import { JitsiConferenceErrors, JitsiConferenceEvents } from '../base/lib-jitsi-meet';
|
||||
import { getFirstLoadableAvatarUrl, getParticipantDisplayName } from '../base/participants';
|
||||
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
|
||||
import { isTestModeEnabled } from '../base/testing';
|
||||
import { NOTIFICATION_TYPE, showNotification } from '../notifications';
|
||||
import { isPrejoinPageEnabled } from '../prejoin/functions';
|
||||
|
||||
@@ -194,5 +193,5 @@ function _maybeSendLobbyNotification(origin, message, { dispatch, getState }) {
|
||||
break;
|
||||
}
|
||||
|
||||
dispatch(showNotification(notificationProps, isTestModeEnabled(getState()) ? undefined : 5000));
|
||||
dispatch(showNotification(notificationProps, 5000));
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import { toState } from '../base/redux';
|
||||
|
||||
/**
|
||||
* Checks whether rtcstats is enabled or not.
|
||||
*
|
||||
* @param {Function|Object} stateful - The redux store or {@code getState} function.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isRtcstatsEnabled(stateful: Function | Object) {
|
||||
// TODO: Remove when rtcstats is fully cimpatible with mobile.
|
||||
if (navigator.product === 'ReactNative') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const state = toState(stateful);
|
||||
const config = state['features/base/config'];
|
||||
|
||||
return config?.analytics?.rtcstatsEnabled ?? false;
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import { getLocalParticipant } from '../base/participants';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
|
||||
import RTCStats from './RTCStats';
|
||||
import { isRtcstatsEnabled } from './functions';
|
||||
import logger from './logger';
|
||||
|
||||
/**
|
||||
@@ -26,7 +25,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
|
||||
switch (action.type) {
|
||||
case LIB_WILL_INIT: {
|
||||
if (isRtcstatsEnabled(state)) {
|
||||
if (analytics.rtcstatsEnabled) {
|
||||
// RTCStats "proxies" WebRTC functions such as GUM and RTCPeerConnection by rewriting the global
|
||||
// window functions. Because lib-jitsi-meet uses references to those functions that are taken on
|
||||
// init, we need to add these proxies before it initializes, otherwise lib-jitsi-meet will use the
|
||||
@@ -48,7 +47,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
break;
|
||||
}
|
||||
case CONFERENCE_JOINED: {
|
||||
if (isRtcstatsEnabled(state) && RTCStats.isInitialized()) {
|
||||
if (analytics.rtcstatsEnabled && RTCStats.isInitialized()) {
|
||||
// Once the conference started connect to the rtcstats server and send data.
|
||||
try {
|
||||
RTCStats.connect();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// @flow
|
||||
|
||||
import * as StackBlur from 'stackblur-canvas';
|
||||
import * as bodyPix from '@tensorflow-models/body-pix';
|
||||
|
||||
import {
|
||||
CLEAR_TIMEOUT,
|
||||
TIMEOUT_TICK,
|
||||
SET_TIMEOUT,
|
||||
CLEAR_INTERVAL,
|
||||
INTERVAL_TIMEOUT,
|
||||
SET_INTERVAL,
|
||||
timerWorkerScript
|
||||
} from './TimerWorker';
|
||||
|
||||
@@ -17,7 +17,6 @@ import {
|
||||
export default class JitsiStreamBlurEffect {
|
||||
_bpModel: Object;
|
||||
_inputVideoElement: HTMLVideoElement;
|
||||
_inputVideoCanvasElement: HTMLCanvasElement;
|
||||
_onMaskFrameTimer: Function;
|
||||
_maskFrameTimerWorker: Worker;
|
||||
_maskInProgress: boolean;
|
||||
@@ -44,7 +43,6 @@ export default class JitsiStreamBlurEffect {
|
||||
this._outputCanvasElement = document.createElement('canvas');
|
||||
this._outputCanvasElement.getContext('2d');
|
||||
this._inputVideoElement = document.createElement('video');
|
||||
this._inputVideoCanvasElement = document.createElement('canvas');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,8 +53,10 @@ export default class JitsiStreamBlurEffect {
|
||||
* @returns {void}
|
||||
*/
|
||||
async _onMaskFrameTimer(response: Object) {
|
||||
if (response.data.id === TIMEOUT_TICK) {
|
||||
await this._renderMask();
|
||||
if (response.data.id === INTERVAL_TIMEOUT) {
|
||||
if (!this._maskInProgress) {
|
||||
await this._renderMask();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,53 +67,20 @@ export default class JitsiStreamBlurEffect {
|
||||
* @returns {void}
|
||||
*/
|
||||
async _renderMask() {
|
||||
if (!this._maskInProgress) {
|
||||
this._maskInProgress = true;
|
||||
this._bpModel.segmentPerson(this._inputVideoElement, {
|
||||
internalResolution: 'low', // resized to 0.5 times of the original resolution before inference
|
||||
maxDetections: 1, // max. number of person poses to detect per image
|
||||
segmentationThreshold: 0.7, // represents probability that a pixel belongs to a person
|
||||
flipHorizontal: false,
|
||||
scoreThreshold: 0.2
|
||||
}).then(data => {
|
||||
this._segmentationData = data;
|
||||
this._maskInProgress = false;
|
||||
});
|
||||
}
|
||||
const inputCanvasCtx = this._inputVideoCanvasElement.getContext('2d');
|
||||
|
||||
inputCanvasCtx.drawImage(this._inputVideoElement, 0, 0);
|
||||
|
||||
const currentFrame = inputCanvasCtx.getImageData(
|
||||
0,
|
||||
0,
|
||||
this._inputVideoCanvasElement.width,
|
||||
this._inputVideoCanvasElement.height
|
||||
);
|
||||
|
||||
if (this._segmentationData) {
|
||||
const blurData = new ImageData(currentFrame.data.slice(), currentFrame.width, currentFrame.height);
|
||||
|
||||
StackBlur.imageDataRGB(blurData, 0, 0, currentFrame.width, currentFrame.height, 12);
|
||||
|
||||
for (let x = 0; x < this._outputCanvasElement.width; x++) {
|
||||
for (let y = 0; y < this._outputCanvasElement.height; y++) {
|
||||
const n = (y * this._outputCanvasElement.width) + x;
|
||||
|
||||
if (this._segmentationData.data[n] === 0) {
|
||||
currentFrame.data[n * 4] = blurData.data[n * 4];
|
||||
currentFrame.data[(n * 4) + 1] = blurData.data[(n * 4) + 1];
|
||||
currentFrame.data[(n * 4) + 2] = blurData.data[(n * 4) + 2];
|
||||
currentFrame.data[(n * 4) + 3] = blurData.data[(n * 4) + 3];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this._outputCanvasElement.getContext('2d').putImageData(currentFrame, 0, 0);
|
||||
this._maskFrameTimerWorker.postMessage({
|
||||
id: SET_TIMEOUT,
|
||||
timeMs: 1000 / 30
|
||||
this._maskInProgress = true;
|
||||
this._segmentationData = await this._bpModel.segmentPerson(this._inputVideoElement, {
|
||||
internalResolution: 'medium', // resized to 0.5 times of the original resolution before inference
|
||||
maxDetections: 1, // max. number of person poses to detect per image
|
||||
segmentationThreshold: 0.7 // represents probability that a pixel belongs to a person
|
||||
});
|
||||
this._maskInProgress = false;
|
||||
bodyPix.drawBokehEffect(
|
||||
this._outputCanvasElement,
|
||||
this._inputVideoElement,
|
||||
this._segmentationData,
|
||||
12, // Constant for background blur, integer values between 0-20
|
||||
7 // Constant for edge blur, integer values between 0-20
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,16 +110,14 @@ export default class JitsiStreamBlurEffect {
|
||||
|
||||
this._outputCanvasElement.width = parseInt(width, 10);
|
||||
this._outputCanvasElement.height = parseInt(height, 10);
|
||||
this._inputVideoCanvasElement.width = parseInt(width, 10);
|
||||
this._inputVideoCanvasElement.height = parseInt(height, 10);
|
||||
this._inputVideoElement.width = parseInt(width, 10);
|
||||
this._inputVideoElement.height = parseInt(height, 10);
|
||||
this._inputVideoElement.autoplay = true;
|
||||
this._inputVideoElement.srcObject = stream;
|
||||
this._inputVideoElement.onloadeddata = () => {
|
||||
this._maskFrameTimerWorker.postMessage({
|
||||
id: SET_TIMEOUT,
|
||||
timeMs: 1000 / 30
|
||||
id: SET_INTERVAL,
|
||||
timeMs: 1000 / parseInt(frameRate, 10)
|
||||
});
|
||||
};
|
||||
|
||||
@@ -166,7 +131,7 @@ export default class JitsiStreamBlurEffect {
|
||||
*/
|
||||
stopEffect() {
|
||||
this._maskFrameTimerWorker.postMessage({
|
||||
id: CLEAR_TIMEOUT
|
||||
id: CLEAR_INTERVAL
|
||||
});
|
||||
|
||||
this._maskFrameTimerWorker.terminate();
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
|
||||
/**
|
||||
* SET_TIMEOUT constant is used to set interval and it is set in
|
||||
* SET_INTERVAL constant is used to set interval and it is set in
|
||||
* the id property of the request.data property. timeMs property must
|
||||
* also be set. request.data example:
|
||||
*
|
||||
* {
|
||||
* id: SET_TIMEOUT,
|
||||
* id: SET_INTERVAL,
|
||||
* timeMs: 33
|
||||
* }
|
||||
*/
|
||||
export const SET_TIMEOUT = 1;
|
||||
export const SET_INTERVAL = 1;
|
||||
|
||||
/**
|
||||
* CLEAR_TIMEOUT constant is used to clear the interval and it is set in
|
||||
* CLEAR_INTERVAL constant is used to clear the interval and it is set in
|
||||
* the id property of the request.data property.
|
||||
*
|
||||
* {
|
||||
* id: CLEAR_TIMEOUT
|
||||
* id: CLEAR_INTERVAL
|
||||
* }
|
||||
*/
|
||||
export const CLEAR_TIMEOUT = 2;
|
||||
export const CLEAR_INTERVAL = 2;
|
||||
|
||||
/**
|
||||
* TIMEOUT_TICK constant is used as response and it is set in the id property.
|
||||
* INTERVAL_TIMEOUT constant is used as response and it is set in the id property.
|
||||
*
|
||||
* {
|
||||
* id: TIMEOUT_TICK
|
||||
* id: INTERVAL_TIMEOUT
|
||||
* }
|
||||
*/
|
||||
export const TIMEOUT_TICK = 3;
|
||||
export const INTERVAL_TIMEOUT = 3;
|
||||
|
||||
/**
|
||||
* The following code is needed as string to create a URL from a Blob.
|
||||
@@ -40,15 +40,15 @@ const code = `
|
||||
|
||||
onmessage = function(request) {
|
||||
switch (request.data.id) {
|
||||
case ${SET_TIMEOUT}: {
|
||||
timer = setTimeout(() => {
|
||||
postMessage({ id: ${TIMEOUT_TICK} });
|
||||
case ${SET_INTERVAL}: {
|
||||
timer = setInterval(() => {
|
||||
postMessage({ id: ${INTERVAL_TIMEOUT} });
|
||||
}, request.data.timeMs);
|
||||
break;
|
||||
}
|
||||
case ${CLEAR_TIMEOUT}: {
|
||||
case ${CLEAR_INTERVAL}: {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
clearInterval(timer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ import {
|
||||
import { connect, equals } from '../../../base/redux';
|
||||
import { OverflowMenuItem } from '../../../base/toolbox/components';
|
||||
import { getLocalVideoTrack, toggleScreensharing } from '../../../base/tracks';
|
||||
import { isVpaasMeeting } from '../../../billing-counter/functions';
|
||||
import { VideoBlurButton } from '../../../blur';
|
||||
import { CHAT_SIZE, ChatCounter, toggleChat } from '../../../chat';
|
||||
import { EmbedMeetingDialog } from '../../../embed-meeting';
|
||||
@@ -137,11 +136,6 @@ type Props = {
|
||||
*/
|
||||
_isGuest: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the current meeting belongs to a JaaS user.
|
||||
*/
|
||||
_isVpaasMeeting: boolean,
|
||||
|
||||
/**
|
||||
* The ID of the local participant.
|
||||
*/
|
||||
@@ -977,15 +971,6 @@ class Toolbox extends Component<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the profile button is visible and false otherwise.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isEmbedMeetingVisible() {
|
||||
return !this.props._isVpaasMeeting && this._shouldShowButton('embedmeeting');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the profile button is visible and false otherwise.
|
||||
*
|
||||
@@ -1062,7 +1047,7 @@ class Toolbox extends Component<Props, State> {
|
||||
key = 'stats'
|
||||
onClick = { this._onToolbarOpenSpeakerStats }
|
||||
text = { t('toolbar.speakerStats') } />,
|
||||
this._isEmbedMeetingVisible()
|
||||
this._shouldShowButton('embedmeeting')
|
||||
&& <OverflowMenuItem
|
||||
accessibilityLabel = { t('toolbar.accessibilityLabel.embedMeeting') }
|
||||
icon = { IconCodeBlock }
|
||||
@@ -1448,7 +1433,6 @@ function _mapStateToProps(state) {
|
||||
_dialog: Boolean(state['features/base/dialog'].component),
|
||||
_feedbackConfigured: Boolean(callStatsID),
|
||||
_isGuest: state['features/base/jwt'].isGuest,
|
||||
_isVpaasMeeting: isVpaasMeeting(state),
|
||||
_fullScreen: fullScreen,
|
||||
_tileViewEnabled: shouldDisplayTileView(state),
|
||||
_localParticipantID: localParticipant.id,
|
||||
|
||||
@@ -5,7 +5,7 @@ import debounce from 'lodash/debounce';
|
||||
import { pinParticipant, getPinnedParticipant } from '../base/participants';
|
||||
import { StateListenerRegistry, equals } from '../base/redux';
|
||||
import { isFollowMeActive } from '../follow-me';
|
||||
import { selectParticipant } from '../large-video/actions';
|
||||
import { selectParticipant } from '../large-video';
|
||||
|
||||
import { setParticipantsWithScreenShare } from './actions';
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
local new_throttle = require "util.throttle".create;
|
||||
local st = require "util.stanza";
|
||||
|
||||
local token_util = module:require "token/util".new(module);
|
||||
@@ -11,19 +10,12 @@ if token_util == nil then
|
||||
return;
|
||||
end
|
||||
|
||||
-- The maximum number of simultaneous calls,
|
||||
-- and also the maximum number of new calls per minute that a session is allowed to create.
|
||||
local limit_outgoing_calls;
|
||||
local function load_config()
|
||||
limit_outgoing_calls = module:get_option_number("max_number_outgoing_calls", -1);
|
||||
end
|
||||
load_config();
|
||||
-- configuration to limit number of outgoing calls
|
||||
local LIMIT_OUTGOING_CALLS = module:get_option_number("max_number_outgoing_calls", -1);
|
||||
|
||||
-- Header names to use to push extra data extracted from token, if any
|
||||
local OUT_INITIATOR_USER_ATTR_NAME = "X-outbound-call-initiator-user";
|
||||
local OUT_INITIATOR_GROUP_ATTR_NAME = "X-outbound-call-initiator-group";
|
||||
local OUTGOING_CALLS_THROTTLE_INTERVAL = 60; -- if max_number_outgoing_calls is enabled it will be
|
||||
-- the max number of outgoing calls a user can try for a minute
|
||||
|
||||
-- filters rayo iq in case of requested from not jwt authenticated sessions
|
||||
-- or if the session has features in user context and it doesn't mention
|
||||
@@ -61,21 +53,15 @@ module:hook("pre-iq/full", function(event)
|
||||
end
|
||||
|
||||
-- now lets check any limits if configured
|
||||
if limit_outgoing_calls > 0 then
|
||||
if not session.dial_out_throttle then
|
||||
module:log("debug", "Enabling dial-out throttle session=%s.", session);
|
||||
session.dial_out_throttle = new_throttle(limit_outgoing_calls, OUTGOING_CALLS_THROTTLE_INTERVAL);
|
||||
end
|
||||
|
||||
if not session.dial_out_throttle:poll(1) -- we first check the throttle so we can mark one incoming dial for the balance
|
||||
or get_concurrent_outgoing_count(session.jitsi_meet_context_user["id"], session.jitsi_meet_context_group)
|
||||
>= limit_outgoing_calls
|
||||
then
|
||||
module:log("warn",
|
||||
"Filtering stanza dial, stanza:%s, outgoing calls limit reached", tostring(stanza));
|
||||
session.send(st.error_reply(stanza, "cancel", "resource-constraint"));
|
||||
return true;
|
||||
end
|
||||
if LIMIT_OUTGOING_CALLS > 0
|
||||
and get_concurrent_outgoing_count(
|
||||
session.jitsi_meet_context_user["id"],
|
||||
session.jitsi_meet_context_group) >= LIMIT_OUTGOING_CALLS
|
||||
then
|
||||
module:log("warn",
|
||||
"Filtering stanza dial, stanza:%s, outgoing calls limit reached", tostring(stanza));
|
||||
session.send(st.error_reply(stanza, "cancel", "resource-constraint"));
|
||||
return true;
|
||||
end
|
||||
|
||||
-- now lets insert token information if any
|
||||
@@ -177,4 +163,3 @@ function get_concurrent_outgoing_count(context_user, context_group)
|
||||
return count;
|
||||
end
|
||||
|
||||
module:hook_global('config-reloaded', load_config);
|
||||
|
||||
@@ -11,7 +11,7 @@ const hints = [
|
||||
];
|
||||
|
||||
/**
|
||||
* Get a random hint message from hint array.
|
||||
* Get a random hint meessage from hint array.
|
||||
*
|
||||
* @return {string} the hint message.
|
||||
*/
|
||||
|
||||
@@ -142,8 +142,7 @@ const config = {
|
||||
// value that is a mock (/index.js).
|
||||
__filename: true,
|
||||
|
||||
// Provide some empty Node modules (required by olm).
|
||||
crypto: 'empty',
|
||||
// Provide an empty 'fs' module.
|
||||
fs: 'empty'
|
||||
},
|
||||
optimization: {
|
||||
@@ -191,7 +190,7 @@ module.exports = [
|
||||
entry: {
|
||||
'app.bundle': './app.js'
|
||||
},
|
||||
performance: getPerformanceHints(4 * 1024 * 1024)
|
||||
performance: getPerformanceHints(4.5 * 1024 * 1024)
|
||||
}),
|
||||
Object.assign({}, config, {
|
||||
entry: {
|
||||
|
||||
Reference in New Issue
Block a user