Compare commits

..

1 Commits

Author SHA1 Message Date
Saúl Ibarra Corretgé
87d6eed612 rn,sdk: bump version to 2.7.0 2020-03-25 09:29:55 +01:00
1060 changed files with 17292 additions and 55501 deletions

View File

@@ -4,45 +4,25 @@ about: Create a report to help us improve
---
<!--
*This Issue tracker is only for reporting bugs and tracking code related issues.*
This issue tracker is only for reporting bugs and tracking issues related to the source code.
Before posting, please make sure you check community.jitsi.org to see if the same or similar bugs have already been discussed.
General questions, installation help, and feature requests can also be posted to community.jitsi.org.
Before posting, please make sure to check if the same or similar bugs have already been discussed: https://github.com/jitsi/jitsi-meet/issues
## Description
---
General questions regarding usage, installation, etc. should be posted at https://community.jitsi.org. They will be closed if posted here.
## Current behavior
---
-->
## Expected Behavior
---
### Description:
## Possible Solution
---
<!-- Please describe the bug clearly and concisely. -->
## Steps to reproduce
---
### Steps to reproduce:
1. <!-- Open '...' -->
2. <!-- Click on '...' -->
3. <!-- and so on... -->
### Expected behavior:
<!-- Please describe what should happen. -->
### Actual behavior:
<!-- Please describe what actually happens. -->
<!-- Please attach screenshot if possible. -->
### Server information:
- Jitsi Meet version:
- Operating System:
### Client information:
- Browser / app version:
- Operating System:
### Additional information:
<!-- Please provide additional information about the bug, if any. -->
# Environment details
---

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

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

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

@@ -1,5 +0,0 @@
<!--
Thank you for your pull request. Please provide a thorough description below.
Contributors guide: https://github.com/jitsi/jitsi-meet/blob/master/CONTRIBUTING.md
-->

View File

@@ -1,10 +1,10 @@
name: Simple CI
name: Linter
on: [pull_request]
jobs:
run-ci:
name: Build Frontend
run-linter:
name: Run Linter
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
@@ -13,4 +13,3 @@ jobs:
node-version: '12.x'
- run: npm install
- run: npm run lint
- run: make

1
.npmrc
View File

@@ -1 +0,0 @@
package-lock=true

View File

@@ -27,128 +27,3 @@ in the agreement, unfortunately, we cannot accept your contribution.
- Maintain a clean list of commits, squash them if necessary.
- Rebase your topic branch on top of the master branch before creating the pull
request.
## Coding style
### Comments
* Comments documenting the source code are required.
* Comments from which documentation is automatically generated are **not**
subject to case-by-case decisions. Such comments are used, for example, on
types and their members. Examples of tools which automatically generate
documentation from such comments include JSDoc, Javadoc, Doxygen.
* Comments which are not automatically processed are strongly encouraged. They
are subject to case-by-case decisions. Such comments are often observed in
function bodies.
* Comments should be formatted as proper English sentences. Such formatting pays
attention to, for example, capitalization and punctuation.
### Duplication
* Don't copy-paste source code. Reuse it.
### Formatting
* Line length is limited to 120 characters.
* Sort by alphabetical order in order to make the addition of new entities as
easy as looking a word up in a dictionary. Otherwise, one risks duplicate
entries (with conflicting values in the cases of key-value pairs). For
example:
* Within an `import` of multiple names from a module, sort the names in
alphabetical order. (Of course, the default name stays first as required by
the `import` syntax.)
````javascript
import {
DOMINANT_SPEAKER_CHANGED,
JITSI_CLIENT_CONNECTED,
JITSI_CLIENT_CREATED,
JITSI_CLIENT_DISCONNECTED,
JITSI_CLIENT_ERROR,
JITSI_CONFERENCE_JOINED,
MODERATOR_CHANGED,
PEER_JOINED,
PEER_LEFT,
RTC_ERROR
} from './actionTypes';
````
* Within a group of imports (e.g. groups of imports delimited by an empty line
may be: third-party modules, then project modules, and eventually the
private files of a module), sort the module names in alphabetical order.
````javascript
import React, { Component } from 'react';
import { connect } from 'react-redux';
````
### Indentation
* Align `switch` and `case`/`default`. Don't indent the `case`/`default` more
than its `switch`.
````javascript
switch (i) {
case 0:
...
break;
default:
...
}
````
### Naming
* An abstraction should have one name within the project and across multiple
projects. For example:
* The instance of lib-jitsi-meet's `JitsiConnection` type should be named
`connection` or `jitsiConnection` in jitsi-meet, not `client`.
* The class `ReducerRegistry` should be defined in ReducerRegistry.js and its
imports in other files should use the same name. Don't define the class
`Registry` in ReducerRegistry.js and then import it as `Reducers` in other
files.
* The names of global constants (including ES6 module-global constants) should
be written in uppercase with underscores to separate words. For example,
`BACKGROUND_COLOR`.
* The underscore character at the beginning of a name signals that the
respective variable, function, property is non-public i.e. private, protected,
or internal. In contrast, the lack of an underscore at the beginning of a name
signals public API.
### Feature layout
When adding a new feature, this would be the usual layout.
```
react/features/sample/
├── actionTypes.js
├── actions.js
├── components
│   ├── AnotherComponent.js
│   ├── OneComponent.js
│   └── index.js
├── middleware.js
└── reducer.js
```
The middleware must be imported in `react/features/app/` specifically
in `middlewares.any`, `middlewares.native.js` or `middlewares.web.js` where appropriate.
Likewise for the reducer.
An `index.js` file must not be provided for exporting actions, action types and
component. Features / files requiring those must import them explicitly.
This has not always been the case and the entire codebase hasn't been migrated to
this model but new features should follow this new layout.
When working on an old feature, adding the necessary changes to migrate to the new
model is encouraged.

View File

