mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-01-29 01:50:18 +00:00
Compare commits
229 Commits
update-js-
...
4100
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fdb7c176c | ||
|
|
a8da6d4095 | ||
|
|
01fc098d4b | ||
|
|
b50b30e3eb | ||
|
|
1b8e5d0244 | ||
|
|
908712b96f | ||
|
|
a41bda73ff | ||
|
|
75ea0070e2 | ||
|
|
65a8091e53 | ||
|
|
7fea8e2e6c | ||
|
|
d388a7bd3c | ||
|
|
a48aa2b999 | ||
|
|
b3f16926d4 | ||
|
|
f646bc7a7a | ||
|
|
e90b60d661 | ||
|
|
bdd129b9a2 | ||
|
|
4c635a2a63 | ||
|
|
2b526557e4 | ||
|
|
eee1f50ed2 | ||
|
|
e9562adddf | ||
|
|
8accd9e433 | ||
|
|
caabdadf19 | ||
|
|
062bc13d4f | ||
|
|
a56e451536 | ||
|
|
acbf641fb4 | ||
|
|
a18fd1cdb3 | ||
|
|
9be78c60eb | ||
|
|
a45cbf41ef | ||
|
|
5b53232964 | ||
|
|
d4d4490aa9 | ||
|
|
0fd0897531 | ||
|
|
360383440e | ||
|
|
1a40672427 | ||
|
|
1ffd75c0a6 | ||
|
|
77d38731e9 | ||
|
|
13f76c2cce | ||
|
|
9ad87f3706 | ||
|
|
eea8fef044 | ||
|
|
c2cb4ea6b6 | ||
|
|
d6cf0c0afd | ||
|
|
f5faf5bbaa | ||
|
|
363982fad4 | ||
|
|
62f47d5b87 | ||
|
|
223e8560ca | ||
|
|
2085851179 | ||
|
|
47bc6f0470 | ||
|
|
c5686386fa | ||
|
|
e1cededb76 | ||
|
|
268dc33324 | ||
|
|
baaf55a2ab | ||
|
|
a8252103ea | ||
|
|
b0ab51af90 | ||
|
|
69b20cd945 | ||
|
|
8bb0141c1a | ||
|
|
ed766c6fe2 | ||
|
|
d883bae925 | ||
|
|
62d3d1f294 | ||
|
|
dbfed573ac | ||
|
|
640b9bfd52 | ||
|
|
dac6d9d63c | ||
|
|
0662da58b4 | ||
|
|
d7d4ea819f | ||
|
|
2c6cac6526 | ||
|
|
f53251f104 | ||
|
|
8e01f769d9 | ||
|
|
8c4656a3c8 | ||
|
|
a5a36aa1e1 | ||
|
|
6939939a0f | ||
|
|
c60671e008 | ||
|
|
8e4e1f139a | ||
|
|
b608051177 | ||
|
|
2dad7e920b | ||
|
|
be2d20e20e | ||
|
|
fd11c36bc3 | ||
|
|
60148b6439 | ||
|
|
62b4c97423 | ||
|
|
f08fa1e374 | ||
|
|
e5b563ba46 | ||
|
|
c41047344f | ||
|
|
6ae148403d | ||
|
|
b5676c3729 | ||
|
|
3ab6b97b8b | ||
|
|
5ea8e198c7 | ||
|
|
2ad6bfbc20 | ||
|
|
6ce27ef10d | ||
|
|
93ef8495ca | ||
|
|
94a15914d0 | ||
|
|
851976ebdf | ||
|
|
57bb2ead36 | ||
|
|
027c6ddad0 | ||
|
|
8648a5a998 | ||
|
|
c83b30558d | ||
|
|
057dfc8194 | ||
|
|
5eae0b58e9 | ||
|
|
1538107e93 | ||
|
|
cd1862a2d3 | ||
|
|
147a076f5d | ||
|
|
9bdaea4069 | ||
|
|
547d1547bb | ||
|
|
39853e048b | ||
|
|
8b454b5196 | ||
|
|
e2788e0fb2 | ||
|
|
b1d1599a1c | ||
|
|
cef98f457f | ||
|
|
6b0e8aab11 | ||
|
|
086889ed70 | ||
|
|
516e5af118 | ||
|
|
afe1b4b0f9 | ||
|
|
8790ad6013 | ||
|
|
8bbc04d4db | ||
|
|
4fda428be1 | ||
|
|
f972ebfe9e | ||
|
|
3dfcc8d80e | ||
|
|
33ebd241a9 | ||
|
|
cb6fbb0f03 | ||
|
|
0077ee29c5 | ||
|
|
551db30cc7 | ||
|
|
1bd930a3cb | ||
|
|
e0563a743f | ||
|
|
a4ab7ea95f | ||
|
|
b50d6e43d0 | ||
|
|
f9fcb46036 | ||
|
|
4824c8714a | ||
|
|
be56521267 | ||
|
|
b7eda8df7a | ||
|
|
d632b6e13e | ||
|
|
dff7d661ca | ||
|
|
edb8ecd542 | ||
|
|
b64112432d | ||
|
|
d8963bc903 | ||
|
|
5c39a2f6a6 | ||
|
|
a72928a9e7 | ||
|
|
e2ea26eb1f | ||
|
|
9962a2ea61 | ||
|
|
07e203ce8d | ||
|
|
638fdf0370 | ||
|
|
6ce1eaba24 | ||
|
|
4780e48be8 | ||
|
|
7776f0a98c | ||
|
|
2eede7e76b | ||
|
|
72a7bd0a68 | ||
|
|
9085cbf363 | ||
|
|
be80f26086 | ||
|
|
a876f78fd7 | ||
|
|
73d948d150 | ||
|
|
c5aa555816 | ||
|
|
7902223f09 | ||
|
|
ac117cd50d | ||
|
|
f2df5906f6 | ||
|
|
0fcecaf18f | ||
|
|
8cc4b73722 | ||
|
|
c08f5c7e18 | ||
|
|
2e0f3ae84f | ||
|
|
41bfb4c7ec | ||
|
|
4a12cdfac7 | ||
|
|
7b34fb89d1 | ||
|
|
4ec438d3f3 | ||
|
|
e79633b0ca | ||
|
|
49a9934c41 | ||
|
|
193d19ce21 | ||
|
|
fe83d87d2d | ||
|
|
b4a2327264 | ||
|
|
d9edf661dd | ||
|
|
e32f367b0c | ||
|
|
2b181673b5 | ||
|
|
87a058eaa4 | ||
|
|
eef0f5ed97 | ||
|
|
1751fc7635 | ||
|
|
4aa58f041f | ||
|
|
39d789a088 | ||
|
|
2654c77f2c | ||
|
|
7af88e5c4f | ||
|
|
ffdd4f2eed | ||
|
|
0b0a19ea5c | ||
|
|
b10aa422ca | ||
|
|
b706972acb | ||
|
|
5574221044 | ||
|
|
0f4369a9a9 | ||
|
|
0c2e13a453 | ||
|
|
2f817b6633 | ||
|
|
678ed605d7 | ||
|
|
84714ba3bd | ||
|
|
b8963629bf | ||
|
|
47cffeb00a | ||
|
|
b70633ef24 | ||
|
|
145596ac6a | ||
|
|
76607bbad8 | ||
|
|
36113fd54f | ||
|
|
f86ace17d8 | ||
|
|
0e16008085 | ||
|
|
f66a919e08 | ||
|
|
8115fb5e78 | ||
|
|
c9f26dc7ac | ||
|
|
7321f706bb | ||
|
|
9b5f135dae | ||
|
|
dbbdcb0b00 | ||
|
|
06ae1861ee | ||
|
|
e0afd8fadb | ||
|
|
953f838a2a | ||
|
|
bf5f1f0168 | ||
|
|
cdf977ff3f | ||
|
|
ee1dc9dd8e | ||
|
|
7bec68e492 | ||
|
|
97fff02c15 | ||
|
|
b372b2ccf2 | ||
|
|
d00ead932b | ||
|
|
bb2b1b58ec | ||
|
|
ceeea7314c | ||
|
|
9d6a93119b | ||
|
|
08be68cda4 | ||
|
|
3a2081ffed | ||
|
|
57d14d9517 | ||
|
|
c5e693f14a | ||
|
|
a9da047d3a | ||
|
|
171b065db1 | ||
|
|
9da0b7fee3 | ||
|
|
716c9eb46f | ||
|
|
a85c72d859 | ||
|
|
0ba567856e | ||
|
|
7f1eb83dbd | ||
|
|
6e4c1f64d8 | ||
|
|
82aa51770a | ||
|
|
990c77bd3d | ||
|
|
5bb23b2d17 | ||
|
|
9cc05ef838 | ||
|
|
a21e3a1946 | ||
|
|
c05ca1d9fc | ||
|
|
1b05d7269c | ||
|
|
86ebfe8dad |
@@ -9,7 +9,7 @@ Thank you for suggesting an idea to make Jitsi Meet better.
|
||||
|
||||
Please fill in as much of the template below as you're able.
|
||||
|
||||
Note that the ultimate decission for implementing features lies on the Jitsi team, not all feature requests shall be accepted.
|
||||
Note that the ultimate decision for implementing features lies on the Jitsi team, not all feature requests shall be accepted.
|
||||
-->
|
||||
|
||||
**Is your feature request related to a problem you are facing?**
|
||||
10
.github/ISSUE_TEMPLATE/2-help.md
vendored
10
.github/ISSUE_TEMPLATE/2-help.md
vendored
@@ -1,10 +0,0 @@
|
||||
---
|
||||
name: Need help with Jitsi Meet?
|
||||
about: Please ask it in our community at https://community.jitsi.org
|
||||
|
||||
---
|
||||
|
||||
If you have a question about Jitsi Meet that is not a bug report or feature
|
||||
request, please post it in https://community.jitsi.org
|
||||
|
||||
Questions posted to this repository will be closed.
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Need help with Jitsi Meet?
|
||||
url: https://community.jitsi.org
|
||||
about: Please ask it in our community.
|
||||
2
Makefile
2
Makefile
@@ -84,7 +84,7 @@ dev: deploy-init deploy-css deploy-rnnoise-binary deploy-lib-jitsi-meet deploy-l
|
||||
|
||||
source-package:
|
||||
mkdir -p source_package/jitsi-meet/css && \
|
||||
cp -r *.js *.html connection_optimization favicon.ico fonts images libs static sounds LICENSE lang source_package/jitsi-meet && \
|
||||
cp -r *.js *.html resources/*.txt connection_optimization favicon.ico fonts images libs static sounds LICENSE lang source_package/jitsi-meet && \
|
||||
cp css/all.css source_package/jitsi-meet/css && \
|
||||
(cd source_package ; tar cjf ../jitsi-meet.tar.bz2 jitsi-meet) && \
|
||||
rm -rf source_package
|
||||
|
||||
22
README.md
22
README.md
@@ -1,8 +1,8 @@
|
||||
# Jitsi Meet - Secure, Simple and Scalable Video Conferences
|
||||
|
||||
Jitsi Meet is an open-source (Apache) WebRTC JavaScript application that uses [Jitsi Videobridge](https://jitsi.org/videobridge) to provide high quality, [secure](#security) and scalable video conferences. Jitsi Meet in action can be seen at [here at the session #482 of the VoIP Users Conference](http://youtu.be/7vFUVClsNh0).
|
||||
Jitsi Meet is an open-source (Apache) WebRTC JavaScript application that uses [Jitsi Videobridge](https://jitsi.org/videobridge) to provide high quality, [secure](https://jitsi.org/security) and scalable video conferences. Jitsi Meet in action can be seen at [here at the session #482 of the VoIP Users Conference](http://youtu.be/7vFUVClsNh0).
|
||||
|
||||
The Jitsi Meet client runs in your browser, without installing anything else on your computer. You can try it out at https://meet.jit.si .
|
||||
The Jitsi Meet client runs in your browser, without installing anything else on your computer. You can try it out at https://meet.jit.si.
|
||||
|
||||
Jitsi Meet allows very efficient collaboration. Users can stream their desktop or only some windows. It also supports shared document editing with Etherpad.
|
||||
|
||||
@@ -61,25 +61,13 @@ Jitsi Meet provides a very flexible way of embedding in external applications by
|
||||
|
||||
## Security
|
||||
|
||||
WebRTC does not (yet) provide a way of conducting multi-party conversations with end-to-end encryption.
|
||||
Unless you consistently compare DTLS fingerprints with your peers vocally, the same goes for one-to-one calls.
|
||||
As a result, your stream is encrypted on the network but decrypted on the machine that hosts the bridge when using Jitsi Meet.
|
||||
The security section here was starting to feel a bit too succinct for the complexity of the topic, so we created a post that covers the topic much more broadly here: https://jitsi.org/security
|
||||
|
||||
The Jitsi Meet architecture allows you to deploy your own version, including
|
||||
all server components. In that case, your security guarantees will be roughly
|
||||
equivalent to a direct one-to-one WebRTC call. This is the uniqueness of
|
||||
Jitsi Meet in terms of security.
|
||||
|
||||
The [meet.jit.si](https://meet.jit.si) service is maintained by the Jitsi team
|
||||
at [8x8](https://8x8.com).
|
||||
The section on end-to-end encryption in that document is likely going to be one of the key points of interest: https://jitsi.org/security/#e2ee
|
||||
|
||||
## Security issues
|
||||
|
||||
We take security very seriously and develop all Jitsi projects to be secure and safe.
|
||||
|
||||
If you find (or simply suspect) a security issue in any of the Jitsi projects, please send us an email to security@jitsi.org.
|
||||
|
||||
**We encourage responsible disclosure for the sake of our users, so please reach out before posting in a public space.**
|
||||
For information on reporting security vulnerabilities in Jitsi Meet, see [SECURITY.md](./SECURITY.md).
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
---
|
||||
name: Security issues
|
||||
about: Please email security@jitsi.org
|
||||
# Security
|
||||
|
||||
---
|
||||
## Reporting security issuess
|
||||
|
||||
We take security very seriously and develop all Jitsi projects to be secure and safe.
|
||||
|
||||
If you find (or simply suspect) a security issue in any of the Jitsi projects, please send us an email to security@jitsi.org.
|
||||
|
||||
We encourage responsible disclosure for the sake of our users, so please reach out before posting in a public space.
|
||||
**We encourage responsible disclosure for the sake of our users, so please reach out before posting in a public space.**
|
||||
@@ -1,8 +1,5 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
boolean googleServicesEnabled \
|
||||
= project.file('google-services.json').exists() && !rootProject.ext.libreBuild
|
||||
|
||||
// Crashlytics integration is done as part of Firebase now, so it gets
|
||||
// automagically activated with google-services.json
|
||||
if (googleServicesEnabled) {
|
||||
@@ -13,7 +10,7 @@ if (googleServicesEnabled) {
|
||||
// This lets us upload a new build at most every 10 seconds for the
|
||||
// next ~680 years.
|
||||
// https://stackoverflow.com/a/38643838
|
||||
def vcode = (int)(((new Date().getTime()/1000) - 1546297200) / 10)
|
||||
def vcode = (int) (((new Date().getTime() / 1000) - 1546297200) / 10)
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
@@ -143,8 +140,8 @@ gradle.projectsEvaluated {
|
||||
def targetName = variant.name.capitalize()
|
||||
|
||||
def currentRunPackagerTask = tasks.create(
|
||||
name: "run${targetName}ReactPackager",
|
||||
type: Exec) {
|
||||
name: "run${targetName}ReactPackager",
|
||||
type: Exec) {
|
||||
group = "react"
|
||||
description = "Run the React packager."
|
||||
|
||||
@@ -175,5 +172,5 @@ gradle.projectsEvaluated {
|
||||
}
|
||||
|
||||
if (googleServicesEnabled) {
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.crashlytics.android.Crashlytics;
|
||||
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks;
|
||||
import io.fabric.sdk.android.Fabric;
|
||||
|
||||
import org.jitsi.meet.sdk.JitsiMeet;
|
||||
import org.jitsi.meet.sdk.JitsiMeetActivity;
|
||||
|
||||
/**
|
||||
@@ -21,7 +22,9 @@ final class GoogleServicesHelper {
|
||||
if (BuildConfig.GOOGLE_SERVICES_ENABLED) {
|
||||
Log.d(activity.getClass().getSimpleName(), "Initializing Google Services");
|
||||
|
||||
Fabric.with(activity, new Crashlytics());
|
||||
if (!JitsiMeet.isCrashReportingDisabled(activity)) {
|
||||
Fabric.with(activity, new Crashlytics());
|
||||
}
|
||||
|
||||
FirebaseDynamicLinks.getInstance().getDynamicLink(activity.getIntent())
|
||||
.addOnSuccessListener(activity, pendingDynamicLinkData -> {
|
||||
|
||||
@@ -161,6 +161,8 @@ ext {
|
||||
|
||||
// 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
|
||||
|
||||
@@ -20,5 +20,5 @@
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
appVersion=20.2.0
|
||||
sdkVersion=2.8.0
|
||||
appVersion=20.3.0
|
||||
sdkVersion=2.8.2
|
||||
|
||||
@@ -14,11 +14,13 @@ android {
|
||||
buildTypes {
|
||||
debug {
|
||||
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
|
||||
buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${rootProject.ext.googleServicesEnabled}"
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
|
||||
buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${rootProject.ext.googleServicesEnabled}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +72,7 @@ dependencies {
|
||||
implementation project(':react-native-calendar-events')
|
||||
implementation project(':react-native-community-async-storage')
|
||||
implementation project(':react-native-community_netinfo')
|
||||
implementation project(':react-native-default-preference')
|
||||
implementation project(':react-native-immersive')
|
||||
implementation project(':react-native-keep-awake')
|
||||
implementation project(':react-native-linear-gradient')
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
@@ -40,6 +42,8 @@ class AmplitudeModule
|
||||
extends ReactContextBaseJavaModule {
|
||||
|
||||
public static final String NAME = "Amplitude";
|
||||
public static final String JITSI_PREFERENCES = "jitsi-preferences";
|
||||
public static final String AMPLITUDE_DEVICE_ID_KEY = "amplitudeDeviceId";
|
||||
|
||||
public AmplitudeModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
@@ -58,10 +62,14 @@ class AmplitudeModule
|
||||
Amplitude.getInstance(instanceName).initialize(getCurrentActivity(), apiKey);
|
||||
|
||||
// Set the device ID to something consistent.
|
||||
String android_id
|
||||
= Settings.Secure.getString(getReactApplicationContext().getContentResolver(), Settings.Secure.ANDROID_ID);
|
||||
SharedPreferences sharedPreferences = getReactApplicationContext().getSharedPreferences(JITSI_PREFERENCES, Context.MODE_PRIVATE);
|
||||
String android_id = sharedPreferences.getString(AMPLITUDE_DEVICE_ID_KEY, "");
|
||||
if (!TextUtils.isEmpty(android_id)) {
|
||||
Amplitude.getInstance(instanceName).setDeviceId(android_id);
|
||||
} else {
|
||||
String amplitudeId = Amplitude.getInstance(instanceName).getDeviceId();
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putString(JITSI_PREFERENCES, amplitudeId).apply();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ class AppInfoModule
|
||||
"version",
|
||||
packageInfo == null ? "" : packageInfo.versionName);
|
||||
constants.put("LIBRE_BUILD", BuildConfig.LIBRE_BUILD);
|
||||
constants.put("GOOGLE_SERVICES_ENABLED", BuildConfig.GOOGLE_SERVICES_ENABLED);
|
||||
|
||||
return constants;
|
||||
}
|
||||
|
||||
@@ -16,11 +16,14 @@
|
||||
*/
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
|
||||
public class JitsiMeet {
|
||||
|
||||
/**
|
||||
* Default {@link JitsiMeetConferenceOptions} which will be used for all conferences. When
|
||||
* joining a conference these options will be merged with the ones passed to
|
||||
@@ -72,4 +75,10 @@ public class JitsiMeet {
|
||||
reactInstanceManager.showDevOptionsDialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isCrashReportingDisabled(Context context) {
|
||||
SharedPreferences preferences = context.getSharedPreferences("jitsi-default-preferences", Context.MODE_PRIVATE);
|
||||
String value = preferences.getString("isCrashReportingDisabled", "");
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
@@ -162,6 +163,7 @@ public class JitsiMeetActivity extends FragmentActivity
|
||||
// Activity lifecycle methods
|
||||
//
|
||||
|
||||
@SuppressLint("MissingSuperCall")
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
JitsiMeetActivityDelegate.onActivityResult(this, requestCode, resultCode, data);
|
||||
|
||||
@@ -288,6 +288,7 @@ public class JitsiMeetConferenceOptions implements Parcelable {
|
||||
}
|
||||
|
||||
private JitsiMeetConferenceOptions(Parcel in) {
|
||||
serverURL = (URL) in.readSerializable();
|
||||
room = in.readString();
|
||||
subject = in.readString();
|
||||
token = in.readString();
|
||||
@@ -376,6 +377,7 @@ public class JitsiMeetConferenceOptions implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeSerializable(serverURL);
|
||||
dest.writeString(room);
|
||||
dest.writeString(subject);
|
||||
dest.writeString(token);
|
||||
|
||||
@@ -57,22 +57,6 @@ public class JitsiMeetFragment extends Fragment {
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
JitsiMeetActivityDelegate.onActivityResult(
|
||||
getActivity(), requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
if (view != null) {
|
||||
view.dispose();
|
||||
view = null;
|
||||
}
|
||||
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
@@ -201,4 +201,10 @@ public class JitsiMeetView extends BaseReactView<JitsiMeetViewListener>
|
||||
protected void onExternalAPIEvent(String name, ReadableMap data) {
|
||||
onExternalAPIEvent(LISTENER_METHODS, name, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
dispose();
|
||||
super.onDetachedFromWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,6 +190,7 @@ class ReactInstanceManagerHolder {
|
||||
new com.corbt.keepawake.KCKeepAwakePackage(),
|
||||
new com.facebook.react.shell.MainReactPackage(),
|
||||
new com.horcrux.svg.SvgPackage(),
|
||||
new com.kevinresol.react_native_default_preference.RNDefaultPreferencePackage(),
|
||||
new com.ocetnik.timer.BackgroundTimerPackage(),
|
||||
new com.reactnativecommunity.asyncstorage.AsyncStoragePackage(),
|
||||
new com.reactnativecommunity.netinfo.NetInfoPackage(),
|
||||
|
||||
@@ -9,6 +9,8 @@ include ':react-native-community-async-storage'
|
||||
project(':react-native-community-async-storage').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/async-storage/android')
|
||||
include ':react-native-community_netinfo'
|
||||
project(':react-native-community_netinfo').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/netinfo/android')
|
||||
include ':react-native-default-preference'
|
||||
project(':react-native-default-preference').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-default-preference/android')
|
||||
include ':react-native-google-signin'
|
||||
project(':react-native-google-signin').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/google-signin/android')
|
||||
include ':react-native-immersive'
|
||||
@@ -24,4 +26,4 @@ project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../
|
||||
include ':react-native-webrtc'
|
||||
project(':react-native-webrtc').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webrtc/android')
|
||||
include ':react-native-webview'
|
||||
project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android')
|
||||
project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android')
|
||||
358
conference.js
358
conference.js
@@ -19,7 +19,6 @@ import {
|
||||
createDeviceChangedEvent,
|
||||
createStartSilentEvent,
|
||||
createScreenSharingEvent,
|
||||
createStreamSwitchDelayEvent,
|
||||
createTrackMutedEvent,
|
||||
sendAnalytics
|
||||
} from './react/features/analytics';
|
||||
@@ -28,6 +27,13 @@ import {
|
||||
redirectToStaticPage,
|
||||
reloadWithStoredParams
|
||||
} from './react/features/app';
|
||||
import {
|
||||
initPrejoin,
|
||||
isPrejoinPageEnabled,
|
||||
isPrejoinPageVisible,
|
||||
replacePrejoinAudioTrack,
|
||||
replacePrejoinVideoTrack
|
||||
} from './react/features/prejoin';
|
||||
|
||||
import EventEmitter from 'events';
|
||||
|
||||
@@ -113,6 +119,7 @@ import {
|
||||
import { getJitsiMeetGlobalNS } from './react/features/base/util';
|
||||
import { showDesktopPicker } from './react/features/desktop-picker';
|
||||
import { appendSuffix } from './react/features/display-name';
|
||||
import { setE2EEKey } from './react/features/e2ee';
|
||||
import {
|
||||
maybeOpenFeedbackDialog,
|
||||
submitFeedback
|
||||
@@ -133,6 +140,15 @@ const eventEmitter = new EventEmitter();
|
||||
let room;
|
||||
let connection;
|
||||
|
||||
/**
|
||||
* The promise is used when the prejoin screen is shown.
|
||||
* While the user configures the devices the connection can be made.
|
||||
*
|
||||
* @type {Promise<Object>}
|
||||
* @private
|
||||
*/
|
||||
let _connectionPromise;
|
||||
|
||||
/**
|
||||
* This promise is used for chaining mutePresenterVideo calls in order to avoid calling GUM multiple times if it takes
|
||||
* a while to finish.
|
||||
@@ -340,6 +356,7 @@ class ConferenceConnector {
|
||||
}
|
||||
|
||||
case JitsiConferenceErrors.FOCUS_LEFT:
|
||||
case JitsiConferenceErrors.ICE_FAILED:
|
||||
case JitsiConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE:
|
||||
case JitsiConferenceErrors.OFFER_ANSWER_FAILED:
|
||||
APP.store.dispatch(conferenceWillLeave(room));
|
||||
@@ -471,28 +488,13 @@ export default {
|
||||
localVideo: null,
|
||||
|
||||
/**
|
||||
* Creates local media tracks and connects to a room. Will show error
|
||||
* dialogs in case accessing the local microphone and/or camera failed. Will
|
||||
* show guidance overlay for users on how to give access to camera and/or
|
||||
* microphone.
|
||||
* @param {string} roomName
|
||||
* @param {object} options
|
||||
* @param {boolean} options.startAudioOnly=false - if <tt>true</tt> then
|
||||
* only audio track will be created and the audio only mode will be turned
|
||||
* on.
|
||||
* @param {boolean} options.startScreenSharing=false - if <tt>true</tt>
|
||||
* should start with screensharing instead of camera video.
|
||||
* @param {boolean} options.startWithAudioMuted - will start the conference
|
||||
* without any audio tracks.
|
||||
* @param {boolean} options.startWithVideoMuted - will start the conference
|
||||
* without any video tracks.
|
||||
* @returns {Promise.<JitsiLocalTrack[], JitsiConnection>}
|
||||
* Returns an object containing a promise which resolves with the created tracks &
|
||||
* the errors resulting from that process.
|
||||
*
|
||||
* @returns {Promise<JitsiLocalTrack[]>, Object}
|
||||
*/
|
||||
createInitialLocalTracksAndConnect(roomName, options = {}) {
|
||||
let audioAndVideoError,
|
||||
audioOnlyError,
|
||||
screenSharingError,
|
||||
videoOnlyError;
|
||||
createInitialLocalTracks(options = {}) {
|
||||
const errors = {};
|
||||
const initialDevices = [ 'audio' ];
|
||||
const requestedAudio = true;
|
||||
let requestedVideo = false;
|
||||
@@ -524,7 +526,7 @@ export default {
|
||||
// FIXME is there any simpler way to rewrite this spaghetti below ?
|
||||
if (options.startScreenSharing) {
|
||||
tryCreateLocalTracks = this._createDesktopTrack()
|
||||
.then(desktopStream => {
|
||||
.then(([ desktopStream ]) => {
|
||||
if (!requestedAudio) {
|
||||
return [ desktopStream ];
|
||||
}
|
||||
@@ -533,21 +535,21 @@ export default {
|
||||
.then(([ audioStream ]) =>
|
||||
[ desktopStream, audioStream ])
|
||||
.catch(error => {
|
||||
audioOnlyError = error;
|
||||
errors.audioOnlyError = error;
|
||||
|
||||
return [ desktopStream ];
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('Failed to obtain desktop stream', error);
|
||||
screenSharingError = error;
|
||||
errors.screenSharingError = error;
|
||||
|
||||
return requestedAudio
|
||||
? createLocalTracksF({ devices: [ 'audio' ] }, true)
|
||||
: [];
|
||||
})
|
||||
.catch(error => {
|
||||
audioOnlyError = error;
|
||||
errors.audioOnlyError = error;
|
||||
|
||||
return [];
|
||||
});
|
||||
@@ -560,16 +562,16 @@ export default {
|
||||
if (requestedAudio && requestedVideo) {
|
||||
|
||||
// Try audio only...
|
||||
audioAndVideoError = err;
|
||||
errors.audioAndVideoError = err;
|
||||
|
||||
return (
|
||||
createLocalTracksF({ devices: [ 'audio' ] }, true));
|
||||
} else if (requestedAudio && !requestedVideo) {
|
||||
audioOnlyError = err;
|
||||
errors.audioOnlyError = err;
|
||||
|
||||
return [];
|
||||
} else if (requestedVideo && !requestedAudio) {
|
||||
videoOnlyError = err;
|
||||
errors.videoOnlyError = err;
|
||||
|
||||
return [];
|
||||
}
|
||||
@@ -580,7 +582,7 @@ export default {
|
||||
if (!requestedAudio) {
|
||||
logger.error('The impossible just happened', err);
|
||||
}
|
||||
audioOnlyError = err;
|
||||
errors.audioOnlyError = err;
|
||||
|
||||
// Try video only...
|
||||
return requestedVideo
|
||||
@@ -592,7 +594,7 @@ export default {
|
||||
if (!requestedVideo) {
|
||||
logger.error('The impossible just happened', err);
|
||||
}
|
||||
videoOnlyError = err;
|
||||
errors.videoOnlyError = err;
|
||||
|
||||
return [];
|
||||
});
|
||||
@@ -603,8 +605,44 @@ export default {
|
||||
// cases, when auth is rquired, for instance, that won't happen until
|
||||
// the user inputs their credentials, but the dialog would be
|
||||
// overshadowed by the overlay.
|
||||
tryCreateLocalTracks.then(() =>
|
||||
APP.store.dispatch(mediaPermissionPromptVisibilityChanged(false)));
|
||||
tryCreateLocalTracks.then(tracks => {
|
||||
APP.store.dispatch(mediaPermissionPromptVisibilityChanged(false));
|
||||
|
||||
return tracks;
|
||||
});
|
||||
|
||||
return {
|
||||
tryCreateLocalTracks,
|
||||
errors
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates local media tracks and connects to a room. Will show error
|
||||
* dialogs in case accessing the local microphone and/or camera failed. Will
|
||||
* show guidance overlay for users on how to give access to camera and/or
|
||||
* microphone.
|
||||
* @param {string} roomName
|
||||
* @param {object} options
|
||||
* @param {boolean} options.startAudioOnly=false - if <tt>true</tt> then
|
||||
* only audio track will be created and the audio only mode will be turned
|
||||
* on.
|
||||
* @param {boolean} options.startScreenSharing=false - if <tt>true</tt>
|
||||
* should start with screensharing instead of camera video.
|
||||
* @param {boolean} options.startWithAudioMuted - will start the conference
|
||||
* without any audio tracks.
|
||||
* @param {boolean} options.startWithVideoMuted - will start the conference
|
||||
* without any video tracks.
|
||||
* @returns {Promise.<JitsiLocalTrack[], JitsiConnection>}
|
||||
*/
|
||||
createInitialLocalTracksAndConnect(roomName, options = {}) {
|
||||
const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(options);
|
||||
const {
|
||||
audioAndVideoError,
|
||||
audioOnlyError,
|
||||
screenSharingError,
|
||||
videoOnlyError
|
||||
} = errors;
|
||||
|
||||
return Promise.all([ tryCreateLocalTracks, connect(roomName) ])
|
||||
.then(([ tracks, con ]) => {
|
||||
@@ -636,103 +674,132 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
startConference(con, tracks) {
|
||||
tracks.forEach(track => {
|
||||
if ((track.isAudioTrack() && this.isLocalAudioMuted())
|
||||
|| (track.isVideoTrack() && this.isLocalVideoMuted())) {
|
||||
const mediaType = track.getType();
|
||||
|
||||
sendAnalytics(
|
||||
createTrackMutedEvent(mediaType, 'initial mute'));
|
||||
logger.log(`${mediaType} mute: initially muted.`);
|
||||
track.mute();
|
||||
}
|
||||
});
|
||||
logger.log(`Initialized with ${tracks.length} local tracks`);
|
||||
|
||||
this._localTracksInitialized = true;
|
||||
con.addEventListener(JitsiConnectionEvents.CONNECTION_FAILED, _connectionFailedHandler);
|
||||
APP.connection = connection = con;
|
||||
|
||||
// Desktop sharing related stuff:
|
||||
this.isDesktopSharingEnabled
|
||||
= JitsiMeetJS.isDesktopSharingEnabled();
|
||||
eventEmitter.emit(JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED, this.isDesktopSharingEnabled);
|
||||
|
||||
APP.store.dispatch(
|
||||
setDesktopSharingEnabled(this.isDesktopSharingEnabled));
|
||||
|
||||
this._createRoom(tracks);
|
||||
APP.remoteControl.init();
|
||||
|
||||
// if user didn't give access to mic or camera or doesn't have
|
||||
// them at all, we mark corresponding toolbar buttons as muted,
|
||||
// so that the user can try unmute later on and add audio/video
|
||||
// to the conference
|
||||
if (!tracks.find(t => t.isAudioTrack())) {
|
||||
this.setAudioMuteStatus(true);
|
||||
}
|
||||
|
||||
if (!tracks.find(t => t.isVideoTrack())) {
|
||||
this.setVideoMuteStatus(true);
|
||||
}
|
||||
|
||||
if (config.iAmRecorder) {
|
||||
this.recorder = new Recorder();
|
||||
}
|
||||
|
||||
if (config.startSilent) {
|
||||
sendAnalytics(createStartSilentEvent());
|
||||
APP.store.dispatch(showNotification({
|
||||
descriptionKey: 'notify.startSilentDescription',
|
||||
titleKey: 'notify.startSilentTitle'
|
||||
}));
|
||||
}
|
||||
|
||||
// XXX The API will take care of disconnecting from the XMPP
|
||||
// server (and, thus, leaving the room) on unload.
|
||||
return new Promise((resolve, reject) => {
|
||||
(new ConferenceConnector(resolve, reject)).connect();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Open new connection and join to the conference.
|
||||
* @param {object} options
|
||||
* @param {string} roomName - The name of the conference.
|
||||
* Open new connection and join the conference when prejoin page is not enabled.
|
||||
* If prejoin page is enabled open an new connection in the background
|
||||
* and create local tracks.
|
||||
*
|
||||
* @param {{ roomName: string }} options
|
||||
* @returns {Promise}
|
||||
*/
|
||||
init(options) {
|
||||
this.roomName = options.roomName;
|
||||
async init({ roomName }) {
|
||||
const initialOptions = {
|
||||
startAudioOnly: config.startAudioOnly,
|
||||
startScreenSharing: config.startScreenSharing,
|
||||
startWithAudioMuted: config.startWithAudioMuted
|
||||
|| config.startSilent
|
||||
|| isUserInteractionRequiredForUnmute(APP.store.getState()),
|
||||
startWithVideoMuted: config.startWithVideoMuted
|
||||
|| isUserInteractionRequiredForUnmute(APP.store.getState())
|
||||
};
|
||||
|
||||
return (
|
||||
this.roomName = roomName;
|
||||
|
||||
window.addEventListener('hashchange', this.onHashChange.bind(this), false);
|
||||
|
||||
try {
|
||||
// Initialize the device list first. This way, when creating tracks
|
||||
// based on preferred devices, loose label matching can be done in
|
||||
// cases where the exact ID match is no longer available, such as
|
||||
// when the camera device has switched USB ports.
|
||||
// when in startSilent mode we want to start with audio muted
|
||||
this._initDeviceList()
|
||||
.catch(error => logger.warn(
|
||||
'initial device list initialization failed', error))
|
||||
.then(() => this.createInitialLocalTracksAndConnect(
|
||||
options.roomName, {
|
||||
startAudioOnly: config.startAudioOnly,
|
||||
startScreenSharing: config.startScreenSharing,
|
||||
startWithAudioMuted: config.startWithAudioMuted
|
||||
|| config.startSilent
|
||||
|| isUserInteractionRequiredForUnmute(APP.store.getState()),
|
||||
startWithVideoMuted: config.startWithVideoMuted
|
||||
|| isUserInteractionRequiredForUnmute(APP.store.getState())
|
||||
}))
|
||||
.then(([ tracks, con ]) => {
|
||||
tracks.forEach(track => {
|
||||
if ((track.isAudioTrack() && this.isLocalAudioMuted())
|
||||
|| (track.isVideoTrack() && this.isLocalVideoMuted())) {
|
||||
const mediaType = track.getType();
|
||||
await this._initDeviceList();
|
||||
} catch (error) {
|
||||
logger.warn('initial device list initialization failed', error);
|
||||
}
|
||||
|
||||
sendAnalytics(
|
||||
createTrackMutedEvent(mediaType, 'initial mute'));
|
||||
logger.log(`${mediaType} mute: initially muted.`);
|
||||
track.mute();
|
||||
}
|
||||
});
|
||||
logger.log(`initialized with ${tracks.length} local tracks`);
|
||||
this._localTracksInitialized = true;
|
||||
con.addEventListener(
|
||||
JitsiConnectionEvents.CONNECTION_FAILED,
|
||||
_connectionFailedHandler);
|
||||
APP.connection = connection = con;
|
||||
if (isPrejoinPageEnabled(APP.store.getState())) {
|
||||
_connectionPromise = connect(roomName);
|
||||
|
||||
// Desktop sharing related stuff:
|
||||
this.isDesktopSharingEnabled
|
||||
= JitsiMeetJS.isDesktopSharingEnabled();
|
||||
eventEmitter.emit(
|
||||
JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED,
|
||||
this.isDesktopSharingEnabled);
|
||||
const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(initialOptions);
|
||||
const tracks = await tryCreateLocalTracks;
|
||||
|
||||
APP.store.dispatch(
|
||||
setDesktopSharingEnabled(this.isDesktopSharingEnabled));
|
||||
// Initialize device list a second time to ensure device labels
|
||||
// get populated in case of an initial gUM acceptance; otherwise
|
||||
// they may remain as empty strings.
|
||||
this._initDeviceList(true);
|
||||
|
||||
this._createRoom(tracks);
|
||||
APP.remoteControl.init();
|
||||
return APP.store.dispatch(initPrejoin(tracks, errors));
|
||||
}
|
||||
|
||||
// if user didn't give access to mic or camera or doesn't have
|
||||
// them at all, we mark corresponding toolbar buttons as muted,
|
||||
// so that the user can try unmute later on and add audio/video
|
||||
// to the conference
|
||||
if (!tracks.find(t => t.isAudioTrack())) {
|
||||
this.setAudioMuteStatus(true);
|
||||
}
|
||||
const [ tracks, con ] = await this.createInitialLocalTracksAndConnect(
|
||||
roomName, initialOptions);
|
||||
|
||||
if (!tracks.find(t => t.isVideoTrack())) {
|
||||
this.setVideoMuteStatus(true);
|
||||
}
|
||||
this._initDeviceList(true);
|
||||
|
||||
// Initialize device list a second time to ensure device labels
|
||||
// get populated in case of an initial gUM acceptance; otherwise
|
||||
// they may remain as empty strings.
|
||||
this._initDeviceList(true);
|
||||
return this.startConference(con, tracks);
|
||||
},
|
||||
|
||||
if (config.iAmRecorder) {
|
||||
this.recorder = new Recorder();
|
||||
}
|
||||
/**
|
||||
* Joins conference after the tracks have been configured in the prejoin screen.
|
||||
*
|
||||
* @param {Object[]} tracks - An array with the configured tracks
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async prejoinStart(tracks) {
|
||||
const con = await _connectionPromise;
|
||||
|
||||
if (config.startSilent) {
|
||||
sendAnalytics(createStartSilentEvent());
|
||||
APP.store.dispatch(showNotification({
|
||||
descriptionKey: 'notify.startSilentDescription',
|
||||
titleKey: 'notify.startSilentTitle'
|
||||
}));
|
||||
}
|
||||
|
||||
// XXX The API will take care of disconnecting from the XMPP
|
||||
// server (and, thus, leaving the room) on unload.
|
||||
return new Promise((resolve, reject) => {
|
||||
(new ConferenceConnector(resolve, reject)).connect();
|
||||
});
|
||||
})
|
||||
);
|
||||
return this.startConference(con, tracks);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -1177,6 +1244,34 @@ export default {
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handled location hash change events.
|
||||
*/
|
||||
onHashChange() {
|
||||
const items = {};
|
||||
const parts = window.location.hash.substr(1).split('&');
|
||||
|
||||
for (const part of parts) {
|
||||
const param = part.split('=');
|
||||
const key = param[0];
|
||||
|
||||
if (!key) {
|
||||
continue; // eslint-disable-line no-continue
|
||||
}
|
||||
|
||||
items[key] = param[1];
|
||||
}
|
||||
|
||||
if (typeof items.e2eekey !== undefined) {
|
||||
APP.store.dispatch(setE2EEKey(items.e2eekey));
|
||||
|
||||
// Clean URL in browser history.
|
||||
const cleanUrl = window.location.href.split('#')[0];
|
||||
|
||||
history.replaceState(history.state, document.title, cleanUrl);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Exposes a Command(s) API on this instance. It is necessitated by (1) the
|
||||
* desire to keep room private to this instance and (2) the need of other
|
||||
@@ -1322,6 +1417,18 @@ export default {
|
||||
useVideoStream(newStream) {
|
||||
return new Promise((resolve, reject) => {
|
||||
_replaceLocalVideoTrackQueue.enqueue(onFinish => {
|
||||
/**
|
||||
* When the prejoin page is visible there is no conference object
|
||||
* created. The prejoin tracks are managed separately,
|
||||
* so this updates the prejoin video track.
|
||||
*/
|
||||
if (isPrejoinPageVisible(APP.store.getState())) {
|
||||
return APP.store.dispatch(replacePrejoinVideoTrack(newStream))
|
||||
.then(resolve)
|
||||
.catch(reject)
|
||||
.then(onFinish);
|
||||
}
|
||||
|
||||
APP.store.dispatch(
|
||||
replaceLocalTrack(this.localVideo, newStream, room))
|
||||
.then(() => {
|
||||
@@ -1375,6 +1482,18 @@ export default {
|
||||
useAudioStream(newStream) {
|
||||
return new Promise((resolve, reject) => {
|
||||
_replaceLocalAudioTrackQueue.enqueue(onFinish => {
|
||||
/**
|
||||
* When the prejoin page is visible there is no conference object
|
||||
* created. The prejoin tracks are managed separately,
|
||||
* so this updates the prejoin audio stream.
|
||||
*/
|
||||
if (isPrejoinPageVisible(APP.store.getState())) {
|
||||
return APP.store.dispatch(replacePrejoinAudioTrack(newStream))
|
||||
.then(resolve)
|
||||
.catch(reject)
|
||||
.then(onFinish);
|
||||
}
|
||||
|
||||
APP.store.dispatch(
|
||||
replaceLocalTrack(this.localAudio, newStream, room))
|
||||
.then(() => {
|
||||
@@ -1786,7 +1905,7 @@ export default {
|
||||
const desktopVideoStream = streams.find(stream => stream.getType() === MEDIA_TYPE.VIDEO);
|
||||
|
||||
if (desktopVideoStream) {
|
||||
this.useVideoStream(desktopVideoStream);
|
||||
await this.useVideoStream(desktopVideoStream);
|
||||
}
|
||||
|
||||
this._desktopAudioStream = streams.find(stream => stream.getType() === MEDIA_TYPE.AUDIO);
|
||||
@@ -1975,6 +2094,7 @@ export default {
|
||||
logger.info(`My role changed, new role: ${role}`);
|
||||
|
||||
APP.store.dispatch(localParticipantRoleChanged(role));
|
||||
APP.API.notifyUserRoleChanged(id, role);
|
||||
} else {
|
||||
APP.store.dispatch(participantRoleChanged(id, role));
|
||||
}
|
||||
@@ -2232,18 +2352,6 @@ export default {
|
||||
});
|
||||
});
|
||||
|
||||
/* eslint-disable max-params */
|
||||
APP.UI.addListener(
|
||||
UIEvents.RESOLUTION_CHANGED,
|
||||
(id, oldResolution, newResolution, delay) => {
|
||||
sendAnalytics(createStreamSwitchDelayEvent(
|
||||
{
|
||||
'old_resolution': oldResolution,
|
||||
'new_resolution': newResolution,
|
||||
value: delay
|
||||
}));
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.AUTH_CLICKED, () => {
|
||||
AuthHandler.authenticate(room);
|
||||
});
|
||||
@@ -2811,7 +2919,7 @@ export default {
|
||||
leaveRoomAndDisconnect() {
|
||||
APP.store.dispatch(conferenceWillLeave(room));
|
||||
|
||||
if (room.isJoined()) {
|
||||
if (room && room.isJoined()) {
|
||||
return room.leave().then(disconnect, disconnect);
|
||||
}
|
||||
|
||||
|
||||
36
config.js
36
config.js
@@ -44,9 +44,6 @@ var config = {
|
||||
//
|
||||
|
||||
testing: {
|
||||
// Enables experimental simulcast support on Firefox.
|
||||
enableFirefoxSimulcast: false,
|
||||
|
||||
// P2P test mode disables automatic switching to P2P when there are 2
|
||||
// participants in the conference.
|
||||
p2pTestMode: false
|
||||
@@ -111,11 +108,10 @@ var config = {
|
||||
// w3c spec-compliant video constraints to use for video capture. Currently
|
||||
// used by browsers that return true from lib-jitsi-meet's
|
||||
// util#browser#usesNewGumFlow. The constraints are independent from
|
||||
// this config's resolution value. Defaults to requesting an ideal aspect
|
||||
// ratio of 16:9 with an ideal resolution of 720.
|
||||
// this config's resolution value. Defaults to requesting an ideal
|
||||
// resolution of 720p.
|
||||
// constraints: {
|
||||
// video: {
|
||||
// aspectRatio: 16 / 9,
|
||||
// height: {
|
||||
// ideal: 720,
|
||||
// max: 720,
|
||||
@@ -230,6 +226,14 @@ var config = {
|
||||
// disabled, then bandwidth estimations are disabled.
|
||||
// enableRemb: false,
|
||||
|
||||
// Enables ICE restart logic in LJM and displays the page reload overlay on
|
||||
// ICE failure. Current disabled by default because it's causing issues with
|
||||
// signaling when Octo is enabled. Also when we do an "ICE restart"(which is
|
||||
// not a real ICE restart), the client maintains the TCC sequence number
|
||||
// counter, but the bridge resets it. The bridge sends media packets with
|
||||
// TCC sequence numbers starting from 0.
|
||||
// enableIceRestart: false,
|
||||
|
||||
// Defines the minimum number of participants to start a call (the default
|
||||
// is set in Jicofo and set to 2).
|
||||
// minParticipants: 2,
|
||||
@@ -293,6 +297,9 @@ var config = {
|
||||
// and microsoftApiApplicationClientID
|
||||
// enableCalendarIntegration: false,
|
||||
|
||||
// When 'true', it shows an intermediate page before joining, where the user can configure its devices.
|
||||
// prejoinPageEnabled: false,
|
||||
|
||||
// Stats
|
||||
//
|
||||
|
||||
@@ -343,7 +350,7 @@ var config = {
|
||||
// The STUN servers that will be used in the peer to peer connections
|
||||
stunServers: [
|
||||
|
||||
// { urls: 'stun:jitsi-meet.example.com:443' },
|
||||
// { urls: 'stun:jitsi-meet.example.com:4446' },
|
||||
{ urls: 'stun:meet-jit-si-turnrelay.jitsi.net:443' }
|
||||
],
|
||||
|
||||
@@ -372,6 +379,10 @@ var config = {
|
||||
// The Google Analytics Tracking ID:
|
||||
// googleAnalyticsTrackingId: 'your-tracking-id-UA-123456-1'
|
||||
|
||||
// Matomo configuration:
|
||||
// matomoEndpoint: 'https://your-matomo-endpoint/',
|
||||
// matomoSiteID: '42',
|
||||
|
||||
// The Amplitude APP Key:
|
||||
// amplitudeAPPKey: '<APP_KEY>'
|
||||
|
||||
@@ -390,6 +401,9 @@ var config = {
|
||||
// userRegion: "asia"
|
||||
},
|
||||
|
||||
// Decides whether the start/stop recording audio notifications should play on record.
|
||||
// disableRecordAudioNotification: false,
|
||||
|
||||
// Information for the chrome extension banner
|
||||
// chromeExtensionBanner: {
|
||||
// // The chrome extension to be installed address
|
||||
@@ -449,6 +463,14 @@ var config = {
|
||||
// the menu has option to flip the locally seen video for local presentations
|
||||
// disableLocalVideoFlip: false,
|
||||
|
||||
// Mainly privacy related settings
|
||||
|
||||
// Disables all invite functions from the app (share, invite, dial out...etc)
|
||||
// disableInviteFunctions: true,
|
||||
|
||||
// Disables storing the room name to the recents list
|
||||
// doNotStoreRoom: true,
|
||||
|
||||
// Deployment specific URLs.
|
||||
// deploymentUrls: {
|
||||
// // If specified a 'Help' button will be displayed in the overflow menu with a link to the specified URL for
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/* global APP, JitsiMeetJS, config */
|
||||
|
||||
import { jitsiLocalStorage } from 'js-utils';
|
||||
|
||||
import AuthHandler from './modules/UI/authentication/AuthHandler';
|
||||
import jitsiLocalStorage from './modules/util/JitsiLocalStorage';
|
||||
|
||||
import {
|
||||
connectionEstablished,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* global config, createConnectionExternally */
|
||||
|
||||
import getRoomName from '../react/features/base/config/getRoomName';
|
||||
import parseURLParams from '../react/features/base/config/parseURLParams';
|
||||
import { parseURLParams } from '../react/features/base/util/parseURLParams';
|
||||
|
||||
/**
|
||||
* Implements external connect using createConnectionExternally function defined
|
||||
|
||||
135
css/_audio-preview.css
Normal file
135
css/_audio-preview.css
Normal file
@@ -0,0 +1,135 @@
|
||||
.audio-preview {
|
||||
&-content {
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
max-height: 456px;
|
||||
overflow: auto;
|
||||
width: 328px;
|
||||
}
|
||||
|
||||
&-header {
|
||||
color: #fff;
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
|
||||
&-icon {
|
||||
color: #A4B8D1;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
&-text {
|
||||
font-weight: bold;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&-entry {
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
padding: 12px 0;
|
||||
margin-left: 48px;
|
||||
|
||||
&--selected {
|
||||
background: rgba(28,32,37,0.5);
|
||||
cursor: initial;
|
||||
margin-left: 0;
|
||||
padding-left: 21px;
|
||||
}
|
||||
|
||||
&-text {
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
display: inline-block;
|
||||
line-height: 24px;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 213px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
&-speaker {
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
.audio-preview-entry {
|
||||
background: rgba(255,255,255, 0.2);
|
||||
margin-left: 0;
|
||||
padding-left: 48px;
|
||||
|
||||
&--selected {
|
||||
padding-left: 21px;
|
||||
}
|
||||
}
|
||||
|
||||
.audio-preview-test-button {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.audio-preview-entry-text {
|
||||
max-width: 196px;
|
||||
}
|
||||
}
|
||||
|
||||
.audio-preview-entry-text {
|
||||
max-width: 256px;
|
||||
}
|
||||
}
|
||||
|
||||
&-microphone {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
&-icon {
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
|
||||
& svg {
|
||||
fill: #1C2025;
|
||||
}
|
||||
|
||||
&--check {
|
||||
background: #31B76A;
|
||||
margin-right: 13px;
|
||||
}
|
||||
|
||||
&--exclamation {
|
||||
margin-left: 6px;
|
||||
& svg {
|
||||
fill: #E54B4B;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-test-button {
|
||||
display: none;
|
||||
background: #FFF;
|
||||
border: 1px solid #D1DBE8;
|
||||
border-radius: 3px;
|
||||
color: #1C2025;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
padding: 4px 16px;
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 8px;
|
||||
}
|
||||
|
||||
&-meter-mic {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 18px;
|
||||
}
|
||||
|
||||
// Override @atlaskit/InlineDialog container which is made with styled components
|
||||
& > div > div:nth-child(2) > div > div {
|
||||
outline: none;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
@@ -20,18 +20,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-foreign {
|
||||
align-items: center;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
font-size: 40pt;
|
||||
justify-content: center;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.avatar-svg {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
@@ -63,4 +51,4 @@
|
||||
@include avatarBadge;
|
||||
background-color: $presence-idle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
30
css/_meter.css
Normal file
30
css/_meter.css
Normal file
@@ -0,0 +1,30 @@
|
||||
.jitsi-icon {
|
||||
&.metr {
|
||||
display: inline-block;
|
||||
|
||||
& > svg {
|
||||
fill: #4E5E6C;
|
||||
width: 38px;
|
||||
}
|
||||
}
|
||||
|
||||
&.metr--disabled {
|
||||
& > svg {
|
||||
fill: #4E5E6C;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.metr-l-0 {
|
||||
rect:first-child {
|
||||
fill: #31B76A;
|
||||
}
|
||||
}
|
||||
|
||||
@for $i from 1 through 7 {
|
||||
.metr-l-#{$i} {
|
||||
rect:nth-child(-n+#{$i+1}) {
|
||||
fill: #31B76A;
|
||||
}
|
||||
}
|
||||
}
|
||||
331
css/_prejoin.scss
Normal file
331
css/_prejoin.scss
Normal file
@@ -0,0 +1,331 @@
|
||||
.prejoin {
|
||||
&-full-page {
|
||||
background: #1C2025;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: $toolbarZ + 1;
|
||||
}
|
||||
|
||||
&-input-area-container {
|
||||
position: absolute;
|
||||
bottom: 48px;
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&-input-area {
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
&-title {
|
||||
color: #fff;
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
&-btn {
|
||||
border-radius: 3px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
padding: 7px 16px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
width: 286px;
|
||||
|
||||
&--primary {
|
||||
background: #0376DA;
|
||||
border: 1px solid #0376DA;
|
||||
}
|
||||
|
||||
&--secondary {
|
||||
background: #2A3A4B;
|
||||
border: 1px solid #5E6D7A;
|
||||
}
|
||||
|
||||
&--text {
|
||||
width: auto;
|
||||
font-size: 13px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-btn-options {
|
||||
align-items: center;
|
||||
border-left: 1px solid #fff;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
&-text-btns {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&-input-label {
|
||||
color: #A4B8D1;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
margin-top: 32px 0 8px 0;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-checkbox {
|
||||
border: 0;
|
||||
height: 16px;
|
||||
margin-right: 8px;
|
||||
padding: 0;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
&-checkbox-container {
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
display: none;
|
||||
font-size: 13px;
|
||||
justify-content: center;
|
||||
line-height: 20px;
|
||||
margin-top: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin name-placeholder {
|
||||
color: #fff;
|
||||
font-weight: 300;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.prejoin-preview {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
|
||||
&--no-video {
|
||||
background: radial-gradient(50% 50% at 50% 50%, #5B6F80 0%, #365067 100%), #FFFFFF;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&-video {
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-name {
|
||||
color: #fff;
|
||||
font-size: 19px;
|
||||
line-height: 28px;
|
||||
|
||||
&--editable {
|
||||
background: none;
|
||||
border: 0;
|
||||
border-bottom: 1px solid #D1DBE8;
|
||||
margin: 24px 0 16px 0;
|
||||
outline: none;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
|
||||
&::-webkit-input-placeholder {
|
||||
@include name-placeholder;
|
||||
}
|
||||
&::-moz-placeholder {
|
||||
@include name-placeholder;
|
||||
}
|
||||
&:-ms-input-placeholder {
|
||||
@include name-placeholder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-avatar.avatar {
|
||||
background: #A4B8D1;
|
||||
margin: 200px auto 0 auto;
|
||||
}
|
||||
|
||||
&-btn-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 32px;
|
||||
width: 100%;
|
||||
|
||||
&> div {
|
||||
margin: 0 12px;
|
||||
}
|
||||
|
||||
.settings-button-small-icon {
|
||||
right: -8px;
|
||||
|
||||
&--hovered {
|
||||
right: -10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-overlay {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
background: linear-gradient(0deg, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.3));
|
||||
}
|
||||
|
||||
&-bottom-overlay {
|
||||
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.9) 100%);
|
||||
bottom: 0;
|
||||
height: 50%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&-status {
|
||||
align-items: center;
|
||||
bottom: 0;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
font-size: 13px;
|
||||
min-height: 24px;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
|
||||
&--warning {
|
||||
background: rgba(241, 173, 51, 0.5)
|
||||
}
|
||||
&--ok {
|
||||
background: rgba(49, 183, 106, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
&-icon {
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
margin-right: 8px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
&-error-desc {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.settings-button-container {
|
||||
width: 49px;
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
&-dropdown-btns {
|
||||
width: 320px;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
&-dropdown-btn {
|
||||
align-items: center;
|
||||
color: #1C2025;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
height: 40px;
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
padding: 0 16px;
|
||||
|
||||
&:hover {
|
||||
background-color: #DAEBFA;
|
||||
}
|
||||
}
|
||||
|
||||
&-dropdown-icon {
|
||||
display: inline-block;
|
||||
margin-right: 16px;
|
||||
|
||||
& > svg {
|
||||
fill: #1C2025;
|
||||
}
|
||||
}
|
||||
|
||||
&-dropdown-container {
|
||||
& > div > div:nth-child(2) > div > div {
|
||||
background: #fff;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.prejoin-copy {
|
||||
&-meeting {
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
font-weight: 300;
|
||||
line-height: 24px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&-url {
|
||||
max-width: 278px;
|
||||
padding: 8px 10px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&-badge {
|
||||
border-radius: 4px;
|
||||
height: 100%;
|
||||
line-height: 38px;
|
||||
position: absolute;
|
||||
padding-left: 10px;
|
||||
text-align: left;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
|
||||
&--hover {
|
||||
background: #1C2025;
|
||||
}
|
||||
|
||||
&--done {
|
||||
background: #31B76A;
|
||||
}
|
||||
}
|
||||
|
||||
&-icon {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 8px;
|
||||
|
||||
&--white {
|
||||
&> svg > path {
|
||||
fill: #fff
|
||||
}
|
||||
}
|
||||
|
||||
&--light {
|
||||
&> svg > path {
|
||||
fill: #D1DBE8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-textarea {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
}
|
||||
}
|
||||
@@ -71,6 +71,11 @@
|
||||
display: flex;
|
||||
margin-top: 5px;
|
||||
text-align: right;
|
||||
flex-direction: column;
|
||||
|
||||
.help-container {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.live-stream-cta {
|
||||
|
||||
80
css/_settings-button.scss
Normal file
80
css/_settings-button.scss
Normal file
@@ -0,0 +1,80 @@
|
||||
.settings-button {
|
||||
&-container {
|
||||
position: relative;
|
||||
|
||||
.toolbox-icon {
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #d1dbe8;
|
||||
justify-content: center;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
|
||||
&:hover {
|
||||
background-color: #daebfa;
|
||||
border: 1px solid #daebfa;
|
||||
}
|
||||
|
||||
&.toggled {
|
||||
background: #2a3a4b;
|
||||
border: 1px solid #5e6d7a;
|
||||
|
||||
svg {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #5e6d7a;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled, .disabled & {
|
||||
cursor: initial;
|
||||
color: #fff;
|
||||
background-color: #a4b8d1;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: #5e6d7a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-small-icon {
|
||||
background: #FFF;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
border-radius: 50%;
|
||||
bottom: 0;
|
||||
box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.25);
|
||||
cursor: pointer;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
right: 4px;
|
||||
width: 16px;
|
||||
|
||||
&> svg {
|
||||
fill: #5e6d7a;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
background-color: #a4b8d1;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&--hovered {
|
||||
bottom: -1px;
|
||||
height: 20px;
|
||||
right: 2px;
|
||||
width: 20px;
|
||||
|
||||
&> svg {
|
||||
margin-top: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
70
css/_video-preview.css
Normal file
70
css/_video-preview.css
Normal file
@@ -0,0 +1,70 @@
|
||||
.video-preview {
|
||||
background: none;
|
||||
max-height: 290px;
|
||||
|
||||
&-container {
|
||||
overflow: auto;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
&-entry {
|
||||
cursor: pointer;
|
||||
height: 135px;
|
||||
margin-bottom: 16px;
|
||||
position: relative;
|
||||
width: 240px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&--selected {
|
||||
border: 3px solid #31B76A;
|
||||
cursor: default;
|
||||
height: 129px;
|
||||
width: 234px;
|
||||
}
|
||||
}
|
||||
|
||||
&-video {
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-overlay {
|
||||
background: rgba(42, 58, 75, 0.6);
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&-error {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-label {
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
overflow: hidden;
|
||||
padding: 8px;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
width: 220px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
// Override @atlaskit/InlineDialog container which is made with styled components
|
||||
& > div > div:nth-child(2) > div > div {
|
||||
outline: none;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,9 @@
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
height: calc(100vh - 200px);
|
||||
width: 100vw;
|
||||
margin: 100px 0px;
|
||||
}
|
||||
|
||||
.filmstrip__videos .videocontainer {
|
||||
@@ -77,9 +78,9 @@
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
height: 100vh;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
justify-content: center;
|
||||
padding: 100px 0;
|
||||
|
||||
.videocontainer {
|
||||
border: 0;
|
||||
|
||||
@@ -86,5 +86,10 @@ $flagsImagePath: "../images/";
|
||||
@import 'avatar';
|
||||
@import 'promotional-footer';
|
||||
@import 'chrome-extension-banner';
|
||||
@import 'settings-button';
|
||||
@import 'meter';
|
||||
@import 'audio-preview';
|
||||
@import 'video-preview';
|
||||
@import 'prejoin';
|
||||
|
||||
/* Modules END */
|
||||
|
||||
@@ -164,6 +164,13 @@
|
||||
background: #B8C7E0;
|
||||
}
|
||||
|
||||
.circular-label.e2ee {
|
||||
align-items: center;
|
||||
background: #76CF9C;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.circular-label.file {
|
||||
background: #FF5630;
|
||||
}
|
||||
|
||||
1
debian/control
vendored
1
debian/control
vendored
@@ -53,5 +53,6 @@ Description: Prosody token authentication plugin for Jitsi Meet
|
||||
Package: jitsi-meet-turnserver
|
||||
Architecture: all
|
||||
Breaks: apache2
|
||||
Pre-Depends: jitsi-meet-web-config
|
||||
Depends: ${misc:Depends}, nginx (>= 1.13.10) | nginx-full (>= 1.13.10) | nginx-extras (>= 1.13.10), jitsi-meet-prosody, coturn, dnsutils
|
||||
Description: Configures coturn to be used with Jitsi Meet
|
||||
|
||||
22
debian/jitsi-meet-prosody.postinst
vendored
22
debian/jitsi-meet-prosody.postinst
vendored
@@ -17,6 +17,9 @@ set -e
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
|
||||
function generateRandomPassword() {
|
||||
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 16
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
@@ -51,7 +54,7 @@ case "$1" in
|
||||
db_get jicofo/jicofo-authpassword
|
||||
if [ -z "$RET" ] ; then
|
||||
# if password is missing generate it, and store it
|
||||
JICOFO_AUTH_PASSWORD=`head -c 8 /dev/urandom | tr '\0-\377' 'a-zA-Z0-9a-zA-Z0-9a-zA-Z0-9a-zA-Z0-9@@@@####'`
|
||||
JICOFO_AUTH_PASSWORD=`generateRandomPassword`
|
||||
db_set jicofo/jicofo-authpassword "$JICOFO_AUTH_PASSWORD"
|
||||
else
|
||||
JICOFO_AUTH_PASSWORD="$RET"
|
||||
@@ -60,7 +63,7 @@ case "$1" in
|
||||
db_get jicofo/jicofosecret
|
||||
if [ -z "$RET" ] ; then
|
||||
# if secret is missing generate it, and store it
|
||||
JICOFO_SECRET=`head -c 8 /dev/urandom | tr '\0-\377' 'a-zA-Z0-9a-zA-Z0-9a-zA-Z0-9a-zA-Z0-9@@@@####'`
|
||||
JICOFO_SECRET=`generateRandomPassword`
|
||||
db_set jicofo/jicofosecret "$JICOFO_SECRET"
|
||||
else
|
||||
JICOFO_SECRET="$RET"
|
||||
@@ -83,7 +86,7 @@ case "$1" in
|
||||
db_get jitsi-meet-prosody/turn-secret
|
||||
if [ -z "$RET" ] ; then
|
||||
# 8-chars random secret used for the turnserver
|
||||
TURN_SECRET=`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1`
|
||||
TURN_SECRET=`generateRandomPassword`
|
||||
db_set jitsi-meet-prosody/turn-secret "$TURN_SECRET"
|
||||
else
|
||||
TURN_SECRET="$RET"
|
||||
@@ -134,7 +137,7 @@ case "$1" in
|
||||
# as we are migrating configs
|
||||
if [ -f $PROSODY_HOST_CONFIG ] && ! grep -q "internal.auth.$JVB_HOSTNAME" $PROSODY_HOST_CONFIG; then
|
||||
echo -e "\nComponent \"internal.auth.$JVB_HOSTNAME\" \"muc\"" >> $PROSODY_HOST_CONFIG
|
||||
echo -e " storage = \"null\"" >> $PROSODY_HOST_CONFIG
|
||||
echo -e " storage = \"memory\"" >> $PROSODY_HOST_CONFIG
|
||||
echo -e " modules_enabled = { \"ping\"; }" >> $PROSODY_HOST_CONFIG
|
||||
echo -e " admins = { \"$JICOFO_AUTH_USER@auth.$JVB_HOSTNAME\", \"jvb@auth.$JVB_HOSTNAME\" }" >> $PROSODY_HOST_CONFIG
|
||||
fi
|
||||
@@ -148,14 +151,13 @@ case "$1" in
|
||||
ln -sf /var/lib/prosody/$JVB_HOSTNAME.crt /etc/prosody/certs/$JVB_HOSTNAME.crt
|
||||
fi
|
||||
|
||||
PR11_INSTALL_CHECK="$(dpkg-query -f '${Status}' -W 'prosody-0.11' 2>/dev/null | awk '{print $3}' || true)"
|
||||
PRTRUNK_INSTALL_CHECK="$(dpkg-query -f '${Status}' -W 'prosody-trunk' 2>/dev/null | awk '{print $3}' || true)"
|
||||
PR10_INSTALL_CHECK="$(dpkg-query -f '${Status}' -W 'prosody-0.10' 2>/dev/null | awk '{print $3}' || true)"
|
||||
PR_VER_INSTALLED=$(dpkg-query -f='${Version}\n' --show prosody 2>/dev/null || true)
|
||||
if [ "$PR11_INSTALL_CHECK" = "installed" ] \
|
||||
|| [ "$PR11_INSTALL_CHECK" = "unpacked" ] \
|
||||
|| dpkg --compare-versions "$PR_VER_INSTALLED" gt "0.11" ; then
|
||||
if [ "$PRTRUNK_INSTALL_CHECK" = "installed" ] \
|
||||
|| [ "$PRTRUNK_INSTALL_CHECK" = "unpacked" ] ; then
|
||||
if [ -f $PROSODY_HOST_CONFIG ]; then
|
||||
sed -i 's/storage = \"null\"/storage = \"memory\"/g' $PROSODY_HOST_CONFIG
|
||||
sed -i 's/storage = \"memory\"/storage = \"null\"/g' $PROSODY_HOST_CONFIG
|
||||
|
||||
# trigger a restart
|
||||
PROSODY_CONFIG_PRESENT="false"
|
||||
@@ -168,7 +170,7 @@ case "$1" in
|
||||
# if the version is 0.10.X (>0.10 and <0.11)
|
||||
if [ -f $PROSODY_HOST_CONFIG ] \
|
||||
&& dpkg --compare-versions "$PR_VER_INSTALLED" lt "0.11" ; then
|
||||
sed -i 's/storage = \"null\"/storage = \"none\"/g' $PROSODY_HOST_CONFIG
|
||||
sed -i 's/storage = \"memory\"/storage = \"none\"/g' $PROSODY_HOST_CONFIG
|
||||
|
||||
# trigger a restart
|
||||
PROSODY_CONFIG_PRESENT="false"
|
||||
|
||||
13
debian/jitsi-meet-tokens.postinst
vendored
13
debian/jitsi-meet-tokens.postinst
vendored
@@ -69,12 +69,15 @@ case "$1" in
|
||||
echo "Failed to install basexx - try installing it manually"
|
||||
fi
|
||||
|
||||
PR11_INSTALL_CHECK="$(dpkg-query -f '${Status}' -W 'prosody-0.11' 2>/dev/null | awk '{print $3}' || true)"
|
||||
PR10_INSTALL_CHECK="$(dpkg-query -f '${Status}' -W 'prosody-0.10' 2>/dev/null | awk '{print $3}' || true)"
|
||||
PRTRUNK_INSTALL_CHECK="$(dpkg-query -f '${Status}' -W 'prosody-trunk' 2>/dev/null | awk '{print $3}' || true)"
|
||||
PR_VER_INSTALLED=$(dpkg-query -f='${Version}\n' --show prosody 2>/dev/null || true)
|
||||
if [ "$PR11_INSTALL_CHECK" = "installed" ] \
|
||||
|| [ "$PR11_INSTALL_CHECK" = "unpacked" ] \
|
||||
|| dpkg --compare-versions "$PR_VER_INSTALLED" gt "0.11" ; then
|
||||
sed -i 's/module:hook/module:hook_global/g' /usr/share/jitsi-meet/prosody-plugins/mod_auth_token.lua
|
||||
if [ "$PR10_INSTALL_CHECK" = "installed" ] \
|
||||
|| "$PR10_INSTALL_CHECK" = "unpacked" \
|
||||
|| "$PRTRUNK_INSTALL_CHECK" = "installed" \
|
||||
|| "$PRTRUNK_INSTALL_CHECK" = "unpacked" \
|
||||
|| dpkg --compare-versions "$PR_VER_INSTALLED" lt "0.11" ; then
|
||||
sed -i 's/module:hook_global(/module:hook(/g' /usr/share/jitsi-meet/prosody-plugins/mod_auth_token.lua
|
||||
fi
|
||||
|
||||
if [ -x "/etc/init.d/prosody" ]; then
|
||||
|
||||
5
debian/jitsi-meet-turnserver.install
vendored
5
debian/jitsi-meet-turnserver.install
vendored
@@ -1,2 +1,3 @@
|
||||
doc/debian/jitsi-meet-turn/turnserver.conf /usr/share/jitsi-meet-turnserver/
|
||||
doc/debian/jitsi-meet/jitsi-meet.conf /usr/share/jitsi-meet-turnserver/
|
||||
doc/debian/jitsi-meet-turn/turnserver.conf /usr/share/jitsi-meet-turnserver/
|
||||
doc/debian/jitsi-meet/jitsi-meet.conf /usr/share/jitsi-meet-turnserver/
|
||||
doc/debian/jitsi-meet-turn/coturn-certbot-deploy.sh /usr/share/jitsi-meet-turnserver/
|
||||
|
||||
1
debian/jitsi-meet-turnserver.links
vendored
1
debian/jitsi-meet-turnserver.links
vendored
@@ -1 +0,0 @@
|
||||
/usr/share/jitsi-meet-turnserver/jitsi-meet.conf /etc/nginx/modules-enabled/60-jitsi-meet.conf
|
||||
129
debian/jitsi-meet-turnserver.postinst
vendored
129
debian/jitsi-meet-turnserver.postinst
vendored
@@ -36,20 +36,60 @@ 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 4445 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
|
||||
mv $TURN_CONFIG $TURN_CONFIG.bak
|
||||
fi
|
||||
|
||||
# detect dpkg-reconfigure, just delete old links
|
||||
db_get jitsi-meet-turnserver/jvb-hostname
|
||||
JVB_HOSTNAME_OLD=$RET
|
||||
if [ -n "$RET" ] && [ ! "$JVB_HOSTNAME_OLD" = "$JVB_HOSTNAME" ] ; then
|
||||
rm -f $TURN_CONFIG
|
||||
if [[ -f $TURN_CONFIG ]] && grep -q "jitsi-meet coturn config" "$TURN_CONFIG" ; then
|
||||
rm -f $TURN_CONFIG
|
||||
fi
|
||||
fi
|
||||
|
||||
# this detect only old installations with no nginx
|
||||
db_get jitsi-meet/jvb-serve || true
|
||||
if [ ! -f $NGINX_CONFIG -o "$RET" = "true" ] ; then
|
||||
# nothing to do
|
||||
echo "------------------------------------------------"
|
||||
echo ""
|
||||
echo "turnserver not configured as no nginx found to multiplex traffic"
|
||||
echo "turnserver not configured"
|
||||
echo ""
|
||||
echo "------------------------------------------------"
|
||||
db_stop
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -f $TURN_CONFIG ]] ; then
|
||||
echo "------------------------------------------------"
|
||||
echo ""
|
||||
echo "turnserver is already configured on this machine, skipping."
|
||||
echo ""
|
||||
echo "------------------------------------------------"
|
||||
db_stop
|
||||
exit 0
|
||||
fi
|
||||
@@ -65,46 +105,61 @@ case "$1" in
|
||||
fi
|
||||
TURN_SECRET="$RET"
|
||||
|
||||
if [[ -f $TURN_CONFIG ]] && ! grep -q "jitsi-meet coturn config" "$TURN_CONFIG" ; then
|
||||
PUBLIC_IP=$(dig +short myip.opendns.com @resolver1.opendns.com)
|
||||
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__/$JVB_HOSTNAME/g" $TURN_CONFIG
|
||||
# no turn config exists, lt's copy template and fill it in
|
||||
PUBLIC_IP=$(dig +short myip.opendns.com @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
|
||||
CERT_CHOICE="$RET"
|
||||
# SSL for nginx
|
||||
db_get jitsi-meet/cert-choice
|
||||
CERT_CHOICE="$RET"
|
||||
|
||||
if [ "$CERT_CHOICE" = "I want to use my own certificate" ] ; then
|
||||
db_get jitsi-meet/cert-path-key
|
||||
CERT_KEY="$RET"
|
||||
db_get jitsi-meet/cert-path-crt
|
||||
CERT_CRT="$RET"
|
||||
if [ "$CERT_CHOICE" = "I want to use my own certificate" ] ; then
|
||||
db_get jitsi-meet/cert-path-key
|
||||
CERT_KEY="$RET"
|
||||
db_get jitsi-meet/cert-path-crt
|
||||
CERT_CRT="$RET"
|
||||
|
||||
# replace self-signed certificate paths with user provided ones
|
||||
CERT_KEY_ESC=$(echo $CERT_KEY | sed 's/\./\\\./g')
|
||||
CERT_KEY_ESC=$(echo $CERT_KEY_ESC | sed 's/\//\\\//g')
|
||||
sed -i "s/pkey=\/etc\/jitsi\/meet\/.*key/pkey=$CERT_KEY_ESC/g" $TURN_CONFIG
|
||||
CERT_CRT_ESC=$(echo $CERT_CRT | sed 's/\./\\\./g')
|
||||
CERT_CRT_ESC=$(echo $CERT_CRT_ESC | sed 's/\//\\\//g')
|
||||
sed -i "s/cert=\/etc\/jitsi\/meet\/.*crt/cert=$CERT_CRT_ESC/g" $TURN_CONFIG
|
||||
# replace self-signed certificate paths with user provided ones
|
||||
CERT_KEY_ESC=$(echo $CERT_KEY | sed 's/\./\\\./g')
|
||||
CERT_KEY_ESC=$(echo $CERT_KEY_ESC | sed 's/\//\\\//g')
|
||||
sed -i "s/pkey=\/etc\/jitsi\/meet\/.*key/pkey=$CERT_KEY_ESC/g" $TURN_CONFIG
|
||||
CERT_CRT_ESC=$(echo $CERT_CRT | sed 's/\./\\\./g')
|
||||
CERT_CRT_ESC=$(echo $CERT_CRT_ESC | sed 's/\//\\\//g')
|
||||
sed -i "s/cert=\/etc\/jitsi\/meet\/.*crt/cert=$CERT_CRT_ESC/g" $TURN_CONFIG
|
||||
fi
|
||||
|
||||
sed -i "s/#TURNSERVER_ENABLED/TURNSERVER_ENABLED/g" /etc/default/coturn
|
||||
invoke-rc.d coturn restart || true
|
||||
|
||||
NGINX_STREAM_CONFIG="/etc/nginx/modules-enabled/60-jitsi-meet.conf"
|
||||
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"/"4445"/g' $PROSODY_HOST_CONFIG
|
||||
invoke-rc.d prosody restart || true
|
||||
fi
|
||||
fi
|
||||
|
||||
sed -i "s/#TURNSERVER_ENABLED/TURNSERVER_ENABLED/g" /etc/default/coturn
|
||||
invoke-rc.d coturn restart || true
|
||||
|
||||
NGINX_STREAM_CONFIG="/etc/nginx/modules-enabled/60-jitsi-meet.conf"
|
||||
if [ -f $NGINX_STREAM_CONFIG ] && [ -f $NGINX_CONFIG ] ; then
|
||||
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
|
||||
fi
|
||||
|
||||
# Enable turn server in config.js
|
||||
if [ -f $JITSI_MEET_CONFIG ] ; then
|
||||
sed -i "s/\/\/ useStunTurn: true/useStunTurn: true/g" $JITSI_MEET_CONFIG
|
||||
fi
|
||||
# Enable turn server in config.js
|
||||
if [ -f $JITSI_MEET_CONFIG ] ; then
|
||||
sed -i "s/\/\/ useStunTurn: true/useStunTurn: true/g" $JITSI_MEET_CONFIG
|
||||
fi
|
||||
|
||||
# and we're done with debconf
|
||||
|
||||
3
debian/jitsi-meet-turnserver.postrm
vendored
3
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,8 @@ 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
|
||||
fi
|
||||
|
||||
45
doc/README.md
Normal file
45
doc/README.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Documentation
|
||||
|
||||
This document is the entrypoint to different guides, divided in three groups:
|
||||
|
||||
* User guide: these documents are designed to help users of the service, to better
|
||||
understand all the available features and how to use them.
|
||||
|
||||
* Developer guide: these documents are designed to help developers who want to either
|
||||
integrate the Jitsi Meet API / SDK in their products or want to improve Jitsi Meet
|
||||
itself by developing new features or fixing bugs.
|
||||
|
||||
* DevOps guide: these documents are designed for DevOps folks, system administrators
|
||||
or anyone who wishes to deploy and operate their own Jitsi Meet instance.
|
||||
|
||||
## User guide
|
||||
|
||||
Work in progress.
|
||||
|
||||
## Developer guide
|
||||
|
||||
### Web
|
||||
|
||||
* [iframe API](https://github.com/jitsi/jitsi-meet/blob/master/doc/api.md)
|
||||
* [Jitsi Meet development](https://github.com/jitsi/jitsi-meet/blob/master/doc/development.md)
|
||||
|
||||
### Mobile
|
||||
|
||||
* [Building the mobile apps](https://github.com/jitsi/jitsi-meet/blob/master/doc/mobile.md)
|
||||
* [SDK usage examples](https://github.com/jitsi/jitsi-meet-sdk-samples)
|
||||
* [Enabling Dropbox support](https://github.com/jitsi/jitsi-meet/blob/master/doc/mobile-dropbox.md)
|
||||
* [Enabling Google authentication](https://github.com/jitsi/jitsi-meet/blob/master/doc/mobile-google-auth.md)
|
||||
|
||||
## DevOps guide
|
||||
|
||||
* [Quick install](https://github.com/jitsi/jitsi-meet/blob/master/doc/quick-install.md)
|
||||
* [Docker install](https://github.com/jitsi/docker-jitsi-meet/blob/master/README.md)
|
||||
* [Google Calendar, MS Calendar, Dropbox integrations](https://github.com/jitsi/jitsi-meet/blob/master/doc/integrations.md)
|
||||
* [Video tutorials on deployment and scalability](https://jitsi.org/tutorials/)
|
||||
* [Configuring a video SIP gateway](https://github.com/jitsi/jitsi-meet/blob/master/doc/sipgw-config.md)
|
||||
* [Enabling speaker stats](https://github.com/jitsi/jitsi-meet/blob/master/doc/speakerstats-prosody.md)
|
||||
* [Enabling TURN](https://github.com/jitsi/jitsi-meet/blob/master/doc/turn.md)
|
||||
* [Networking FAQ](https://github.com/jitsi/jitsi-meet/blob/master/doc/faq.md)
|
||||
* [Cloud APIs](https://github.com/jitsi/jitsi-meet/blob/master/doc/cloud-api.md)
|
||||
* [Manual Installation](https://github.com/jitsi/jitsi-meet/blob/master/doc/manual-install.md)
|
||||
* [Scalable Installation](https://github.com/jitsi/jitsi-meet/blob/master/doc/scalable-installation.md)
|
||||
17
doc/api.md
17
doc/api.md
@@ -85,14 +85,15 @@ const options = {
|
||||
const api = new JitsiMeetExternalAPI(domain, options);
|
||||
```
|
||||
|
||||
You can set the userInfo(email) for the call:
|
||||
You can set the userInfo(email, display name) for the call:
|
||||
|
||||
```javascript
|
||||
var domain = "meet.jit.si";
|
||||
var options = {
|
||||
...
|
||||
userInfo: {
|
||||
email: 'email@jitsiexamplemail.com'
|
||||
email: 'email@jitsiexamplemail.com',
|
||||
displayName: 'John Doe'
|
||||
}
|
||||
}
|
||||
var api = new JitsiMeetExternalAPI(domain, options);
|
||||
@@ -274,6 +275,10 @@ api.executeCommand('avatarUrl', 'https://avatars0.githubusercontent.com/u/367164
|
||||
```javascript
|
||||
api.executeCommand('receiverParticipantId', 'text');
|
||||
```
|
||||
* **setVideoQuality** - Sets the send and receive video resolution. This command requires one argument - the resolution height to be set.
|
||||
```javascript
|
||||
api.executeCommand('setVideoQuality', 720);
|
||||
```
|
||||
|
||||
You can also execute multiple commands using the `executeCommands` method:
|
||||
```javascript
|
||||
@@ -464,6 +469,14 @@ changes. The listener will receive an object with the following structure:
|
||||
}
|
||||
```
|
||||
|
||||
* **participantRoleChanged** - event notification fired when the role of the local user has changed (none, moderator, participant). The listener will receive an object with the following structure:
|
||||
```javascript
|
||||
{
|
||||
id: string // the id of the participant
|
||||
role: string // the new role of the participant
|
||||
}
|
||||
```
|
||||
|
||||
* **passwordRequired** - event notifications fired when failing to join a room because it has a password.
|
||||
|
||||
* **videoConferenceJoined** - event notifications fired when the local user has joined the video conference. The listener will receive an object with the following structure:
|
||||
|
||||
@@ -6,8 +6,8 @@ muc_mapper_domain_base = "jitmeet.example.com";
|
||||
turncredentials_secret = "__turnSecret__";
|
||||
|
||||
turncredentials = {
|
||||
{ type = "stun", host = "jitmeet.example.com", port = "443" },
|
||||
{ type = "turn", host = "jitmeet.example.com", port = "443", transport = "udp" },
|
||||
{ type = "stun", host = "jitmeet.example.com", port = "4446" },
|
||||
{ type = "turn", host = "jitmeet.example.com", port = "4446", transport = "udp" },
|
||||
{ type = "turns", host = "jitmeet.example.com", port = "443", transport = "tcp" }
|
||||
};
|
||||
|
||||
@@ -43,7 +43,7 @@ VirtualHost "jitmeet.example.com"
|
||||
c2s_require_encryption = false
|
||||
|
||||
Component "conference.jitmeet.example.com" "muc"
|
||||
storage = "null"
|
||||
storage = "memory"
|
||||
modules_enabled = {
|
||||
"muc_meeting_id";
|
||||
"muc_domain_mapper";
|
||||
@@ -55,11 +55,13 @@ Component "conference.jitmeet.example.com" "muc"
|
||||
|
||||
-- internal muc component
|
||||
Component "internal.auth.jitmeet.example.com" "muc"
|
||||
storage = "null"
|
||||
storage = "memory"
|
||||
modules_enabled = {
|
||||
"ping";
|
||||
}
|
||||
admins = { "focusUser@auth.jitmeet.example.com", "jvb@auth.jitmeet.example.com" }
|
||||
muc_room_locking = false
|
||||
muc_room_default_public_jids = true
|
||||
|
||||
VirtualHost "auth.jitmeet.example.com"
|
||||
authentication = "internal_plain"
|
||||
|
||||
45
doc/debian/jitsi-meet-turn/coturn-certbot-deploy.sh
Normal file
45
doc/debian/jitsi-meet-turn/coturn-certbot-deploy.sh
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
COTURN_CERT_DIR="/etc/coturn/certs"
|
||||
TURN_CONFIG="/etc/turnserver.conf"
|
||||
|
||||
# create a directory to store certs if it does not exists
|
||||
if [ ! -d "$COTURN_CERT_DIR" ]; then
|
||||
mkdir -p $COTURN_CERT_DIR
|
||||
chown -R turnserver:turnserver /etc/coturn/
|
||||
chmod -R 700 /etc/coturn/
|
||||
fi
|
||||
|
||||
# This is a template and when copied to /etc/letsencrypt/renewal-hooks/deploy/
|
||||
# during creating the Let's encrypt certs script
|
||||
# jitsi-meet.example.com will be replaced with the real domain of deployment
|
||||
for domain in $RENEWED_DOMAINS; do
|
||||
case $domain in
|
||||
jitsi-meet.example.com)
|
||||
# Make sure the certificate and private key files are
|
||||
# never world readable, even just for an instant while
|
||||
# we're copying them into daemon_cert_root.
|
||||
umask 077
|
||||
|
||||
cp "$RENEWED_LINEAGE/fullchain.pem" "$COTURN_CERT_DIR/$domain.fullchain.pem"
|
||||
cp "$RENEWED_LINEAGE/privkey.pem" "$COTURN_CERT_DIR/$domain.privkey.pem"
|
||||
|
||||
# Apply the proper file ownership and permissions for
|
||||
# the daemon to read its certificate and key.
|
||||
chown turnserver "$COTURN_CERT_DIR/$domain.fullchain.pem" \
|
||||
"$COTURN_CERT_DIR/$domain.privkey.pem"
|
||||
chmod 400 "$COTURN_CERT_DIR/$domain.fullchain.pem" \
|
||||
"$COTURN_CERT_DIR/$domain.privkey.pem"
|
||||
|
||||
if [ -f $TURN_CONFIG ] && grep -q "jitsi-meet coturn config" "$TURN_CONFIG" ; then
|
||||
echo "Configuring turnserver"
|
||||
sed -i "/^cert/c\cert=\/etc\/coturn\/certs\/${domain}.fullchain.pem" $TURN_CONFIG
|
||||
sed -i "/^pkey/c\pkey=\/etc\/coturn\/certs\/${domain}.privkey.pem" $TURN_CONFIG
|
||||
fi
|
||||
service coturn restart
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# jitsi-meet coturn config. Do not modify this line
|
||||
lt-cred-mech
|
||||
use-auth-secret
|
||||
keep-address-family
|
||||
static-auth-secret=__turnSecret__
|
||||
@@ -8,6 +7,8 @@ cert=/etc/jitsi/meet/jitsi-meet.example.com.crt
|
||||
pkey=/etc/jitsi/meet/jitsi-meet.example.com.key
|
||||
|
||||
no-tcp
|
||||
listening-port=443
|
||||
listening-port=4446
|
||||
tls-listening-port=4445
|
||||
external-ip=__external_ip_address__
|
||||
|
||||
syslog
|
||||
|
||||
@@ -11,14 +11,14 @@ stream {
|
||||
}
|
||||
# since 1.13.10
|
||||
map $ssl_preread_alpn_protocols $upstream {
|
||||
"h2" web;
|
||||
"http/1.1" web;
|
||||
"h2,http/1.1" web;
|
||||
~\bh2\b web;
|
||||
~\bhttp/1\. web;
|
||||
default turn;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443;
|
||||
listen [::]:443;
|
||||
|
||||
# since 1.11.5
|
||||
ssl_preread on;
|
||||
|
||||
@@ -39,6 +39,10 @@ server {
|
||||
index index.html index.htm;
|
||||
error_page 404 /static/404.html;
|
||||
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/javascript application/json;
|
||||
gzip_vary on;
|
||||
|
||||
location = /config.js {
|
||||
alias /etc/jitsi/meet/jitsi-meet.example.com-config.js;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Building the sources
|
||||
|
||||
Node.js >= 10 and npm >= 6 are required.
|
||||
Node.js >= 12 and npm >= 6 are required.
|
||||
|
||||
On Debian/Ubuntu systems, the required packages can be installed with:
|
||||
```
|
||||
@@ -69,10 +69,14 @@ Use it at the CLI, type
|
||||
make dev
|
||||
```
|
||||
|
||||
By default the backend deployment used is `beta.meet.jit.si`. You can point the Jitsi-Meet app at a different backend by using a proxy server. To do this, set the WEBPACK_DEV_SERVER_PROXY_TARGET variable:
|
||||
By default the backend deployment used is `alpha.jitsi.net`. You can point the Jitsi-Meet app at a different backend by using a proxy server. To do this, set the WEBPACK_DEV_SERVER_PROXY_TARGET variable:
|
||||
```
|
||||
export WEBPACK_DEV_SERVER_PROXY_TARGET=https://your-example-server.com
|
||||
make dev
|
||||
```
|
||||
|
||||
The app should be running at https://localhost:8080/
|
||||
|
||||
#### Chrome Privacy Error
|
||||
|
||||
Newer versions of Chrome may block localhost under https and show `NET::ERR_CERT_INVALID` on the page. To solve this open [chrome://flags/#allow-insecure-localhost](chrome://flags/#allow-insecure-localhost) and select Enable, then press Relaunch or quit and restart Chrome.
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# Jitsi Conference Focus settings
|
||||
# sets the host name of the XMPP server
|
||||
JICOFO_HOST=localhost
|
||||
|
||||
# sets the XMPP domain (default: none)
|
||||
JICOFO_HOSTNAME=meet.example.com
|
||||
|
||||
# sets the secret used to authenticate as an XMPP component
|
||||
JICOFO_SECRET=$JICOFO_SECRET
|
||||
|
||||
# sets the port to use for the XMPP component connection
|
||||
JICOFO_PORT=5347
|
||||
|
||||
# sets the XMPP domain name to use for XMPP user logins
|
||||
JICOFO_AUTH_DOMAIN=auth.meet.example.com
|
||||
|
||||
# sets the username to use for XMPP user logins
|
||||
JICOFO_AUTH_USER=focus
|
||||
|
||||
# sets the password to use for XMPP user logins
|
||||
JICOFO_AUTH_PASSWORD=$JICOFO_PASSWORD
|
||||
|
||||
# extra options to pass to the jicofo daemon
|
||||
JICOFO_OPTS=""
|
||||
|
||||
# adds java system props that are passed to jicofo (default are for home and logging config file)
|
||||
JAVA_SYS_PROPS="-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION=/etc/jitsi -Dnet.java.sip.communicator.SC_HOME_DIR_NAME=jicofo -Dnet.java.sip.communicator.SC_LOG_DIR_LOCATION=/var/log/jitsi -Djava.util.logging.config.file=/etc/jitsi/jicofo/logging.properties"
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
org.jitsi.jicofo.BRIDGE_MUC=JvbBrewery@internal.auth.meet.example.com
|
||||
org.jitsi.jicofo.ALWAYS_TRUST_MODE_ENABLED=true
|
||||
|
||||
org.jitsi.jicofo.jibri.BREWERY=JibriBrewery@internal.auth.meet.example.com
|
||||
org.jitsi.jicofo.jibri.PENDING_TIMEOUT=90
|
||||
@@ -0,0 +1,88 @@
|
||||
plugin_paths = { "/usr/share/jitsi-meet/prosody-plugins/" }
|
||||
|
||||
-- domain mapper options, must at least have domain base set to use the mapper
|
||||
muc_mapper_domain_base = "meet.example.com";
|
||||
|
||||
turncredentials_secret = "turncredentials_secret_test";
|
||||
|
||||
turncredentials = {
|
||||
{ type = "stun", host = "meet.example.com", port = "443" },
|
||||
{ type = "turn", host = "meet.example.com", port = "443", transport = "udp" },
|
||||
{ type = "turns", host = "meet.example.com", port = "443", transport = "tcp" }
|
||||
};
|
||||
|
||||
cross_domain_bosh = false;
|
||||
consider_bosh_secure = true;
|
||||
|
||||
VirtualHost "meet.example.com"
|
||||
-- enabled = false -- Remove this line to enable this host
|
||||
authentication = "anonymous"
|
||||
-- Properties below are modified by jitsi-meet-tokens package config
|
||||
-- and authentication above is switched to "token"
|
||||
--app_id="example_app_id"
|
||||
--app_secret="example_app_secret"
|
||||
-- Assign this host a certificate for TLS, otherwise it would use the one
|
||||
-- set in the global section (if any).
|
||||
-- Note that old-style SSL on port 5223 only supports one certificate, and will always
|
||||
-- use the global one.
|
||||
ssl = {
|
||||
key = "/etc/prosody/certs/meet.example.com.key";
|
||||
certificate = "/etc/prosody/certs/meet.example.com.crt";
|
||||
}
|
||||
speakerstats_component = "speakerstats.meet.example.com"
|
||||
conference_duration_component = "conferenceduration.meet.example.com"
|
||||
-- we need bosh
|
||||
modules_enabled = {
|
||||
"bosh";
|
||||
"pubsub";
|
||||
"ping"; -- Enable mod_ping
|
||||
"speakerstats";
|
||||
"turncredentials";
|
||||
"conference_duration";
|
||||
}
|
||||
c2s_require_encryption = false
|
||||
|
||||
Component "conference.meet.example.com" "muc"
|
||||
storage = "memory"
|
||||
modules_enabled = {
|
||||
"muc_meeting_id";
|
||||
"muc_domain_mapper";
|
||||
-- "token_verification";
|
||||
}
|
||||
admins = { "focus@auth.meet.example.com" }
|
||||
muc_room_locking = false
|
||||
muc_room_default_public_jids = true
|
||||
|
||||
-- internal muc component
|
||||
-- Note: This is also used from jibris
|
||||
Component "internal.auth.meet.example.com" "muc"
|
||||
storage = "memory"
|
||||
modules_enabled = {
|
||||
"ping";
|
||||
}
|
||||
admins = { "focus@auth.meet.example.com", "jvb@auth.meet.example.com" }
|
||||
|
||||
VirtualHost "auth.meet.example.com"
|
||||
ssl = {
|
||||
key = "/etc/prosody/certs/auth.meet.example.com.key";
|
||||
certificate = "/etc/prosody/certs/auth.meet.example.com.crt";
|
||||
}
|
||||
authentication = "internal_plain"
|
||||
|
||||
Component "focus.meet.example.com"
|
||||
component_secret = "jicofo_secret_test"
|
||||
|
||||
Component "speakerstats.meet.example.com" "speakerstats_component"
|
||||
muc_component = "conference.meet.example.com"
|
||||
|
||||
|
||||
Component "conferenceduration.meet.example.com" "conference_duration_component"
|
||||
muc_component = "conference.meet.example.com"
|
||||
|
||||
-- for Jibri
|
||||
VirtualHost "recorder.meet.example.com"
|
||||
modules_enabled = {
|
||||
"ping";
|
||||
}
|
||||
authentication = "internal_plain"
|
||||
c2s_require_encryption = false
|
||||
@@ -0,0 +1,114 @@
|
||||
-- Prosody XMPP Server Configuration
|
||||
|
||||
---------- Server-wide settings ----------
|
||||
-- Settings in this section apply to the whole server and are the default settings
|
||||
-- for any virtual hosts
|
||||
|
||||
admins = { }
|
||||
|
||||
network_backend = "epoll"
|
||||
|
||||
-- This is the list of modules Prosody will load on startup.
|
||||
-- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too.
|
||||
-- Documentation for bundled modules can be found at: https://prosody.im/doc/modules
|
||||
modules_enabled = {
|
||||
|
||||
-- Generally required
|
||||
"roster"; -- Allow users to have a roster. Recommended ;)
|
||||
"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
|
||||
"tls"; -- Add support for secure TLS on c2s/s2s connections
|
||||
"dialback"; -- s2s dialback support
|
||||
"disco"; -- Service discovery
|
||||
|
||||
-- Not essential, but recommended
|
||||
"carbons"; -- Keep multiple clients in sync
|
||||
"pep"; -- Enables users to publish their avatar, mood, activity, playing music and more
|
||||
"private"; -- Private XML storage (for room bookmarks, etc.)
|
||||
"blocklist"; -- Allow users to block communications with other users
|
||||
"vcard4"; -- User profiles (stored in PEP)
|
||||
"vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard
|
||||
|
||||
-- Nice to have
|
||||
"version"; -- Replies to server version requests
|
||||
"uptime"; -- Report how long server has been running
|
||||
"time"; -- Let others know the time here on this server
|
||||
"ping"; -- Replies to XMPP pings with pongs
|
||||
"register"; -- Allow users to register on this server using a client and change passwords
|
||||
--"mam"; -- Store messages in an archive and allow users to access it
|
||||
--"csi_simple"; -- Simple Mobile optimizations
|
||||
|
||||
-- Admin interfaces
|
||||
"admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
|
||||
--"admin_telnet"; -- Opens telnet console interface on localhost port 5582
|
||||
|
||||
-- HTTP modules
|
||||
--"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
|
||||
--"websocket"; -- XMPP over WebSockets
|
||||
--"http_files"; -- Serve static files from a directory over HTTP
|
||||
|
||||
-- Other specific functionality
|
||||
--"limits"; -- Enable bandwidth limiting for XMPP connections
|
||||
--"groups"; -- Shared roster support
|
||||
--"server_contact_info"; -- Publish contact information for this service
|
||||
--"announce"; -- Send announcement to all online users
|
||||
--"welcome"; -- Welcome users who register accounts
|
||||
--"watchregistrations"; -- Alert admins of registrations
|
||||
--"motd"; -- Send a message to users when they log in
|
||||
--"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
|
||||
--"proxy65"; -- Enables a file transfer proxy service which clients behind NAT can use
|
||||
}
|
||||
|
||||
-- These modules are auto-loaded, but should you want
|
||||
-- to disable them then uncomment them here:
|
||||
modules_disabled = {
|
||||
-- "offline"; -- Store offline messages
|
||||
-- "c2s"; -- Handle client connections
|
||||
-- "s2s"; -- Handle server-to-server connections
|
||||
-- "posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
|
||||
}
|
||||
|
||||
-- Disable account creation by default, for security
|
||||
-- For more information see https://prosody.im/doc/creating_accounts
|
||||
allow_registration = false
|
||||
|
||||
-- Force clients to use encrypted connections? This option will
|
||||
-- prevent clients from authenticating unless they are using encryption.
|
||||
|
||||
c2s_require_encryption = true
|
||||
|
||||
-- Force servers to use encrypted connections? This option will
|
||||
-- prevent servers from authenticating unless they are using encryption.
|
||||
|
||||
s2s_require_encryption = true
|
||||
|
||||
-- Force certificate authentication for server-to-server connections?
|
||||
|
||||
s2s_secure_auth = false
|
||||
|
||||
|
||||
-- Required for init scripts and prosodyctl
|
||||
pidfile = "/var/run/prosody/prosody.pid"
|
||||
|
||||
-- Select the authentication backend to use. The 'internal' providers
|
||||
-- use Prosody's configured data storage to store the authentication data.
|
||||
|
||||
authentication = "internal_hashed"
|
||||
|
||||
archive_expires_after = "1w" -- Remove archived messages after 1 week
|
||||
|
||||
-- Logging configuration
|
||||
-- For advanced logging see https://prosody.im/doc/logging
|
||||
log = {
|
||||
info = "/var/log/prosody/prosody.log"; -- Change 'info' to 'debug' for verbose logging
|
||||
error = "/var/log/prosody/prosody.err";
|
||||
-- "*syslog"; -- Uncomment this for logging to syslog
|
||||
-- "*console"; -- Log to the console, useful for debugging with daemonize=false
|
||||
}
|
||||
|
||||
|
||||
-- Location of directory to find certificates in (relative to main config file):
|
||||
certificates = "certs"
|
||||
|
||||
VirtualHost "localhost"
|
||||
|
||||
Include "conf.d/*.cfg.lua"
|
||||
@@ -0,0 +1,20 @@
|
||||
# Jitsi Videobridge settings
|
||||
|
||||
# sets the XMPP domain (default: none)
|
||||
JVB_HOSTNAME=meet.example.com
|
||||
|
||||
# sets the hostname of the XMPP server (default: domain if set, localhost otherwise)
|
||||
JVB_HOST=
|
||||
|
||||
# sets the port of the XMPP server (default: 5275)
|
||||
JVB_PORT=5347
|
||||
|
||||
# sets the shared secret used to authenticate to the XMPP server
|
||||
JVB_SECRET=$VP_SECRET
|
||||
|
||||
# extra options to pass to the JVB daemon
|
||||
JVB_OPTS="--apis=rest,"
|
||||
|
||||
|
||||
# adds java system props that are passed to jvb (default are for home and logging config file)
|
||||
JAVA_SYS_PROPS="-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION=/etc/jitsi -Dnet.java.sip.communicator.SC_HOME_DIR_NAME=videobridge -Dnet.java.sip.communicator.SC_LOG_DIR_LOCATION=/var/log/jitsi -Djava.util.logging.config.file=/etc/jitsi/videobridge/logging.properties"
|
||||
@@ -0,0 +1,19 @@
|
||||
org.ice4j.ice.harvest.DISABLE_AWS_HARVESTER=true
|
||||
org.ice4j.ice.harvest.STUN_MAPPING_HARVESTER_ADDRESSES=meet-jit-si-turnrelay.jitsi.net:443
|
||||
|
||||
org.jitsi.jicofo.ALWAYS_TRUST_MODE_ENABLED=true
|
||||
|
||||
org.jitsi.videobridge.ENABLE_REST_SHUTDOWN=true
|
||||
|
||||
# Enable broadcasting stats/presence in a MUC
|
||||
org.jitsi.videobridge.ENABLE_STATISTICS=true
|
||||
org.jitsi.videobridge.STATISTICS_TRANSPORT=muc,colibri,rest
|
||||
org.jitsi.videobridge.STATISTICS_INTERVAL=5000
|
||||
|
||||
org.jitsi.videobridge.xmpp.user.shard-1.HOSTNAME=meet.example.com
|
||||
org.jitsi.videobridge.xmpp.user.shard-1.DOMAIN=auth.meet.example.com
|
||||
org.jitsi.videobridge.xmpp.user.shard-1.USERNAME=jvb
|
||||
org.jitsi.videobridge.xmpp.user.shard-1.PASSWORD=$VB_PASSWORD
|
||||
org.jitsi.videobridge.xmpp.user.shard-1.MUC_JIDS=JvbBrewery@internal.auth.meet.example.com
|
||||
org.jitsi.videobridge.xmpp.user.shard-1.MUC_NICKNAME=$NICKNAME_OF_VB
|
||||
org.jitsi.videobridge.xmpp.user.shard-1.DISABLE_CERTIFICATE_VERIFICATION=true
|
||||
@@ -8,6 +8,8 @@ change references to that to match your host, and generate some passwords for
|
||||
|
||||
There are also some complete [example config files](https://github.com/jitsi/jitsi-meet/tree/master/doc/example-config-files/) available, mentioned in each section.
|
||||
|
||||
There are additional configurations to be done for a [scalable installation](https://github.com/jitsi/jitsi-meet/tree/master/doc/scalable-installation.md)
|
||||
|
||||
## Network description
|
||||
|
||||
This is how the network looks:
|
||||
@@ -225,7 +227,7 @@ npm install
|
||||
make
|
||||
```
|
||||
|
||||
_NOTE: When installing on older distributions keep in mind that you need Node.js >= 10 and npm >= 6._
|
||||
_NOTE: When installing on older distributions keep in mind that you need Node.js >= 12 and npm >= 6._
|
||||
|
||||
Edit host names in `/srv/jitsi-meet/config.js` (see also the example config file):
|
||||
```
|
||||
|
||||
@@ -7,8 +7,10 @@ Jitsi Meet can be built as a standalone app for Android or iOS. It uses the
|
||||
|
||||
First make sure the [React Native dependencies] are installed.
|
||||
|
||||
**NOTE**: This document assumes the app is being built on a macOS system.
|
||||
**NOTE**: Node 10.X and npm 6.X are recommended for building.
|
||||
**NOTE**: This document assumes the app is being built on a macOS system. GNU/Linux is also
|
||||
supported for building the Android app and Windows **is not supported at alll**.
|
||||
|
||||
**NOTE**: Node 12.X and npm 6.X are recommended for building.
|
||||
|
||||
|
||||
## iOS
|
||||
|
||||
@@ -22,14 +22,22 @@ Finally on the same machine test that you can ping the FQDN with: `ping "$(hostn
|
||||
|
||||
### Add the Jitsi package repository
|
||||
```sh
|
||||
echo 'deb https://download.jitsi.org stable/' >> /etc/apt/sources.list.d/jitsi-stable.list
|
||||
wget -qO - https://download.jitsi.org/jitsi-key.gpg.key | apt-key add -
|
||||
echo 'deb https://download.jitsi.org stable/' | sudo tee /etc/apt/sources.list.d/jitsi-stable.list
|
||||
wget -qO - https://download.jitsi.org/jitsi-key.gpg.key | sudo apt-key add -
|
||||
```
|
||||
### Open ports in your firewall
|
||||
|
||||
Open the following ports in your firewall, to allow traffic to the machine running jitsi:
|
||||
|
||||
- 80 TCP
|
||||
- 443 TCP
|
||||
- 10000 UDP
|
||||
|
||||
|
||||
### Install Jitsi Meet
|
||||
|
||||
_Note_: The installer will check if [Nginx](https://nginx.org/) or [Apache](https://httpd.apache.org/) is present (in that order) and configure a virtualhost within the web server it finds to serve Jitsi Meet. If none of the above is found it then defaults to Nginx.
|
||||
If you are already running Nginx on port 443 on the same machine you better skip the turnserver configuration as it will conflict with your current port 443, so use the command `apt install --no-install-recommends jitsi-meet`.
|
||||
If you are already running Nginx on port 443 on the same machine turnserver configuration will be skipped as it will conflict with your current port 443.
|
||||
|
||||
```sh
|
||||
# Ensure support is available for apt repositories served via HTTPS
|
||||
@@ -50,7 +58,7 @@ This hostname (or IP address) will be used for virtualhost configuration inside
|
||||
|
||||
In order to have encrypted communications, you need a [TLS certificate](https://en.wikipedia.org/wiki/Transport_Layer_Security). The easiest way is to use [Let's Encrypt](https://letsencrypt.org/).
|
||||
|
||||
_Note_: Jitsi Meet mobile apps *require* a valid certificate signed by a trusted [Certificate Authority](https://en.wikipedia.org/wiki/Certificate_authority) and will not be able to connect to your server if you choose a self-signed certificate.
|
||||
_Note_: Jitsi Meet mobile apps *require* a valid certificate signed by a trusted [Certificate Authority](https://en.wikipedia.org/wiki/Certificate_authority) (such as a Let's Encrypt certificate) and will not be able to connect to your server if you choose a self-signed certificate.
|
||||
|
||||
Simply run the following in your shell:
|
||||
|
||||
@@ -73,12 +81,18 @@ See [the documentation of ice4j](https://github.com/jitsi/ice4j/blob/master/doc/
|
||||
for details.
|
||||
|
||||
Default deployments on systems using systemd will have low default values for maximum processes and open files. If the used bridge will expect higher number of participants the default values need to be adjusted (the default values are good for less than 100 participants).
|
||||
To update the values edit `/etc/systemd/system.conf` and make sure you have the following values:
|
||||
To update the values edit `/etc/systemd/system.conf` and make sure you have the following values if values are smaller, if not do not update.
|
||||
```
|
||||
DefaultLimitNOFILE=65000
|
||||
DefaultLimitNPROC=65000
|
||||
DefaultTasksMax=65000
|
||||
```
|
||||
To check values just run :
|
||||
```
|
||||
systemctl show --property DefaultLimitNPROC
|
||||
systemctl show --property DefaultLimitNOFILE
|
||||
systemctl show --property DefaultTasksMax
|
||||
```
|
||||
To load the values and check them look [here](#systemd-details) for details.
|
||||
|
||||
By default, anyone who has access to your jitsi instance will be able to start a conference: if your server is open to the world, anyone can have a chat with anyone else. If you want to limit the ability to start a conference to registered users, set up a "secure domain". Follow the instructions at https://github.com/jitsi/jicofo#secure-domain.
|
||||
|
||||
166
doc/scalable-installation.md
Normal file
166
doc/scalable-installation.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# Scalable Jitsi installation
|
||||
|
||||
A single server Jitsi installation is good for a limited size of concurrent conferences.
|
||||
The first limiting factor is the videobridge component, that handles the actual video and audio traffic.
|
||||
It is easy to scale the video bridges horizontally by adding as many as needed.
|
||||
In a cloud based environment, additionally the bridges can be scaled up or down as needed.
|
||||
|
||||
*NB*: The [Youtube Tutorial on Scaling](https://www.youtube.com/watch?v=LyGV4uW8km8) is outdated and describes an old configuration method.
|
||||
|
||||
*NB*: Building a scalable infrastructure is not a task for beginning Jitsi Administrators.
|
||||
The instructions assume that you have installed a single node version successfully, and that
|
||||
you are comfortable installing, configuring and debugging Linux software.
|
||||
This is not a step-by-step guide, but will show you, which packages to install and which
|
||||
configurations to change. Use the [manual install](https://github.com/jitsi/jitsi-meet/blob/master/doc/manual-install.md) for
|
||||
details on how to setup Jitsi on a single host.
|
||||
It is highly recommended to use configuration management tools like Ansible or Puppet to manage the
|
||||
installation and configuration.
|
||||
|
||||
## Architecture (Single Jitsi-Meet, multiple videobridges)
|
||||
|
||||
A first step is to split the functions of the central jitsi-meet instance (with nginx, prosody and jicofo) and
|
||||
videobridges.
|
||||
|
||||
A simplified diagram (with open network ports) of an installation with one Jitsi-Meet instance and three
|
||||
videobridges that are load balanced looks as follows. Each box is a server/VM.
|
||||
|
||||
```
|
||||
+ +
|
||||
| |
|
||||
| |
|
||||
v v
|
||||
80, 443 TCP 443 TCP, 10000 UDP
|
||||
+--------------+ +---------------------+
|
||||
| nginx | 5222, 5347 TCP | |
|
||||
| jitsi-meet |<-------------------+| jitsi-videobridge |
|
||||
| prosody | | | |
|
||||
| jicofo | | +---------------------+
|
||||
+--------------+ |
|
||||
| +---------------------+
|
||||
| | |
|
||||
+----------+| jitsi-videobridge |
|
||||
| | |
|
||||
| +---------------------+
|
||||
|
|
||||
| +---------------------+
|
||||
| | |
|
||||
+----------+| jitsi-videobridge |
|
||||
| |
|
||||
+---------------------+
|
||||
```
|
||||
|
||||
## Machine Sizing
|
||||
|
||||
The Jitsi-Meet server will generally not have that much load (unless you have many) conferences
|
||||
going at the same time. A 4 CPU, 8 GB machine will probably be fine.
|
||||
|
||||
The videobridges will have more load. 4 or 8 CPU with 8 GB RAM seems to be a good configuration.
|
||||
|
||||
|
||||
### Installation of Jitsi-Meet
|
||||
|
||||
Assuming that the installation will run under the following FQDN: `meet.example.com` and you have
|
||||
SSL cert and key in `/etc/ssl/meet.example.com.{crt,key}`
|
||||
|
||||
Set the following DebConf variables prior to installing the packages.
|
||||
(We are not installing the `jitsi-meet` package which would handle that for us)
|
||||
|
||||
Install the `debconf-utils` package
|
||||
|
||||
```
|
||||
$ cat << EOF | sudo debconf-set-selections
|
||||
jitsi-videobridge jitsi-videobridge/jvb-hostname string meet.example.com
|
||||
jitsi-meet jitsi-meet/jvb-serve boolean false
|
||||
jitsi-meet-prosody jitsi-videobridge/jvb-hostname string meet.example.com
|
||||
jitsi-meet-web-config jitsi-meet/cert-choice select I want to use my own certificate
|
||||
jitsi-meet-web-config jitsi-meet/cert-path-crt string /etc/ssl/meet.example.com.crt
|
||||
jitsi-meet-web-config jitsi-meet/cert-path-key string /etc/ssl/meet.example.com.key
|
||||
EOF
|
||||
```
|
||||
|
||||
On the jitsi-meet server, install the following packages:
|
||||
|
||||
* `nginx`
|
||||
* `prosody`
|
||||
* `jicofo`
|
||||
* `jitsi-meet-web`
|
||||
* `jitsi-meet-prosody`
|
||||
* `jitsi-meet-web-config`
|
||||
|
||||
### Installation of Videobridge(s)
|
||||
|
||||
For simplicities sake, set the same `debconf` variables as above and install
|
||||
|
||||
* `jitsi-videobridge2`
|
||||
|
||||
### Configuration of jitsi-meet
|
||||
|
||||
#### Firewall
|
||||
|
||||
Open the following ports:
|
||||
|
||||
Open to world:
|
||||
|
||||
* 80 TCP
|
||||
* 443 TCP
|
||||
|
||||
Open to the videobridges only
|
||||
|
||||
* 5222 TCP (for Prosody)
|
||||
* 5347 TCP (for Jicofo)
|
||||
|
||||
|
||||
#### NGINX
|
||||
|
||||
Create the `/etc/nginx/sites-available/meet.example.com.conf` as usual
|
||||
|
||||
#### Prosody
|
||||
|
||||
Follow the steps in the [manual install](https://github.com/jitsi/jitsi-meet/blob/master/doc/manual-install.md) for setup tasks
|
||||
|
||||
You will need to adapt the following files (see the files in `example-config-files/scalable`)
|
||||
|
||||
* `/etc/prosody/prosody.cfg.lua`
|
||||
* `/etc/prosody/conf.avail/meet.example.com.cfg.lua`
|
||||
|
||||
#### Jitsi-Meet
|
||||
|
||||
Adapt `/usr/share/jitsi-meet/config.js` and `/usr/share/jitsi-meet/interface-config.js` to your specific needs
|
||||
|
||||
#### Jicofo
|
||||
|
||||
You will need to adapt the following files (see the files in `example-config-files/scalable`)
|
||||
|
||||
* `/etc/jitsi/jicofo/config` (hostname, jicofo_secret, jicofo_password)
|
||||
* `/etc/jitsi/jicofo/sip-communicator.properties` (hostname)
|
||||
|
||||
### Configuration of the Videobridge
|
||||
|
||||
#### Firewall
|
||||
|
||||
Open the following ports:
|
||||
|
||||
Open to world:
|
||||
|
||||
* 443 TCP
|
||||
* 10000 UDP
|
||||
|
||||
#### jitsi-videobridge2
|
||||
|
||||
You will need to adapt the following files (see the files in `example-config-files/scalable`)
|
||||
|
||||
Each videobridge will have to have it's own, unique nickname
|
||||
|
||||
* `/etc/jitsi/videobridge/config` (hostname, password)
|
||||
* `/etc/jitsi/jicofo/sip-communicator.properties` (hostname of jitsi-meet, nickname of videobridge, vb_password)
|
||||
|
||||
With the latest stable (April 2020) videobridge, it is no longer necessary to set public and private IP
|
||||
adresses in the `sip-communicator.properties` as the bridge will figure out the correct configuration by itself.
|
||||
|
||||
## Testing
|
||||
|
||||
After restarting all services (`prosody`, `jicofo` and all the `jitsi-videobridge2`) you can see in
|
||||
`/var/log/prosody/prosody.log` and
|
||||
`/var/log/jitsi/jicofo.log` that the videobridges connect to Prososy and that Jicofo picks them up.
|
||||
|
||||
When a new conference starts, Jicofo picks a videobridge and schedules the conference on it.
|
||||
@@ -51,7 +51,8 @@ var interfaceConfig = {
|
||||
'fodeviceselection', 'hangup', 'profile', 'info', 'chat', 'recording',
|
||||
'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
|
||||
'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
|
||||
'tileview', 'videobackgroundblur', 'download', 'help', 'mute-everyone'
|
||||
'tileview', 'videobackgroundblur', 'download', 'help', 'mute-everyone',
|
||||
'e2ee'
|
||||
],
|
||||
|
||||
SETTINGS_SECTIONS: [ 'devices', 'language', 'moderator', 'profile', 'calendar' ],
|
||||
@@ -175,7 +176,7 @@ var interfaceConfig = {
|
||||
// has a suboptimal experience. Browsers which are not listed as optimal or
|
||||
// unsupported are considered suboptimal. Valid values are:
|
||||
// chrome, chromium, edge, electron, firefox, nwjs, opera, safari
|
||||
OPTIMAL_BROWSERS: [ 'chrome', 'chromium', 'firefox', 'nwjs', 'electron' ],
|
||||
OPTIMAL_BROWSERS: [ 'chrome', 'chromium', 'firefox', 'nwjs', 'electron', 'safari' ],
|
||||
|
||||
// Browsers, in addition to those which do not fully support WebRTC, that
|
||||
// are not supported and should show the unsupported browser page.
|
||||
@@ -206,12 +207,12 @@ var interfaceConfig = {
|
||||
* If this is set to false, the banner will not be rendered at all. If set to true, the check for extension(s)
|
||||
* being already installed is done before rendering.
|
||||
*/
|
||||
SHOW_CHROME_EXTENSION_BANNER: false
|
||||
SHOW_CHROME_EXTENSION_BANNER: false,
|
||||
|
||||
/**
|
||||
* When enabled, the kick participant button will not be presented for users without a JWT
|
||||
*/
|
||||
// HIDE_KICK_BUTTON_FOR_GUESTS: false
|
||||
// HIDE_KICK_BUTTON_FOR_GUESTS: false,
|
||||
|
||||
/**
|
||||
* How many columns the tile view can expand to. The respected range is
|
||||
@@ -229,6 +230,17 @@ var interfaceConfig = {
|
||||
*/
|
||||
// MOBILE_DOWNLOAD_LINK_IOS: 'https://itunes.apple.com/us/app/jitsi-meet/id1165103905',
|
||||
|
||||
/**
|
||||
* Specify Firebase dynamic link properties for the mobile apps.
|
||||
*/
|
||||
// MOBILE_DYNAMIC_LINK: {
|
||||
// APN: 'org.jitsi.meet',
|
||||
// APP_CODE: 'w2atb',
|
||||
// CUSTOM_DOMAIN: undefined,
|
||||
// IBI: 'com.atlassian.JitsiMeet.ios',
|
||||
// ISI: '1165103905'
|
||||
// },
|
||||
|
||||
/**
|
||||
* Specify mobile app scheme for opening the app from the mobile browser.
|
||||
*/
|
||||
@@ -252,6 +264,12 @@ var interfaceConfig = {
|
||||
MOBILE_DYNAMIC_LINK
|
||||
PHONE_NUMBER_REGEX
|
||||
*/
|
||||
|
||||
// Allow all above example options to include a trailing comma and
|
||||
// prevent fear when commenting out the last value.
|
||||
makeJsonParserHappy: 'even if last key had a trailing comma'
|
||||
|
||||
// no configuration value should follow this line.
|
||||
};
|
||||
|
||||
/* eslint-enable no-unused-vars, no-var, max-len */
|
||||
|
||||
@@ -66,6 +66,7 @@ target 'JitsiMeet' do
|
||||
pod 'RNSound', :path => '../node_modules/react-native-sound'
|
||||
pod 'RNSVG', :path => '../node_modules/react-native-svg'
|
||||
pod 'RNWatch', :path => '../node_modules/react-native-watch-connectivity'
|
||||
pod 'RNDefaultPreference', :path => '../node_modules/react-native-default-preference'
|
||||
|
||||
# Native pod dependencies
|
||||
#
|
||||
|
||||
@@ -353,6 +353,8 @@ PODS:
|
||||
- ReactCommon/turbomodule/core (= 0.61.5-jitsi.1)
|
||||
- RNCAsyncStorage (1.3.4):
|
||||
- React
|
||||
- RNDefaultPreference (1.4.2):
|
||||
- React
|
||||
- RNGoogleSignin (3.0.1):
|
||||
- GoogleSignIn (~> 5.0.0)
|
||||
- React
|
||||
@@ -409,6 +411,7 @@ DEPENDENCIES:
|
||||
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
|
||||
- ReactCommon/turbomodule (from `../node_modules/react-native/ReactCommon`)
|
||||
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
|
||||
- RNDefaultPreference (from `../node_modules/react-native-default-preference`)
|
||||
- "RNGoogleSignin (from `../node_modules/@react-native-community/google-signin`)"
|
||||
- RNSound (from `../node_modules/react-native-sound`)
|
||||
- RNSVG (from `../node_modules/react-native-svg`)
|
||||
@@ -416,13 +419,11 @@ DEPENDENCIES:
|
||||
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/CocoaPods/Specs.git:
|
||||
trunk:
|
||||
- Amplitude-iOS
|
||||
- AppAuth
|
||||
- boost-for-react-native
|
||||
- CocoaLumberjack
|
||||
- ObjectiveDropboxOfficial
|
||||
trunk:
|
||||
- AppAuth
|
||||
- Crashlytics
|
||||
- Fabric
|
||||
- Firebase
|
||||
@@ -442,6 +443,7 @@ SPEC REPOS:
|
||||
- GTMAppAuth
|
||||
- GTMSessionFetcher
|
||||
- nanopb
|
||||
- ObjectiveDropboxOfficial
|
||||
- PromisesObjC
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
@@ -509,6 +511,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native/ReactCommon"
|
||||
RNCAsyncStorage:
|
||||
:path: "../node_modules/@react-native-community/async-storage"
|
||||
RNDefaultPreference:
|
||||
:path: "../node_modules/react-native-default-preference"
|
||||
RNGoogleSignin:
|
||||
:path: "../node_modules/@react-native-community/google-signin"
|
||||
RNSound:
|
||||
@@ -578,12 +582,13 @@ SPEC CHECKSUMS:
|
||||
React-RCTVibration: a1bcfcdc0b5a73a1b0829a34cee22bd0e95bacba
|
||||
ReactCommon: 675681aba4fecff5acbc0e440530cc422103c610
|
||||
RNCAsyncStorage: 8e31405a9f12fbf42c2bb330e4560bfd79c18323
|
||||
RNDefaultPreference: 56a405ce61033ac77b95004dccd7ac54c2eb50d1
|
||||
RNGoogleSignin: 39336070b35fc4cea6a98cf111e00480317be0ae
|
||||
RNSound: c980916b596cc15c8dcd2f6ecd3b13c4881dbe20
|
||||
RNSVG: aac12785382e8fd4f28d072fe640612e34914631
|
||||
RNWatch: 09738b339eceb66e4d80a2371633ca5fb380fa42
|
||||
Yoga: 7b4209fda2441f99d54dd6cf4c82b094409bb68f
|
||||
|
||||
PODFILE CHECKSUM: f615794fb9184757b00cd16e534824ba6ee2fc98
|
||||
PODFILE CHECKSUM: 082858daebbe170e7a490de433e7f2a99e0c3701
|
||||
|
||||
COCOAPODS: 1.8.4
|
||||
COCOAPODS: 1.9.1
|
||||
|
||||
@@ -19,7 +19,7 @@ There are 2 ways to integrate the SDK into your project:
|
||||
|
||||
Follow the instructions [here](https://github.com/jitsi/jitsi-meet-ios-sdk-releases/blob/master/README.md).
|
||||
|
||||
### Builduing it yourself
|
||||
### Building it yourself
|
||||
|
||||
1. Install all required [dependencies](https://github.com/jitsi/jitsi-meet/blob/master/doc/mobile.md).
|
||||
|
||||
|
||||
@@ -24,19 +24,10 @@
|
||||
@import Firebase;
|
||||
@import JitsiMeet;
|
||||
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application
|
||||
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||
|
||||
// Initialize Crashlytics and Firebase if a valid GoogleService-Info.plist file was provided.
|
||||
if ([FIRUtilities appContainsRealServiceInfoPlist]) {
|
||||
NSLog(@"Enablign Crashlytics and Firebase");
|
||||
[FIRApp configure];
|
||||
[Fabric with:@[[Crashlytics class]]];
|
||||
}
|
||||
|
||||
JitsiMeet *jitsiMeet = [JitsiMeet sharedInstance];
|
||||
|
||||
jitsiMeet.conferenceActivityType = JitsiMeetConferenceActivityType;
|
||||
@@ -54,6 +45,13 @@
|
||||
#endif
|
||||
}];
|
||||
|
||||
// Initialize Crashlytics and Firebase if a valid GoogleService-Info.plist file was provided.
|
||||
if ([FIRUtilities appContainsRealServiceInfoPlist] && ![jitsiMeet isCrashReportingDisabled]) {
|
||||
NSLog(@"Enabling Crashlytics and Firebase");
|
||||
[FIRApp configure];
|
||||
[Fabric with:@[[Crashlytics class]]];
|
||||
}
|
||||
|
||||
[jitsiMeet application:application didFinishLaunchingWithOptions:launchOptions];
|
||||
|
||||
return YES;
|
||||
|
||||
@@ -16,12 +16,7 @@
|
||||
|
||||
#import "FIRUtilities.h"
|
||||
|
||||
// Plist file name.
|
||||
NSString *const kGoogleServiceInfoFileName = @"GoogleService-Info";
|
||||
// Plist file type.
|
||||
NSString *const kGoogleServiceInfoFileType = @"plist";
|
||||
NSString *const kGoogleAppIDPlistKey = @"GOOGLE_APP_ID";
|
||||
|
||||
@import JitsiMeet;
|
||||
|
||||
@implementation FIRUtilities
|
||||
|
||||
@@ -30,37 +25,11 @@ NSString *const kGoogleAppIDPlistKey = @"GOOGLE_APP_ID";
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSBundle *bundle = [NSBundle mainBundle];
|
||||
containsRealServiceInfoPlist = [self containsRealServiceInfoPlistInBundle:bundle];
|
||||
containsRealServiceInfoPlist = [InfoPlistUtil containsRealServiceInfoPlistInBundle:bundle];
|
||||
});
|
||||
return containsRealServiceInfoPlist;
|
||||
}
|
||||
|
||||
+ (BOOL)containsRealServiceInfoPlistInBundle:(NSBundle *)bundle {
|
||||
NSString *bundlePath = bundle.bundlePath;
|
||||
if (!bundlePath.length) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString *plistFilePath = [bundle pathForResource:kGoogleServiceInfoFileName
|
||||
ofType:kGoogleServiceInfoFileType];
|
||||
if (!plistFilePath.length) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:plistFilePath];
|
||||
if (!plist) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Perform a very naive validation by checking to see if the plist has the dummy google app id
|
||||
NSString *googleAppID = plist[kGoogleAppIDPlistKey];
|
||||
if (!googleAppID.length) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSURL *)extractURL: (FIRDynamicLink*)dynamicLink {
|
||||
NSURL *url = nil;
|
||||
if (dynamicLink != nil) {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>20.2.0</string>
|
||||
<string>20.3.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>20.2.0</string>
|
||||
<string>20.3.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.2.0</string>
|
||||
<string>20.3.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>CLKComplicationPrincipalClass</key>
|
||||
|
||||
@@ -66,6 +66,9 @@ platform :ios do
|
||||
beta_app_feedback_email: ENV["JITSI_REVIEW_EMAIL"],
|
||||
beta_app_review_info: {
|
||||
contact_email: ENV["JITSI_REVIEW_EMAIL"],
|
||||
contact_first_name: ENV["JITSI_REVIEW_NAME"],
|
||||
contact_last_name: ENV["JITSI_REVIEW_SURNAME"],
|
||||
contact_phone: ENV["JITSI_REVIEW_PHONE"],
|
||||
demo_account_name: ENV["JITSI_DEMO_ACCOUNT"],
|
||||
demo_account_password: ENV["JITSI_DEMO_PASSWORD"],
|
||||
},
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
C69EFA0E209A0F660027712B /* JMCallKitListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA0B209A0F660027712B /* JMCallKitListener.swift */; };
|
||||
C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3425E204EF76800E062DD /* DragGestureController.swift */; };
|
||||
C6CC49AF207412CF000DFA42 /* PiPViewCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */; };
|
||||
C8AFD27F2462C613000293D2 /* InfoPlistUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C8AFD27D2462C613000293D2 /* InfoPlistUtil.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C8AFD2802462C613000293D2 /* InfoPlistUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C8AFD27E2462C613000293D2 /* InfoPlistUtil.m */; };
|
||||
DE438CDA2350934700DD541D /* JavaScriptSandbox.m in Sources */ = {isa = PBXBuildFile; fileRef = DE438CD82350934700DD541D /* JavaScriptSandbox.m */; };
|
||||
DE65AACA2317FFCD00290BEC /* LogUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DE65AAC92317FFCD00290BEC /* LogUtils.h */; };
|
||||
DE65AACC2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */; };
|
||||
@@ -105,6 +107,8 @@
|
||||
C6A3425E204EF76800E062DD /* DragGestureController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragGestureController.swift; sourceTree = "<group>"; };
|
||||
C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiPViewCoordinator.swift; sourceTree = "<group>"; };
|
||||
C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetView+Private.h"; sourceTree = "<group>"; };
|
||||
C8AFD27D2462C613000293D2 /* InfoPlistUtil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InfoPlistUtil.h; sourceTree = "<group>"; };
|
||||
C8AFD27E2462C613000293D2 /* InfoPlistUtil.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InfoPlistUtil.m; sourceTree = "<group>"; };
|
||||
DE438CD82350934700DD541D /* JavaScriptSandbox.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JavaScriptSandbox.m; sourceTree = "<group>"; };
|
||||
DE65AAC92317FFCD00290BEC /* LogUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogUtils.h; sourceTree = "<group>"; };
|
||||
DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetBaseLogHandler+Private.h"; sourceTree = "<group>"; };
|
||||
@@ -223,6 +227,8 @@
|
||||
DEFE535521FB2E8300011A3A /* ReactUtils.m */,
|
||||
0B93EF7C1EC9DDCD0030D24D /* RCTBridgeWrapper.h */,
|
||||
0B93EF7D1EC9DDCD0030D24D /* RCTBridgeWrapper.m */,
|
||||
C8AFD27D2462C613000293D2 /* InfoPlistUtil.h */,
|
||||
C8AFD27E2462C613000293D2 /* InfoPlistUtil.m */,
|
||||
);
|
||||
path = src;
|
||||
sourceTree = "<group>";
|
||||
@@ -303,6 +309,7 @@
|
||||
DE81A2D42316AC4D00AE1940 /* JitsiMeetLogger.h in Headers */,
|
||||
DE65AACA2317FFCD00290BEC /* LogUtils.h in Headers */,
|
||||
DEAD3226220C497000E93636 /* JitsiMeetConferenceOptions.h in Headers */,
|
||||
C8AFD27F2462C613000293D2 /* InfoPlistUtil.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -482,6 +489,7 @@
|
||||
0B93EF7F1EC9DDCD0030D24D /* RCTBridgeWrapper.m in Sources */,
|
||||
0BA13D311EE83FF8007BEF7F /* ExternalAPI.m in Sources */,
|
||||
0BCA49601EC4B6C600B793EE /* POSIX.m in Sources */,
|
||||
C8AFD2802462C613000293D2 /* InfoPlistUtil.m in Sources */,
|
||||
C6CC49AF207412CF000DFA42 /* PiPViewCoordinator.swift in Sources */,
|
||||
DEFC743F21B178FA00E4DD96 /* LocaleDetector.m in Sources */,
|
||||
0BCA495F1EC4B6C600B793EE /* AudioMode.m in Sources */,
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTLog.h>
|
||||
|
||||
#import "InfoPlistUtil.h"
|
||||
|
||||
@interface AppInfo : NSObject<RCTBridgeModule>
|
||||
@end
|
||||
|
||||
@@ -67,13 +69,15 @@ RCT_EXPORT_MODULE();
|
||||
buildNumber = @"";
|
||||
}
|
||||
|
||||
BOOL isGoogleServiceEnabled = [InfoPlistUtil containsRealServiceInfoPlistInBundle:[NSBundle mainBundle]];
|
||||
|
||||
return @{
|
||||
@"calendarEnabled": [NSNumber numberWithBool:calendarEnabled],
|
||||
@"buildNumber": buildNumber,
|
||||
@"name": name,
|
||||
@"sdkBundlePath": sdkBundlePath,
|
||||
@"version": version
|
||||
@"version": version,
|
||||
@"GOOGLE_SERVICES_ENABLED": [NSNumber numberWithBool:isGoogleServiceEnabled]
|
||||
};
|
||||
};
|
||||
|
||||
@end
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.8.0</string>
|
||||
<string>2.8.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
23
ios/sdk/src/InfoPlistUtil.h
Normal file
23
ios/sdk/src/InfoPlistUtil.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface InfoPlistUtil : NSObject
|
||||
|
||||
+ (BOOL)containsRealServiceInfoPlistInBundle:(NSBundle *)bundle;
|
||||
|
||||
@end
|
||||
52
ios/sdk/src/InfoPlistUtil.m
Normal file
52
ios/sdk/src/InfoPlistUtil.m
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "InfoPlistUtil.h"
|
||||
|
||||
// Plist file name.
|
||||
NSString *const kGoogleServiceInfoFileName = @"GoogleService-Info";
|
||||
// Plist file type.
|
||||
NSString *const kGoogleServiceInfoFileType = @"plist";
|
||||
NSString *const kGoogleAppIDPlistKey = @"GOOGLE_APP_ID";
|
||||
|
||||
@implementation InfoPlistUtil
|
||||
|
||||
+ (BOOL)containsRealServiceInfoPlistInBundle:(NSBundle *)bundle {
|
||||
NSString *bundlePath = bundle.bundlePath;
|
||||
if (!bundlePath.length) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString *plistFilePath = [bundle pathForResource:kGoogleServiceInfoFileName
|
||||
ofType:kGoogleServiceInfoFileType];
|
||||
if (!plistFilePath.length) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:plistFilePath];
|
||||
if (!plist) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Perform a very naive validation by checking to see if the plist has the dummy google app id
|
||||
NSString *googleAppID = plist[kGoogleAppIDPlistKey];
|
||||
if (!googleAppID.length) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
@@ -20,6 +20,7 @@
|
||||
#import <JitsiMeet/JitsiMeetConferenceOptions.h>
|
||||
#import <JitsiMeet/JitsiMeetLogger.h>
|
||||
#import <JitsiMeet/JitsiMeetBaseLogHandler.h>
|
||||
#import <JitsiMeet/InfoPlistUtil.h>
|
||||
|
||||
|
||||
@interface JitsiMeet : NSObject
|
||||
@@ -64,4 +65,6 @@
|
||||
|
||||
- (JitsiMeetConferenceOptions *_Nonnull)getInitialConferenceOptions;
|
||||
|
||||
- (BOOL)isCrashReportingDisabled;
|
||||
|
||||
@end
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
JitsiMeetConferenceOptions *conferenceOptions = [JitsiMeetConferenceOptions fromBuilder:^(JitsiMeetConferenceOptionsBuilder *builder) {
|
||||
builder.room = [url absoluteString];
|
||||
}];
|
||||
|
||||
|
||||
return [JitsiMeetView setPropsInViews:[conferenceOptions asProps]];
|
||||
}
|
||||
|
||||
@@ -132,6 +132,11 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)isCrashReportingDisabled {
|
||||
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"jitsi-default-preferences"];
|
||||
return [userDefaults stringForKey:@"isCrashReportingDisabled"];
|
||||
}
|
||||
|
||||
- (JitsiMeetConferenceOptions *)optionsFromUserActivity:(NSUserActivity *)userActivity {
|
||||
NSString *activityType = userActivity.activityType;
|
||||
|
||||
|
||||
34
lang/languages-ar.json
Normal file
34
lang/languages-ar.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"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": ""
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"en": "İngilis",
|
||||
"af": "",
|
||||
"az": "",
|
||||
"bg": "Bolqar",
|
||||
"cs": "",
|
||||
"de": "Alman",
|
||||
"el": "",
|
||||
"eo": "",
|
||||
"es": "İspan",
|
||||
"fr": "Fransız",
|
||||
"hy": "",
|
||||
"it": "",
|
||||
"ja": "",
|
||||
"ko": "",
|
||||
"nb": "",
|
||||
"oc": "",
|
||||
"pl": "",
|
||||
"ptBR": "",
|
||||
"ru": "",
|
||||
"sk": "",
|
||||
"sl": "",
|
||||
"sv": "",
|
||||
"tr": "",
|
||||
"vi": "",
|
||||
"zhCN": ""
|
||||
}
|
||||
34
lang/languages-be.json
Normal file
34
lang/languages-be.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"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": "Кітайская (Тайвань)"
|
||||
}
|
||||
@@ -29,5 +29,6 @@
|
||||
"tr": "Turc",
|
||||
"vi": "Vietnamita",
|
||||
"zhCN": "Xinès (Xina)",
|
||||
"zhTW": "Xinès (Taiwan)"
|
||||
"zhTW": "Xinès (Taiwan)",
|
||||
"et": "Estonià"
|
||||
}
|
||||
|
||||
@@ -23,5 +23,16 @@
|
||||
"sv": "Schwedisch",
|
||||
"tr": "Türkisch",
|
||||
"vi": "Vietnamesisch",
|
||||
"zhCN": "Chinesisch (China)"
|
||||
"zhCN": "Chinesisch (China)",
|
||||
"zhTW": "Chinesisch (Taiwan)",
|
||||
"nl": "Niederländisch",
|
||||
"hu": "Ungarisch",
|
||||
"hr": "Kroatisch",
|
||||
"frCA": "Französisch (Kanada)",
|
||||
"fi": "Finnisch",
|
||||
"et": "Estnisch",
|
||||
"esUS": "Spanisch (Lateinamerika)",
|
||||
"enGB": "Englisch (Vereinigtes Königreich)",
|
||||
"da": "Dänisch",
|
||||
"ca": "Katalanisch"
|
||||
}
|
||||
|
||||
@@ -1,27 +1,38 @@
|
||||
{
|
||||
"en": "",
|
||||
"af": "",
|
||||
"en": "English",
|
||||
"af": "Afrikaans",
|
||||
"az": "",
|
||||
"bg": "",
|
||||
"cs": "",
|
||||
"de": "",
|
||||
"el": "",
|
||||
"eo": "",
|
||||
"es": "",
|
||||
"fr": "",
|
||||
"hy": "",
|
||||
"it": "",
|
||||
"ja": "",
|
||||
"ko": "",
|
||||
"bg": "Bulgarian",
|
||||
"cs": "Czech",
|
||||
"de": "German",
|
||||
"el": "Greek",
|
||||
"eo": "Esperanto",
|
||||
"es": "Spanish",
|
||||
"fr": "French",
|
||||
"hy": "Armenian",
|
||||
"it": "Italian",
|
||||
"ja": "Japanese",
|
||||
"ko": "Korean",
|
||||
"nb": "",
|
||||
"oc": "",
|
||||
"pl": "",
|
||||
"ptBR": "",
|
||||
"ru": "",
|
||||
"oc": "Occitan",
|
||||
"pl": "Polish",
|
||||
"ptBR": "Portuguese (Brazil)",
|
||||
"ru": "Russian",
|
||||
"sk": "",
|
||||
"sl": "",
|
||||
"sv": "",
|
||||
"tr": "",
|
||||
"vi": "",
|
||||
"zhCN": ""
|
||||
}
|
||||
"sv": "Swedish",
|
||||
"tr": "Turkish",
|
||||
"vi": "Vietnamese",
|
||||
"zhCN": "Chinese (China)",
|
||||
"zhTW": "Chinese (Taiwan)",
|
||||
"nl": "Dutch",
|
||||
"hu": "Hungarian",
|
||||
"hr": "Croatian",
|
||||
"frCA": "French (Canadian)",
|
||||
"fi": "Finnish",
|
||||
"et": "Estonian",
|
||||
"esUS": "Spanish (Latin America)",
|
||||
"enGB": "English (United Kingdom)",
|
||||
"da": "Danish",
|
||||
"ca": "Catalan"
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"en": "Angla",
|
||||
"af": "",
|
||||
"az": "",
|
||||
"af": "Afrikansa",
|
||||
"az": "Azera",
|
||||
"bg": "Bulgara",
|
||||
"cs": "",
|
||||
"cs": "Ĉeĥa",
|
||||
"de": "Germana",
|
||||
"el": "",
|
||||
"el": "Greka",
|
||||
"eo": "Esperanto",
|
||||
"es": "Hispana",
|
||||
"fr": "Franca",
|
||||
"hy": "Armena",
|
||||
"it": "Itala",
|
||||
"ja": "",
|
||||
"ko": "",
|
||||
"ja": "Japana",
|
||||
"ko": "Korea",
|
||||
"nb": "Norvega (Bukmola)",
|
||||
"oc": "Okcitana",
|
||||
"pl": "Pola",
|
||||
@@ -22,6 +22,6 @@
|
||||
"sl": "Slovena",
|
||||
"sv": "Sveda",
|
||||
"tr": "Turka",
|
||||
"vi": "",
|
||||
"vi": "Vjetnama",
|
||||
"zhCN": "Ĉina (Ĉinuja)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"en": "Inglés",
|
||||
"af": "Africano",
|
||||
"af": "Afrikáans",
|
||||
"bg": "Búlgaro",
|
||||
"ca": "Catalán",
|
||||
"cs": "Checo",
|
||||
@@ -12,21 +12,25 @@
|
||||
"esUS": "Español (América Latina)",
|
||||
"fi": "Finlandés",
|
||||
"fr": "Francés",
|
||||
"frCA": "Franco (Canadiense)",
|
||||
"frCA": "Francés (Canadiense)",
|
||||
"he": "Hebreo",
|
||||
"hr": "Croata",
|
||||
"hu": "Húngaro",
|
||||
"hy": "Armenio",
|
||||
"it": "Italiano",
|
||||
"ja": "Jopones",
|
||||
"ja": "Japonés",
|
||||
"ko": "Coreano",
|
||||
"nl": "Holandés",
|
||||
"oc": "Occitano",
|
||||
"pl": "Polaco",
|
||||
"ptBR": "Portugués (Brasil)",
|
||||
"ru": "Ruso",
|
||||
"sk": "Eslovaco",
|
||||
"sv": "Sueco",
|
||||
"tr": "Turco",
|
||||
"vi": "Vietnamita",
|
||||
"zhCN": "Chino (China)",
|
||||
"zhTW": "Chino (Taiwan)"
|
||||
}
|
||||
"zhTW": "Chino (Taiwán)",
|
||||
"et": "Estonio",
|
||||
"da": "Danés"
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"fi": "Finlandés",
|
||||
"fr": "Francés",
|
||||
"frCA": "Francés (Canadiense)",
|
||||
"he": "Hebreo",
|
||||
"hr": "Croata",
|
||||
"hu": "Húngaro",
|
||||
"hy": "Armenio",
|
||||
@@ -24,9 +25,10 @@
|
||||
"pl": "Polaco",
|
||||
"ptBR": "Portugués (Brasil)",
|
||||
"ru": "Ruso",
|
||||
"sk": "Eslovaco",
|
||||
"sv": "Sueco",
|
||||
"tr": "Turco",
|
||||
"vi": "Vietnamita",
|
||||
"zhCN": "Chino (China)",
|
||||
"zhTW": "Chino (Taiwan)"
|
||||
}
|
||||
}
|
||||
|
||||
34
lang/languages-eu.json
Normal file
34
lang/languages-eu.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"en": "Ingelesa",
|
||||
"af": "Afrikaans",
|
||||
"bg": "Bulgariera",
|
||||
"ca": "Katalana",
|
||||
"cs": "Txekiera",
|
||||
"da": "Daniera",
|
||||
"de": "Alemana",
|
||||
"el": "Greziera",
|
||||
"enGB": "Ingelesa (Erresuma Batua)",
|
||||
"eo": "Esperantoa",
|
||||
"es": "Gaztelania",
|
||||
"esUS": "Gaztelania (Latinamerika)",
|
||||
"et": "Estoniera",
|
||||
"fi": "Finlandiera",
|
||||
"fr": "Frantsesa",
|
||||
"frCA": "Frantsesa (Kanada)",
|
||||
"hr": "Kroaziera",
|
||||
"hu": "Hungariera",
|
||||
"hy": "Armeniera",
|
||||
"it": "Italiera",
|
||||
"ja": "Japoniera",
|
||||
"ko": "Koreera",
|
||||
"nl": "Nederlandera",
|
||||
"oc": "Okzitaniera",
|
||||
"pl": "Poloniera",
|
||||
"ptBR": "Portugesa (Brasil)",
|
||||
"ru": "Errusiera",
|
||||
"sv": "Suediera",
|
||||
"tr": "Turkiera",
|
||||
"vi": "Vietnamera",
|
||||
"zhCN": "Txinera (Txina)",
|
||||
"zhTW": "Txinera (Taiwan)"
|
||||
}
|
||||
@@ -1,27 +1,38 @@
|
||||
{
|
||||
"en": "",
|
||||
"af": "",
|
||||
"en": "englanti",
|
||||
"af": "afrikaans",
|
||||
"az": "",
|
||||
"bg": "",
|
||||
"cs": "",
|
||||
"de": "",
|
||||
"el": "",
|
||||
"eo": "",
|
||||
"es": "",
|
||||
"fr": "",
|
||||
"hy": "",
|
||||
"it": "",
|
||||
"ja": "",
|
||||
"ko": "",
|
||||
"bg": "bulgaria",
|
||||
"cs": "tšekki",
|
||||
"de": "saksa",
|
||||
"el": "kreikka",
|
||||
"eo": "esperanto",
|
||||
"es": "espanja",
|
||||
"fr": "ranska",
|
||||
"hy": "armenia",
|
||||
"it": "italia",
|
||||
"ja": "japani",
|
||||
"ko": "korea",
|
||||
"nb": "",
|
||||
"oc": "",
|
||||
"pl": "",
|
||||
"ptBR": "",
|
||||
"ru": "",
|
||||
"oc": "oksitaani",
|
||||
"pl": "puola",
|
||||
"ptBR": "portugali (Brasilia)",
|
||||
"ru": "venäjä",
|
||||
"sk": "",
|
||||
"sl": "",
|
||||
"sv": "",
|
||||
"tr": "",
|
||||
"vi": "",
|
||||
"zhCN": ""
|
||||
}
|
||||
"sv": "ruotsi",
|
||||
"tr": "turkki",
|
||||
"vi": "vietnam",
|
||||
"zhCN": "kiina (Kiina)",
|
||||
"zhTW": "kiina (Taiwan)",
|
||||
"nl": "hollanti",
|
||||
"hu": "unkari",
|
||||
"hr": "kroaatti",
|
||||
"frCA": "ranska (Kanada)",
|
||||
"fi": "suomi",
|
||||
"et": "viro",
|
||||
"esUS": "espanja (Latinalainen Amerikka)",
|
||||
"enGB": "englanti (Yhdistynyt kuningaskunta)",
|
||||
"da": "tanska",
|
||||
"ca": "katalaani"
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
"cs": "Tchèque",
|
||||
"de": "Allemand",
|
||||
"el": "Grec",
|
||||
"enGB": "Anglais (Royaume-Uni) ",
|
||||
"enGB": "Anglais (Royaume-Uni)",
|
||||
"eo": "Espéranto",
|
||||
"es": "Espagnol",
|
||||
"esUS": "Espagnol (Amérique latine)",
|
||||
"fi": "Finlandais",
|
||||
"fi": "Finnois",
|
||||
"fr": "Français",
|
||||
"frCA": "Français (Canadien)",
|
||||
"frCA": "Français (Canada)",
|
||||
"hr": "Croate",
|
||||
"hu": "Hongrois",
|
||||
"hy": "Arménien",
|
||||
@@ -24,9 +24,12 @@
|
||||
"pl": "Polonais",
|
||||
"ptBR": "Portugais (Brésil)",
|
||||
"ru": "Russe",
|
||||
"sk": "Slovaque",
|
||||
"sv": "Suédois",
|
||||
"tr": "Turc",
|
||||
"vi": "Vietnamien",
|
||||
"zhCN": "Chinois (Chine)",
|
||||
"zhTW": "Chinois (Taiwan)"
|
||||
}
|
||||
"zhTW": "Chinois (Taiwan)",
|
||||
"et": "Estonien",
|
||||
"da": "Danois"
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
"cs": "Tchèque",
|
||||
"de": "Allemand",
|
||||
"el": "Grec",
|
||||
"enGB": "Anglais (Royaume-Uni) ",
|
||||
"enGB": "Anglais (Royaume-Uni)",
|
||||
"eo": "Espéranto",
|
||||
"es": "Espagnol",
|
||||
"esUS": "Espagnol (Amérique latine)",
|
||||
"fi": "Finlandais",
|
||||
"fi": "Finnois",
|
||||
"fr": "Français",
|
||||
"frCA": "Français (Canadien)",
|
||||
"hr": "Croate",
|
||||
@@ -24,9 +24,12 @@
|
||||
"pl": "Polonais",
|
||||
"ptBR": "Portugais (Brésil)",
|
||||
"ru": "Russe",
|
||||
"sk": "Slovaque",
|
||||
"sv": "Suédois",
|
||||
"tr": "Turc",
|
||||
"vi": "Vietnamien",
|
||||
"zhCN": "Chinois (Chine)",
|
||||
"zhTW": "Chinois (Taiwan)"
|
||||
}
|
||||
"zhTW": "Chinois (Taiwan)",
|
||||
"et": "Estonien",
|
||||
"da": "Danois"
|
||||
}
|
||||
|
||||
34
lang/languages-fy.json
Normal file
34
lang/languages-fy.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"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": ""
|
||||
}
|
||||
@@ -28,5 +28,7 @@
|
||||
"tr": "Turco",
|
||||
"vi": "Vietnamita",
|
||||
"zhCN": "Chinés (China)",
|
||||
"zhTW": "Chinés (Taiwan)"
|
||||
}
|
||||
"zhTW": "Chinés (Taiwan)",
|
||||
"et": "Estoniano",
|
||||
"da": "Dinamarqués"
|
||||
}
|
||||
|
||||
37
lang/languages-he.json
Normal file
37
lang/languages-he.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"en": "אנגלית",
|
||||
"af": "אפריקאית",
|
||||
"bg": "בולגרית",
|
||||
"ca": "קטלנית",
|
||||
"cs": "קזחית",
|
||||
"da": "דנית",
|
||||
"de": "גרמנית",
|
||||
"el": "יוונית",
|
||||
"enGB": "אנגלית (בריטניה)",
|
||||
"eo": "אספרנטו",
|
||||
"es": "ספרדית",
|
||||
"esUS": "ספרדית (אמריקה הלטינית)",
|
||||
"et": "אסטונית",
|
||||
"fi": "פינית",
|
||||
"fr": "צרפתית",
|
||||
"frCA": "צרפתית (קנדה)",
|
||||
"he": "עברית",
|
||||
"hr": "קראוטית",
|
||||
"hu": "הונגרית",
|
||||
"hy": "ארמנית",
|
||||
"it": "איטלקית",
|
||||
"ja": "יפנית",
|
||||
"ko": "קוראנית",
|
||||
"nl": "הולנדית",
|
||||
"oc": "אוקיאנית",
|
||||
"pl": "פולנית",
|
||||
"ptBR": "פורטוגזית (ברזיל)",
|
||||
"ru": "רוסית",
|
||||
"sc": "סרבית",
|
||||
"sk": "סלובקית",
|
||||
"sv": "שוודית",
|
||||
"tr": "טורקית",
|
||||
"vi": "ויטנאמית",
|
||||
"zhCN": "סינית (סין)",
|
||||
"zhTW": "סינית (טיוואן)"
|
||||
}
|
||||
@@ -24,9 +24,12 @@
|
||||
"pl": "Lengyel",
|
||||
"ptBR": "Portugál (Brazil)",
|
||||
"ru": "Orosz",
|
||||
"sk": "Szlovákul",
|
||||
"sv": "Svéd",
|
||||
"tr": "Török",
|
||||
"vi": "Vietnámi",
|
||||
"zhCN": "Kínai (Kína)",
|
||||
"zhTW": "Kínai (Tajvan)"
|
||||
}
|
||||
"zhTW": "Kínai (Tajvan)",
|
||||
"et": "Észt",
|
||||
"da": "Dán"
|
||||
}
|
||||
|
||||
39
lang/languages-id.json
Normal file
39
lang/languages-id.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"en": "Bahasa Inggris - US",
|
||||
"af": "Bahasa Afrika",
|
||||
"bg": "Bahasa Bulgaria",
|
||||
"ca": "Bahasa Katalan",
|
||||
"cs": "Bahasa Ceko",
|
||||
"da": "Bahasa Denmark",
|
||||
"de": "Bahasa Jerman",
|
||||
"el": "Bahasa Yunani",
|
||||
"enGB": "Bahasa Inggris - UK",
|
||||
"eo": "Esperanto",
|
||||
"es": "Bahasa Spanyol",
|
||||
"esUS": "Bahasa Spanyol - Latin",
|
||||
"et": "Bahasa Estonia",
|
||||
"fi": "Bahasa Finlandia",
|
||||
"fr": "Bahasa Prancis",
|
||||
"frCA": "Bahasa Prancis - Kanada",
|
||||
"he": "Bahasa Hebrew",
|
||||
"hr": "Bahasa Kroasia",
|
||||
"hu": "Bahasa Hongaria",
|
||||
"hy": "Bahasa Armenia",
|
||||
"id": "Bahasa Indonesia",
|
||||
"it": "Bahasa Italia",
|
||||
"ja": "Bahasa Jepang",
|
||||
"ko": "Bahasa Korea",
|
||||
"lt": "Bahasa Lituania",
|
||||
"nl": "Bahasa Belanda",
|
||||
"oc": "Bahasa Oceania",
|
||||
"pl": "Bahasa Polandia",
|
||||
"ptBR": "Bahasa Portugis - Brazil",
|
||||
"ru": "Bahasa Rusia",
|
||||
"sc": "Bahasa Sardinia",
|
||||
"sk": "Bahasa Slovakia",
|
||||
"sv": "Bahasa Swedia",
|
||||
"tr": "Bahasa Turki",
|
||||
"vi": "Bahasa Vietnam",
|
||||
"zhCN": "Bahasa Mandarin",
|
||||
"zhTW": "Bahasa Mandarin - Taiwan"
|
||||
}
|
||||
34
lang/languages-is.json
Normal file
34
lang/languages-is.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"en": "Enska",
|
||||
"af": "Afríkanska",
|
||||
"bg": "Búlgarska",
|
||||
"ca": "Katalónska",
|
||||
"cs": "Tékkneska",
|
||||
"da": "Danska",
|
||||
"de": "Þýska",
|
||||
"el": "Gríska",
|
||||
"enGB": "Enska (Bretland)",
|
||||
"eo": "Esperantó",
|
||||
"es": "Spænska",
|
||||
"esUS": "Spænska (spænskumælandi Ameríka)",
|
||||
"et": "Eistneska",
|
||||
"fi": "Finnska",
|
||||
"fr": "Franska",
|
||||
"frCA": "Franska (kanadísk)",
|
||||
"hr": "Króatíska",
|
||||
"hu": "Ungverska",
|
||||
"hy": "Armenska",
|
||||
"it": "Ítalska",
|
||||
"ja": "Japanska",
|
||||
"ko": "Kóreska",
|
||||
"nl": "Hollenska",
|
||||
"oc": "Occitanska",
|
||||
"pl": "Pólska",
|
||||
"ptBR": "Portúgalska (Brasilía)",
|
||||
"ru": "Rússneska",
|
||||
"sv": "Sænska",
|
||||
"tr": "Tyrkneska",
|
||||
"vi": "Víetnamska",
|
||||
"zhCN": "Kínverska (Kína)",
|
||||
"zhTW": "Kínverska (Taívan)"
|
||||
}
|
||||
@@ -23,5 +23,16 @@
|
||||
"sv": "Svedese",
|
||||
"tr": "Turco",
|
||||
"vi": "Vietnamita",
|
||||
"zhCN": "Cinese (Cina)"
|
||||
"zhCN": "Cinese (Cina)",
|
||||
"enGB": "Inglese (Regno Unito)",
|
||||
"da": "Danese",
|
||||
"ca": "Catalano",
|
||||
"zhTW": "",
|
||||
"nl": "",
|
||||
"hu": "",
|
||||
"hr": "",
|
||||
"frCA": "",
|
||||
"fi": "",
|
||||
"et": "",
|
||||
"esUS": ""
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"en": "Taglizit",
|
||||
"af": "",
|
||||
"az": "",
|
||||
"af": "Tafrikant",
|
||||
"az": "Tazirit",
|
||||
"bg": "Tabulgarit",
|
||||
"cs": "Taččikit",
|
||||
"de": "Talmanit",
|
||||
@@ -24,4 +24,4 @@
|
||||
"tr": "Taṭurkit",
|
||||
"vi": "Tavyitnamit",
|
||||
"zhCN": "Tavyitnamit"
|
||||
}
|
||||
}
|
||||
|
||||
35
lang/languages-lt.json
Normal file
35
lang/languages-lt.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"en": "Anglų",
|
||||
"af": "Afrikanų",
|
||||
"bg": "Bulgarų",
|
||||
"ca": "Katalanų",
|
||||
"cs": "Čekų",
|
||||
"da": "Danų",
|
||||
"de": "Vokiečių",
|
||||
"el": "Graikų",
|
||||
"enGB": "Anglų (Britų)",
|
||||
"eo": "Esperanto",
|
||||
"es": "Ispanų",
|
||||
"esUS": "Ispanų (Lotynų Amerika)",
|
||||
"et": "Estų",
|
||||
"fi": "Suomių",
|
||||
"fr": "Prancūzų",
|
||||
"frCA": "Prancūzų (Kanada)",
|
||||
"hr": "Kroatų",
|
||||
"hu": "Vengrų",
|
||||
"hy": "Armėnų",
|
||||
"it": "Italų",
|
||||
"ja": "Japonų",
|
||||
"lt": "Lietuvių",
|
||||
"ko": "Korėjiečių",
|
||||
"nl": "Olandų",
|
||||
"oc": "Oksitanų",
|
||||
"pl": "Lenkų",
|
||||
"ptBR": "Portugalų (Brazilija)",
|
||||
"ru": "Rusų",
|
||||
"sv": "Švedų",
|
||||
"tr": "Turkų",
|
||||
"vi": "Vietnamiečių",
|
||||
"zhCN": "Kinų (China)",
|
||||
"zhTW": "Kinų (Taivanas)"
|
||||
}
|
||||
34
lang/languages-lv.json
Normal file
34
lang/languages-lv.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"en": "angļu",
|
||||
"af": "āfrikāņu",
|
||||
"bg": "bulgāru",
|
||||
"ca": "kataloniešu",
|
||||
"cs": "čehu",
|
||||
"de": "vācu",
|
||||
"el": "grieķu",
|
||||
"enGB": "angļu (Lielbritānija)",
|
||||
"eo": "esperanto",
|
||||
"es": "spāņu",
|
||||
"esUS": "spāņu (Dienvidamerika)",
|
||||
"et": "igauņu",
|
||||
"fi": "somu",
|
||||
"fr": "franču",
|
||||
"frCA": "franču (Kanāda)",
|
||||
"hr": "horvātu",
|
||||
"hu": "ungāru",
|
||||
"hy": "armēņu",
|
||||
"it": "itāļu",
|
||||
"ja": "japānu",
|
||||
"ko": "korejiešu",
|
||||
"lv": "laviešu",
|
||||
"nl": "holandiešu",
|
||||
"oc": "oksitāņu",
|
||||
"pl": "poļu",
|
||||
"ptBR": "portugāļu (Brazīlija)",
|
||||
"ru": "krievu",
|
||||
"sv": "zviedru",
|
||||
"tr": "turku",
|
||||
"vi": "vjetnamiešu",
|
||||
"zhCN": "ķīniešu (Ķīna)",
|
||||
"zhTW": "ķīniešu (Taivana)"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user