Compare commits

..

1 Commits

Author SHA1 Message Date
Boris Grozev
7469e7fa3d chore(package.json): Update js-utils 2020-04-01 08:59:47 -05:00
411 changed files with 5318 additions and 22803 deletions

10
.github/ISSUE_TEMPLATE/2-help.md vendored Normal file
View File

@@ -0,0 +1,10 @@
---
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.

View File

@@ -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 decision for implementing features lies on the Jitsi team, not all feature requests shall be accepted.
Note that the ultimate decission 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?**

View File

@@ -1,9 +1,11 @@
# Security
---
name: Security issues
about: Please email security@jitsi.org
## 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.

View File

@@ -1,5 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Need help with Jitsi Meet?
url: https://community.jitsi.org
about: Please ask it in our community.

View File

@@ -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 resources/*.txt connection_optimization favicon.ico fonts images libs static sounds LICENSE lang source_package/jitsi-meet && \
cp -r *.js *.html 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

View File

@@ -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](https://jitsi.org/security) and scalable video conferences. Jitsi Meet in action can be seen at [here at the session #482 of the VoIP Users Conference](http://youtu.be/7vFUVClsNh0).
Jitsi Meet is 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).
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,13 +61,25 @@ Jitsi Meet provides a very flexible way of embedding in external applications by
## Security
The security section here was starting to feel a bit too succinct for the complexity of the topic, so we created a post that covers the topic much more broadly here: https://jitsi.org/security
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 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
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).
## Security issues
For information on reporting security vulnerabilities in Jitsi Meet, see [SECURITY.md](./SECURITY.md).
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.**
## Acknowledgements

View File

@@ -1,5 +1,8 @@
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) {
@@ -10,7 +13,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
@@ -140,8 +143,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."
@@ -172,5 +175,5 @@ gradle.projectsEvaluated {
}
if (googleServicesEnabled) {
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.gms.google-services'
}

View File

@@ -7,7 +7,6 @@ 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;
/**
@@ -22,9 +21,7 @@ final class GoogleServicesHelper {
if (BuildConfig.GOOGLE_SERVICES_ENABLED) {
Log.d(activity.getClass().getSimpleName(), "Initializing Google Services");
if (!JitsiMeet.isCrashReportingDisabled(activity)) {
Fabric.with(activity, new Crashlytics());
}
Fabric.with(activity, new Crashlytics());
FirebaseDynamicLinks.getInstance().getDynamicLink(activity.getIntent())
.addOnSuccessListener(activity, pendingDynamicLinkData -> {

View File

@@ -161,8 +161,6 @@ 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

View File

@@ -20,5 +20,5 @@
android.useAndroidX=true
android.enableJetifier=true
appVersion=20.3.0
sdkVersion=2.8.2
appVersion=20.2.0
sdkVersion=2.8.0

View File

@@ -14,13 +14,11 @@ 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}"
}
}
@@ -72,7 +70,6 @@ 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')

View File

@@ -17,8 +17,6 @@
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;
@@ -42,8 +40,6 @@ 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);
@@ -62,14 +58,10 @@ class AmplitudeModule
Amplitude.getInstance(instanceName).initialize(getCurrentActivity(), apiKey);
// Set the device ID to something consistent.
SharedPreferences sharedPreferences = getReactApplicationContext().getSharedPreferences(JITSI_PREFERENCES, Context.MODE_PRIVATE);
String android_id = sharedPreferences.getString(AMPLITUDE_DEVICE_ID_KEY, "");
String android_id
= Settings.Secure.getString(getReactApplicationContext().getContentResolver(), Settings.Secure.ANDROID_ID);
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();
}
}

View File

@@ -76,7 +76,6 @@ 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;
}

View File

@@ -16,14 +16,11 @@
*/
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
@@ -75,10 +72,4 @@ 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);
}
}
}

View File

@@ -16,7 +16,6 @@
package org.jitsi.meet.sdk;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@@ -163,7 +162,6 @@ 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);

View File

@@ -288,7 +288,6 @@ public class JitsiMeetConferenceOptions implements Parcelable {
}
private JitsiMeetConferenceOptions(Parcel in) {
serverURL = (URL) in.readSerializable();
room = in.readString();
subject = in.readString();
token = in.readString();
@@ -377,7 +376,6 @@ 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);

View File

@@ -57,6 +57,22 @@ 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();

View File

@@ -201,10 +201,4 @@ 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();
}
}

View File

@@ -190,7 +190,6 @@ 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(),

View File

@@ -9,8 +9,6 @@ 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'
@@ -26,4 +24,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')

View File