@@ -21,7 +21,6 @@ compile:
clean:
rm -fr $(BUILD_DIR)
.NOTPARALLEL:
deploy: deploy-init deploy-appbundle deploy-rnnoise-binary deploy-lib-jitsi-meet deploy-libflac deploy-css deploy-local
deploy-init:
@@ -74,19 +73,18 @@ deploy-rnnoise-binary:
deploy-css:
$(NODE_SASS) $(STYLES_MAIN) $(STYLES_BUNDLE) && \
$(CLEANCSS) --skip-rebase $(STYLES_BUNDLE) > $(STYLES_DESTINATION) ; \
$(CLEANCSS) $(STYLES_BUNDLE) > $(STYLES_DESTINATION) ; \
rm $(STYLES_BUNDLE)
deploy-local:
([ ! -x deploy-local.sh ] || ./deploy-local.sh)
.NOTPARALLEL:
dev: deploy-init deploy-css deploy-rnnoise-binary deploy-lib-jitsi-meet deploy-libflac
$(WEBPACK_DEV_SERVER) --detect-circular-deps
$(WEBPACK_DEV_SERVER)
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.
@@ -10,11 +10,9 @@ Jitsi Meet allows very efficient collaboration. Users can stream their desktop o
On the client side, no installation is necessary. You just point your browser to the URL of your deployment. This section is about installing a Jitsi Meet suite on your server and hosting your own conferencing service.
Installing Jitsi Meet is a simple experience. For Debian-based system, following the [quick install](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-quickstart) document, which uses the package system. You can also see a demonstration of the process in [this tutorial video](https://jitsi.org/tutorial).
Installing Jitsi Meet is a simple experience. For Debian-based system, following the [quick-install](https://github.com/jitsi/jitsi-meet/blob/master/doc/quick-install.md) document, which uses the package system. You can also see a demonstration of the process in [this tutorial video](https://jitsi.org/tutorial).
For other systems, or if you wish to install all components manually, see the [detailed manual installation instructions](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-manual).
Installation with Docker is also available. Please see the [instruction](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker).
For other systems, or if you wish to install all components manually, see the [detailed manual installation instructions](https://github.com/jitsi/jitsi-meet/blob/master/doc/manual-install.md).
## Download
@@ -48,13 +46,9 @@ You can also sign up for our open beta testing here:
* [Android](https://play.google.com/apps/testing/org.jitsi.meet)
* [iOS](https://testflight.apple.com/join/isy6ja7S)
## Release notes
Release notes for Jitsi Meet are maintained on [this repository](https://github.com/jitsi/jitsi-meet-release-notes).
## Development
For web development see [here](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-web), and for mobile see [here](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-mobile).
For web development see [here](doc/development.md), and for mobile see [here](doc/mobile.md).
## Contributing
@@ -67,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,9 +0,0 @@
# Security
## Reporting security issues
We take security very seriously and develop all Jitsi projects to be secure and safe.
If you find (or simply suspect) a security issue in any of the Jitsi projects, please report it to us via [HackerOne](https://hackerone.com/8x8) or 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.**

View File

@@ -1,3 +1,380 @@
# Jitsi Meet SDK for Android
This document has been moved to [The Handbook](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-android-sdk).
## Sample applications using the SDK
If you want to see how easy integrating the Jitsi Meet SDK into a native application is, take a look at the
[sample applications repository](https://github.com/jitsi/jitsi-meet-sdk-samples).
## Build your own, or use a pre-build SDK artifacts/binaries
Jitsi conveniently provides a pre-build SDK artifacts/binaries in its Maven repository. When you do not require any
modification to the SDK itself or any of its dependencies, it's suggested to use the pre-build SDK. This avoids the
complexity of building and installing your own SDK artifacts/binaries.
### Use pre-build SDK artifacts/binaries
In your project, add the Maven repository
`https://github.com/jitsi/jitsi-maven-repository/raw/master/releases` and the
dependency `org.jitsi.react:jitsi-meet-sdk` into your `build.gradle` files.
The repository typically goes into the `build.gradle` file in the root of your project:
```gradle
allprojects {
repositories {
google()
jcenter()
maven {
url "https://github.com/jitsi/jitsi-maven-repository/raw/master/releases"
}
}
}
```
Dependency definitions belong in the individual module `build.gradle` files:
```gradle
dependencies {
// (other dependencies)
implementation ('org.jitsi.react:jitsi-meet-sdk:2.+') { transitive = true }
}
```
### Build and use your own SDK artifacts/binaries
<details>
<summary>Show building instructions</summary>
Start by making sure that your development environment [is set up correctly](https://github.com/jitsi/jitsi-meet/blob/master/doc/mobile.md).
A note on dependencies: Apart from the SDK, Jitsi also publishes a binary Maven artifact for some of the SDK dependencies (that are not otherwise publicly available) to the Jitsi Maven repository. When you're planning to use a SDK that is built from source, you'll likely use a version of the source code that is newer (or at least _different_) than the version of the source that was used to create the binary SDK artifact. As a consequence, the dependencies that your project will need, might also be different from those that are published in the Jitsi Maven repository. This might lead to build problems, caused by dependencies that are unavailable.
If you want to use a SDK that is built from source, you will likely benefit from composing a local Maven repository that contains these dependencies. The text below describes how you create a repository that includes both the SDK as well as these dependencies. For illustration purposes, we'll define the location of this local Maven repository as `/tmp/repo`
In source code form, the Android SDK dependencies are locked/pinned by package.json and package-lock.json of the Jitsi Meet project. To obtain the data, execute NPM in the jitsi-meet project directory:
npm install
This will pull in the dependencies in either binary format, or in source code format, somewhere under /node_modules/
Third-party React Native _modules_, which Jitsi Meet SDK for Android depends on, are download by NPM in source code
or binary form. These need to be assembled into Maven artifacts, and then published to your local Maven repository.
A script is provided to facilitate this. From the root of the jitsi-meet project repository, run:
./android/scripts/release-sdk.sh /tmp/repo
This will build and publish the SDK, and all of its dependencies to the specified Maven repository (`/tmp/repo`) in
this example.
You're now ready to use the artifacts. In _your_ project, add the Maven repository that you used above (`/tmp/repo`) into your top-level `build.gradle` file:
allprojects {
repositories {
maven { url "file:/tmp/repo" }
google()
jcenter()
}
}
You can use your local repository to replace the Jitsi repository (`maven { url "https://github.com/jitsi/jitsi-maven-repository/raw/master/releases" }`) when you published _all_ subprojects. If you didn't do that, you'll have to add both repositories. Make sure your local repository is listed first!
Then, define the dependency `org.jitsi.react:jitsi-meet-sdk` into the `build.gradle` file of your module:
implementation ('org.jitsi.react:jitsi-meet-sdk:+') { transitive = true }
Note that there should not be a need to explicitly add the other dependencies, as they will be pulled in as transitive
dependencies of `jitsi-meet-sdk`.
</details>
## Using the API
Jitsi Meet SDK is an Android library which embodies the whole Jitsi Meet
experience and makes it reusable by third-party apps.
First, add Java 1.8 compatibility support to your project by adding the
following lines into your `build.gradle` file:
```
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
```
To get started, extends your `android.app.Activity` from
`org.jitsi.meet.sdk.JitsiMeetActivity`:
```java
package org.jitsi.example;
import org.jitsi.meet.sdk.JitsiMeetActivity;
public class MainActivity extends JitsiMeetActivity {
}
```
Alternatively, you can use the `org.jitsi.meet.sdk.JitsiMeetView` class which
extends `android.view.View`.
Note that this should only be needed when `JitsiMeetActivity` cannot be used for
some reason. Extending `JitsiMeetView` requires manual wiring of the view to
the activity, using a lot of boilerplate code. Using the Activity instead of the
View is strongly recommended.
<details>
<summary>Show example</summary>
```java
package org.jitsi.example;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import org.jitsi.meet.sdk.JitsiMeetView;
import org.jitsi.meet.sdk.ReactActivityLifecycleCallbacks;
// Example
//
public class MainActivity extends FragmentActivity implements JitsiMeetActivityInterface {
private JitsiMeetView view;
@Override
protected void onActivityResult(
int requestCode,
int resultCode,
Intent data) {
JitsiMeetActivityDelegate.onActivityResult(
this, requestCode, resultCode, data);
}
@Override
public void onBackPressed() {
JitsiMeetActivityDelegate.onBackPressed();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view = new JitsiMeetView(this);
JitsiMeetConferenceOptions options = new JitsiMeetConferenceOptions.Builder()
.setRoom("https://meet.jit.si/test123")
.build();
view.join(options);
setContentView(view);
}
@Override
protected void onDestroy() {
super.onDestroy();
view.dispose();
view = null;
JitsiMeetActivityDelegate.onHostDestroy(this);
}
@Override
public void onNewIntent(Intent intent) {
JitsiMeetActivityDelegate.onNewIntent(intent);
}
@Override
public void onRequestPermissionsResult(
final int requestCode,
final String[] permissions,
final int[] grantResults) {
JitsiMeetActivityDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
protected void onResume() {
super.onResume();
JitsiMeetActivityDelegate.onHostResume(this);
}
@Override
protected void onStop() {
super.onStop();
JitsiMeetActivityDelegate.onHostPause(this);
}
}
```
</details>
### JitsiMeetActivity
This class encapsulates a high level API in the form of an Android `FragmentActivity`
which displays a single `JitsiMeetView`. You can pass a URL as a `ACTION_VIEW`
on the Intent when starting it and it will join the conference, and will be
automatically terminated (finish() will be called on the activity) when the
conference ends or fails.
### JitsiMeetView
The `JitsiMeetView` class is the core of Jitsi Meet SDK. It's designed to
display a Jitsi Meet conference (or a welcome page).
#### join(options)
Joins the conference specified by the given `JitsiMeetConferenceOptions`.
#### leave()
Leaves the currently active conference. If the welcome page is enabled it will
go back to it, otherwise a black window will be shown.
#### dispose()
Releases all resources associated with this view. This method MUST be called
when the Activity holding this view is going to be destroyed, usually in the
`onDestroy()` method.
#### getListener()
Returns the `JitsiMeetViewListener` instance attached to the view.
#### setListener(listener)
Sets the given listener (class implementing the `JitsiMeetViewListener`
interface) on the view.
### JitsiMeetConferenceOptions
This object encapsulates all the options that can be tweaked when joining
a conference.
Example:
```java
JitsiMeetConferenceOptions options = new JitsiMeetConferenceOptions.Builder()
.setServerURL(new URL("https://meet.jit.si"))
.setRoom("test123")
.setAudioMuted(false)
.setVideoMuted(false)
.setAudioOnly(false)
.setWelcomePageEnabled(false)
.build();
```
See the `JitsiMeetConferenceOptions` implementation for all available options.
### JitsiMeetActivityDelegate
This class handles the interaction between `JitsiMeetView` and its enclosing
`Activity`. Generally this shouldn't be consumed by users, because they'd be
using `JitsiMeetActivity` instead, which is already completely integrated.
All its methods are static.
#### onActivityResult(...)
Helper method to handle results of auxiliary activities launched by the SDK.
Should be called from the activity method of the same name.
#### onBackPressed()
Helper method which should be called from the activity's `onBackPressed` method.
If this function returns `true`, it means the action was handled and thus no
extra processing is required; otherwise the app should call the parent's
`onBackPressed` method.
#### onHostDestroy(...)
Helper method which should be called from the activity's `onDestroy` method.
#### onHostResume(...)
Helper method which should be called from the activity's `onResume` or `onStop`
method.
#### onHostStop(...)
Helper method which should be called from the activity's `onSstop` method.
#### onNewIntent(...)
Helper method for integrating the *deep linking* functionality. If your app's
activity is launched in "singleTask" mode this method should be called from the
activity's `onNewIntent` method.
#### onRequestPermissionsResult(...)
Helper method to handle permission requests inside the SDK. It should be called
from the activity method of the same name.
#### onUserLeaveHint()
Helper method for integrating automatic Picture-in-Picture. It should be called
from the activity's `onUserLeaveHint` method.
This is a static method.
#### JitsiMeetViewListener
`JitsiMeetViewListener` provides an interface apps can implement to listen to
the state of the Jitsi Meet conference displayed in a `JitsiMeetView`.
#### onConferenceJoined
Called when a conference was joined.
The `data` `Map` contains a "url" key with the conference URL.
#### onConferenceTerminated
Called when a conference was terminated either by user choice or due to a
failure.
The `data` `Map` contains an "error" key with the error and a "url" key
with the conference URL. If the conference finished gracefully no `error`
key will be present.
#### onConferenceWillJoin
Called before a conference is joined.
The `data` `Map` contains a "url" key with the conference URL.
## ProGuard rules
When using the SDK on a project some proguard rules have to be added in order
to avoid necessary code being stripped. Add the following to your project's
rules file: https://github.com/jitsi/jitsi-meet/blob/master/android/app/proguard-rules.pro
## Picture-in-Picture
`JitsiMeetView` will automatically adjust its UI when presented in a
Picture-in-Picture style scenario, in a rectangle too small to accommodate its
"full" UI.
## Dropbox integration
To setup the Dropbox integration, follow these steps:
1. Add the following to the app's AndroidManifest.xml and change `<APP_KEY>` to
your Dropbox app key:
```
<activity
android:configChanges="keyboard|orientation"
android:launchMode="singleTask"
android:name="com.dropbox.core.android.AuthActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="db-<APP_KEY>" />
</intent-filter>
</activity>
```
2. Add the following to the app's strings.xml and change `<APP_KEY>` to your
Dropbox app key:
```
<string name="dropbox_app_key"><APP_KEY></string>
```

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

@@ -1,16 +1,12 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="org.jitsi.meet"
android:installLocation="auto">
package="org.jitsi.meet">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/AppTheme">
<meta-data
android:name="android.content.APP_RESTRICTIONS"
android:resource="@xml/app_restrictions" />
<activity
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize"
android:label="@string/app_name"

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

@@ -16,14 +16,9 @@
package org.jitsi.meet;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.RestrictionEntry;
import android.content.RestrictionsManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Build;
import android.provider.Settings;
import android.util.Log;
import android.view.KeyEvent;
@@ -36,7 +31,6 @@ import org.jitsi.meet.sdk.JitsiMeetConferenceOptions;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.Map;
/**
@@ -54,27 +48,6 @@ public class MainActivity extends JitsiMeetActivity {
private static final int OVERLAY_PERMISSION_REQUEST_CODE
= (int) (Math.random() * Short.MAX_VALUE);
/**
* ServerURL configuration key for restriction configuration using {@link android.content.RestrictionsManager}
*/
public static final String RESTRICTION_SERVER_URL = "SERVER_URL";
/**
* Broadcast receiver for restrictions handling
*/
private BroadcastReceiver broadcastReceiver;
/**
* Flag if configuration is provided by RestrictionManager
*/
private boolean configurationByRestrictions = false;
/**
* Default URL as could be obtained from RestrictionManager
*/
private String defaultURL;
// JitsiMeetActivity overrides
//
@@ -95,7 +68,7 @@ public class MainActivity extends JitsiMeetActivity {
// In Debug builds React needs permission to write over other apps in
// order to display the warning and error overlays.
if (BuildConfig.DEBUG) {
if (!Settings.canDrawOverlays(this)) {
if (canRequestOverlayPermission() && !Settings.canDrawOverlays(this)) {
Intent intent
= new Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
@@ -112,67 +85,16 @@ public class MainActivity extends JitsiMeetActivity {
@Override
protected void initialize() {
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// As new restrictions including server URL are received,
// conference should be restarted with new configuration.
leave();
recreate();
}
};
registerReceiver(broadcastReceiver,
new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED));
resolveRestrictions();
setJitsiMeetConferenceDefaultOptions();
super.initialize();
}
@Override
public void onDestroy() {
if (broadcastReceiver != null) {
unregisterReceiver(broadcastReceiver);
broadcastReceiver = null;
}
super.onDestroy();
}
private void setJitsiMeetConferenceDefaultOptions() {
// Set default options
JitsiMeetConferenceOptions defaultOptions
= new JitsiMeetConferenceOptions.Builder()
.setWelcomePageEnabled(true)
.setServerURL(buildURL(defaultURL))
.setFeatureFlag("call-integration.enabled", false)
.setFeatureFlag("resolution", 360)
.setFeatureFlag("server-url-change.enabled", !configurationByRestrictions)
.build();
.setWelcomePageEnabled(true)
.setServerURL(buildURL("https://meet.jit.si"))
.setFeatureFlag("call-integration.enabled", false)
.build();
JitsiMeet.setDefaultConferenceOptions(defaultOptions);
}
private void resolveRestrictions() {
RestrictionsManager manager =
(RestrictionsManager) getSystemService(Context.RESTRICTIONS_SERVICE);
Bundle restrictions = manager.getApplicationRestrictions();
Collection<RestrictionEntry> entries = manager.getManifestRestrictions(
getApplicationContext().getPackageName());
for (RestrictionEntry restrictionEntry : entries) {
String key = restrictionEntry.getKey();
if (RESTRICTION_SERVER_URL.equals(key)) {
// If restrictions are passed to the application.
if (restrictions != null &&
restrictions.containsKey(RESTRICTION_SERVER_URL)) {
defaultURL = restrictions.getString(RESTRICTION_SERVER_URL);
configurationByRestrictions = true;
// Otherwise use default URL from app-restrictions.xml.
} else {
defaultURL = restrictionEntry.getSelectedString();
configurationByRestrictions = false;
}
}
}
super.initialize();
}
@Override
@@ -185,7 +107,8 @@ public class MainActivity extends JitsiMeetActivity {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OVERLAY_PERMISSION_REQUEST_CODE) {
if (requestCode == OVERLAY_PERMISSION_REQUEST_CODE
&& canRequestOverlayPermission()) {
if (Settings.canDrawOverlays(this)) {
initialize();
return;
@@ -208,18 +131,6 @@ public class MainActivity extends JitsiMeetActivity {
return super.onKeyUp(keyCode, event);
}
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode);
Log.d(TAG, "Is in picture-in-picture mode: " + isInPictureInPictureMode);
if (!isInPictureInPictureMode) {
this.startActivity(new Intent(this, getClass())
.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT));
}
}
// Helper methods
//
@@ -230,4 +141,10 @@ public class MainActivity extends JitsiMeetActivity {
return null;
}
}
private boolean canRequestOverlayPermission() {
return
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.M;
}
}

View File

@@ -1,5 +1,3 @@
<resources>
<string name="app_name">Jitsi Meet</string>
<string name="restriction_server_url_description">URL of Jitsi Meet server instance to connect to</string>
<string name="restriction_server_url_title">Server URL</string>
</resources>

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Server URL configuration -->
<restriction
android:defaultValue="https://meet.jit.si"
android:description="@string/restriction_server_url_description"
android:key="SERVER_URL"
android:restrictionType="string"
android:title="@string/restriction_server_url_title"/>
</restrictions>

View File

@@ -1,12 +1,6 @@
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="false">localhost</domain>
<domain includeSubdomains="false">10.0.2.2</domain>
</domain-config>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="false">localhost</domain>
<domain includeSubdomains="false">10.0.2.2</domain>
</domain-config>
</network-security-config>

View File

@@ -142,10 +142,10 @@ allprojects {
}
ext {
buildToolsVersion = "29.0.3"
compileSdkVersion = 29
minSdkVersion = 23
targetSdkVersion = 29
buildToolsVersion = "28.0.3"
compileSdkVersion = 28
minSdkVersion = 21
targetSdkVersion = 28
supportLibVersion = "28.0.0"
// The Maven artifact groupdId of the third-party react-native modules which
@@ -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.4.0
sdkVersion=2.10.0
appVersion=20.1.0
sdkVersion=2.7.0

View File

@@ -1,5 +0,0 @@
#!/bin/bash
THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
exec ${THIS_DIR}/../../node_modules/react-native/scripts/launchPackager.command --reset-cache

View File

@@ -8,7 +8,7 @@ THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOUR
export RCT_METRO_PORT="${RCT_METRO_PORT:=8081}"
echo "export RCT_METRO_PORT=${RCT_METRO_PORT}" > "${THIS_DIR}/../../node_modules/react-native/scripts/.packager.env"
adb reverse tcp:$RCT_METRO_PORT tcp:$RCT_METRO_PORT
adb reverse tcp:8081 tcp:8081
if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then
if ! curl -s "http://localhost:${RCT_METRO_PORT}/status" | grep -q "packager-status:running" ; then
@@ -16,10 +16,11 @@ if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then
exit 2
fi
else
CMD="$THIS_DIR/run-packager-helper.command"
CMD="${THIS_DIR}/../../node_modules/react-native/scripts/launchPackager.command"
if [[ `uname` == "Darwin" ]]; then
open -g "${CMD}" || echo "Can't start packager automatically"
else
xdg-open "${CMD}" || echo "Can't start packager automatically"
fi
fi

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,8 +16,11 @@
package org.jitsi.meet.sdk;
import android.content.Context;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.os.Build;
import androidx.annotation.RequiresApi;
import java.util.HashSet;
import java.util.Set;
@@ -31,6 +34,7 @@ import org.jitsi.meet.sdk.log.JitsiMeetLogger;
* default it's only used on versions < O, since versions >= O use ConnectionService, but it
* can be disabled.
*/
@RequiresApi(Build.VERSION_CODES.M)
class AudioDeviceHandlerGeneric implements
AudioModeModule.AudioDeviceHandlerInterface,
AudioManager.OnAudioFocusChangeListener {

View File

@@ -0,0 +1,230 @@
/*
* Copyright @ 2017-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.
*/
package org.jitsi.meet.sdk;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
/**
* {@link AudioModeModule.AudioDeviceHandlerInterface} module implementing device handling for
* legacy (pre-M) Android versions.
*/
class AudioDeviceHandlerLegacy implements
AudioModeModule.AudioDeviceHandlerInterface,
AudioManager.OnAudioFocusChangeListener,
BluetoothHeadsetMonitor.Listener {
private final static String TAG = AudioDeviceHandlerLegacy.class.getSimpleName();
/**
* Reference to the main {@code AudioModeModule}.
*/
private AudioModeModule module;
/**
* Indicator that we have lost audio focus.
*/
private boolean audioFocusLost = false;
/**
* {@link AudioManager} instance used to interact with the Android audio
* subsystem.
*/
private AudioManager audioManager;
/**
* {@link BluetoothHeadsetMonitor} for detecting Bluetooth device changes in
* old (< M) Android versions.
*/
private BluetoothHeadsetMonitor bluetoothHeadsetMonitor;
public AudioDeviceHandlerLegacy(AudioManager audioManager) {
this.audioManager = audioManager;
}
/**
* Helper method to trigger an audio route update when Bluetooth devices are
* connected / disconnected.
*/
@Override
public void onBluetoothDeviceChange(final boolean deviceAvailable) {
module.runInAudioThread(new Runnable() {
@Override
public void run() {
if (deviceAvailable) {
module.addDevice(AudioModeModule.DEVICE_BLUETOOTH);
} else {
module.removeDevice(AudioModeModule.DEVICE_BLUETOOTH);
}
module.updateAudioRoute();
}
});
}
/**
* Helper method to trigger an audio route update when a headset is plugged
* or unplugged.
*/
private void onHeadsetDeviceChange() {
module.runInAudioThread(new Runnable() {
@Override
public void run() {
// XXX: isWiredHeadsetOn is not deprecated when used just for
// knowing if there is a wired headset connected, regardless of
// audio being routed to it.
//noinspection deprecation
if (audioManager.isWiredHeadsetOn()) {
module.addDevice(AudioModeModule.DEVICE_HEADPHONES);
} else {
module.removeDevice(AudioModeModule.DEVICE_HEADPHONES);
}
module.updateAudioRoute();
}
});
}
/**
* {@link AudioManager.OnAudioFocusChangeListener} interface method. Called
* when the audio focus of the system is updated.
*
* @param focusChange - The type of focus change.
*/
@Override
public void onAudioFocusChange(final int focusChange) {
module.runInAudioThread(new Runnable() {
@Override
public void run() {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN: {
JitsiMeetLogger.d(TAG + " Audio focus gained");
// Some other application potentially stole our audio focus
// temporarily. Restore our mode.
if (audioFocusLost) {
module.updateAudioRoute();
}
audioFocusLost = false;
break;
}
case AudioManager.AUDIOFOCUS_LOSS:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: {
JitsiMeetLogger.d(TAG + " Audio focus lost");
audioFocusLost = true;
break;
}
}
}
});
}
/**
* Helper method to set the output route to a Bluetooth device.
*
* @param enabled true if Bluetooth should use used, false otherwise.
*/
private void setBluetoothAudioRoute(boolean enabled) {
if (enabled) {
audioManager.startBluetoothSco();
audioManager.setBluetoothScoOn(true);
} else {
audioManager.setBluetoothScoOn(false);
audioManager.stopBluetoothSco();
}
}
@Override
public void start(AudioModeModule audioModeModule) {
JitsiMeetLogger.i("Using " + TAG + " as the audio device handler");
module = audioModeModule;
Context context = module.getContext();
// Setup runtime device change detection.
//
// Detect changes in wired headset connections.
IntentFilter wiredHeadSetFilter = new IntentFilter(AudioManager.ACTION_HEADSET_PLUG);
BroadcastReceiver wiredHeadsetReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
JitsiMeetLogger.d(TAG + " Wired headset added / removed");
onHeadsetDeviceChange();
}
};
context.registerReceiver(wiredHeadsetReceiver, wiredHeadSetFilter);
// Detect Bluetooth device changes.
bluetoothHeadsetMonitor = new BluetoothHeadsetMonitor(context, this);
// On Android < M, detect if we have an earpiece.
PackageManager pm = context.getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
module.addDevice(AudioModeModule.DEVICE_EARPIECE);
}
// Always assume there is a speaker.
module.addDevice(AudioModeModule.DEVICE_SPEAKER);
}
@Override
public void stop() {
bluetoothHeadsetMonitor.stop();
bluetoothHeadsetMonitor = null;
}
@Override
public void setAudioRoute(String device) {
// Turn speaker on / off
audioManager.setSpeakerphoneOn(device.equals(AudioModeModule.DEVICE_SPEAKER));
// Turn bluetooth on / off
setBluetoothAudioRoute(device.equals(AudioModeModule.DEVICE_BLUETOOTH));
}
@Override
public boolean setMode(int mode) {
if (mode == AudioModeModule.DEFAULT) {
audioFocusLost = false;
audioManager.setMode(AudioManager.MODE_NORMAL);
audioManager.abandonAudioFocus(this);
audioManager.setSpeakerphoneOn(false);
setBluetoothAudioRoute(false);
return true;
}
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
audioManager.setMicrophoneMute(false);
if (audioManager.requestAudioFocus(this, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN)
== AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
JitsiMeetLogger.w(TAG + " Audio focus request failed");
return false;
}
return true;
}
}

View File

@@ -222,8 +222,10 @@ class AudioModeModule extends ReactContextBaseJavaModule {
if (useConnectionService()) {
audioDeviceHandler = new AudioDeviceHandlerConnectionService(audioManager);
} else {
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
audioDeviceHandler = new AudioDeviceHandlerGeneric(audioManager);
} else {
audioDeviceHandler = new AudioDeviceHandlerLegacy(audioManager);
}
audioDeviceHandler.start(this);
@@ -425,6 +427,15 @@ class AudioModeModule extends ReactContextBaseJavaModule {
}
}
/**
* Needed on the legacy handler...
*
* @return Context for the application.
*/
Context getContext() {
return getReactApplicationContext();
}
/**
* Interface for the modules implementing the actual audio device management.
*/

View File

@@ -0,0 +1,191 @@
/*
* Copyright @ 2017-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.
*/
package org.jitsi.meet.sdk;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
/**
* Helper class to detect and handle Bluetooth device changes. It monitors
* Bluetooth headsets being connected / disconnected and notifies the module
* about device changes when this occurs.
*/
class BluetoothHeadsetMonitor {
private final static String TAG = BluetoothHeadsetMonitor.class.getSimpleName();
/**
* The {@link Context} in which this module executes.
*/
private final Context context;
/**
* Reference to the {@link BluetoothAdapter} object, used to access Bluetooth functionality.
*/
private BluetoothAdapter adapter;
/**
* Reference to a proxy object which allows us to query connected devices.
*/
private BluetoothHeadset headset;
/**
* receiver registered for receiving Bluetooth connection state changes.
*/
private BroadcastReceiver receiver;
/**
* Listener for receiving Bluetooth device change events.
*/
private Listener listener;
public BluetoothHeadsetMonitor(Context context, Listener listener) {
this.context = context;
this.listener = listener;
}
private boolean getBluetoothHeadsetProfileProxy() {
adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter == null) {
JitsiMeetLogger.w(TAG + " Device doesn't support Bluetooth");
return false;
}
// XXX: The profile listener listens for system services of the given
// type being available to the application. That is, if our Bluetooth
// adapter has the "headset" profile.
BluetoothProfile.ServiceListener listener
= new BluetoothProfile.ServiceListener() {
@Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
headset = (BluetoothHeadset) proxy;
updateDevices();
}
}
@Override
public void onServiceDisconnected(int profile) {
// The logic is the same as the logic of onServiceConnected.
onServiceConnected(profile, /* proxy */ null);
}
};
return adapter.getProfileProxy(context, listener, BluetoothProfile.HEADSET);
}
private void onBluetoothReceiverReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
// XXX: This action will be fired when a Bluetooth headset is
// connected or disconnected to the system. This is not related to
// audio routing.
int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, -99);
switch (state) {
case BluetoothHeadset.STATE_CONNECTED:
case BluetoothHeadset.STATE_DISCONNECTED:
JitsiMeetLogger.d(TAG + " BT headset connection state changed: " + state);
updateDevices();
break;
}
} else if (action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)) {
// XXX: This action will be fired when the connection established
// with a Bluetooth headset (called a SCO connection) changes state.
// When the SCO connection is active we route audio to it.
int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -99);
switch (state) {
case AudioManager.SCO_AUDIO_STATE_CONNECTED:
case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:
JitsiMeetLogger.d(TAG + " BT SCO connection state changed: " + state);
updateDevices();
break;
}
}
}
private void registerBluetoothReceiver() {
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
onBluetoothReceiverReceive(context, intent);
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
context.registerReceiver(receiver, filter);
}
/**
* Detects if there are new devices connected / disconnected and fires the
* {@link Listener} registered event.
*/
private void updateDevices() {
boolean headsetAvailable = (headset != null) && !headset.getConnectedDevices().isEmpty();
listener.onBluetoothDeviceChange(headsetAvailable);
}
public void start() {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
if (!audioManager.isBluetoothScoAvailableOffCall()) {
JitsiMeetLogger.w(TAG + " Bluetooth SCO is not available");
return;
}
if (!getBluetoothHeadsetProfileProxy()) {
JitsiMeetLogger.w(TAG + " Couldn't get BT profile proxy");
return;
}
registerBluetoothReceiver();
// Initial detection.
updateDevices();
}
public void stop() {
if (receiver != null) {
context.unregisterReceiver(receiver);
}
if (adapter != null && headset != null) {
adapter.closeProfileProxy(BluetoothProfile.HEADSET, headset);
}
receiver = null;
headset = null;
adapter = null;
}
interface Listener {
void onBluetoothDeviceChange(boolean deviceAvailable);
}
}

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