@@ -19,6 +19,7 @@ import {
createDeviceChangedEvent,
createStartSilentEvent,
createScreenSharingEvent,
createStreamSwitchDelayEvent,
createTrackMutedEvent,
sendAnalytics
} from './react/features/analytics';
@@ -27,13 +28,6 @@ import {
redirectToStaticPage,
reloadWithStoredParams
} from './react/features/app';
import {
initPrejoin,
isPrejoinPageEnabled,
isPrejoinPageVisible,
replacePrejoinAudioTrack,
replacePrejoinVideoTrack
} from './react/features/prejoin';
import EventEmitter from 'events';
@@ -119,7 +113,6 @@ 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
@@ -140,15 +133,6 @@ 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.
@@ -356,7 +340,6 @@ 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));
@@ -488,13 +471,28 @@ export default {
localVideo: null,
/**
* Returns an object containing a promise which resolves with the created tracks &
* the errors resulting from that process.
*
* @returns {Promise<JitsiLocalTrack[]>, Object}
* 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>}
*/
createInitialLocalTracks(options = {}) {
const errors = {};
createInitialLocalTracksAndConnect(roomName, options = {}) {
let audioAndVideoError,
audioOnlyError,
screenSharingError,
videoOnlyError;
const initialDevices = [ 'audio' ];
const requestedAudio = true;
let requestedVideo = false;
@@ -526,7 +524,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 ];
}
@@ -535,21 +533,21 @@ export default {
.then(([ audioStream ]) =>
[ desktopStream, audioStream ])
.catch(error => {
errors.audioOnlyError = error;
audioOnlyError = error;
return [ desktopStream ];
});
})
.catch(error => {
logger.error('Failed to obtain desktop stream', error);
errors.screenSharingError = error;
screenSharingError = error;
return requestedAudio
? createLocalTracksF({ devices: [ 'audio' ] }, true)
: [];
})
.catch(error => {
errors.audioOnlyError = error;
audioOnlyError = error;
return [];
});
@@ -562,16 +560,16 @@ export default {
if (requestedAudio && requestedVideo) {
// Try audio only...
errors.audioAndVideoError = err;
audioAndVideoError = err;
return (
createLocalTracksF({ devices: [ 'audio' ] }, true));
} else if (requestedAudio && !requestedVideo) {
errors.audioOnlyError = err;
audioOnlyError = err;
return [];
} else if (requestedVideo && !requestedAudio) {
errors.videoOnlyError = err;
videoOnlyError = err;
return [];
}
@@ -582,7 +580,7 @@ export default {
if (!requestedAudio) {
logger.error('The impossible just happened', err);
}
errors.audioOnlyError = err;
audioOnlyError = err;
// Try video only...
return requestedVideo
@@ -594,7 +592,7 @@ export default {
if (!requestedVideo) {
logger.error('The impossible just happened', err);
}
errors.videoOnlyError = err;
videoOnlyError = err;
return [];
});
@@ -605,44 +603,8 @@ 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(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;
tryCreateLocalTracks.then(() =>
APP.store.dispatch(mediaPermissionPromptVisibilityChanged(false)));
return Promise.all([ tryCreateLocalTracks, connect(roomName) ])
.then(([ tracks, con ]) => {
@@ -674,132 +636,103 @@ 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 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
* Open new connection and join to the conference.
* @param {object} options
* @param {string} roomName - The name of the conference.
* @returns {Promise}
*/
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())
};
init(options) {
this.roomName = options.roomName;
this.roomName = roomName;
return (
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
await this._initDeviceList();
} catch (error) {
logger.warn('initial device list initialization failed', error);
}
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();
if (isPrejoinPageEnabled(APP.store.getState())) {
_connectionPromise = connect(roomName);
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;
const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(initialOptions);
const tracks = await tryCreateLocalTracks;
// Desktop sharing related stuff:
this.isDesktopSharingEnabled
= JitsiMeetJS.isDesktopSharingEnabled();
eventEmitter.emit(
JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED,
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);
APP.store.dispatch(
setDesktopSharingEnabled(this.isDesktopSharingEnabled));
return APP.store.dispatch(initPrejoin(tracks, errors));
}
this._createRoom(tracks);
APP.remoteControl.init();
const [ tracks, con ] = await this.createInitialLocalTracksAndConnect(
roomName, initialOptions);
// 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);
}
this._initDeviceList(true);
if (!tracks.find(t => t.isVideoTrack())) {
this.setVideoMuteStatus(true);
}
return this.startConference(con, tracks);
},
// 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);
/**
* 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.iAmRecorder) {
this.recorder = new Recorder();
}
return this.startConference(con, tracks);
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();
});
})
);
},
/**
@@ -1244,34 +1177,6 @@ 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
@@ -1417,18 +1322,6 @@ export default {
useVideoStream(newStream) {
return new Promise((resolve, reject) => {
_replaceLocalVideoTrackQueue.enqueue(onFinish => {
/**
* When the prejoin page is visible there is no conference object
* created. The prejoin tracks are managed separately,
* so this updates the prejoin video track.
*/
if (isPrejoinPageVisible(APP.store.getState())) {
return APP.store.dispatch(replacePrejoinVideoTrack(newStream))
.then(resolve)
.catch(reject)
.then(onFinish);
}
APP.store.dispatch(
replaceLocalTrack(this.localVideo, newStream, room))
.then(() => {
@@ -1482,18 +1375,6 @@ export default {
useAudioStream(newStream) {
return new Promise((resolve, reject) => {
_replaceLocalAudioTrackQueue.enqueue(onFinish => {
/**
* When the prejoin page is visible there is no conference object
* created. The prejoin tracks are managed separately,
* so this updates the prejoin audio stream.
*/
if (isPrejoinPageVisible(APP.store.getState())) {
return APP.store.dispatch(replacePrejoinAudioTrack(newStream))
.then(resolve)
.catch(reject)
.then(onFinish);
}
APP.store.dispatch(
replaceLocalTrack(this.localAudio, newStream, room))
.then(() => {
@@ -1905,7 +1786,7 @@ export default {
const desktopVideoStream = streams.find(stream => stream.getType() === MEDIA_TYPE.VIDEO);
if (desktopVideoStream) {
await this.useVideoStream(desktopVideoStream);
this.useVideoStream(desktopVideoStream);
}
this._desktopAudioStream = streams.find(stream => stream.getType() === MEDIA_TYPE.AUDIO);
@@ -2094,7 +1975,6 @@ 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));
}
@@ -2352,6 +2232,18 @@ 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);
});
@@ -2919,7 +2811,7 @@ export default {
leaveRoomAndDisconnect() {
APP.store.dispatch(conferenceWillLeave(room));
if (room && room.isJoined()) {
if (room.isJoined()) {
return room.leave().then(disconnect, disconnect);
}

View File

@@ -44,6 +44,9 @@ 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
@@ -108,10 +111,11 @@ 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
// resolution of 720p.
// this config's resolution value. Defaults to requesting an ideal aspect
// ratio of 16:9 with an ideal resolution of 720.
// constraints: {
// video: {
// aspectRatio: 16 / 9,
// height: {
// ideal: 720,
// max: 720,
@@ -226,14 +230,6 @@ 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,
@@ -297,9 +293,6 @@ 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
//
@@ -350,7 +343,7 @@ var config = {
// The STUN servers that will be used in the peer to peer connections
stunServers: [
// { urls: 'stun:jitsi-meet.example.com:4446' },
// { urls: 'stun:jitsi-meet.example.com:443' },
{ urls: 'stun:meet-jit-si-turnrelay.jitsi.net:443' }
],
@@ -379,10 +372,6 @@ 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>'
@@ -401,9 +390,6 @@ 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
@@ -463,14 +449,6 @@ 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

View File

@@ -1,8 +1,7 @@
/* global APP, JitsiMeetJS, config */
import { jitsiLocalStorage } from 'js-utils';
import AuthHandler from './modules/UI/authentication/AuthHandler';
import jitsiLocalStorage from './modules/util/JitsiLocalStorage';
import {
connectionEstablished,

View File

@@ -1,7 +1,7 @@
/* global config, createConnectionExternally */
import getRoomName from '../react/features/base/config/getRoomName';
import { parseURLParams } from '../react/features/base/util/parseURLParams';
import parseURLParams from '../react/features/base/config/parseURLParams';
/**
* Implements external connect using createConnectionExternally function defined

View File

@@ -1,135 +0,0 @@
.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;
}
}

View File

@@ -20,6 +20,18 @@
}
}
.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%;
@@ -51,4 +63,4 @@
@include avatarBadge;
background-color: $presence-idle;
}
}
}

View File

@@ -1,30 +0,0 @@
.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;
}
}
}

View File

@@ -1,331 +0,0 @@
.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;
}
}

View File

@@ -71,11 +71,6 @@
display: flex;
margin-top: 5px;
text-align: right;
flex-direction: column;
.help-container {
display: flex;
}
}
.live-stream-cta {

View File

@@ -1,80 +0,0 @@
.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;
}
}
}
}

View File

@@ -1,70 +0,0 @@
.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;
}
}

View File

@@ -15,9 +15,8 @@
box-sizing: border-box;
display: flex;
flex-direction: column;
height: calc(100vh - 200px);
height: 100vh;
width: 100vw;
margin: 100px 0px;
}
.filmstrip__videos .videocontainer {
@@ -78,9 +77,9 @@
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
margin-top: auto;
margin-bottom: auto;
height: 100vh;
justify-content: center;
padding: 100px 0;
.videocontainer {
border: 0;

View File

@@ -86,10 +86,5 @@ $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 */

View File

@@ -164,13 +164,6 @@
background: #B8C7E0;
}
.circular-label.e2ee {
align-items: center;
background: #76CF9C;
display: flex;
justify-content: center;
}
.circular-label.file {
background: #FF5630;
}

1
debian/control vendored
View File

@@ -53,6 +53,5 @@ 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

View File

@@ -17,9 +17,6 @@ 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)
@@ -54,7 +51,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=`generateRandomPassword`
JICOFO_AUTH_PASSWORD=`head -c 8 /dev/urandom | tr '\0-\377' 'a-zA-Z0-9a-zA-Z0-9a-zA-Z0-9a-zA-Z0-9@@@@####'`
db_set jicofo/jicofo-authpassword "$JICOFO_AUTH_PASSWORD"
else
JICOFO_AUTH_PASSWORD="$RET"
@@ -63,7 +60,7 @@ case "$1" in
db_get jicofo/jicofosecret
if [ -z "$RET" ] ; then
# if secret is missing generate it, and store it
JICOFO_SECRET=`generateRandomPassword`
JICOFO_SECRET=`head -c 8 /dev/urandom | tr '\0-\377' 'a-zA-Z0-9a-zA-Z0-9a-zA-Z0-9a-zA-Z0-9@@@@####'`
db_set jicofo/jicofosecret "$JICOFO_SECRET"
else
JICOFO_SECRET="$RET"
@@ -86,7 +83,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=`generateRandomPassword`
TURN_SECRET=`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1`
db_set jitsi-meet-prosody/turn-secret "$TURN_SECRET"
else
TURN_SECRET="$RET"
@@ -137,7 +134,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 = \"memory\"" >> $PROSODY_HOST_CONFIG
echo -e " storage = \"null\"" >> $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
@@ -151,13 +148,14 @@ case "$1" in
ln -sf /var/lib/prosody/$JVB_HOSTNAME.crt /etc/prosody/certs/$JVB_HOSTNAME.crt
fi
PRTRUNK_INSTALL_CHECK="$(dpkg-query -f '${Status}' -W 'prosody-trunk' 2>/dev/null | awk '{print $3}' || true)"
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)"
PR_VER_INSTALLED=$(dpkg-query -f='${Version}\n' --show prosody 2>/dev/null || true)
if [ "$PRTRUNK_INSTALL_CHECK" = "installed" ] \
|| [ "$PRTRUNK_INSTALL_CHECK" = "unpacked" ] ; then
if [ "$PR11_INSTALL_CHECK" = "installed" ] \
|| [ "$PR11_INSTALL_CHECK" = "unpacked" ] \
|| dpkg --compare-versions "$PR_VER_INSTALLED" gt "0.11" ; then
if [ -f $PROSODY_HOST_CONFIG ]; then
sed -i 's/storage = \"memory\"/storage = \"null\"/g' $PROSODY_HOST_CONFIG
sed -i 's/storage = \"null\"/storage = \"memory\"/g' $PROSODY_HOST_CONFIG
# trigger a restart
PROSODY_CONFIG_PRESENT="false"
@@ -170,7 +168,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 = \"memory\"/storage = \"none\"/g' $PROSODY_HOST_CONFIG
sed -i 's/storage = \"null\"/storage = \"none\"/g' $PROSODY_HOST_CONFIG
# trigger a restart
PROSODY_CONFIG_PRESENT="false"

View File

@@ -69,15 +69,12 @@ case "$1" in
echo "Failed to install basexx - try installing it manually"
fi
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)"
PR11_INSTALL_CHECK="$(dpkg-query -f '${Status}' -W 'prosody-0.11' 2>/dev/null | awk '{print $3}' || true)"
PR_VER_INSTALLED=$(dpkg-query -f='${Version}\n' --show prosody 2>/dev/null || true)
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
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
fi
if [ -x "/etc/init.d/prosody" ]; then

View File

@@ -1,3 +1,2 @@
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/
doc/debian/jitsi-meet-turn/turnserver.conf /usr/share/jitsi-meet-turnserver/
doc/debian/jitsi-meet/jitsi-meet.conf /usr/share/jitsi-meet-turnserver/

1
debian/jitsi-meet-turnserver.links vendored Normal file
View File

@@ -0,0 +1 @@
/usr/share/jitsi-meet-turnserver/jitsi-meet.conf /etc/nginx/modules-enabled/60-jitsi-meet.conf

View File

@@ -36,60 +36,20 @@ 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
if [[ -f $TURN_CONFIG ]] && grep -q "jitsi-meet coturn config" "$TURN_CONFIG" ; then
rm -f $TURN_CONFIG
fi
rm -f $TURN_CONFIG
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"
echo "turnserver not configured as no nginx found to multiplex traffic"
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
@@ -105,61 +65,46 @@ case "$1" in
fi
TURN_SECRET="$RET"
# 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
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
# 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
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
# 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
fi
# Enable turn server in config.js
if [ -f $JITSI_MEET_CONFIG ] ; then
sed -i "s/\/\/ useStunTurn: true/useStunTurn: true/g" $JITSI_MEET_CONFIG
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
fi
# and we're done with debconf

View File

@@ -24,7 +24,6 @@ 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
@@ -33,8 +32,6 @@ 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

View File

@@ -1,45 +0,0 @@
# 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)

View File

@@ -85,15 +85,14 @@ const options = {
const api = new JitsiMeetExternalAPI(domain, options);
```
You can set the userInfo(email, display name) for the call:
You can set the userInfo(email) for the call:
```javascript
var domain = "meet.jit.si";
var options = {
...
userInfo: {
email: 'email@jitsiexamplemail.com',
displayName: 'John Doe'
email: 'email@jitsiexamplemail.com'
}
}
var api = new JitsiMeetExternalAPI(domain, options);
@@ -275,10 +274,6 @@ 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
@@ -469,14 +464,6 @@ 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:

View File

@@ -6,8 +6,8 @@ muc_mapper_domain_base = "jitmeet.example.com";
turncredentials_secret = "__turnSecret__";
turncredentials = {
{ type = "stun", host = "jitmeet.example.com", port = "4446" },
{ type = "turn", host = "jitmeet.example.com", port = "4446", transport = "udp" },
{ type = "stun", host = "jitmeet.example.com", port = "443" },
{ type = "turn", host = "jitmeet.example.com", port = "443", 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 = "memory"
storage = "null"
modules_enabled = {
"muc_meeting_id";
"muc_domain_mapper";
@@ -55,13 +55,11 @@ Component "conference.jitmeet.example.com" "muc"
-- internal muc component
Component "internal.auth.jitmeet.example.com" "muc"
storage = "memory"
storage = "null"
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"

View File

@@ -1,45 +0,0 @@
#!/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

View File

@@ -1,4 +1,5 @@
# jitsi-meet coturn config. Do not modify this line
lt-cred-mech
use-auth-secret
keep-address-family
static-auth-secret=__turnSecret__
@@ -7,8 +8,6 @@ cert=/etc/jitsi/meet/jitsi-meet.example.com.crt
pkey=/etc/jitsi/meet/jitsi-meet.example.com.key
no-tcp
listening-port=4446
listening-port=443
tls-listening-port=4445
external-ip=__external_ip_address__
syslog

View File

@@ -11,14 +11,14 @@ stream {
}
# since 1.13.10
map $ssl_preread_alpn_protocols $upstream {
~\bh2\b web;
~\bhttp/1\. web;
"h2" web;
"http/1.1" web;
"h2,http/1.1" web;
default turn;
}
server {
listen 443;
listen [::]:443;
# since 1.11.5
ssl_preread on;

View File

@@ -39,10 +39,6 @@ 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;
}

View File

@@ -2,7 +2,7 @@
## Building the sources
Node.js >= 12 and npm >= 6 are required.
Node.js >= 10 and npm >= 6 are required.
On Debian/Ubuntu systems, the required packages can be installed with:
```
@@ -69,14 +69,10 @@ Use it at the CLI, type
make dev
```
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:
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:
```
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.

View File

@@ -1,27 +0,0 @@
# 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"

View File

@@ -1,6 +0,0 @@
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

View File

@@ -1,88 +0,0 @@
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

View File

@@ -1,114 +0,0 @@
-- 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"

View File

@@ -1,20 +0,0 @@
# 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"

View File

@@ -1,19 +0,0 @@
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

View File

@@ -8,8 +8,6 @@ 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:
@@ -227,7 +225,7 @@ npm install
make
```
_NOTE: When installing on older distributions keep in mind that you need Node.js >= 12 and npm >= 6._
_NOTE: When installing on older distributions keep in mind that you need Node.js >= 10 and npm >= 6._
Edit host names in `/srv/jitsi-meet/config.js` (see also the example config file):
```

View File

@@ -7,10 +7,8 @@ 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. 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.
**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.
## iOS

View File

@@ -22,22 +22,14 @@ 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/' | sudo tee /etc/apt/sources.list.d/jitsi-stable.list
wget -qO - https://download.jitsi.org/jitsi-key.gpg.key | sudo apt-key add -
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 -
```
### 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 turnserver configuration will be skipped as it will conflict with your current port 443.
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`.
```sh
# Ensure support is available for apt repositories served via HTTPS
@@ -58,7 +50,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) (such as a Let's Encrypt certificate) 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) and will not be able to connect to your server if you choose a self-signed certificate.
Simply run the following in your shell:
@@ -81,18 +73,12 @@ 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 if values are smaller, if not do not update.
To update the values edit `/etc/systemd/system.conf` and make sure you have the following values:
```
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.

View File

@@ -1,166 +0,0 @@
# 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.

View File

@@ -51,8 +51,7 @@ 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',
'e2ee'
'tileview', 'videobackgroundblur', 'download', 'help', 'mute-everyone'
],
SETTINGS_SECTIONS: [ 'devices', 'language', 'moderator', 'profile', 'calendar' ],
@@ -176,7 +175,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', 'safari' ],
OPTIMAL_BROWSERS: [ 'chrome', 'chromium', 'firefox', 'nwjs', 'electron' ],
// Browsers, in addition to those which do not fully support WebRTC, that
// are not supported and should show the unsupported browser page.
@@ -207,12 +206,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
@@ -230,17 +229,6 @@ 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.
*/
@@ -264,12 +252,6 @@ 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 */

View File

@@ -66,7 +66,6 @@ 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
#

View File

@@ -353,8 +353,6 @@ 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
@@ -411,7 +409,6 @@ 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`)
@@ -419,11 +416,13 @@ DEPENDENCIES:
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
trunk:
https://github.com/CocoaPods/Specs.git:
- Amplitude-iOS
- AppAuth
- boost-for-react-native
- CocoaLumberjack
- ObjectiveDropboxOfficial
trunk:
- AppAuth
- Crashlytics
- Fabric
- Firebase
@@ -443,7 +442,6 @@ SPEC REPOS:
- GTMAppAuth
- GTMSessionFetcher
- nanopb
- ObjectiveDropboxOfficial
- PromisesObjC
EXTERNAL SOURCES:
@@ -511,8 +509,6 @@ 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:
@@ -582,13 +578,12 @@ SPEC CHECKSUMS:
React-RCTVibration: a1bcfcdc0b5a73a1b0829a34cee22bd0e95bacba
ReactCommon: 675681aba4fecff5acbc0e440530cc422103c610
RNCAsyncStorage: 8e31405a9f12fbf42c2bb330e4560bfd79c18323
RNDefaultPreference: 56a405ce61033ac77b95004dccd7ac54c2eb50d1
RNGoogleSignin: 39336070b35fc4cea6a98cf111e00480317be0ae
RNSound: c980916b596cc15c8dcd2f6ecd3b13c4881dbe20
RNSVG: aac12785382e8fd4f28d072fe640612e34914631
RNWatch: 09738b339eceb66e4d80a2371633ca5fb380fa42
Yoga: 7b4209fda2441f99d54dd6cf4c82b094409bb68f
PODFILE CHECKSUM: 082858daebbe170e7a490de433e7f2a99e0c3701
PODFILE CHECKSUM: f615794fb9184757b00cd16e534824ba6ee2fc98
COCOAPODS: 1.9.1
COCOAPODS: 1.8.4

View File

@@ -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).
### Building it yourself
### Builduing it yourself
1. Install all required [dependencies](https://github.com/jitsi/jitsi-meet/blob/master/doc/mobile.md).

View File

@@ -24,10 +24,19 @@
@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;
@@ -45,13 +54,6 @@
#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;

View File

@@ -16,7 +16,12 @@
#import "FIRUtilities.h"
@import JitsiMeet;
// Plist file name.
NSString *const kGoogleServiceInfoFileName = @"GoogleService-Info";
// Plist file type.
NSString *const kGoogleServiceInfoFileType = @"plist";
NSString *const kGoogleAppIDPlistKey = @"GOOGLE_APP_ID";
@implementation FIRUtilities
@@ -25,11 +30,37 @@
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSBundle *bundle = [NSBundle mainBundle];
containsRealServiceInfoPlist = [InfoPlistUtil containsRealServiceInfoPlistInBundle:bundle];
containsRealServiceInfoPlist = [self 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) {

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>20.3.0</string>
<string>20.2.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>20.3.0</string>
<string>20.2.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>UISupportedInterfaceOrientations</key>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>20.3.0</string>
<string>20.2.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CLKComplicationPrincipalClass</key>

View File

@@ -66,9 +66,6 @@ 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"],
},

View File

@@ -42,8 +42,6 @@
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 */; };
@@ -107,8 +105,6 @@
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>"; };
@@ -227,8 +223,6 @@
DEFE535521FB2E8300011A3A /* ReactUtils.m */,
0B93EF7C1EC9DDCD0030D24D /* RCTBridgeWrapper.h */,
0B93EF7D1EC9DDCD0030D24D /* RCTBridgeWrapper.m */,
C8AFD27D2462C613000293D2 /* InfoPlistUtil.h */,
C8AFD27E2462C613000293D2 /* InfoPlistUtil.m */,
);
path = src;
sourceTree = "<group>";
@@ -309,7 +303,6 @@
DE81A2D42316AC4D00AE1940 /* JitsiMeetLogger.h in Headers */,
DE65AACA2317FFCD00290BEC /* LogUtils.h in Headers */,
DEAD3226220C497000E93636 /* JitsiMeetConferenceOptions.h in Headers */,
C8AFD27F2462C613000293D2 /* InfoPlistUtil.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -489,7 +482,6 @@
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 */,

View File

@@ -19,8 +19,6 @@
#import <React/RCTBridgeModule.h>
#import <React/RCTLog.h>
#import "InfoPlistUtil.h"
@interface AppInfo : NSObject<RCTBridgeModule>
@end
@@ -69,15 +67,13 @@ RCT_EXPORT_MODULE();
buildNumber = @"";
}
BOOL isGoogleServiceEnabled = [InfoPlistUtil containsRealServiceInfoPlistInBundle:[NSBundle mainBundle]];
return @{
@"calendarEnabled": [NSNumber numberWithBool:calendarEnabled],
@"buildNumber": buildNumber,
@"name": name,
@"sdkBundlePath": sdkBundlePath,
@"version": version,
@"GOOGLE_SERVICES_ENABLED": [NSNumber numberWithBool:isGoogleServiceEnabled]
@"version": version
};
};
@end

View File

@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.8.1</string>
<string>2.8.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>

View File

@@ -1,23 +0,0 @@
/*
* 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

View File

@@ -1,52 +0,0 @@
/*
* 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

View File

@@ -20,7 +20,6 @@
#import <JitsiMeet/JitsiMeetConferenceOptions.h>
#import <JitsiMeet/JitsiMeetLogger.h>
#import <JitsiMeet/JitsiMeetBaseLogHandler.h>
#import <JitsiMeet/InfoPlistUtil.h>
@interface JitsiMeet : NSObject
@@ -65,6 +64,4 @@
- (JitsiMeetConferenceOptions *_Nonnull)getInitialConferenceOptions;
- (BOOL)isCrashReportingDisabled;
@end

View File

@@ -107,7 +107,7 @@
JitsiMeetConferenceOptions *conferenceOptions = [JitsiMeetConferenceOptions fromBuilder:^(JitsiMeetConferenceOptionsBuilder *builder) {
builder.room = [url absoluteString];
}];
return [JitsiMeetView setPropsInViews:[conferenceOptions asProps]];
}
@@ -132,11 +132,6 @@
return nil;
}
- (BOOL)isCrashReportingDisabled {
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"jitsi-default-preferences"];
return [userDefaults stringForKey:@"isCrashReportingDisabled"];
}
- (JitsiMeetConferenceOptions *)optionsFromUserActivity:(NSUserActivity *)userActivity {
NSString *activityType = userActivity.activityType;

View File

@@ -1,34 +0,0 @@
{
"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": ""
}

27
lang/languages-az.json Normal file
View File

@@ -0,0 +1,27 @@
{
"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": ""
}

View File

@@ -1,34 +0,0 @@
{
"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": "Кітайская (Тайвань)"
}

View File

@@ -29,6 +29,5 @@
"tr": "Turc",
"vi": "Vietnamita",
"zhCN": "Xinès (Xina)",
"zhTW": "Xinès (Taiwan)",
"et": "Estonià"
"zhTW": "Xinès (Taiwan)"
}

View File

@@ -23,16 +23,5 @@
"sv": "Schwedisch",
"tr": "Türkisch",
"vi": "Vietnamesisch",
"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"
"zhCN": "Chinesisch (China)"
}

View File

@@ -1,38 +1,27 @@
{
"en": "English",
"af": "Afrikaans",
"en": "",
"af": "",
"az": "",
"bg": "Bulgarian",
"cs": "Czech",
"de": "German",
"el": "Greek",
"eo": "Esperanto",
"es": "Spanish",
"fr": "French",
"hy": "Armenian",
"it": "Italian",
"ja": "Japanese",
"ko": "Korean",
"bg": "",
"cs": "",
"de": "",
"el": "",
"eo": "",
"es": "",
"fr": "",
"hy": "",
"it": "",
"ja": "",
"ko": "",
"nb": "",
"oc": "Occitan",
"pl": "Polish",
"ptBR": "Portuguese (Brazil)",
"ru": "Russian",
"oc": "",
"pl": "",
"ptBR": "",
"ru": "",
"sk": "",
"sl": "",
"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"
}
"sv": "",
"tr": "",
"vi": "",
"zhCN": ""
}

View File

@@ -1,18 +1,18 @@
{
"en": "Angla",
"af": "Afrikansa",
"az": "Azera",
"af": "",
"az": "",
"bg": "Bulgara",
"cs": "Ĉeĥa",
"cs": "",
"de": "Germana",
"el": "Greka",
"el": "",
"eo": "Esperanto",
"es": "Hispana",
"fr": "Franca",
"hy": "Armena",
"it": "Itala",
"ja": "Japana",
"ko": "Korea",
"ja": "",
"ko": "",
"nb": "Norvega (Bukmola)",
"oc": "Okcitana",
"pl": "Pola",
@@ -22,6 +22,6 @@
"sl": "Slovena",
"sv": "Sveda",
"tr": "Turka",
"vi": "Vjetnama",
"vi": "",
"zhCN": "Ĉina (Ĉinuja)"
}
}

View File

@@ -1,6 +1,6 @@
{
"en": "Inglés",
"af": "Afrians",
"af": "Africano",
"bg": "Búlgaro",
"ca": "Catalán",
"cs": "Checo",
@@ -12,25 +12,21 @@
"esUS": "Español (América Latina)",
"fi": "Finlandés",
"fr": "Francés",
"frCA": "Francés (Canadiense)",
"he": "Hebreo",
"frCA": "Franco (Canadiense)",
"hr": "Croata",
"hu": "Húngaro",
"hy": "Armenio",
"it": "Italiano",
"ja": "Japonés",
"ja": "Jopones",
"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 (Taiwán)",
"et": "Estonio",
"da": "Danés"
}
"zhTW": "Chino (Taiwan)"
}

View File

@@ -13,7 +13,6 @@
"fi": "Finlandés",
"fr": "Francés",
"frCA": "Francés (Canadiense)",
"he": "Hebreo",
"hr": "Croata",
"hu": "Húngaro",
"hy": "Armenio",
@@ -25,10 +24,9 @@
"pl": "Polaco",
"ptBR": "Portugués (Brasil)",
"ru": "Ruso",
"sk": "Eslovaco",
"sv": "Sueco",
"tr": "Turco",
"vi": "Vietnamita",
"zhCN": "Chino (China)",
"zhTW": "Chino (Taiwan)"
}
}

View File

@@ -1,34 +0,0 @@
{
"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)"
}

View File

@@ -1,38 +1,27 @@
{
"en": "englanti",
"af": "afrikaans",
"en": "",
"af": "",
"az": "",
"bg": "bulgaria",
"cs": "tšekki",
"de": "saksa",
"el": "kreikka",
"eo": "esperanto",
"es": "espanja",
"fr": "ranska",
"hy": "armenia",
"it": "italia",
"ja": "japani",
"ko": "korea",
"bg": "",
"cs": "",
"de": "",
"el": "",
"eo": "",
"es": "",
"fr": "",
"hy": "",
"it": "",
"ja": "",
"ko": "",
"nb": "",
"oc": "oksitaani",
"pl": "puola",
"ptBR": "portugali (Brasilia)",
"ru": "venäjä",
"oc": "",
"pl": "",
"ptBR": "",
"ru": "",
"sk": "",
"sl": "",
"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"
}
"sv": "",
"tr": "",
"vi": "",
"zhCN": ""
}

View File

@@ -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": "Finnois",
"fi": "Finlandais",
"fr": "Français",
"frCA": "Français (Canada)",
"frCA": "Français (Canadien)",
"hr": "Croate",
"hu": "Hongrois",
"hy": "Arménien",
@@ -24,12 +24,9 @@
"pl": "Polonais",
"ptBR": "Portugais (Brésil)",
"ru": "Russe",
"sk": "Slovaque",
"sv": "Suédois",
"tr": "Turc",
"vi": "Vietnamien",
"zhCN": "Chinois (Chine)",
"zhTW": "Chinois (Taiwan)",
"et": "Estonien",
"da": "Danois"
}
"zhTW": "Chinois (Taiwan)"
}

View File

@@ -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": "Finnois",
"fi": "Finlandais",
"fr": "Français",
"frCA": "Français (Canadien)",
"hr": "Croate",
@@ -24,12 +24,9 @@
"pl": "Polonais",
"ptBR": "Portugais (Brésil)",
"ru": "Russe",
"sk": "Slovaque",
"sv": "Suédois",
"tr": "Turc",
"vi": "Vietnamien",
"zhCN": "Chinois (Chine)",
"zhTW": "Chinois (Taiwan)",
"et": "Estonien",
"da": "Danois"
}
"zhTW": "Chinois (Taiwan)"
}

View File

@@ -1,34 +0,0 @@
{
"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": ""
}

View File

@@ -28,7 +28,5 @@
"tr": "Turco",
"vi": "Vietnamita",
"zhCN": "Chinés (China)",
"zhTW": "Chinés (Taiwan)",
"et": "Estoniano",
"da": "Dinamarqués"
}
"zhTW": "Chinés (Taiwan)"
}

View File

@@ -1,37 +0,0 @@
{
"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": "סינית (טיוואן)"
}

View File

@@ -24,12 +24,9 @@
"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)",
"et": "Észt",
"da": "Dán"
}
"zhTW": "Kínai (Tajvan)"
}

View File

@@ -1,39 +0,0 @@
{
"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"
}

View File

@@ -1,34 +0,0 @@
{
"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)"
}

View File

@@ -23,16 +23,5 @@
"sv": "Svedese",
"tr": "Turco",
"vi": "Vietnamita",
"zhCN": "Cinese (Cina)",
"enGB": "Inglese (Regno Unito)",
"da": "Danese",
"ca": "Catalano",
"zhTW": "",
"nl": "",
"hu": "",
"hr": "",
"frCA": "",
"fi": "",
"et": "",
"esUS": ""
"zhCN": "Cinese (Cina)"
}

View File

@@ -1,7 +1,7 @@
{
"en": "Taglizit",
"af": "Tafrikant",
"az": "Tazirit",
"af": "",
"az": "",
"bg": "Tabulgarit",
"cs": "Taččikit",
"de": "Talmanit",
@@ -24,4 +24,4 @@
"tr": "Taṭurkit",
"vi": "Tavyitnamit",
"zhCN": "Tavyitnamit"
}
}

View File

@@ -1,35 +0,0 @@
{
"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)"
}

View File

@@ -1,34 +0,0 @@
{
"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