@@ -20,7 +20,6 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
@@ -68,9 +67,6 @@ public class JitsiMeetActivity extends FragmentActivity
setContentView(R.layout.activity_jitsi_meet);
// Listen for conference events.
getJitsiView().setListener(this);
if (!extraInitialize()) {
initialize();
}
@@ -155,6 +151,9 @@ public class JitsiMeetActivity extends FragmentActivity
}
protected void initialize() {
// Listen for conference events.
getJitsiView().setListener(this);
// Join the room specified by the URL the app was launched with.
// Joining without the room option displays the welcome page.
join(getConferenceOptions(getIntent()));
@@ -165,8 +164,6 @@ public class JitsiMeetActivity extends FragmentActivity
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
JitsiMeetActivityDelegate.onActivityResult(this, requestCode, resultCode, data);
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright @ 2018-present 8x8, Inc.
* Copyright @ 2019-present 8x8, Inc.
* Copyright @ 2018 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,9 +17,12 @@
package org.jitsi.meet.sdk;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import com.calendarevents.CalendarEventsPackage;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactContext;
@@ -163,7 +167,13 @@ public class JitsiMeetActivityDelegate {
}
public static void onRequestPermissionsResult(
final int requestCode, final String[] permissions, final int[] grantResults) {
final int requestCode,
final String[] permissions,
final int[] grantResults) {
CalendarEventsPackage.onRequestPermissionsResult(
requestCode,
permissions,
grantResults);
permissionsCallback = new Callback() {
@Override
public void invoke(Object... args) {
@@ -175,6 +185,7 @@ public class JitsiMeetActivityDelegate {
};
}
@TargetApi(Build.VERSION_CODES.M)
public static void requestPermissions(Activity activity, String[] permissions, int requestCode, PermissionListener listener) {
permissionListener = listener;
activity.requestPermissions(permissions, requestCode);

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

@@ -1,5 +1,6 @@
/*
* Copyright @ 2017-present 8x8, Inc.
* Copyright @ 2018-present 8x8, Inc.
* Copyright @ 2017-2018 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -125,7 +126,7 @@ public class JitsiMeetView extends BaseReactView<JitsiMeetViewListener>
= ReactInstanceManagerHolder.getNativeModule(
PictureInPictureModule.class);
if (pipModule != null
&& pipModule.isPictureInPictureSupported()
&& PictureInPictureModule.isPictureInPictureSupported()
&& !JitsiMeetActivityDelegate.arePermissionsBeingRequested()
&& this.url != null) {
try {
@@ -200,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

@@ -1,5 +1,5 @@
/*
* Copyright @ 2017-present 8x8, Inc.
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@ package org.jitsi.meet.sdk;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.PictureInPictureParams;
import android.os.Build;
import android.util.Rational;
@@ -31,41 +30,20 @@ import com.facebook.react.module.annotations.ReactModule;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
import java.util.HashMap;
import java.util.Map;
import static android.content.Context.ACTIVITY_SERVICE;
@ReactModule(name = PictureInPictureModule.NAME)
class PictureInPictureModule extends ReactContextBaseJavaModule {
class PictureInPictureModule
extends ReactContextBaseJavaModule {
public static final String NAME = "PictureInPicture";
private static final String TAG = NAME;
private static boolean isSupported;
static boolean isPictureInPictureSupported() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
}
public PictureInPictureModule(ReactApplicationContext reactContext) {
super(reactContext);
ActivityManager am = (ActivityManager) reactContext.getSystemService(ACTIVITY_SERVICE);
// Android Go devices don't support PiP. There doesn't seem to be a better way to detect it than
// to use ActivityManager.isLowRamDevice().
// https://stackoverflow.com/questions/58340558/how-to-detect-android-go
isSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !am.isLowRamDevice();
}
/**
* Gets a {@code Map} of constants this module exports to JS. Supports JSON
* types.
*
* @return a {@link Map} of constants this module exports to JS
*/
@Override
public Map<String, Object> getConstants() {
Map<String, Object> constants = new HashMap<>();
constants.put("SUPPORTED", isSupported);
return constants;
}
/**
@@ -83,7 +61,7 @@ class PictureInPictureModule extends ReactContextBaseJavaModule {
*/
@TargetApi(Build.VERSION_CODES.O)
public void enterPictureInPicture() {
if (!isSupported) {
if (!isPictureInPictureSupported()) {
throw new IllegalStateException("Picture-in-Picture not supported");
}
@@ -126,10 +104,6 @@ class PictureInPictureModule extends ReactContextBaseJavaModule {
}
}
public boolean isPictureInPictureSupported() {
return isSupported;
}
@Override
public String getName() {
return NAME;

View File

@@ -1,5 +1,5 @@
/*
* Copyright @ 2017-present 8x8, Inc.
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,10 +33,21 @@ import com.facebook.react.module.annotations.ReactModule;
* is used with the conference audio-only mode.
*/
@ReactModule(name = ProximityModule.NAME)
class ProximityModule extends ReactContextBaseJavaModule {
class ProximityModule
extends ReactContextBaseJavaModule {
public static final String NAME = "Proximity";
/**
* This type of wake lock (the one activated by the proximity sensor) has
* been available for a while, but the constant was only exported in API
* level 21 (Android Marshmallow) so make no assumptions and use its value
* directly.
*
* TODO: Remove when we bump the API level to 21.
*/
private static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32;
/**
* {@link WakeLock} instance.
*/
@@ -60,7 +71,7 @@ class ProximityModule extends ReactContextBaseJavaModule {
try {
wakeLock
= powerManager.newWakeLock(
PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
PROXIMITY_SCREEN_OFF_WAKE_LOCK,
"jitsi:"+NAME);
} catch (Throwable ignored) {
wakeLock = null;

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')

2
app.js
View File

@@ -6,10 +6,10 @@ import 'jQuery-Impromptu';
import conference from './conference';
import API from './modules/API';
import UI from './modules/UI/UI';
import keyboardshortcut from './modules/keyboardshortcut/keyboardshortcut';
import remoteControl from './modules/remotecontrol/RemoteControl';
import translation from './modules/translation/translation';
import UI from './modules/UI/UI';
window.APP = {
API,

View File

@@ -1 +0,0 @@
<base href="/" />

File diff suppressed because it is too large Load Diff

189
config.js
View File

@@ -37,8 +37,6 @@ var config = {
clientNode: 'http://jitsi.org/jitsimeet',
// The real JID of focus participant - can be overridden here
// Do not change username - FIXME: Make focus username configurable
// https://github.com/jitsi/jitsi-meet/issues/7376
// focusUserJid: 'focus@auth.jitsi-meet.example.com',
@@ -46,9 +44,8 @@ var config = {
//
testing: {
// Disables the End to End Encryption feature. Useful for debugging
// issues related to insertable streams.
// disableE2EE: false,
// Enables experimental simulcast support on Firefox.
enableFirefoxSimulcast: false,
// P2P test mode disables automatic switching to P2P when there are 2
// participants in the conference.
@@ -60,13 +57,6 @@ var config = {
// Disables the auto-play behavior of *all* newly created video element.
// This is useful when the client runs on a host with limited resources.
// noAutoPlayVideo: false
// Enable / disable 500 Kbps bitrate cap on desktop tracks. When enabled,
// simulcast is turned off for the desktop share. If presenter is turned
// on while screensharing is in progress, the max bitrate is automatically
// adjusted to 2.5 Mbps. This takes a value between 0 and 1 which determines
// the probability for this to be enabled.
// capScreenshareBitrate: 1 // 0 to disable
},
// Disables ICE/UDP by filtering out local and remote UDP candidates in
@@ -113,27 +103,19 @@ var config = {
// participants and to enable it back a reload is needed.
// startSilent: false
// Sets the preferred target bitrate for the Opus audio codec by setting its
// 'maxaveragebitrate' parameter. Currently not available in p2p mode.
// Valid values are in the range 6000 to 510000
// opusMaxAverageBitrate: 20000,
// Video
// Sets the preferred resolution (height) for local video. Defaults to 720.
// resolution: 720,
// How many participants while in the tile view mode, before the receiving video quality is reduced from HD to SD.
// Use -1 to disable.
// maxFullResolutionParticipants: 2
// 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.
// util#browser#usesNewGumFlow. The constraints are independency from
// 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,
@@ -169,6 +151,22 @@ var config = {
// Desktop sharing
// The ID of the jidesha extension for Chrome.
desktopSharingChromeExtId: null,
// Whether desktop sharing should be disabled on Chrome.
// desktopSharingChromeDisabled: false,
// The media sources to use when using screen sharing with the Chrome
// extension.
desktopSharingChromeSources: [ 'screen', 'window', 'tab' ],
// Required version of Chrome extension
desktopSharingChromeMinExtVersion: '0.1',
// Whether desktop sharing should be disabled on Firefox.
// desktopSharingFirefoxDisabled: false,
// Optional desktop sharing frame rate options. Default value: min:5, max:5.
// desktopSharingFrameRate: {
// min: 5,
@@ -216,52 +214,6 @@ var config = {
// Default value for the channel "last N" attribute. -1 for unlimited.
channelLastN: -1,
// Provides a way to use different "last N" values based on the number of participants in the conference.
// The keys in an Object represent number of participants and the values are "last N" to be used when number of
// participants gets to or above the number.
//
// For the given example mapping, "last N" will be set to 20 as long as there are at least 5, but less than
// 29 participants in the call and it will be lowered to 15 when the 30th participant joins. The 'channelLastN'
// will be used as default until the first threshold is reached.
//
// lastNLimits: {
// 5: 20,
// 30: 15,
// 50: 10,
// 70: 5,
// 90: 2
// },
// Specify the settings for video quality optimizations on the client.
// videoQuality: {
//
// // Provides a way to configure the maximum bitrates that will be enforced on the simulcast streams for
// // video tracks. The keys in the object represent the type of the stream (LD, SD or HD) and the values
// // are the max.bitrates to be set on that particular type of stream. The actual send may vary based on
// // the available bandwidth calculated by the browser, but it will be capped by the values specified here.
// // This is currently not implemented on app based clients on mobile.
// maxBitratesVideo: {
// low: 200000,
// standard: 500000,
// high: 1500000
// }
// },
// // Options for the recording limit notification.
// recordingLimit: {
//
// // The recording limit in minutes. Note: This number appears in the notification text
// // but doesn't enforce the actual recording time limit. This should be configured in
// // jibri!
// limit: 60,
//
// // The name of the app with unlimited recordings.
// appName: 'Unlimited recordings APP',
//
// // The URL of the app with unlimited recordings.
// appURL: 'https://unlimited.recordings.app.com/'
// },
// Disables or enables RTX (RFC 4588) (defaults to false).
// disableRtx: false,
@@ -278,26 +230,15 @@ 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,
// Use the TURN servers discovered via XEP-0215 for the jitsi-videobridge
// connection
// Use XEP-0215 to fetch STUN and TURN servers.
// useStunTurn: true,
// Use TURN/UDP servers for the jitsi-videobridge connection (by default
// we filter out TURN/UDP because it is usually not needed since the
// bridge itself is reachable via UDP)
// useTurnUdp: false
// Enable IPv6 support.
// useIPv6: true,
// Enables / disables a data communication channel with the Videobridge.
// Values can be 'datachannel', 'websocket', true (treat it as
@@ -309,6 +250,9 @@ var config = {
// UI
//
// Use display name as XMPP nickname.
// useNicks: false,
// Require users to always specify a display name.
// requireDisplayName: true,
@@ -349,14 +293,6 @@ var config = {
// and microsoftApiApplicationClientID
// enableCalendarIntegration: false,
// When 'true', it shows an intermediate page before joining, where the user can configure their devices.
// prejoinPageEnabled: false,
// If true, shows the unsafe room name warning label when a room name is
// deemed unsafe (due to the simplicity in the name) and a password is not
// set or the lobby is not enabled.
// enableInsecureRoomNameWarning: false,
// Stats
//
@@ -374,10 +310,10 @@ var config = {
// callStatsID: '',
// callStatsSecret: '',
// Enables sending participants' display names to callstats
// enables sending participants display name to callstats
// enableDisplayNameInStats: false,
// Enables sending participants' emails (if available) to callstats and other analytics
// enables sending participants email if available to callstats and other analytics
// enableEmailInStats: false,
// Privacy
@@ -407,9 +343,11 @@ var config = {
// The STUN servers that will be used in the peer to peer connections
stunServers: [
// { urls: 'stun:jitsi-meet.example.com:3478' },
{ urls: 'stun:meet-jit-si-turnrelay.jitsi.net:443' }
]
// { urls: 'stun:jitsi-meet.example.com:443' },
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'stun:stun1.l.google.com:19302' },
{ urls: 'stun:stun2.l.google.com:19302' }
],
// Sets the ICE transport policy for the p2p connection. At the time
// of this writing the list of possible values are 'all' and 'relay',
@@ -421,7 +359,7 @@ var config = {
// If set to true, it will prefer to use H.264 for P2P calls (if H.264
// is supported).
// preferH264: true
preferH264: true
// If set to true, disable H.264 video codec by stripping it out of the
// SDP.
@@ -436,22 +374,9 @@ 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>'
// Configuration for the rtcstats server:
// In order to enable rtcstats one needs to provide a endpoint url.
// rtcstatsEndpoint: wss://rtcstats-server-pilot.jitsi.net/,
// The interval at which rtcstats will poll getStats, defaults to 1000ms.
// If the value is set to 0 getStats won't be polled and the rtcstats client
// will only send data related to RTCPeerConnection events.
// rtcstatsPolIInterval: 1000
// Array of script URLs to load as lib-jitsi-meet "analytics handlers".
// scriptURLs: [
// "libs/analytics-ga.min.js", // google-analytics
@@ -467,9 +392,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
@@ -529,14 +451,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
@@ -547,37 +461,6 @@ var config = {
// downloadAppsUrl: 'https://docs.example.com/our-apps.html'
// },
// Options related to the remote participant menu.
// remoteVideoMenu: {
// // If set to true the 'Kick out' button will be disabled.
// disableKick: true
// },
// If set to true all muting operations of remote participants will be disabled.
// disableRemoteMute: true,
/**
External API url used to receive branding specific information.
If there is no url set or there are missing fields, the defaults are applied.
None of the fields are mandatory and the response must have the shape:
{
// The hex value for the colour used as background
backgroundColor: '#fff',
// The url for the image used as background
backgroundImageUrl: 'https://example.com/background-img.png',
// The anchor url used when clicking the logo image
logoClickUrl: 'https://example-company.org',
// The url used for the image used as logo
logoImageUrl: 'https://example.com/logo-img.png'
}
*/
// brandingDataUrl: '',
// The URL of the moderated rooms microservice, if available. If it
// is present, a link to the service will be rendered on the welcome page,
// otherwise the app doesn't render it.
// moderatedRoomServiceUrl: 'https://moderated.jitsi-meet.example.com',
// List of undocumented settings used in jitsi-meet
/**
_immediateReloadThreshold

View File

@@ -1,21 +1,19 @@
/* global APP, JitsiMeetJS, config */
import { jitsiLocalStorage } from '@jitsi/js-utils';
import Logger from 'jitsi-meet-logger';
import AuthHandler from './modules/UI/authentication/AuthHandler';
import jitsiLocalStorage from './modules/util/JitsiLocalStorage';
import {
connectionEstablished,
connectionFailed
} from './react/features/base/connection/actions';
} from './react/features/base/connection';
import {
isFatalJitsiConnectionError,
JitsiConnectionErrors,
JitsiConnectionEvents
} from './react/features/base/lib-jitsi-meet';
import { setPrejoinDisplayNameRequired } from './react/features/prejoin/actions';
const logger = Logger.getLogger(__filename);
const logger = require('jitsi-meet-logger').getLogger(__filename);
/**
* The feature announced so we can distinguish jibri participants.
@@ -114,10 +112,6 @@ function connect(id, password, roomName) {
connection.addEventListener(
JitsiConnectionEvents.CONNECTION_FAILED,
connectionFailedHandler);
connection.addEventListener(
JitsiConnectionEvents.DISPLAY_NAME_REQUIRED,
displayNameRequiredHandler
);
/* eslint-disable max-params */
/**
@@ -171,14 +165,6 @@ function connect(id, password, roomName) {
reject(err);
}
/**
* Marks the display name for the prejoin screen as required.
* This can happen if a user tries to join a room with lobby enabled.
*/
function displayNameRequiredHandler() {
APP.store.dispatch(setPrejoinDisplayNameRequired());
}
checkForAttachParametersAndConnect(id, password, connection);
});
}

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

@@ -2,7 +2,7 @@
* Move the @atlaskit/flag container up a little bit so it does not cover the
* toolbar with the first notification.
*/
.jIMojv{
.cjMOOK{
bottom: calc(#{$newToolbarSizeWithPadding}) !important;
}

View File

@@ -1,151 +0,0 @@
.audio-preview {
&-content {
background: #2A3A4B;
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: #1C2025;
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: #3F4E5E;
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;
&:hover {
.audio-preview-entry {
background: #3F4E5E;
margin-left: 0;
padding-left: 48px;
&--selected {
padding-left: 21px;
}
}
}
.audio-preview-entry-text {
max-width: 196px;
}
}
&-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

@@ -33,26 +33,6 @@ body {
}
}
/**
* AtlasKit sets a default margin on the rendered modals, so
* when the shift-right class is set when the chat opens, we
* pad the modal container in order for the modals to be centered
* while also taking the chat size into consideration.
*/
@media (min-width: 480px + $sidebarWidth) {
.shift-right [class^="Modal__FillScreen"] {
padding-left: $sidebarWidth;
}
}
/**
* Similarly, we offset the notifications when the chat is open by
* padding the container.
*/
.shift-right [class^="styledFlagGroup-"] {
padding-left: $sidebarWidth;
}
.jitsi-icon svg {
fill: white;
}
@@ -135,9 +115,8 @@ form {
.leftwatermark {
left: 32px;
top: 32px;
background-image: url($defaultWatermarkLink);
background-position: center left;
background-repeat: no-repeat;
background-size: contain;
}
.rightwatermark {

View File

@@ -4,11 +4,16 @@
color: #FFF;
display: flex;
flex-direction: column;
height: 100%;
/**
* Make the sidebar flush with the top of the toolbar. Take the size of
* the toolbar and subtract from 100%.
*/
height: calc(100% - #{$newToolbarSizeWithPadding});
left: -$sidebarWidth;
overflow: hidden;
position: absolute;
top: 0;
transition: left 0.5s;
width: $sidebarWidth;
z-index: $sideToolbarContainerZ;

View File

@@ -1,75 +0,0 @@
.cpick {
border: 1px solid #A4B8D1;
color: #fff;
display: flex;
font-size: 15px;
height: 38px;
line-height: 24px;
&-selector {
align-items: center;
background-color: #283447;
border-right: 1px solid #A4B8D1;
cursor: pointer;
display: flex;
padding: 8px 10px;
position: relative;
width: 88px;
}
&-icon {
margin-right: 8px;
position: absolute;
right: 0;
top: 12px;
& > svg {
fill: #fff;
}
}
&-input {
padding: 8px;
background: #1C2025;
border: 0;
margin: 0;
color: #fff;
caret-color: #0376DA;
flex-grow: 1;
}
&-dropdown {
height: 190px;
overflow-y: auto;
width: 343px;
}
&-dropdown-entry {
align-items: center;
cursor: pointer;
display: flex;
height: 40px;
padding: 0 10px;
&:hover {
background-color: #66768b;
}
&-text {
color: #fff;
flex-grow: 1;
font-size: 15px;
line-height: 24px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
// Override @Atlaskit/inline-dialog styles
.cpick-container > div > div:nth-child(2) > div > div {
outline: none;
padding: 8px 0 0 0;
}

View File

@@ -1,41 +0,0 @@
#e2ee-section {
.title {
font-weight: 700;
}
.description {
font-size: 13px;
margin: 15px 0;
.read-more {
cursor: pointer;
opacity: .7;
}
}
.key-field {
align-items: center;
display: flex;
flex-direction: row;
label {
font-size: 14px;
font-weight: 700;
}
input {
background-color: inherit;
border: none;
color: inherit;
flex: 1;
padding: 0 5px;
}
a {
color: #6FB1EA;
cursor: pointer;
font-size: 14px;
text-decoration: none;
}
}
}

View File

@@ -1,68 +0,0 @@
.large-video-labels {
display: flex;
position: absolute;
top: 30px;
right: 30px;
transition: right 0.5s;
z-index: $filmstripVideosZ + 1;
.circular-label {
align-items: center;
color: white;
display: flex;
font-weight: bold;
justify-content: center;
margin-left: 8px;
opacity: 0.8;
}
.circular-label {
background: #B8C7E0;
}
.circular-label.e2ee {
align-items: center;
background: #76CF9C;
display: flex;
justify-content: center;
}
.circular-label.file {
background: #FF5630;
}
.circular-label.local-rec {
background: #FF5630;
}
.circular-label.stream {
background: #0065FF;
}
.circular-label.insecure {
background: $defaultWarningColor;
}
.recording-label.center-message {
background: $videoStateIndicatorBackground;
bottom: 50%;
display: block;
left: 50%;
padding: 10px;
position: fixed;
transform: translate(-50%, -50%);
z-index: $centeredVideoLabelZ;
}
}
.circular-label {
background: $videoStateIndicatorBackground;
border-radius: 50%;
box-sizing: border-box;
cursor: default;
font-size: 13px;
height: $videoStateIndicatorSize;
line-height: $videoStateIndicatorSize;
text-align: center;
min-width: $videoStateIndicatorSize;
}

View File

@@ -1,144 +0,0 @@
#lobby-screen {
.content {
.container {
align-items: center;
display: flex;
flex-direction: column;
.spinner {
margin: 30px;
}
.joining-message {
margin: 10px;
}
}
.form {
align-items: stretch;
display: flex;
flex-direction: column;
min-width: 400px;
}
.participant-info {
align-items: center;
display: flex;
flex-direction: column;
}
}
}
#lobby-section {
display: flex;
flex-direction: column;
.description {
font-size: 13px;
}
.control-row {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-top: 15px;
label {
font-size: 14px;
font-weight: bold;
}
}
}
#knocking-participant-list {
background-color: $newToolbarBackgroundColor;
border: 1px solid rgba(255, 255, 255, .4);
border-radius: 8px;
display: flex;
flex-direction: column;
left: 0;
margin: 20px;
position: fixed;
top: 20;
transition: top 1s ease;
z-index: 100;
&.toolbox-visible {
// Same as toolbox subject position
top: 120px;
}
.title {
background-color: rgba(0, 0, 0, .2);
font-size: 1.2em;
padding: 15px
}
ul {
list-style-type: none;
padding: 0 15px 15px 15px;
li {
align-items: center;
display: flex;
flex-direction: row;
margin: 8px 0;
.details {
display: flex;
flex: 1;
flex-direction: column;
justify-content: space-evenly;
margin: 0 30px 0 10px;
}
button {
align-self: unset;
margin: 0 5px;
}
}
}
input {
align-self: stretch;
background-color: transparent;
border: 1px solid #B8C7E0;
border-radius: 4px;
color: white;
padding: 12px 8px;
&:focus {
border-color: rgb(3, 118, 218);
}
}
button {
align-self: stretch;
margin: 8px 0;
padding: 12px;
transition: .2s transform ease;
&:disabled {
opacity: .5;
}
&:hover {
transform: scale(1.05);
&:disabled {
transform: none;
}
}
&.borderLess {
background-color: transparent;
border-width: 0;
}
&.primary {
background-color: rgb(3, 118, 218);
border-width: 0;
}
}
}

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,74 +0,0 @@
@include keyframes(exiting) {
from {
opacity: 1;
transform: translate(0, 0);
}
to {
opacity: 0;
transform: translate(-200px, 0);
}
}
.notificationsContainer {
display: flex;
position: absolute;
bottom: 0px;
flex-direction: column;
width: 400px;
left: 80px;
.topContainer {
padding-bottom: 16px;
// transition: height 0.4s ease-in-out;
.notification {
width: 400px;
z-index: 5;
&:nth-child(n+2) {
margin-top: 16px;
}
&.exiting {
animation-name: exiting;
animation-duration: 0.4s;
}
}
}
.bottomContainer {
margin-bottom: 64px;
position: relative;
height: 100%;
.notification {
width: 400px;
bottom: 0px;
&:nth-child(1) {
z-index: 5;
}
&:nth-child(n+2) {
transition: transform 0.4s ease-in-out;
z-index: 4;
position: absolute;
transform: translateY(100%) translateY(16px);
}
&:nth-child(n+4) {
display: none;
}
&.exiting {
animation-name: exiting;
animation-duration: 0.4s;
}
&.exiting+.notification {
transform: translateY(0);
}
}
}
}

View File

@@ -1,187 +0,0 @@
.prejoin-dialog {
background: #1C2025;
box-shadow: 0px 2px 20px rgba(0, 0, 0, 0.5);
border-radius: 5px;
color: #fff;
height: 400px;
width: 375px;
&--small {
height: 300;
width: 400;
}
&-label {
font-size: 15px;
line-height: 24px;
&-num {
background: #2b3b4b;
border: 1px solid #A4B8D1;
border-radius: 50%;
color: #fff;
display: inline-block;
height: 24px;
margin-right: 8px;
width: 24px;
}
}
&-container {
align-items: center;
background: rgba(0,0,0,0.6);
display: flex;
height: 100vh;
justify-content: center;
left: 0;
position: absolute;
top: 0;
width: 100vw;
z-index: 3;
}
&-flag {
display: inline-block;
margin-right: 8px;
transform: scale(1.2);
}
&-title {
display: inline-block;
font-size: 24px;
line-height: 32px;
}
&-icon {
cursor: pointer;
> svg {
fill: #A4B8D1;
}
}
&-btn {
width: 309px;
}
&-dialin-container {
text-align: center;
}
&-delimiter {
background: #5f6266;
border: 0;
height: 1px;
margin: 0;
padding: 0;
width: 100%;
&-container {
margin: 16px 0 24px 0;
position: relative;
}
&-txt-container {
position: absolute;
text-align: center;
top: -8px;
width: 100%;
}
&-txt {
background: #1C2025;
color: #5f6266;
font-size: 11px;
text-transform: uppercase;
padding: 0 8px;
}
}
.prejoin-dialog-btn.primary,
.action-btn.prejoin-dialog-btn.text {
width: 310px;
}
}
.prejoin-dialog-callout {
padding: 16px;
&-header {
display: flex;
justify-content: space-between;
margin-bottom: 24px;
}
&-picker {
margin: 8px 0 16px 0;
}
}
.prejoin-dialog-dialin {
text-align: center;
&-header {
align-items: center;
margin: 16px 0 32px 16px;
display: flex;
}
&-icon {
margin-right: 16px;
}
&-num {
background: #3e474f;
border-radius: 4px;
display: inline-block;
font-size: 15px;
line-height: 24px;
margin: 4px;
padding: 8px;
&-container {
min-height: 48px;
margin: 8px 0;
}
}
&-link {
color: #6FB1EA;
cursor: pointer;
display: inline-block;
font-size: 13px;
line-height: 20px;
margin-bottom: 24px;
}
&-spaced-label {
margin-bottom: 16px;
margin-top: 28px;
}
&-btns {
&> div {
margin-bottom: 16px;
}
}
}
.prejoin-dialog-calling {
padding: 16px;
text-align: center;
&-header {
text-align: right;
}
&-label {
font-size: 15px;
margin: 8px 0 16px 0;
}
&-number {
font-size: 19px;
line-height: 28px;
margin: 16px 0;
}
}

View File

@@ -1,193 +0,0 @@
.prejoin {
&-input-area {
margin: 0 auto;
text-align: center;
width: 320px;
}
&-title {
color: #fff;
font-size: 24px;
line-height: 32px;
margin-bottom: 16px;
}
&-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 {
margin-bottom: 14px;
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;
}
}
&--text {
margin: 16px 0;
outline: none;
}
}
&-avatar.avatar {
background: #A4B8D1;
margin: 200px auto 0 auto;
}
&-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;
align-self: stretch;
color: #fff;
display: flex;
font-size: 13px;
min-height: 24px;
justify-content: center;
text-align: center;
z-index: 1;
&--warning {
background: rgba(241, 173, 51, 0.7)
}
&--ok {
background: rgba(49, 183, 106, 0.7);
}
}
&-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;
}
}
}

View File

@@ -1,281 +0,0 @@
/**
* Shared style for full screen local track based dialogs/modals.
*/
.premeeting-screen,
.preview-overlay {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.premeeting-screen {
align-items: stretch;
background: radial-gradient(50% 50% at 50% 50%, #5D95C7 0%, #376288 100%), #FFFFFF;
display: flex;
flex-direction: column;
font-size: 1.3em;
z-index: $toolbarZ + 1;
.action-btn {
border-radius: 3px;
color: #fff;
cursor: pointer;
display: inline-block;
font-size: 15px;
line-height: 24px;
margin-top: 16px;
padding: 7px 16px;
position: relative;
text-align: center;
width: 286px;
&.primary {
background: #0376DA;
border: 1px solid #0376DA;
}
&.secondary {
background: transparent;
border: 1px solid #5E6D7A;
}
&.text {
width: auto;
font-size: 13px;
margin: 0;
padding: 0;
}
&.disabled {
background: #5E6D7A;
border: 1px solid #5E6D7A;
color: #AFB6BC;
cursor: initial;
.icon {
& > svg {
fill: #AFB6BC;
}
}
.options {
border-left: 1px solid #AFB6BC;
}
}
.options {
align-items: center;
border-left: 1px solid #fff;
display: flex;
height: 100%;
justify-content: center;
position: absolute;
right: 0;
top: 0;
width: 40px;
}
}
.preview-overlay {
background-image: linear-gradient(transparent, black);
z-index: $toolbarZ + 1;
}
.content {
align-items: center;
display: flex;
flex: 1;
flex-direction: column;
justify-content: flex-end;
z-index: $toolbarZ + 2;
.title {
color: #fff;
font-size: 24px;
line-height: 32px;
margin-bottom: 16px;
}
.copy-meeting {
align-items: center;
cursor: pointer;
color: #fff;
display: flex;
flex-direction: row;
font-size: 15px;
font-weight: 300;
justify-content: center;
line-height: 24px;
margin-bottom: 16px;
.url {
display: flex;
padding: 8px 10px;
&:hover {
background: #1C2025;
border-radius: 4px;
}
&.done {
background: #31B76A;
}
.jitsi-icon {
margin-left: 10px;
}
}
.copy-meeting-text {
width: 266px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&:hover {
align-self: stretch;
}
textarea {
border-width: 0;
height: 0;
opacity: 0;
padding: 0;
width: 0;
}
}
input.field {
background-color: transparent;
border: 1px solid transparent;
color: white;
outline-width: 0;
padding: 8px 0;
text-align: center;
width: 100%;
&.focused {
border-bottom: 1px solid white;
}
&.error::placeholder {
color: $defaultWarningColor;
}
}
}
.media-btn-container {
display: flex;
justify-content: center;
margin: 32px 0;
width: 100%;
&> div {
margin: 0 12px;
}
.settings-button-small-icon {
right: -8px;
&--hovered {
right: -10px;
}
}
}
}
#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;
}
.preview-avatar-container {
width: 100%;
height: 80%;
display: flex;
align-items: center;
justify-content: center;
}
.avatar {
background: #A4B8D1;
}
video {
height: 100%;
object-fit: cover;
position: absolute;
width: 100%;
}
}
@mixin flex-centered() {
align-items: center;
display: flex;
justify-content: center;
}
@mixin icon-container($bg, $fill) {
.toggle-button-icon-container {
background: $bg;
svg {
fill: $fill
}
}
}
.toggle-button {
border-radius: 3px;
cursor: pointer;
color: #fff;
font-size: 13px;
height: 40px;
margin: 0 auto;
width: 320px;
@include flex-centered();
svg {
fill: transparent;
}
&:hover {
background: #1C2025;
@include icon-container(#A4B8D1, #1C2025);
}
&-container {
position: relative;
@include flex-centered();
}
&-icon-container {
border-radius: 50%;
left: -22px;
padding: 2px;
position: absolute;
}
&--toggled {
background: #75757A;
&:hover {
background: #75757A;
@include icon-container(#A4B8D1, #75757A);
}
@include icon-container(#A4B8D1, #75757A);
}
}

View File

@@ -71,11 +71,6 @@
display: flex;
margin-top: 5px;
text-align: right;
flex-direction: column;
.help-container {
display: flex;
}
}
.live-stream-cta {
@@ -115,19 +110,3 @@
font-size: 12px;
}
}
.jibri-queue-info {
display: flex;
flex-flow: column;
.footer {
background: #a4b8a4D1;
border-radius: 3px;
font-weight: bold;
color: #5e6d7a;
padding: 5px;
margin-right: 30px;
margin-top: 5px;
}
}

View File

@@ -1,70 +0,0 @@
@media only screen and (max-width: $smallScreen) {
.watermark {
width: 20%;
height: 20%;
}
.new-toolbox {
.toolbox-content {
.button-group-center, .button-group-left, .button-group-right {
.toolbox-button {
.toolbox-icon {
width: 28px;
height: 28px;
svg {
width: 18px;
height: 18px;
}
}
&:nth-child(2) {
.toolbox-icon {
width: 30px;
height: 30px;
}
}
}
}
}
}
}
@media only screen and (max-width: $verySmallScreen) {
#videoResolutionLabel {
display: none;
}
.desktop-browser {
.vertical-filmstrip .filmstrip {
display: none;
}
}
.new-toolbox {
.toolbox-content {
.button-group-center, .button-group-left, .button-group-right {
.settings-button-small-icon {
display: none;
}
.toolbox-button {
.toolbox-icon {
width: 18px;
height: 18px;
svg {
width: 12px;
height: 12px;
}
}
&:nth-child(2) {
.toolbox-icon {
width: 20px;
height: 20px;
}
}
}
}
}
}
.chrome-extension-banner {
display: none;
}
}

View File

@@ -1,84 +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;
&:hover {
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

@@ -42,11 +42,6 @@
display: none;
}
&.shift-right {
margin-left: $sidebarWidth;
width: calc(100% - #{$sidebarWidth});
}
.toolbox-background {
background-image: linear-gradient(to top, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0));
transition: bottom .3s ease-in;

View File

@@ -101,6 +101,7 @@ $sidebarWidth: 375px;
* Misc.
*/
$borderRadius: 4px;
$defaultWatermarkLink: '../images/watermark.png';
$popoverMenuPadding: 13px;
$happySoftwareBackground: transparent;
$desktopAppDragBarHeight: 25px;
@@ -164,9 +165,6 @@ $unsupportedDesktopBrowserTextFontSize: 21px;
$watermarkWidth: 186px;
$watermarkHeight: 74px;
$welcomePageWatermarkWidth: 186px;
$welcomePageWatermarkHeight: 74px;
/**
* Welcome page variables.
*/
@@ -181,12 +179,9 @@ $welcomePageHeaderBackgroundPosition: none;
$welcomePageHeaderBackgroundRepeat: none;
$welcomePageHeaderBackgroundSize: none;
$welcomePageHeaderPaddingBottom: 0px;
$welcomePageHeaderMinHeight: fit-content;
$welcomePageHeaderTextMarginTop: 35px;
$welcomePageHeaderTextMarginBottom: 35px;
$welcomePageHeaderTextDisplay: flex;
$welcomePageHeaderTextWidth: 650px;
$welcomePageHeaderTextTitleMarginBottom: 16px;
$welcomePageHeaderTextTitleFontSize: 2.5rem;
@@ -201,7 +196,6 @@ $welcomePageHeaderTextDescriptionLineHeight: 24px;
$welcomePageHeaderTextDescriptionMarginBottom: 20px;
$welcomePageHeaderTextDescriptionAlignSelf: inherit;
$welcomePageEnterRoomDisplay: flex;
$welcomePageEnterRoomWidth: 680px;
$welcomePageEnterRoomPadding: 25px 30px;
$welcomePageEnterRoomBorderRadius: 0px;
@@ -277,8 +271,3 @@ $chromeExtensionBannerRight: 16px;
$chromeExtensionBannerTopInMeeting: 10px;
$chromeExtensionBannerRightInMeeeting: 10px;
/**
* media type thresholds
*/
$smallScreen: 700px;
$verySmallScreen: 500px;

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

@@ -181,13 +181,6 @@
visibility: hidden;
z-index: $zindex2;
}
&.shift-right {
&#largeVideoContainer {
margin-left: $sidebarWidth;
width: calc(100% - #{$sidebarWidth});
}
}
}
#localVideoWrapper {

View File

@@ -21,18 +21,18 @@ body.welcome-page {
align-items: center;
display: flex;
flex-direction: column;
min-height: $welcomePageHeaderMinHeight;
min-height: fit-content;
overflow: hidden;
position: relative;
text-align: center;
.header-text {
display: $welcomePageHeaderTextDisplay;
display: flex;
flex-direction: column;
margin-top: $watermarkHeight + $welcomePageHeaderTextMarginTop;
margin-bottom: $welcomePageHeaderTextMarginBottom;
max-width: calc(100% - 40px);
width: $welcomePageHeaderTextWidth;
width: 650px;
z-index: $zindex2;
}
@@ -56,7 +56,7 @@ body.welcome-page {
}
#enter_room {
display: $welcomePageEnterRoomDisplay;
display: flex;
align-items: center;
max-width: calc(100% - 40px);
width: $welcomePageEnterRoomWidth;
@@ -71,6 +71,9 @@ body.welcome-page {
text-align: left;
color: #253858;
height: fit-content;
border-width: $welcomePageEnterRoomInputContainerBorderWidth;
border-style: $welcomePageEnterRoomInputContainerBorderStyle;
border-image: $welcomePageEnterRoomInputContainerBorderImage;
.enter-room-title {
display: $welcomePageEnterRoomTitleDisplay;
@@ -80,30 +83,12 @@ body.welcome-page {
}
.enter-room-input {
border-width: $welcomePageEnterRoomInputContainerBorderWidth;
border-style: $welcomePageEnterRoomInputContainerBorderStyle;
border-image: $welcomePageEnterRoomInputContainerBorderImage;
border: none;
display: inline-block;
width: 100%;
font-size: 14px;
}
.insecure-room-name-warning {
align-items: center;
color: $defaultWarningColor;
display: flex;
flex-direction: row;
margin-top: 5px;
.jitsi-icon {
margin-right: 15px;
svg {
fill: $defaultWarningColor
}
}
}
::placeholder {
color: #253858;
}
@@ -111,22 +96,6 @@ body.welcome-page {
}
#moderated-meetings {
max-width: calc(100% - 40px);
padding: 16px 0 39px 0;
width: $welcomePageEnterRoomWidth;
p {
color: $welcomePageDescriptionColor;
text-align: left;
a {
color: inherit;
font-weight: 600;
}
}
}
.tab-container {
font-size: 16px;
position: relative;
@@ -211,10 +180,5 @@ body.welcome-page {
position: absolute;
width: 100%;
height: 100%;
.watermark.leftwatermark {
width: $welcomePageWatermarkWidth;
height: $welcomePageWatermarkHeight;
}
}
}

View File

@@ -1,38 +0,0 @@
.copy-button {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 8px 8px 16px;
margin-top: 8px;
width: calc(100% - 24px);
height: 24px;
background: #0376DA;
border-radius: 4px;
cursor: pointer;
&:hover {
background: #278ADF;
font-weight: 600;
}
&-content {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 292px;
margin-right: 16px;
&.selected {
font-weight: 600;
}
}
&.clicked {
background: #31B76A;
}
& > div > svg > path {
fill: #fff;
}
}

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 {
@@ -46,16 +45,7 @@
position: fixed;
top: 0;
width: 100%;
z-index: $filmstripVideosZ;
&.shift-right {
margin-left: $sidebarWidth;
width: calc(100% - #{$sidebarWidth});
#filmstripRemoteVideos {
width: calc(100vw - #{$sidebarWidth});
}
}
z-index: $filmstripVideosZ
}
/**
@@ -87,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

@@ -40,6 +40,9 @@
#remotePresenceMessage {
display: none !important;
}
#largeVideoContainer {
background-color: $defaultBackground !important;
}
/**
* Thumbnail popover menus can overlap other thumbnails. Setting an auto

View File

@@ -33,11 +33,9 @@ $flagsImagePath: "../images/";
@import 'inlay';
@import 'reload_overlay/reload_overlay';
@import 'mini_toolbox';
@import 'buttons/copy.scss';
@import 'modals/desktop-picker/desktop-picker';
@import 'modals/device-selection/device-selection';
@import 'modals/dialog';
@import 'modals/embed-meeting/embed-meeting';
@import 'modals/feedback/feedback';
@import 'modals/invite/info';
@import 'modals/settings/settings';
@@ -77,8 +75,6 @@ $flagsImagePath: "../images/";
@import 'filmstrip/tile_view_overrides';
@import 'filmstrip/vertical_filmstrip';
@import 'filmstrip/vertical_filmstrip_overrides';
@import 'labels';
@import 'lobby';
@import 'unsupported-browser/main';
@import 'modals/invite/add-people';
@import 'deep-linking/main';
@@ -90,18 +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';
@import 'prejoin-dialog';
@import 'country-picker';
@import 'modals/invite/invite_more';
@import 'modals/security/security';
@import 'premeeting-screens';
@import 'e2ee';
@import 'responsive';
@import 'notifications';
/* Modules END */

View File

@@ -1,59 +0,0 @@
.embed-meeting {
&-dialog {
display: flex;
flex-direction: column;
&-header {
display: flex;
justify-content: space-between;
margin: 16px 16px 24px;
width: calc(100% - 32px);
color: #fff;
font-weight: 600;
font-size: 24px;
line-height: 32px;
& > div > svg {
cursor: pointer;
fill: #A4B8D1;
}
}
}
&-copy {
color: white;
font-size: 15px;
margin-left: auto;
margin-top: 16px;
width: auto;
}
&-code {
background: transparent;
border: 1px solid #A4B8D1;
color: white;
font-size: 15px;
height: 165px;
line-height: 24px;
padding: 8px;
width: 100%;
resize: vertical;
}
&-trigger {
display: flex;
align-items: center;
padding: 8px 8px 8px 16px;
margin-top: 24px;
width: calc(100% - 24px);
height: 24px;
background: #2A3A4B;
border: 1px solid #5E6D7A;
border-radius: 4px;
cursor: pointer;
.jitsi-icon {
margin-right: 20px;
}
}
}

View File

@@ -3,7 +3,6 @@
*/
.modal-dialog-form {
.add-people-form-wrap {
margin-top: 8px;
.error {
padding-left: 5px;

View File

@@ -3,6 +3,47 @@
display: flex;
font-size: 14px;
.info-dialog-action-link {
display: inline-block;
line-height: 1.5em;
a {
cursor: pointer;
vertical-align: middle;
}
}
.info-dialog-action-link:before {
color: $linkFontColor;
content: '\2022';
font-size: 1.5em;
padding: 0 10px;
vertical-align: middle;
}
.info-dialog-action-link:first-child:before {
content: '';
padding: 0;
}
.info-dialog-action-links {
font-weight: bold;
margin-top: 10px;
white-space: nowrap;
}
.info-dialog-action-separator {
display: inline-block;
}
.info-dialog-copy-element {
opacity: 0;
pointer-events: none;
position: absolute;
-webkit-user-select: text;
user-select: text;
}
.info-dialog-column {
margin-right: 10px;
overflow: hidden;
@@ -15,6 +56,52 @@
}
}
.info-dialog-conference-url,
.info-dialog-live-stream-url {
width: max-content;
width: -moz-max-content;
width: -webkit-max-content;
word-break: break-all;
max-width: 400px;
display: flex;
align-items: center;
}
.info-dialog-dial-in {
word-break: break-all;
.conference-id,
.phone-number {
user-select: text;
}
}
.info-dialog-icon {
color: #6453C0;
font-size: 16px;
min-width: 30px;
}
.info-dialog-url-text,
.info-dialog-url-text:hover {
color: inherit;
cursor: inherit;
}
.info-dialog-url-icon {
display: inline-block;
margin-left: 5px;
svg {
cursor: pointer;
}
}
.info-dialog-title {
font-weight: bold;
margin-bottom: 10px;
}
.info-dialog-password,
.info-password,
.info-password-form {
@@ -38,7 +125,6 @@
}
.info-password-input {
width: 100%;
background-color: transparent;
border: none;
color: inherit;
@@ -137,4 +223,10 @@
-moz-user-select: text;
-webkit-user-select: text;
}
.info-dialog-url-text-unselectable {
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
}
}

View File

@@ -1,216 +0,0 @@
.invite-more {
&-container {
color: #fff;
font-weight: 600;
position: absolute;
width: 100%;
text-align: center;
z-index: $zindex2;
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
&.elevated {
z-index: $filmstripVideosZ + 1;
}
}
&-header {
font-size: 19px;
line-height: 28px;
margin: 24px 0 16px 0;
}
&-button {
display: flex;
margin: auto;
padding: 8px 16px;
width: fit-content;
width: -moz-fit-content;
height: 24px;
background: #0376DA;
border-radius: 3px;
font-size: 14px;
line-height: 24px;
cursor: pointer;
&:hover {
background: #278ADF;
}
&-text {
margin-left: 8px;
font-size: 15px;
line-height: 24px;
}
}
&-dialog {
color: #fff;
font-size: 15px;
line-height: 24px;
&.header {
display: flex;
justify-content: space-between;
margin: 16px 16px 24px;
width: calc(100% - 32px);
color: #fff;
font-weight: 600;
font-size: 24px;
line-height: 32px;
& > div > svg {
cursor: pointer;
fill: #A4B8D1;
}
}
&.separator {
margin: 24px 0 24px -20px;
padding: 0 20px;
width: 100%;
height: 1px;
background: #5E6D7A;
}
&.email-container {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 8px 8px 16px;
margin-top: 24px;
width: calc(100% - 26px);
height: 22px;
background: #2A3A4B;
border: 1px solid #5E6D7A;
border-radius: 3px;
cursor: pointer;
&.active {
border-radius: 3px 3px 0 0;
}
}
&.icon-container {
display: none;
&.active {
display: flex;
width: calc(100% - 26px);
padding: 8px 8px 8px 16px;
background: #2A3A4B;
border: 1px solid #5E6D7A;
border-top: none;
border-radius: 0 0 3px 3px;
& > * {
display: flex;
justify-content: center;
align-items: center;
height: 40px;
width: 40px;
border-radius: 4px;
cursor: pointer;
}
&:hover > div:hover {
background-color: rgba(255, 255, 255, 0.2);
}
& > :not(:last-child) {
margin-right: 16px;
}
.copy-invite-icon > div > svg > path {
fill: #A4B8D1;
}
}
}
&.dial-in-display {
.info-label {
color: #A4B8D1;
}
.dial-in-copy {
display: inline-block;
vertical-align: middle;
margin-left: 21px;
cursor: pointer;
}
}
&.invite-buttons {
width: 100%;
text-align: right;
margin-top: 8px;
& > a {
display: inline-block;
height: 24px;
width: 48px;
border-radius: 3px;
text-align: center;
text-decoration: none;
cursor: pointer;
}
&-cancel {
margin-right: 16px;
padding: 7px 15px;
background: #2A3A4B;
border: 1px solid #5E6D7A;
}
&-add {
padding: 8px 16px;
background: #0376DA;
}
&.disabled {
& > a {
pointer-events: none;
}
}
}
&.stream {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 8px 8px 16px;
margin-top: 8px;
width: calc(100% - 26px);
height: 22px;
background: #2A3A4B;
border: 1px solid #5E6D7A;
border-radius: 3px;
cursor: pointer;
&:hover {
font-weight: 600;
}
&-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 292px;
&.selected {
font-weight: 600;
}
}
&.clicked {
background: #31B76A;
border: 1px solid #31B76A;
}
& > div > svg > path {
fill: #fff;
}
}
}
}

View File

@@ -1,56 +0,0 @@
.security {
&-dialog {
color: #fff;
font-size: 15px;
line-height: 24px;
&.password-section {
display: flex;
flex-direction: column;
.description {
font-size: 13px;
}
.password {
align-items: center;
display: flex;
justify-content: space-between;
margin-top: 15px;
&-actions {
a {
cursor: pointer;
text-decoration: none;
font-size: 14px;
color: #6FB1EA;
}
& > :first-child:not(:last-child) {
margin-right: 24px;
}
}
}
}
.separator-line {
margin: 24px 0 24px -20px;
padding: 0 20px;
width: 100%;
height: 1px;
background: #5E6D7A;
&:last-child {
display: none;
}
}
}
}
.new-toolbox .toolbox-content .toolbox-icon.toggled.security-toolbar-button {
border-width: 0;
&:not(:hover) {
background: unset;
}
}

View File

@@ -30,11 +30,9 @@
width: 100%;
}
.profile-edit-field {
flex: 1;
}
.profile-edit-field,
.settings-sub-pane {
flex-grow: 1;
flex: 1;
}
.profile-edit-field {

View File

@@ -144,3 +144,58 @@
#videoResolutionLabel {
z-index: $zindex3 + 1;
}
.large-video-labels {
display: flex;
position: absolute;
top: 30px;
right: 30px;
transition: right 0.5s;
z-index: $zindex3;
.circular-label {
color: white;
font-weight: bold;
margin-left: 8px;
opacity: 0.8;
}
.circular-label {
background: #B8C7E0;
}
.circular-label.file {
background: #FF5630;
}
.circular-label.local-rec {
background: #FF5630;
}
.circular-label.stream {
background: #0065FF;
}
.recording-label.center-message {
background: $videoStateIndicatorBackground;
bottom: 50%;
display: block;
left: 50%;
padding: 10px;
position: fixed;
transform: translate(-50%, -50%);
z-index: $centeredVideoLabelZ;
}
}
.circular-label {
background: $videoStateIndicatorBackground;
border-radius: 50%;
box-sizing: border-box;
cursor: default;
font-size: 13px;
height: $videoStateIndicatorSize;
line-height: $videoStateIndicatorSize;
text-align: center;
min-width: $videoStateIndicatorSize;
}

14
debian/control vendored
View File

@@ -3,7 +3,7 @@ Section: net
Priority: extra
Maintainer: Jitsi Team <dev@jitsi.org>
Uploaders: Emil Ivov <emcho@jitsi.org>, Damian Minkov <damencho@jitsi.org>
Build-Depends: debhelper (>= 8.0.0), nodejs
Build-Depends: debhelper (>= 8.0.0)
Standards-Version: 3.9.6
Homepage: https://jitsi.org/meet
@@ -16,7 +16,8 @@ Description: WebRTC JavaScript video conferences
Videobridge to provide high quality, scalable video conferences.
.
It is a web interface to Jitsi Videobridge for audio and video
forwarding and relaying.
forwarding and relaying, configured to work with jetty instance
running embedded into Jitsi Videobridge
Package: jitsi-meet-web-config
Architecture: all
@@ -26,7 +27,9 @@ Description: Configuration for web serving of Jitsi Meet
Videobridge to provide high quality, scalable video conferences.
.
It is a web interface to Jitsi Videobridge for audio and video
forwarding and relaying, using a webserver Nginx or Apache2.
forwarding and relaying, configured to work with jetty instance
running embedded into Jitsi Videobridge or using a webserver Nginx or
Apache2.
.
This package contains configuration for Nginx to be used with
Jitsi Meet.
@@ -40,7 +43,8 @@ Description: Prosody configuration for Jitsi Meet
Videobridge to provide high quality, scalable video conferences.
.
It is a web interface to Jitsi Videobridge for audio and video
forwarding and relaying.
forwarding and relaying, configured to work with jetty instance
running embedded into Jitsi Videobridge
.
This package contains configuration for Prosody to be used with
Jitsi Meet.
@@ -52,7 +56,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,9 +134,9 @@ 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
echo -e " admins = { \"focusUser@auth.jitmeet.example.com\", \"jvb@auth.jitmeet.example.com\" }" >> $PROSODY_HOST_CONFIG
fi
if [ ! -f /var/lib/prosody/$JVB_HOSTNAME.crt ]; then
@@ -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

@@ -36,17 +36,13 @@ case "$1" in
rm -f /etc/prosody/conf.avail/$JVB_HOSTNAME.cfg.lua
rm -f /etc/prosody/conf.d/$JVB_HOSTNAME.cfg.lua
JICOFO_AUTH_DOMAIN="auth.$JVB_HOSTNAME"
# clean up generated certificates
rm -f /etc/prosody/certs/$JVB_HOSTNAME.crt
rm -f /etc/prosody/certs/$JVB_HOSTNAME.key
rm -f /etc/prosody/certs/$JICOFO_AUTH_DOMAIN.crt
rm -f /etc/prosody/certs/$JICOFO_AUTH_DOMAIN.key
rm -rf /var/lib/prosody/$JICOFO_AUTH_DOMAIN.*
rm -f /etc/prosody/certs/auth.$JVB_HOSTNAME.crt
rm -f /etc/prosody/certs/auth.$JVB_HOSTNAME.key
rm -rf /var/lib/prosody/auth.$JVB_HOSTNAME.*
rm -rf /var/lib/prosody/$JVB_HOSTNAME.*
# clean created users
rm -rf /var/lib/prosody/`echo $JICOFO_AUTH_DOMAIN | sed -e "s/\./%2e/g"`
fi
# Clear the debconf variable

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,87 +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 5349 as other nginx sites use port 443"
echo ""
echo "------------------------------------------------"
NGINX_MULTIPLEXING="false"
fi
done
# if there was a turn config backup it so we can configure
# we cannot recognize at the moment is this a user config or default config when installing coturn
if [[ -f $TURN_CONFIG ]] && ! grep -q "jitsi-meet coturn config" "$TURN_CONFIG" ; then
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."
echo ""
echo "------------------------------------------------"
if grep -q "jitsi-meet coturn config" "$TURN_CONFIG" && ! grep -q "jitsi-meet coturn relay disable config" "$TURN_CONFIG" ; then
echo "Updating coturn config"
echo "# jitsi-meet coturn relay disable config. Do not modify this line
no-multicast-peers
no-cli
no-loopback-peers
no-tcp-relay
denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.0.0.0-192.0.0.255
denied-peer-ip=192.0.2.0-192.0.2.255
denied-peer-ip=192.88.99.0-192.88.99.255
denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=198.18.0.0-198.19.255.255
denied-peer-ip=198.51.100.0-198.51.100.255
denied-peer-ip=203.0.113.0-203.0.113.255
denied-peer-ip=240.0.0.0-255.255.255.255" >> $TURN_CONFIG
invoke-rc.d coturn restart || true
fi
db_stop
exit 0
fi
@@ -132,61 +65,45 @@ denied-peer-ip=240.0.0.0-255.255.255.255" >> $TURN_CONFIG
fi
TURN_SECRET="$RET"
# no turn config exists, lt's copy template and fill it in
PUBLIC_IP=$(dig -4 +short myip.opendns.com a @resolver1.opendns.com) || true
if [ -z "$PUBLIC_IP" ] ; then
PUBLIC_IP="127.0.0.1"
echo "------------------------------------------------"
echo "Warning! Could not resolve your external ip address! Error:^"
echo "Your turn server will not work till you edit your $TURN_CONFIG config file."
echo "You need to set your external ip address in external-ip and restart coturn service."
echo "------------------------------------------------"
fi
cp /usr/share/jitsi-meet-turnserver/turnserver.conf $TURN_CONFIG
sed -i "s/jitsi-meet.example.com/$JVB_HOSTNAME/g" $TURN_CONFIG
sed -i "s/__turnSecret__/$TURN_SECRET/g" $TURN_CONFIG
sed -i "s/__external_ip_address__/$PUBLIC_IP/g" $TURN_CONFIG
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"/"5349"/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
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

@@ -1,63 +0,0 @@
#!/bin/sh
# postrm script for jitsi-meet-turnserver
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postrm> `remove'
# * <postrm> `purge'
# * <old-postrm> `upgrade' <new-version>
# * <new-postrm> `failed-upgrade' <old-version>
# * <new-postrm> `abort-install'
# * <new-postrm> `abort-install' <old-version>
# * <new-postrm> `abort-upgrade' <old-version>
# * <disappearer's-postrm> `disappear' <overwriter>
# <overwriter-version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
# Load debconf
. /usr/share/debconf/confmodule
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
if [ -x "/etc/init.d/apache2" ]; then
invoke-rc.d apache2 reload || true
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
if [ -x "/etc/init.d/apache2" ]; then
invoke-rc.d apache2 reload || true
fi
# Clear the debconf variable
db_purge
;;
upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
;;
*)
echo "postrm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
db_stop
exit 0

View File

@@ -68,11 +68,12 @@ case "$1" in
FORCE_APACHE="true"
fi
UPLOADED_CERT_CHOICE="I want to use my own certificate"
# if first time config ask for certs, or if we are reconfiguring
if [ -z "$JVB_HOSTNAME_OLD" ] || [ "$RECONFIGURING" = "true" ] ; then
# SSL for nginx
db_get jitsi-meet/cert-choice
CERT_CHOICE="$RET"
UPLOADED_CERT_CHOICE="I want to use my own certificate"
if [ "$CERT_CHOICE" = "$UPLOADED_CERT_CHOICE" ] ; then
db_set jitsi-meet/cert-path-key "/etc/ssl/$JVB_HOSTNAME.key"
@@ -91,14 +92,10 @@ case "$1" in
CERT_CRT="/etc/jitsi/meet/$JVB_HOSTNAME.crt"
HOST="$( (hostname -s; echo localhost) | head -n 1)"
DOMAIN="$( (hostname -d; echo localdomain) | head -n 1)"
openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 -subj \
openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj \
"/O=$DOMAIN/OU=$HOST/CN=$JVB_HOSTNAME/emailAddress=webmaster@$HOST.$DOMAIN" \
-keyout $CERT_KEY \
-out $CERT_CRT \
-reqexts SAN \
-extensions SAN \
-config <(cat /etc/ssl/openssl.cnf \
<(printf "[SAN]\nsubjectAltName=DNS:localhost,DNS:$JVB_HOSTNAME"))
-out $CERT_CRT
fi
fi
@@ -107,57 +104,24 @@ case "$1" in
if [ ! -f $JITSI_MEET_CONFIG ] ; then
cp /usr/share/jitsi-meet-web-config/config.js $JITSI_MEET_CONFIG
# replaces needed config for multidomain as it works only with nginx
if [[ "$FORCE_NGINX" = "true" ]] ; then
sed -i "s/conference.jitsi-meet.example.com/conference.<\!--# echo var=\"subdomain\" default=\"\" -->jitsi-meet.example.com/g" $JITSI_MEET_CONFIG
fi
sed -i "s/conference.jitsi-meet.example.com/conference.<\!--# echo var=\"subdomain\" default=\"\" -->jitsi-meet.example.com/g" $JITSI_MEET_CONFIG
sed -i "s/jitsi-meet.example.com/$JVB_HOSTNAME/g" $JITSI_MEET_CONFIG
fi
# getting rid of jetty serving web
# this is new install let's configure jvb to serve meet
# no-nginx, no-apache installed on machine, this is new install or reconfiguring old one which have jvb_serve set
if [[ "$JVB_SERVE" = "true" ]] ; then
JVB_CONFIG="/etc/jitsi/videobridge/sip-communicator.properties"
# we will write to the file if missing create it
if [ -f $JVB_CONFIG ] ; then
echo ""
echo "------------------------------------------------"
echo ""
echo "You are using jetty to serve jitsi-meet, we are now upgrading you to use nginx!"
echo ""
echo "If you are using Lets Encrypt certificates please re-run the script."
echo ""
echo "------------------------------------------------"
echo ""
sed -i "s/org.jitsi.videobridge.rest.jetty/#org.jitsi.videobridge.rest.jetty/g" $JVB_CONFIG
sed -i "s/org.jitsi.videobridge.TCP_HARVESTER_PORT/#org.jitsi.videobridge.TCP_HARVESTER_PORT/g" $JVB_CONFIG
if [ -d /run/systemd/system ]; then
systemctl restart jitsi-videobridge2.service >/dev/null || true
fi
# Removing this value will force nginx or apache to be locally configured
JVB_HOSTNAME_OLD=""
db_get jitsi-meet/cert-choice
CERT_CHOICE="$RET"
# Fix certs on upgrade from jetty
if [ "$CERT_CHOICE" = "$UPLOADED_CERT_CHOICE" ] ; then
db_get jitsi-meet/cert-path-key
CERT_KEY="$RET"
db_get jitsi-meet/cert-path-crt
CERT_CRT="$RET"
else
# create self-signed certs
CERT_KEY="/etc/jitsi/meet/$JVB_HOSTNAME.key"
CERT_CRT="/etc/jitsi/meet/$JVB_HOSTNAME.crt"
fi
fi
db_set jitsi-meet/jvb-serve "false"
fi
if [[ "$FORCE_NGINX" = "true" && ( -z "$JVB_HOSTNAME_OLD" || "$RECONFIGURING" = "true" ) ]] ; then
echo ""
echo "------------------------------------------------"
echo "You are using jetty to serve jitsi-meet, it is recommended to uninstall(purge) and use default installation that comes with nginx!"
echo ""
echo "When using the following command, any custom config will be LOST, please backup /etc/jitsi !!!"
echo ""
echo "You can purge your installation using the following command:"
echo "apt-get purge jitsi-meet jitsi-meet-web-config jitsi-meet-prosody jitsi-meet-web jicofo jitsi-videobridge"
echo "------------------------------------------------"
echo ""
elif [[ "$FORCE_NGINX" = "true" && ( -z "$JVB_HOSTNAME_OLD" || "$RECONFIGURING" = "true" ) ]] ; then
# this is a reconfigure, lets just delete old links
if [ "$RECONFIGURING" = "true" ] ; then

View File

@@ -11,5 +11,4 @@ fonts /usr/share/jitsi-meet/
images /usr/share/jitsi-meet/
lang /usr/share/jitsi-meet/
connection_optimization /usr/share/jitsi-meet/
resources/robots.txt /usr/share/jitsi-meet/
resources/*.sh /usr/share/jitsi-meet/scripts/

View File

@@ -1,3 +0,0 @@
# Documentation
The Jitsi documentation has been moved to [The Handbook](https://jitsi.github.io/handbook/). The repo is https://github.com/jitsi/handbook.

View File

@@ -1,3 +1,618 @@
# Jitsi Meet API
This document has been moved [here](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-iframe).
You can use the Jitsi Meet API to embed Jitsi Meet in to your application. You are also welcome to use it for embedding the globally distributed and highly available deployment on meet.jit.si itself. The only thing we ask for in that case is that you please DO NOT remove the jitsi.org logo from the top left corner.
## Installation
To embed Jitsi Meet in your application you need to add the Jitsi Meet API library:
```javascript
<script src='https://meet.jit.si/external_api.js'></script>
```
## API
### `api = new JitsiMeetExternalAPI(domain, options)`
The next step for embedding Jitsi Meet is to create the Jitsi Meet API object.
Its constructor gets a number of options:
* **domain**: domain used to build the conference URL, 'meet.jit.si' for
example.
* **options**: object with properties - the optional arguments:
* **roomName**: (optional) name of the room to join.
* **width**: (optional) width for the iframe which will be created. If a number is specified it's treated as pixel units. If a string is specified the format is number followed by 'px', 'em', 'pt' or '%'.
* **height**: (optional) height for the iframe which will be created. If a number is specified it's treated as pixel units. If a string is specified the format is number followed by 'px', 'em', 'pt' or '%'.
* **parentNode**: (optional) HTML DOM Element where the iframe will be added as a child.
* **configOverwrite**: (optional) JS object with overrides for options defined in [config.js].
* **interfaceConfigOverwrite**: (optional) JS object with overrides for options defined in [interface_config.js].
* **noSSL**: (optional, defaults to true) Boolean indicating if the server should be contacted using HTTP or HTTPS.
* **jwt**: (optional) [JWT](https://jwt.io/) token.
* **onload**: (optional) handler for the iframe onload event.
* **invitees**: (optional) Array of objects containing information about new participants that will be invited in the call.
* **devices**: (optional) A map containing information about the initial devices that will be used in the call.
* **userInfo**: (optional) JS object containing information about the participant opening the meeting, such as `email`.
Example:
```javascript
const domain = 'meet.jit.si';
const options = {
roomName: 'JitsiMeetAPIExample',
width: 700,
height: 700,
parentNode: document.querySelector('#meet')
};
const api = new JitsiMeetExternalAPI(domain, options);
```
You can set the initial media devices for the call:
```javascript
const domain = 'meet.jit.si';
const options = {
...
devices: {
audioInput: '<deviceLabel>',
audioOutput: '<deviceLabel>',
videoInput: '<deviceLabel>'
},
...
};
const api = new JitsiMeetExternalAPI(domain, options);
```
You can overwrite options set in [config.js] and [interface_config.js].
For example, to enable the filmstrip-only interface mode, you can use:
```javascript
const options = {
...
interfaceConfigOverwrite: { filmStripOnly: true },
...
};
const api = new JitsiMeetExternalAPI(domain, options);
```
You can also pass a jwt token to Jitsi Meet:
```javascript
const options = {
...
jwt: '<jwt_token>',
noSsl: false,
...
};
const api = new JitsiMeetExternalAPI(domain, options);
```
You can set the userInfo(email) for the call:
```javascript
var domain = "meet.jit.si";
var options = {
...
userInfo: {
email: 'email@jitsiexamplemail.com'
}
}
var api = new JitsiMeetExternalAPI(domain, options);
```
### Controlling the embedded Jitsi Meet Conference
Device management `JitsiMeetExternalAPI` methods:
* **getAvailableDevices** - Retrieve a list of available devices.
```javascript
api.getAvailableDevices().then(devices => {
// devices = {
// audioInput: [{
// deviceId: 'ID'
// groupId: 'grpID'
// kind: 'audioinput'
// label: 'label'
// },....],
// audioOutput: [{
// deviceId: 'ID'
// groupId: 'grpID'
// kind: 'audioOutput'
// label: 'label'
// },....],
// videoInput: [{
// deviceId: 'ID'
// groupId: 'grpID'
// kind: 'videoInput'
// label: 'label'
// },....]
// }
...
});
```
* **getCurrentDevices** - Retrieve a list with the devices that are currently selected.
```javascript
api.getCurrentDevices().then(devices => {
// devices = {
// audioInput: {
// deviceId: 'ID'
// groupId: 'grpID'
// kind: 'videoInput'
// label: 'label'
// },
// audioOutput: {
// deviceId: 'ID'
// groupId: 'grpID'
// kind: 'videoInput'
// label: 'label'
// },
// videoInput: {
// deviceId: 'ID'
// groupId: 'grpID'
// kind: 'videoInput'
// label: 'label'
// }
// }
...
});
```
* **isDeviceChangeAvailable** - Resolves with true if the device change is available and with false if not.
```javascript
// The accepted deviceType values are - 'output', 'input' or undefined.
api.isDeviceChangeAvailable(deviceType).then(isDeviceChangeAvailable => {
...
});
```
* **isDeviceListAvailable** - Resolves with true if the device list is available and with false if not.
```javascript
api.isDeviceListAvailable().then(isDeviceListAvailable => {
...
});
```
* **isMultipleAudioInputSupported** - Resolves with true if multiple audio input is supported and with false if not.
```javascript
api.isMultipleAudioInputSupported().then(isMultipleAudioInputSupported => {
...
});
```
* **setAudioInputDevice** - Sets the audio input device to the one with the label or id that is passed.
```javascript
api.setAudioInputDevice(deviceLabel, deviceId);
```
* **setAudioOutputDevice** - Sets the audio output device to the one with the label or id that is passed.
```javascript
api.setAudioOutputDevice(deviceLabel, deviceId);
```
* **setVideoInputDevice** - Sets the video input device to the one with the label or id that is passed.
```javascript
api.setVideoInputDevice(deviceLabel, deviceId);
```
You can control the embedded Jitsi Meet conference using the `JitsiMeetExternalAPI` object by using `executeCommand`:
```javascript
api.executeCommand(command, ...arguments);
```
The `command` parameter is String object with the name of the command. The following commands are currently supported:
* **displayName** - Sets the display name of the local participant. This command requires one argument - the new display name to be set.
```javascript
api.executeCommand('displayName', 'New Nickname');
```
* **password** - Sets the password for the room. This command requires one argument - the password name to be set.
```javascript
api.executeCommand('password', 'The Password');
```
* **sendTones** - Play touch tones.
```javascript
api.executeCommand('sendTones', {
tones: string, // The dial pad touch tones to play. For example, '12345#'.
duration: number, // Optional. The number of milliseconds each tone should play. The default is 200.
pause: number // Optional. The number of milliseconds between each tone. The default is 200.
});
```
* **subject** - Sets the subject of the conference. This command requires one argument - the new subject to be set.
```javascript
api.executeCommand('subject', 'New Conference Subject');
```
* **toggleAudio** - Mutes / unmutes the audio for the local participant. No arguments are required.
```javascript
api.executeCommand('toggleAudio');
```
* **toggleVideo** - Mutes / unmutes the video for the local participant. No arguments are required.
```javascript
api.executeCommand('toggleVideo');
```
* **toggleFilmStrip** - Hides / shows the filmstrip. No arguments are required.
```javascript
api.executeCommand('toggleFilmStrip');
```
* **toggleChat** - Hides / shows the chat. No arguments are required.
```javascript
api.executeCommand('toggleChat');
```
* **toggleShareScreen** - Starts / stops screen sharing. No arguments are required.
```javascript
api.executeCommand('toggleShareScreen');
```
* **toggleTileView** - Enter / exit tile view layout mode. No arguments are required.
```javascript
api.executeCommand('toggleTileView');
```
* **hangup** - Hangups the call. No arguments are required.
```javascript
api.executeCommand('hangup');
```
* **email** - Changes the local email address. This command requires one argument - the new email address to be set.
```javascript
api.executeCommand('email', 'example@example.com');
```
* **avatarUrl** - Changes the local avatar URL. This command requires one argument - the new avatar URL to be set.
```javascript
api.executeCommand('avatarUrl', 'https://avatars0.githubusercontent.com/u/3671647');
```
* **sendEndpointTextMessage** - Sends a text message to another participant through the datachannels.
```javascript
api.executeCommand('receiverParticipantId', 'text');
```
You can also execute multiple commands using the `executeCommands` method:
```javascript
api.executeCommands(commands);
```
The `commands` parameter is an object with the names of the commands as keys and the arguments for the commands as values:
```javascript
api.executeCommands({
displayName: [ 'nickname' ],
toggleAudio: []
});
```
You can add event listeners to the embedded Jitsi Meet using the `addEventListener` method.
**NOTE: This method still exists but it is deprecated. JitsiMeetExternalAPI class extends [EventEmitter]. Use [EventEmitter] methods (`addListener` or `on`).**
```javascript
api.addEventListener(event, listener);
```
The `event` parameter is a String object with the name of the event.
The `listener` parameter is a Function object with one argument that will be notified when the event occurs with data related to the event.
The following events are currently supported:
* **cameraError** - event notifications about Jitsi-Meet having failed to access the camera. The listener will receive an object with the following structure:
```javascript
{
type: string, // A constant representing the overall type of the error.
message: string // Additional information about the error.
}
```
* **avatarChanged** - event notifications about avatar
changes. The listener will receive an object with the following structure:
```javascript
{
id: string, // the id of the participant that changed his avatar.
avatarURL: string // the new avatar URL.
}
```
* **audioAvailabilityChanged** - event notifications about audio availability status changes. The listener will receive an object with the following structure:
```javascript
{
available: boolean // new available status - boolean
}
```
* **audioMuteStatusChanged** - event notifications about audio mute status changes. The listener will receive an object with the following structure:
```javascript
{
muted: boolean // new muted status - boolean
}
```
* **endpointTextMessageReceived** - event notifications about a text message received through datachannels.
The listener will receive an object with the following structure:
```javascript
{
senderInfo: {
jid: string, // the jid of the sender
id: string // the participant id of the sender
},
eventData: {
name: string // the name of the datachannel event: `endpoint-text-message`
text: string // the received text from the sender
}
}
```
* **micError** - event notifications about Jitsi-Meet having failed to access the mic. The listener will receive an object with the following structure:
```javascript
{
type: string, // A constant representing the overall type of the error.
message: string // Additional information about the error.
}
```
* **screenSharingStatusChanged** - receives event notifications about turning on/off the local user screen sharing. The listener will receive object with the following structure:
```javascript
{
on: boolean, //whether screen sharing is on
details: {
// From where the screen sharing is capturing, if known. Values which are
// passed include 'window', 'screen', 'proxy', 'device'. The value undefined
// will be passed if the source type is unknown or screen share is off.
sourceType: string|undefined
}
}
```
* **dominantSpeakerChanged** - receives event notifications about change in the dominant speaker. The listener will receive object with the following structure:
```javascript
{
id: string //participantId of the new dominant speaker
}
```
* **tileViewChanged** - event notifications about tile view layout mode being entered or exited. The listener will receive object with the following structure:
```javascript
{
enabled: boolean, // whether tile view is not displayed or not
}
```
* **incomingMessage** - Event notifications about incoming
messages. The listener will receive an object with the following structure:
```javascript
{
from: string, // The id of the user that sent the message
nick: string, // the nickname of the user that sent the message
message: string // the text of the message
}
```
* **outgoingMessage** - Event notifications about outgoing
messages. The listener will receive an object with the following structure:
```javascript
{
message: string // the text of the message
}
```
* **displayNameChange** - event notifications about display name
changes. The listener will receive an object with the following structure:
```javascript
{
id: string, // the id of the participant that changed his display name
displayname: string // the new display name
}
```
* **deviceListChanged** - event notifications about device list changes. The listener will receive an object with the following structure:
```javascript
{
devices: Object // the new list of available devices.
}
```
NOTE: The devices object has the same format as the getAvailableDevices result format.
* **emailChange** - event notifications about email
changes. The listener will receive an object with the following structure:
```javascript
{
id: string, // the id of the participant that changed his email
email: string // the new email
}
```
* **feedbackSubmitted** - event notifications about conference feedback submission
```javascript
{
error: string // The error which occurred during submission, if any.
}
```
* **filmstripDisplayChanged** - event notifications about the visibility of the filmstrip being updated.
```javascript
{
visible: boolean // Whether or not the filmstrip is displayed or hidden.
}
```
* **participantJoined** - event notifications about new participants who join the room. The listener will receive an object with the following structure:
```javascript
{
id: string, // the id of the participant
displayName: string // the display name of the participant
}
```
* **participantKickedOut** - event notifications about a participants being removed from the room. The listener will receive an object with the following structure:
```javascript
{
kicked: {
id: string, // the id of the participant removed from the room
local: boolean // whether or not the participant is the local particiapnt
},
kicker: {
id: string // the id of the participant who kicked out the other participant
}
}
```
* **participantLeft** - event notifications about participants that leave the room. The listener will receive an object with the following structure:
```javascript
{
id: string // the id 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:
```javascript
{
roomName: string, // the room name of the conference
id: string, // the id of the local participant
displayName: string, // the display name of the local participant
avatarURL: string // the avatar URL of the local participant
}
```
* **videoConferenceLeft** - event notifications fired when the local user has left the video conference. The listener will receive an object with the following structure:
```javascript
{
roomName: string // the room name of the conference
}
```
* **videoAvailabilityChanged** - event notifications about video availability status changes. The listener will receive an object with the following structure:
```javascript
{
available: boolean // new available status - boolean
}
```
* **videoMuteStatusChanged** - event notifications about video mute status changes. The listener will receive an object with the following structure:
```javascript
{
muted: boolean // new muted status - boolean
}
```
* **readyToClose** - event notification fired when Jitsi Meet is ready to be closed (hangup operations are completed).
* **subjectChange** - event notifications about subject of conference changes.
The listener will receive an object with the following structure:
```javascript
{
subject: string // the new subject
}
```
* **suspendDetected** - event notifications about detecting suspend event in host computer.
You can also add multiple event listeners by using `addEventListeners`.
This method requires one argument of type Object. The object argument must
have the names of the events as keys and the listeners of the events as values.
**NOTE: This method still exists but it is deprecated. JitsiMeetExternalAPI class extends [EventEmitter]. Use [EventEmitter] methods.**
```javascript
function incomingMessageListener(object)
{
// ...
}
function outgoingMessageListener(object)
{
// ...
}
api.addEventListeners({
incomingMessage: incomingMessageListener,
outgoingMessage: outgoingMessageListener
});
```
If you want to remove a listener you can use `removeEventListener` method with argument the name of the event.
**NOTE: This method still exists but it is deprecated. JitsiMeetExternalAPI class extends [EventEmitter]. Use [EventEmitter] methods( `removeListener`).**
```javascript
api.removeEventListener('incomingMessage');
```
If you want to remove more than one event you can use `removeEventListeners` method with an Array with the names of the events as an argument.
**NOTE: This method still exists but it is deprecated. JitsiMeetExternalAPI class extends [EventEmitter]. Use [EventEmitter] methods.**
```javascript
api.removeEventListeners([ 'incomingMessage', 'outgoingMessageListener' ]);
```
You can get the number of participants in the conference with the following API function:
```javascript
const numberOfParticipants = api.getNumberOfParticipants();
```
You can get the avatar URL of a participant in the conference with the following API function:
```javascript
const avatarURL = api.getAvatarURL(participantId);
```
You can get the display name of a participant in the conference with the following API function:
```javascript
const displayName = api.getDisplayName(participantId);
```
You can get the email of a participant in the conference with the following API function:
```javascript
const email = api.getEmail(participantId);
```
You can get the iframe HTML element where Jitsi Meet is loaded with the following API function:
```javascript
const iframe = api.getIFrame();
```
You can check whether the audio is muted with the following API function:
```javascript
api.isAudioMuted().then(muted => {
...
});
```
You can check whether the video is muted with the following API function:
```javascript
api.isVideoMuted().then(muted => {
...
});
```
You can check whether the audio is available with the following API function:
```javascript
api.isAudioAvailable().then(available => {
...
});
```
You can check whether the video is available with the following API function:
```javascript
api.isVideoAvailable().then(available => {
...
});
```
You can invite new participants to the call with the following API function:
```javascript
api.invite([ {...}, {...}, {...} ]).then(() => {
// success
}).catch(() => {
// failure
});
```
**NOTE: The format of the invitees in the array depends on the invite service used for the deployment.**
You can remove the embedded Jitsi Meet Conference with the following API function:
```javascript
api.dispose();
```
NOTE: It's a good practice to remove the conference before the page is unloaded.
[config.js]: https://github.com/jitsi/jitsi-meet/blob/master/config.js
[interface_config.js]: https://github.com/jitsi/jitsi-meet/blob/master/interface_config.js
[EventEmitter]: https://nodejs.org/api/events.html

5
doc/cloud-api.md Normal file
View File

@@ -0,0 +1,5 @@
# Jitsi Meet Cloud API
The Jitsi Meet Cloud API is a specification for services which can support the integration of Jitsi Meet into other applications, for mapping conferences for dial-in support, and for supporting directory search and user invitations to conferences.
The swagger for these services is provided in [cloud-api.swagger](cloud-api.swagger) in this same repository and directory.

93
doc/coding-style.md Normal file
View File

@@ -0,0 +1,93 @@
# Comments
* Comments documenting the source code are required.
* Comments from which documentation is automatically generated are **not**
subject to case-by-case decisions. Such comments are used, for example, on
types and their members. Examples of tools which automatically generate
documentation from such comments include JSDoc, Javadoc, Doxygen.
* Comments which are not automatically processed are strongly encouraged. They
are subject to case-by-case decisions. Such comments are often observed in
function bodies.
* Comments should be formatted as proper English sentences. Such formatting pays
attention to, for example, capitalization and punctuation.
# Duplication
* Don't copy-paste source code. Reuse it.
# Formatting
* Line length is limited to 80 characters.
* Sort by alphabetical order in order to make the addition of new entities as
easy as looking a word up in a dictionary. Otherwise, one risks duplicate
entries (with conflicting values in the cases of key-value pairs). For
example:
* Within an `import` of multiple names from a module, sort the names in
alphabetical order. (Of course, the default name stays first as required by
the `import` syntax.)
````javascript
import {
DOMINANT_SPEAKER_CHANGED,
JITSI_CLIENT_CONNECTED,
JITSI_CLIENT_CREATED,
JITSI_CLIENT_DISCONNECTED,
JITSI_CLIENT_ERROR,
JITSI_CONFERENCE_JOINED,
MODERATOR_CHANGED,
PEER_JOINED,
PEER_LEFT,
RTC_ERROR
} from './actionTypes';
````
* Within a group of imports (e.g. groups of imports delimited by an empty line
may be: third-party modules, then project modules, and eventually the
private files of a module), sort the module names in alphabetical order.
````javascript
import React, { Component } from 'react';
import { connect } from 'react-redux';
````
# Indentation
* Align `switch` and `case`/`default`. Don't indent the `case`/`default` more
than its `switch`.
````javascript
switch (i) {
case 0:
...
break;
default:
...
}
````
# Naming
* An abstraction should have one name within the project and across multiple
projects. For example:
* The instance of lib-jitsi-meet's `JitsiConnection` type should be named
`connection` or `jitsiConnection` in jitsi-meet, not `client`.
* The class `ReducerRegistry` should be defined in ReducerRegistry.js and its
imports in other files should use the same name. Don't define the class
`Registry` in ReducerRegistry.js and then import it as `Reducers` in other
files.
* The names of global constants (including ES6 module-global constants) should
be written in uppercase with underscores to separate words. For example,
`BACKGROUND_COLOR`.
* The underscore character at the beginning of a name signals that the
respective variable, function, property is non-public i.e. private, protected,
or internal. In contrast, the lack of an underscore at the beginning of a name
signals public API.

View File

@@ -6,20 +6,13 @@ muc_mapper_domain_base = "jitmeet.example.com";
turncredentials_secret = "__turnSecret__";
turncredentials = {
{ type = "stun", host = "jitmeet.example.com", port = "3478" },
{ type = "turn", host = "jitmeet.example.com", port = "3478", 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" }
};
cross_domain_bosh = false;
consider_bosh_secure = true;
-- https_ports = { }; -- Remove this line to prevent listening on port 5284
-- https://ssl-config.mozilla.org/#server=haproxy&version=2.1&config=intermediate&openssl=1.1.0g&guideline=5.4
ssl = {
protocol = "tlsv1_2+";
ciphers = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"
}
VirtualHost "jitmeet.example.com"
-- enabled = false -- Remove this line to enable this host
@@ -46,33 +39,25 @@ VirtualHost "jitmeet.example.com"
"speakerstats";
"turncredentials";
"conference_duration";
"muc_lobby_rooms";
}
c2s_require_encryption = false
lobby_muc = "lobby.jitmeet.example.com"
main_muc = "conference.jitmeet.example.com"
-- muc_lobby_whitelist = { "recorder.jitmeet.example.com" } -- Here we can whitelist jibri to enter lobby enabled rooms
Component "conference.jitmeet.example.com" "muc"
storage = "memory"
storage = "null"
modules_enabled = {
"muc_meeting_id";
"muc_domain_mapper";
-- "token_verification";
}
admins = { "focusUser@auth.jitmeet.example.com" }
muc_room_locking = false
muc_room_default_public_jids = true
-- 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"
@@ -85,9 +70,3 @@ Component "speakerstats.jitmeet.example.com" "speakerstats_component"
Component "conferenceduration.jitmeet.example.com" "conference_duration_component"
muc_component = "conference.jitmeet.example.com"
Component "lobby.jitmeet.example.com" "muc"
storage = "memory"
restrict_room_creation = true
muc_room_locking = false
muc_room_default_public_jids = true

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,36 +1,13 @@
# jitsi-meet coturn config. Do not modify this line
lt-cred-mech
use-auth-secret
keep-address-family
static-auth-secret=__turnSecret__
realm=jitsi-meet.example.com
cert=/etc/jitsi/meet/jitsi-meet.example.com.crt
pkey=/etc/jitsi/meet/jitsi-meet.example.com.key
no-multicast-peers
no-cli
no-loopback-peers
no-tcp-relay
no-tcp
listening-port=3478
tls-listening-port=5349
listening-port=443
tls-listening-port=4445
external-ip=__external_ip_address__
no-tlsv1
no-tlsv1_1
# https://ssl-config.mozilla.org/#server=haproxy&version=2.1&config=intermediate&openssl=1.1.0g&guideline=5.4
cipher-list=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
# jitsi-meet coturn relay disable config. Do not modify this line
denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.0.0.0-192.0.0.255
denied-peer-ip=192.0.2.0-192.0.2.255
denied-peer-ip=192.88.99.0-192.88.99.255
denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=198.18.0.0-198.19.255.255
denied-peer-ip=198.51.100.0-198.51.100.255
denied-peer-ip=203.0.113.0-203.0.113.255
denied-peer-ip=240.0.0.0-255.255.255.255
syslog

View File

@@ -7,18 +7,18 @@ stream {
server 127.0.0.1:4444;
}
upstream turn {
server 127.0.0.1:5349;
server 127.0.0.1:4445;
}
# 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;

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