mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-09-17 09:08:57 +00:00
Compare commits
9 Commits
8385
...
release-83
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23cc91391b | ||
|
|
737d24824a | ||
|
|
bff8bbb624 | ||
|
|
d5b76c1abf | ||
|
|
73505d56d7 | ||
|
|
c426f96943 | ||
|
|
2beea0a952 | ||
|
|
52b2444749 | ||
|
|
7ce85a3e83 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -53,8 +53,6 @@ jobs:
|
||||
npm -v
|
||||
- run: npm install
|
||||
- run: make
|
||||
- name: Check config.js syntax
|
||||
run: node config.js
|
||||
android-rn-bundle-build:
|
||||
name: Build mobile bundle (Android)
|
||||
runs-on: macos-15
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -101,9 +101,6 @@ tsconfig.json
|
||||
react-native-sdk/*.tgz
|
||||
react-native-sdk/android/src
|
||||
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/JitsiMeetReactNativePackage.java
|
||||
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/JitsiMeetOngoingConferenceService.java
|
||||
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/JMOngoingConferenceModule.java
|
||||
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/RNOngoingNotification.java
|
||||
react-native-sdk/images
|
||||
react-native-sdk/ios
|
||||
react-native-sdk/lang
|
||||
|
||||
8
Makefile
8
Makefile
@@ -17,11 +17,11 @@ STYLES_BUNDLE = css/all.bundle.css
|
||||
STYLES_DESTINATION = css/all.css
|
||||
STYLES_MAIN = css/main.scss
|
||||
ifeq ($(OS),Windows_NT)
|
||||
WEBPACK = .\node_modules\.bin\webpack --progress
|
||||
WEBPACK_DEV_SERVER = .\node_modules\.bin\webpack serve --mode development --progress
|
||||
WEBPACK = .\node_modules\.bin\webpack
|
||||
WEBPACK_DEV_SERVER = .\node_modules\.bin\webpack serve --mode development
|
||||
else
|
||||
WEBPACK = ./node_modules/.bin/webpack --progress
|
||||
WEBPACK_DEV_SERVER = ./node_modules/.bin/webpack serve --mode development --progress
|
||||
WEBPACK = ./node_modules/.bin/webpack
|
||||
WEBPACK_DEV_SERVER = ./node_modules/.bin/webpack serve --mode development
|
||||
endif
|
||||
|
||||
all: compile deploy
|
||||
|
||||
@@ -34,7 +34,7 @@ mobile apps:
|
||||
|
||||
| Android | Android (F-Droid) | iOS |
|
||||
|:-:|:-:|:-:|
|
||||
| [<img src="resources/img/google-play-badge.png" height="50">](https://play.google.com/store/apps/details?id=org.jitsi.meet) | [<img src="resources/img/f-droid-badge.png" height="50">](https://f-droid.org/packages/org.jitsi.meet/) | [<img src="resources/img/appstore-badge.png" height="50">](https://itunes.apple.com/us/app/jitsi-meet/id1165103905) |
|
||||
| [<img src="resources/img/google-play-badge.png" height="50">](https://play.google.com/store/apps/details?id=org.jitsi.meet) | [<img src="resources/img/f-droid-badge.png" height="50">](https://f-droid.org/en/packages/org.jitsi.meet/) | [<img src="resources/img/appstore-badge.png" height="50">](https://itunes.apple.com/us/app/jitsi-meet/id1165103905) |
|
||||
|
||||
If you are feeling adventurous and want to get an early scoop of the features as they are being
|
||||
developed you can also sign up for our open beta testing here:
|
||||
|
||||
@@ -20,7 +20,7 @@ ext {
|
||||
kotlinVersion = "1.9.24"
|
||||
buildToolsVersion = "34.0.0"
|
||||
compileSdkVersion = 34
|
||||
minSdkVersion = 26
|
||||
minSdkVersion = 24
|
||||
targetSdkVersion = 34
|
||||
supportLibVersion = "28.0.0"
|
||||
ndkVersion = "26.1.10909125"
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jitsi.meet.sdk;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
import android.telecom.CallAudioState;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
@@ -33,6 +34,7 @@ import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
* {@link AudioModeModule.AudioDeviceHandlerInterface} module implementing device handling for
|
||||
* Android versions >= O when ConnectionService is enabled.
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
class AudioDeviceHandlerConnectionService implements
|
||||
AudioModeModule.AudioDeviceHandlerInterface,
|
||||
RNConnectionService.CallAudioStateListener {
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.media.AudioAttributes;
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.media.AudioFocusRequest;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -226,17 +227,22 @@ class AudioDeviceHandlerGeneric implements
|
||||
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
||||
audioManager.setMicrophoneMute(false);
|
||||
|
||||
int gotFocus = audioManager.requestAudioFocus(new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
|
||||
.setAudioAttributes(
|
||||
new AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
|
||||
.build()
|
||||
)
|
||||
.setAcceptsDelayedFocusGain(true)
|
||||
.setOnAudioFocusChangeListener(this)
|
||||
.build()
|
||||
);
|
||||
int gotFocus;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
gotFocus = audioManager.requestAudioFocus(new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
|
||||
.setAudioAttributes(
|
||||
new AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
|
||||
.build()
|
||||
)
|
||||
.setAcceptsDelayedFocusGain(true)
|
||||
.setOnAudioFocusChangeListener(this)
|
||||
.build()
|
||||
);
|
||||
} else {
|
||||
gotFocus = audioManager.requestAudioFocus(this, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN);
|
||||
}
|
||||
|
||||
if (gotFocus == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
|
||||
JitsiMeetLogger.w(TAG + " Audio focus request failed");
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
@@ -57,6 +58,7 @@ import java.util.concurrent.Executors;
|
||||
* Before a call has started and after it has ended the
|
||||
* {@code AudioModeModule.DEFAULT} mode should be used.
|
||||
*/
|
||||
@SuppressLint("AnnotateVersionCheck")
|
||||
@ReactModule(name = AudioModeModule.NAME)
|
||||
class AudioModeModule extends ReactContextBaseJavaModule {
|
||||
public static final String NAME = "AudioMode";
|
||||
@@ -82,10 +84,11 @@ class AudioModeModule extends ReactContextBaseJavaModule {
|
||||
/**
|
||||
* Whether or not the ConnectionService is used for selecting audio devices.
|
||||
*/
|
||||
private static boolean useConnectionService_ = true;
|
||||
private static final boolean supportsConnectionService = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
|
||||
private static boolean useConnectionService_ = supportsConnectionService;
|
||||
|
||||
static boolean useConnectionService() {
|
||||
return useConnectionService_;
|
||||
return supportsConnectionService && useConnectionService_;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,11 +139,6 @@ class AudioModeModule extends ReactContextBaseJavaModule {
|
||||
*/
|
||||
private String userSelectedDevice;
|
||||
|
||||
/**
|
||||
* Whether or not audio is disabled.
|
||||
*/
|
||||
private boolean audioDisabled;
|
||||
|
||||
/**
|
||||
* Initializes a new module instance. There shall be a single instance of
|
||||
* this module throughout the lifetime of the application.
|
||||
@@ -241,12 +239,6 @@ class AudioModeModule extends ReactContextBaseJavaModule {
|
||||
audioDeviceHandler.stop();
|
||||
}
|
||||
|
||||
audioDeviceHandler = null;
|
||||
|
||||
if (audioDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (useConnectionService()) {
|
||||
audioDeviceHandler = new AudioDeviceHandlerConnectionService(audioManager);
|
||||
} else {
|
||||
@@ -289,27 +281,6 @@ class AudioModeModule extends ReactContextBaseJavaModule {
|
||||
});
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setDisabled(final boolean disabled, final Promise promise) {
|
||||
if (audioDisabled == disabled) {
|
||||
promise.resolve(null);
|
||||
return;
|
||||
}
|
||||
|
||||
JitsiMeetLogger.i(TAG + " audio disabled: " + disabled);
|
||||
|
||||
audioDisabled = disabled;
|
||||
setAudioDeviceHandler();
|
||||
|
||||
if (disabled) {
|
||||
mode = -1;
|
||||
availableDevices.clear();
|
||||
resetSelectedDevice();
|
||||
}
|
||||
|
||||
promise.resolve(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public method to set the current audio mode.
|
||||
*
|
||||
@@ -319,12 +290,7 @@ class AudioModeModule extends ReactContextBaseJavaModule {
|
||||
*/
|
||||
@ReactMethod
|
||||
public void setMode(final int mode, final Promise promise) {
|
||||
if (audioDisabled) {
|
||||
promise.resolve(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode < DEFAULT || mode > VIDEO_CALL) {
|
||||
if (mode != DEFAULT && mode != AUDIO_CALL && mode != VIDEO_CALL) {
|
||||
promise.reject("setMode", "Invalid audio mode " + mode);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import java.util.Objects;
|
||||
*
|
||||
* @author Pawel Domas
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public class ConnectionService extends android.telecom.ConnectionService {
|
||||
|
||||
/**
|
||||
|
||||
@@ -271,8 +271,8 @@ public class JitsiMeetActivity extends AppCompatActivity
|
||||
// JitsiMeetLogger.i("Transcription chunk received: " + extraData);
|
||||
// }
|
||||
|
||||
// protected void onCustomButtonPressed(HashMap<String, Object> extraData) {
|
||||
// JitsiMeetLogger.i("Custom button pressed: " + extraData);
|
||||
// protected void onCustomOverflowMenuButtonPressed(HashMap<String, Object> extraData) {
|
||||
// JitsiMeetLogger.i("Custom overflow menu button pressed: " + extraData);
|
||||
// }
|
||||
|
||||
// Activity lifecycle methods
|
||||
@@ -361,8 +361,8 @@ public class JitsiMeetActivity extends AppCompatActivity
|
||||
// case TRANSCRIPTION_CHUNK_RECEIVED:
|
||||
// onTranscriptionChunkReceived(event.getData());
|
||||
// break;
|
||||
// case CUSTOM_BUTTON_PRESSED:
|
||||
// onCustomButtonPressed(event.getData());
|
||||
// case CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED:
|
||||
// onCustomOverflowMenuButtonPressed(event.getData());
|
||||
// break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class JitsiMeetActivityDelegate {
|
||||
/**
|
||||
* Tells whether or not the permissions request is currently in progress.
|
||||
*
|
||||
* @return {@code true} if the permissions are being requested or {@code false} otherwise.
|
||||
* @return {@code true} if the permssions are being requested or {@code false} otherwise.
|
||||
*/
|
||||
static boolean arePermissionsBeingRequested() {
|
||||
return permissionListener != null;
|
||||
|
||||
@@ -83,7 +83,11 @@ public class JitsiMeetOngoingConferenceService extends Service implements Ongoin
|
||||
ComponentName componentName;
|
||||
|
||||
try {
|
||||
componentName = context.startForegroundService(intent);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
componentName = context.startForegroundService(intent);
|
||||
} else {
|
||||
componentName = context.startService(intent);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
// Avoid crashing due to ForegroundServiceStartNotAllowedException (API level 31).
|
||||
// See: https://developer.android.com/guide/components/foreground-services#background-start-restrictions
|
||||
|
||||
@@ -29,6 +29,8 @@ import android.content.Intent;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class for creating the ongoing notification which is used with
|
||||
@@ -43,6 +45,10 @@ class OngoingNotification {
|
||||
static final String ONGOING_CONFERENCE_CHANNEL_ID = "JitsiOngoingConferenceChannel";
|
||||
|
||||
static void createNotificationChannel(Activity context) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context == null) {
|
||||
JitsiMeetLogger.w(TAG + " Cannot create notification channel: no current context");
|
||||
return;
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.PictureInPictureParams;
|
||||
import android.os.Build;
|
||||
import android.util.Rational;
|
||||
|
||||
import com.facebook.react.bridge.Promise;
|
||||
@@ -52,7 +53,7 @@ class PictureInPictureModule extends ReactContextBaseJavaModule {
|
||||
// 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 = !am.isLowRamDevice();
|
||||
isSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !am.isLowRamDevice();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,6 +82,7 @@ class PictureInPictureModule extends ReactContextBaseJavaModule {
|
||||
* including when the activity is not visible (paused or stopped), if the
|
||||
* screen is locked or if the user has an activity pinned.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
public void enterPictureInPicture() {
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.jitsi.meet.sdk;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.telecom.DisconnectCause;
|
||||
import android.telecom.PhoneAccount;
|
||||
@@ -31,6 +32,7 @@ import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
*
|
||||
* @author Pawel Domas
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
@ReactModule(name = RNConnectionService.NAME)
|
||||
class RNConnectionService extends ReactContextBaseJavaModule {
|
||||
|
||||
@@ -51,6 +53,7 @@ class RNConnectionService extends ReactContextBaseJavaModule {
|
||||
* @param audioRoute the new audio route to be set. See
|
||||
* {@link android.telecom.CallAudioState} constants prefixed with "ROUTE_".
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
static void setAudioRoute(int audioRoute) {
|
||||
for (ConnectionService.ConnectionImpl c
|
||||
: ConnectionService.getConnections()) {
|
||||
|
||||
6
app.js
6
app.js
@@ -1,8 +1,4 @@
|
||||
/* Jitsi Meet app main entrypoint. */
|
||||
|
||||
// Polyfill Promise.withReolvers.
|
||||
// FIXME(saghul) webpack + core-js v3 should polyfill this.
|
||||
import 'promise.withresolvers/auto';
|
||||
/* application specific logic */
|
||||
|
||||
// Re-export jQuery
|
||||
// FIXME: Remove this requirement from torture tests.
|
||||
|
||||
@@ -155,6 +155,7 @@ import {
|
||||
NOTIFICATION_TIMEOUT_TYPE
|
||||
} from './react/features/notifications/constants';
|
||||
import { isModerationNotificationDisplayed } from './react/features/notifications/functions';
|
||||
import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay/actions';
|
||||
import { suspendDetected } from './react/features/power-monitor/actions';
|
||||
import { initPrejoin, isPrejoinPageVisible } from './react/features/prejoin/functions';
|
||||
import { disableReceiver, stopReceiver } from './react/features/remote-control/actions';
|
||||
@@ -434,6 +435,15 @@ export default {
|
||||
requestedVideo = true;
|
||||
}
|
||||
|
||||
if (!config.disableInitialGUM) {
|
||||
JitsiMeetJS.mediaDevices.addEventListener(
|
||||
JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN,
|
||||
browserName =>
|
||||
APP.store.dispatch(
|
||||
mediaPermissionPromptVisibilityChanged(true, browserName))
|
||||
);
|
||||
}
|
||||
|
||||
let tryCreateLocalTracks = Promise.resolve([]);
|
||||
|
||||
// On Electron there is no permission prompt for granting permissions. That's why we don't need to
|
||||
@@ -442,7 +452,8 @@ export default {
|
||||
const timeout = browser.isElectron() ? 15000 : 60000;
|
||||
const audioOptions = {
|
||||
devices: [ MEDIA_TYPE.AUDIO ],
|
||||
timeout
|
||||
timeout,
|
||||
firePermissionPromptIsShownEvent: true
|
||||
};
|
||||
|
||||
// Spot uses the _desktopSharingSourceDevice config option to use an external video input device label as
|
||||
@@ -477,7 +488,8 @@ export default {
|
||||
} else if (requestedAudio || requestedVideo) {
|
||||
tryCreateLocalTracks = APP.store.dispatch(createInitialAVTracks({
|
||||
devices: initialDevices,
|
||||
timeout
|
||||
timeout,
|
||||
firePermissionPromptIsShownEvent: true
|
||||
}, recordTimeMetrics)).then(({ tracks, errors: pErrors }) => {
|
||||
Object.assign(errors, pErrors);
|
||||
|
||||
@@ -485,6 +497,15 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
// Hide the permissions prompt/overlay as soon as the tracks are created. Don't wait for the connection to
|
||||
// be established, as in some cases like when auth is required, connection won't be established until the user
|
||||
// inputs their credentials, but the dialog would be overshadowed by the overlay.
|
||||
tryCreateLocalTracks.then(tracks => {
|
||||
APP.store.dispatch(mediaPermissionPromptVisibilityChanged(false));
|
||||
|
||||
return tracks;
|
||||
});
|
||||
|
||||
return {
|
||||
tryCreateLocalTracks,
|
||||
errors
|
||||
@@ -1012,7 +1033,7 @@ export default {
|
||||
},
|
||||
|
||||
/**
|
||||
* Will be filled with values only when config.testing.testMode is true.
|
||||
* Will be filled with values only when config.debug is enabled.
|
||||
* Its used by torture to check audio levels.
|
||||
*/
|
||||
audioLevelsMap: {},
|
||||
@@ -1399,19 +1420,28 @@ export default {
|
||||
/**
|
||||
* Creates desktop (screensharing) {@link JitsiLocalTrack}
|
||||
*
|
||||
* @param {Object} [options] - Screen sharing options that will be passed to
|
||||
* createLocalTracks.
|
||||
* @param {Object} [options.desktopSharing]
|
||||
* @param {Object} [options.desktopStream] - An existing desktop stream to
|
||||
* use instead of creating a new desktop stream.
|
||||
* @return {Promise.<JitsiLocalTrack>} - A Promise resolved with
|
||||
* {@link JitsiLocalTrack} for the screensharing or rejected with
|
||||
* {@link JitsiTrackError}.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_createDesktopTrack() {
|
||||
_createDesktopTrack(options = {}) {
|
||||
const didHaveVideo = !this.isLocalVideoMuted();
|
||||
|
||||
const getDesktopStreamPromise = createLocalTracksF({
|
||||
desktopSharingSourceDevice: config._desktopSharingSourceDevice,
|
||||
devices: [ 'desktop' ]
|
||||
});
|
||||
const getDesktopStreamPromise = options.desktopStream
|
||||
? Promise.resolve([ options.desktopStream ])
|
||||
: createLocalTracksF({
|
||||
desktopSharingSourceDevice: options.desktopSharingSources
|
||||
? null : config._desktopSharingSourceDevice,
|
||||
desktopSharingSources: options.desktopSharingSources,
|
||||
devices: [ 'desktop' ]
|
||||
});
|
||||
|
||||
return getDesktopStreamPromise.then(desktopStreams => {
|
||||
// Stores the "untoggle" handler which remembers whether was
|
||||
@@ -1588,9 +1618,9 @@ export default {
|
||||
newLvl = 0;
|
||||
}
|
||||
|
||||
if (config.testing?.testMode) {
|
||||
if (config.debug) {
|
||||
this.audioLevelsMap[id] = newLvl;
|
||||
if (config.testing?.debugAudioLevels) {
|
||||
if (config.debugAudioLevels) {
|
||||
logger.log(`AudioLevel:${id}/${newLvl}`);
|
||||
}
|
||||
}
|
||||
|
||||
124
config.js
124
config.js
@@ -84,9 +84,6 @@ var config = {
|
||||
// Allows the setting of a custom bandwidth value from the UI.
|
||||
// assumeBandwidth: true,
|
||||
|
||||
// Enables use of getDisplayMedia in electron
|
||||
// electronUseGetDisplayMedia: false,
|
||||
|
||||
// Enables the use of the codec selection API supported by the browsers .
|
||||
// enableCodecSelectionAPI: false,
|
||||
|
||||
@@ -106,12 +103,6 @@ var config = {
|
||||
|
||||
// Dump transcripts to a <transcript> element for debugging.
|
||||
// dumpTranscript: false,
|
||||
|
||||
// Log the audio levels.
|
||||
// debugAudioLevels: true,
|
||||
|
||||
// Will replace ice candidates IPs with invalid ones in order to fail ice.
|
||||
// failICE: true,
|
||||
},
|
||||
|
||||
// Disables moderator indicators.
|
||||
@@ -371,6 +362,9 @@ var config = {
|
||||
|
||||
// Recording
|
||||
|
||||
// DEPRECATED. Use recordingService.enabled instead.
|
||||
// fileRecordingsEnabled: false,
|
||||
|
||||
// Enable the dropbox integration.
|
||||
// dropbox: {
|
||||
// appKey: '<APP_KEY>', // Specify your app key here.
|
||||
@@ -465,7 +459,7 @@ var config = {
|
||||
|
||||
// // Translation languages.
|
||||
// // Available languages can be found in
|
||||
// // ./lang/translation-languages.json.
|
||||
// // ./src/react/features/transcribing/translation-languages.json.
|
||||
// translationLanguages: ['en', 'es', 'fr', 'ro'],
|
||||
|
||||
// // Important languages to show on the top of the language list.
|
||||
@@ -576,6 +570,30 @@ var config = {
|
||||
// useKSVC: true
|
||||
// },
|
||||
//
|
||||
// DEPRECATED! Use `codec specific settings` instead.
|
||||
// // 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: {
|
||||
// H264: {
|
||||
// low: 200000,
|
||||
// standard: 500000,
|
||||
// high: 1500000,
|
||||
// },
|
||||
// VP8 : {
|
||||
// low: 200000,
|
||||
// standard: 500000,
|
||||
// high: 1500000,
|
||||
// },
|
||||
// VP9: {
|
||||
// low: 100000,
|
||||
// standard: 300000,
|
||||
// high: 1200000,
|
||||
// },
|
||||
// },
|
||||
//
|
||||
// // The options can be used to override default thresholds of video thumbnail heights corresponding to
|
||||
// // the video quality levels used in the application. At the time of this writing the allowed levels are:
|
||||
// // 'low' - for the low quality level (180p at the time of this writing)
|
||||
@@ -593,6 +611,22 @@ var config = {
|
||||
//
|
||||
// // Provides a way to set the codec preference on mobile devices, both on RN and mobile browser based endpoint
|
||||
// mobileCodecPreferenceOrder: [ 'VP8', 'VP9', 'H264' ],
|
||||
//
|
||||
// // DEPRECATED! Use `codecPreferenceOrder/mobileCodecPreferenceOrder` instead.
|
||||
// // Provides a way to prevent a video codec from being negotiated on the JVB connection. The codec specified
|
||||
// // here will be removed from the list of codecs present in the SDP answer generated by the client. If the
|
||||
// // same codec is specified for both the disabled and preferred option, the disable settings will prevail.
|
||||
// // Note that 'VP8' cannot be disabled since it's a mandatory codec, the setting will be ignored in this case.
|
||||
// disabledCodec: 'H264',
|
||||
//
|
||||
// // DEPRECATED! Use `codecPreferenceOrder/mobileCodecPreferenceOrder` instead.
|
||||
// // Provides a way to set a preferred video codec for the JVB connection. If 'H264' is specified here,
|
||||
// // simulcast will be automatically disabled since JVB doesn't support H264 simulcast yet. This will only
|
||||
// // rearrange the the preference order of the codecs in the SDP answer generated by the browser only if the
|
||||
// // preferred codec specified here is present. Please ensure that the JVB offers the specified codec for this
|
||||
// // to take effect.
|
||||
// preferredCodec: 'VP8',
|
||||
//
|
||||
// },
|
||||
|
||||
// Notification timeouts
|
||||
@@ -751,9 +785,6 @@ var config = {
|
||||
// and microsoftApiApplicationClientID
|
||||
// enableCalendarIntegration: false,
|
||||
|
||||
// The client id for the google APIs used for the calendar integration, youtube livestreaming, etc.
|
||||
// googleApiApplicationClientID: '<client_id>',
|
||||
|
||||
// Configs for prejoin page.
|
||||
// prejoinConfig: {
|
||||
// // When 'true', it shows an intermediate page before joining, where the user can configure their devices.
|
||||
@@ -788,6 +819,10 @@ var config = {
|
||||
// set or the lobby is not enabled.
|
||||
// enableInsecureRoomNameWarning: false,
|
||||
|
||||
// Whether to automatically copy invitation URL after creating a room.
|
||||
// Document should be focused for this option to work
|
||||
// enableAutomaticUrlCopy: false,
|
||||
|
||||
// Array with avatar URL prefixes that need to use CORS.
|
||||
// corsAvatarURLs: [ 'https://www.gravatar.com/avatar/' ],
|
||||
|
||||
@@ -872,7 +907,7 @@ var config = {
|
||||
// Overrides the buttons displayed in the main toolbar. Depending on the screen size the number of displayed
|
||||
// buttons varies from 2 buttons to 8 buttons. Every array in the mainToolbarButtons array will replace the
|
||||
// corresponding default buttons configuration matched by the number of buttons specified in the array. Arrays with
|
||||
// more than 8 buttons or less then 2 buttons will be ignored. When there there isn't an override for a certain
|
||||
// more than 8 buttons or less then 2 buttons will be ignored. When there there isn't an override for a cerain
|
||||
// configuration (for example when 3 buttons are displayed) the default jitsi-meet configuration will be used.
|
||||
// The order of the buttons in the array is preserved.
|
||||
// mainToolbarButtons: [
|
||||
@@ -1085,6 +1120,15 @@ var config = {
|
||||
// { urls: 'stun:jitsi-meet.example.com:3478' },
|
||||
{ urls: 'stun:meet-jit-si-turnrelay.jitsi.net:443' },
|
||||
],
|
||||
|
||||
// DEPRECATED! Use `codecPreferenceOrder/mobileCodecPreferenceOrder` instead.
|
||||
// Provides a way to set the video codec preference on the p2p connection. Acceptable
|
||||
// codec values are 'VP8', 'VP9' and 'H264'.
|
||||
// preferredCodec: 'H264',
|
||||
|
||||
// DEPRECATED! Use `codecPreferenceOrder/mobileCodecPreferenceOrder` instead.
|
||||
// Provides a way to prevent a video codec from being negotiated on the p2p connection.
|
||||
// disabledCodec: '',
|
||||
},
|
||||
|
||||
analytics: {
|
||||
@@ -1585,38 +1629,20 @@ var config = {
|
||||
// video: true
|
||||
// },
|
||||
// },
|
||||
// The default type of desktop sharing sources that will be used in the electron app.
|
||||
// desktopSharingSources: ['screen', 'window'],
|
||||
|
||||
// Disables the echo cancelation for local audio tracks.
|
||||
// disableAEC: true,
|
||||
|
||||
// Disables the auto gain control for local audio tracks.
|
||||
// disableAGC: true,
|
||||
|
||||
// Disables the audio processing (echo cancelation, auto gain control and noise suppression) for local audio tracks.
|
||||
// disableAP: true,
|
||||
|
||||
// Disables the anoise suppression for local audio tracks.
|
||||
// disableNS: true,
|
||||
|
||||
// Replaces the display name with the JID of the participants.
|
||||
// displayJids: true,
|
||||
|
||||
// Enables disables talk while muted detection.
|
||||
// enableTalkWhileMuted: true,
|
||||
|
||||
// Sets the peer connection ICE transport policy to "relay".
|
||||
// forceTurnRelay: true,
|
||||
|
||||
// List of undocumented settings used in jitsi-meet
|
||||
/**
|
||||
_immediateReloadThreshold
|
||||
debug
|
||||
debugAudioLevels
|
||||
deploymentInfo
|
||||
dialOutAuthUrl
|
||||
dialOutCodesUrl
|
||||
dialOutRegionUrl
|
||||
disableRemoteControl
|
||||
displayJids
|
||||
firefox_fake_device
|
||||
googleApiApplicationClientID
|
||||
iAmRecorder
|
||||
iAmSipGateway
|
||||
microsoftApiApplicationClientID
|
||||
@@ -1635,7 +1661,14 @@ var config = {
|
||||
_peerConnStatusRtcMuteTimeout
|
||||
avgRtpStatsN
|
||||
desktopSharingSources
|
||||
disableAEC
|
||||
disableAGC
|
||||
disableAP
|
||||
disableHPF
|
||||
disableLocalStats
|
||||
disableNS
|
||||
enableTalkWhileMuted
|
||||
forceTurnRelay
|
||||
hiddenDomain
|
||||
hiddenFromRecorderFeatureEnabled
|
||||
ignoreStartMuted
|
||||
@@ -1712,7 +1745,7 @@ var config = {
|
||||
// 'notify.participantsWantToJoin', // shown when lobby is enabled and participants request to join meeting
|
||||
// 'notify.passwordRemovedRemotely', // shown when a password has been removed remotely
|
||||
// 'notify.passwordSetRemotely', // shown when a password has been set remotely
|
||||
// 'notify.raisedHand', // shown when a participant used raise hand,
|
||||
// 'notify.raisedHand', // shown when a partcipant used raise hand,
|
||||
// 'notify.screenShareNoAudio', // shown when the audio could not be shared for the selected screen
|
||||
// 'notify.screenSharingAudioOnlyTitle', // shown when the best performance has been affected by screen sharing
|
||||
// 'notify.selfViewTitle', // show "You can always un-hide the self-view from settings"
|
||||
@@ -1743,7 +1776,7 @@ var config = {
|
||||
// disableFilmstripAutohiding: false,
|
||||
|
||||
// filmstrip: {
|
||||
// // Disable the vertical/horizontal filmstrip.
|
||||
// // Disable the vertical/horizonal filmstrip.
|
||||
// disabled: false,
|
||||
// // Disables user resizable filmstrip. Also, allows configuration of the filmstrip
|
||||
// // (width, tiles aspect ratios) through the interfaceConfig options.
|
||||
@@ -1802,10 +1835,9 @@ var config = {
|
||||
// //disableLogCollector: true,
|
||||
// // Individual loggers are customizable.
|
||||
// loggers: {
|
||||
// // The following are too verbose in their logging with the default level.
|
||||
// 'modules/RTC/TraceablePeerConnection.js': 'info',
|
||||
// 'modules/xmpp/strophe.util.js': 'log',
|
||||
// },
|
||||
// // The following are too verbose in their logging with the default level.
|
||||
// 'modules/RTC/TraceablePeerConnection.js': 'info',
|
||||
// 'modules/xmpp/strophe.util.js': 'log',
|
||||
// },
|
||||
|
||||
// Application logo url
|
||||
@@ -1863,6 +1895,12 @@ var config = {
|
||||
// hideLoginButton: true,
|
||||
};
|
||||
|
||||
// Temporary backwards compatibility with old mobile clients.
|
||||
config.flags = config.flags || {};
|
||||
config.flags.sourceNameSignaling = true;
|
||||
config.flags.sendMultipleVideoStreams = true;
|
||||
config.flags.receiveMultipleVideoStreams = true;
|
||||
|
||||
// Set the default values for JaaS customers
|
||||
if (enableJaaS) {
|
||||
config.dialInNumbersUrl = 'https://conference-mapper.jitsi.net/v1/access/dids';
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
flex-direction: column;
|
||||
|
||||
.description {
|
||||
color: #2f3237;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
margin-bottom: 16px;
|
||||
max-width: 436px;
|
||||
color: #2f3237;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
margin-bottom: 16px;
|
||||
max-width: 436px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,8 +127,7 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.with-click-handler:hover,
|
||||
&.with-click-handler:focus {
|
||||
&.with-click-handler:hover {
|
||||
background-color: #c7ddff;
|
||||
}
|
||||
|
||||
@@ -156,22 +155,14 @@
|
||||
margin-right: 16px;
|
||||
position: absolute;
|
||||
|
||||
&>svg {
|
||||
&> svg {
|
||||
fill: #0074e0;
|
||||
}
|
||||
}
|
||||
|
||||
.item:hover,
|
||||
.item:focus,
|
||||
.item:focus-within {
|
||||
.item:hover, .item:focus, .item:focus-within {
|
||||
.delete-meeting {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.delete-meeting:hover {
|
||||
&>svg {
|
||||
fill: #4687ED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
16
debian/jitsi-meet-web-config.postinst
vendored
16
debian/jitsi-meet-web-config.postinst
vendored
@@ -175,6 +175,22 @@ case "$1" in
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fixes multi-stream flags to workaround problem with mobile joining a multi-stream call with multi-stream disabled
|
||||
FIX_MSG="// Temporary backwards compatibility with old mobile clients."
|
||||
if ! grep -q "^${FIX_MSG}" $JITSI_MEET_CONFIG; then
|
||||
echo $FIX_MSG >> $JITSI_MEET_CONFIG
|
||||
echo "config.flags = config.flags || {};" >> $JITSI_MEET_CONFIG
|
||||
fi
|
||||
if ! grep -q "^config.flags.sourceNameSignaling*" $JITSI_MEET_CONFIG; then
|
||||
echo "config.flags.sourceNameSignaling = true;" >> $JITSI_MEET_CONFIG
|
||||
fi
|
||||
if ! grep -q "^config.flags.sendMultipleVideoStreams*" $JITSI_MEET_CONFIG; then
|
||||
echo "config.flags.sendMultipleVideoStreams = true;" >> $JITSI_MEET_CONFIG
|
||||
fi
|
||||
if ! grep -q "^config.flags.receiveMultipleVideoStreams*" $JITSI_MEET_CONFIG; then
|
||||
echo "config.flags.receiveMultipleVideoStreams = true;" >> $JITSI_MEET_CONFIG
|
||||
fi
|
||||
|
||||
if [[ "$FORCE_OPENRESTY" = "true" ]]; then
|
||||
NGX_COMMON_CONF_PATH="/usr/local/openresty/nginx/conf/$JVB_HOSTNAME.conf"
|
||||
NGX_SVC_NAME=openresty
|
||||
|
||||
1
globals.d.ts
vendored
1
globals.d.ts
vendored
@@ -18,6 +18,7 @@ declare global {
|
||||
JITSI_MEET_LITE_SDK?: boolean;
|
||||
interfaceConfig?: any;
|
||||
JitsiMeetJS?: any;
|
||||
JitsiMeetElectron?: any;
|
||||
PressureObserver?: any;
|
||||
PressureRecord?: any;
|
||||
ReactNativeWebView?: any;
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 4.2 KiB |
@@ -41,6 +41,14 @@ var interfaceConfig = {
|
||||
*/
|
||||
DISABLE_PRESENCE_STATUS: false,
|
||||
|
||||
/**
|
||||
* Whether the ringing sound in the call/ring overlay is disabled. If
|
||||
* {@code undefined}, defaults to {@code false}.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
DISABLE_RINGING: false,
|
||||
|
||||
/**
|
||||
* Whether the speech to text transcription subtitles panel is disabled.
|
||||
* If {@code undefined}, defaults to {@code false}.
|
||||
@@ -62,6 +70,9 @@ var interfaceConfig = {
|
||||
|
||||
ENABLE_DIAL_OUT: true,
|
||||
|
||||
// DEPRECATED. Animation no longer supported.
|
||||
// ENABLE_FEEDBACK_ANIMATION: false,
|
||||
|
||||
FILM_STRIP_MAX_HEIGHT: 120,
|
||||
|
||||
GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true,
|
||||
@@ -216,7 +227,7 @@ var interfaceConfig = {
|
||||
/**
|
||||
* Specify custom URL for downloading f droid app.
|
||||
*/
|
||||
// MOBILE_DOWNLOAD_LINK_F_DROID: 'https://f-droid.org/packages/org.jitsi.meet/',
|
||||
// MOBILE_DOWNLOAD_LINK_F_DROID: 'https://f-droid.org/en/packages/org.jitsi.meet/',
|
||||
|
||||
// Connection indicators (
|
||||
// CONNECTION_INDICATOR_AUTO_HIDE_ENABLED,
|
||||
|
||||
@@ -1,6 +1,2 @@
|
||||
THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
|
||||
|
||||
. ${THIS_DIR}/../node_modules/react-native/scripts/find-node-for-xcode.sh
|
||||
|
||||
export NODE_BINARY=$(command -v node)
|
||||
export ENTRY_FILE="${PROJECT_DIR}/../../index.ios.js"
|
||||
|
||||
@@ -1726,7 +1726,7 @@ PODS:
|
||||
- React
|
||||
- RNCAsyncStorage (1.23.1):
|
||||
- React-Core
|
||||
- RNCClipboard (1.14.3):
|
||||
- RNCClipboard (1.14.1):
|
||||
- React-Core
|
||||
- RNDefaultPreference (1.4.4):
|
||||
- React-Core
|
||||
@@ -2197,7 +2197,7 @@ SPEC CHECKSUMS:
|
||||
ReactCommon: 6a952e50c2a4b694731d7682aaa6c79bc156e4ad
|
||||
RNCalendarEvents: 7e65eb4a94f53c1744d1e275f7fafcfaa619f7a3
|
||||
RNCAsyncStorage: 826b603ae9c0f88b5ac4e956801f755109fa4d5c
|
||||
RNCClipboard: 2821ac938ef46f736a8de0c8814845dde2dcbdfb
|
||||
RNCClipboard: 0a720adef5ec193aa0e3de24c3977222c7e52a37
|
||||
RNDefaultPreference: 08bdb06cfa9188d5da97d4642dac745218d7fb31
|
||||
RNDeviceInfo: 02ea8b23e2280fa18e00a06d7e62804d74028579
|
||||
RNGestureHandler: 939f21fabf5d45a725c0bf175eb819dd25cf2e70
|
||||
@@ -2211,4 +2211,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: 7ed908101076ca2c595b633c34648bcfc7e98614
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
COCOAPODS: 1.16.1
|
||||
|
||||
@@ -34,10 +34,6 @@
|
||||
jitsiMeet.universalLinkDomains = @[@"meet.jit.si", @"alpha.jitsi.net", @"beta.meet.jit.si"];
|
||||
|
||||
jitsiMeet.defaultConferenceOptions = [JitsiMeetConferenceOptions fromBuilder:^(JitsiMeetConferenceOptionsBuilder *builder) {
|
||||
|
||||
// For testing configOverrides a room needs to be set
|
||||
// builder.room = @"test0988test";
|
||||
|
||||
[builder setFeatureFlag:@"welcomepage.enabled" withBoolean:YES];
|
||||
[builder setFeatureFlag:@"ios.screensharing.enabled" withBoolean:YES];
|
||||
[builder setFeatureFlag:@"ios.recording.enabled" withBoolean:YES];
|
||||
|
||||
@@ -88,8 +88,8 @@
|
||||
[self _onJitsiMeetViewDelegateEvent:@"CONFERENCE_WILL_JOIN" withData:data];
|
||||
}
|
||||
|
||||
// - (void)customButtonPressed:(NSDictionary *)data {
|
||||
// [self _onJitsiMeetViewDelegateEvent:@"CUSTOM_BUTTON_PRESSED" withData:data];
|
||||
// - (void)customOverflowMenuButtonPressed:(NSDictionary *)data {
|
||||
// [self _onJitsiMeetViewDelegateEvent:@"CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED" withData:data];
|
||||
// }
|
||||
|
||||
#if 0
|
||||
|
||||
@@ -69,7 +69,7 @@ platform :ios do
|
||||
end
|
||||
)
|
||||
|
||||
# Increment the build number by 1
|
||||
# Inrement the build number by 1
|
||||
increment_build_number(
|
||||
build_number: Time.now.to_i,
|
||||
xcodeproj: "app/app.xcodeproj"
|
||||
|
||||
@@ -54,7 +54,7 @@ pushd ${RELEASE_REPO}
|
||||
|
||||
# Put the new files in the repo
|
||||
cp -a ${PROJECT_REPO}/ios/sdk/out/JitsiMeetSDK.xcframework lite/Frameworks/
|
||||
cp -a ${PROJECT_REPO}/ios/Pods/hermes-engine/destroot/Library/Frameworks/universal/hermes.xcframework lite/Frameworks/
|
||||
cp -a ${PROJECT_REPO}/ios/sdk/out/hermes.xcframework lite/Frameworks/
|
||||
|
||||
# Add all files to git
|
||||
git add -A .
|
||||
|
||||
@@ -54,7 +54,7 @@ pushd ${RELEASE_REPO}
|
||||
|
||||
# Put the new files in the repo
|
||||
cp -a ${PROJECT_REPO}/ios/sdk/out/JitsiMeetSDK.xcframework Frameworks/
|
||||
cp -a ${PROJECT_REPO}/ios/Pods/hermes-engine/destroot/Library/Frameworks/universal/hermes.xcframework Frameworks/
|
||||
cp -a ${PROJECT_REPO}/ios/sdk/out/hermes.xcframework Frameworks/
|
||||
|
||||
# Add all files to git
|
||||
git add -A .
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#import <WebRTC/WebRTC.h>
|
||||
|
||||
#import "JitsiAudioSession+Private.h"
|
||||
#import "callkit/JMCallKitProxy.h"
|
||||
|
||||
|
||||
// Audio mode
|
||||
@@ -55,7 +54,6 @@ static NSString * const kDeviceTypeUnknown = @"UNKNOWN";
|
||||
RTCAudioSessionConfiguration *audioCallConfig;
|
||||
RTCAudioSessionConfiguration *videoCallConfig;
|
||||
RTCAudioSessionConfiguration *earpieceConfig;
|
||||
BOOL audioDisabled;
|
||||
BOOL forceSpeaker;
|
||||
BOOL forceEarpiece;
|
||||
BOOL isSpeakerOn;
|
||||
@@ -148,36 +146,9 @@ RCT_EXPORT_MODULE();
|
||||
|
||||
#pragma mark - Exported methods
|
||||
|
||||
RCT_EXPORT_METHOD(setDisabled:(BOOL)disabled
|
||||
resolve:(RCTPromiseResolveBlock)resolve
|
||||
reject:(RCTPromiseRejectBlock)reject) {
|
||||
if (audioDisabled == disabled) {
|
||||
resolve(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
RCTLogInfo(@"[AudioMode] audio disabled: %d", disabled);
|
||||
|
||||
audioDisabled = disabled;
|
||||
JMCallKitProxy.enabled = !disabled;
|
||||
|
||||
RTCAudioSession *session = JitsiAudioSession.rtcAudioSession;
|
||||
if (disabled) {
|
||||
[session removeDelegate:self];
|
||||
} else {
|
||||
[session addDelegate:self];
|
||||
}
|
||||
session.useManualAudio = disabled;
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(setMode:(int)mode
|
||||
resolve:(RCTPromiseResolveBlock)resolve
|
||||
reject:(RCTPromiseRejectBlock)reject) {
|
||||
if (audioDisabled) {
|
||||
resolve(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
RTCAudioSessionConfiguration *config = [self configForMode:mode];
|
||||
NSError *error;
|
||||
|
||||
@@ -206,11 +177,6 @@ RCT_EXPORT_METHOD(setMode:(int)mode
|
||||
RCT_EXPORT_METHOD(setAudioDevice:(NSString *)device
|
||||
resolve:(RCTPromiseResolveBlock)resolve
|
||||
reject:(RCTPromiseRejectBlock)reject) {
|
||||
if (audioDisabled) {
|
||||
resolve(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
RCTLogInfo(@"[AudioMode] Selected device: %@", device);
|
||||
|
||||
RTCAudioSession *session = JitsiAudioSession.rtcAudioSession;
|
||||
@@ -273,10 +239,6 @@ RCT_EXPORT_METHOD(setAudioDevice:(NSString *)device
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(updateDeviceList) {
|
||||
if (audioDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self notifyDevicesChanged];
|
||||
}
|
||||
|
||||
|
||||
@@ -24,15 +24,11 @@
|
||||
}
|
||||
|
||||
+ (void)activateWithAudioSession:(AVAudioSession *)session {
|
||||
if (!self.rtcAudioSession.useManualAudio) {
|
||||
[self.rtcAudioSession audioSessionDidActivate:session];
|
||||
}
|
||||
[self.rtcAudioSession audioSessionDidActivate:session];
|
||||
}
|
||||
|
||||
+ (void)deactivateWithAudioSession:(AVAudioSession *)session {
|
||||
if (!self.rtcAudioSession.useManualAudio) {
|
||||
[self.rtcAudioSession audioSessionDidDeactivate:session];
|
||||
}
|
||||
[self.rtcAudioSession audioSessionDidDeactivate:session];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -231,9 +231,6 @@
|
||||
}
|
||||
|
||||
- (void)setDefaultConferenceOptions:(JitsiMeetConferenceOptions *)defaultConferenceOptions {
|
||||
|
||||
// For testing configOverrides a room needs to be set,
|
||||
// thus the following check needs to be commented out
|
||||
if (defaultConferenceOptions != nil && defaultConferenceOptions.room != nil) {
|
||||
@throw [NSException exceptionWithName:@"RuntimeError"
|
||||
reason:@"'room' must be null in the default conference options"
|
||||
|
||||
@@ -128,6 +128,6 @@
|
||||
*
|
||||
* The `data` dictionary contains a `id`, `text` key.
|
||||
*/
|
||||
- (void)customButtonPressed:(NSDictionary *)data;
|
||||
- (void)customOverflowMenuButtonPressed:(NSDictionary *)data;
|
||||
|
||||
@end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -334,7 +334,6 @@
|
||||
"kickParticipantButton": "Expulser",
|
||||
"kickParticipantDialog": "Êtes-vous sûr(e) de vouloir expulser ce participant ?",
|
||||
"kickParticipantTitle": "Expulser ce participant ?",
|
||||
"kickSystemTitle": "Oups ! Vous avez été expulsé de la réunion",
|
||||
"kickTitle": "Oups ! vous avez été expulsé(e) par {{participantDisplayName}}",
|
||||
"linkMeeting": "Relier la conférence",
|
||||
"linkMeetingTitle": "Relier la conférence à Salesforce",
|
||||
@@ -440,10 +439,7 @@
|
||||
"shareScreenWarningD2": "vous devez arrêter le partage d'audio, démarrer le partage d'écran et cocher l'option \"Partager l'audio\".",
|
||||
"shareScreenWarningH1": "Si vous voulez partager uniquement votre écran:",
|
||||
"shareScreenWarningTitle": "Vous devez cesser de partager votre audio avant de partager votre écran",
|
||||
"shareVideoConfirmPlay": "Vous êtes sur le point d'ouvrir un site web externe. Voulez-vous continuer ?",
|
||||
"shareVideoConfirmPlayTitle": "{{name}} a partagé une vidéo avec vous.",
|
||||
"shareVideoLinkError": "Veuillez renseigner un lien de diffusion vidéo fonctionnel.",
|
||||
"shareVideoLinkStopped": "La vidéo de {{name}} a été arrêtée.",
|
||||
"shareVideoTitle": "Partager une vidéo",
|
||||
"shareYourScreen": "Partager votre écran",
|
||||
"shareYourScreenDisabled": "Le partage d'écran est désactivé.",
|
||||
@@ -642,7 +638,6 @@
|
||||
"on": "En direct",
|
||||
"onBy": "{{name}} a démarré la diffusion en direct",
|
||||
"pending": "Lancement du direct…",
|
||||
"policyError": "Vous avez essayé de démarrer une diffusion en direct trop rapidement. Veuillez réessayer plus tard !",
|
||||
"serviceName": "Service de diffusion en direct",
|
||||
"sessionAlreadyActive": "Cette session est déjà en cours d'enregistrement ou de diffusion.",
|
||||
"signIn": "Se connecter avec Google",
|
||||
@@ -741,7 +736,6 @@
|
||||
"connectedOneMember": "{{name}} a rejoint la réunion",
|
||||
"connectedThreePlusMembers": "{{name}} et {{count}} autres personnes ont rejoint la réunion",
|
||||
"connectedTwoMembers": "{{first}} et {{second}} ont rejoint la réunion",
|
||||
"connectionFailed": "Connexion échouée. Veuillez réessayer plus tard !",
|
||||
"dataChannelClosed": "Qualité vidéo dégradée",
|
||||
"dataChannelClosedDescription": "Le canal de communication avec le Bridge a été interrompu, la qualité vidéo se trouve limitée à sa valeur la plus faible.",
|
||||
"dataChannelClosedDescriptionWithAudio": "Le canal de pont est fermé, ce qui peut entraîner des perturbations de l'audio et de la vidéo.",
|
||||
@@ -756,9 +750,6 @@
|
||||
"gifsMenu": "GIPHY",
|
||||
"groupTitle": "Notifications",
|
||||
"hostAskedUnmute": "Le modérateur souhaite vous donner la parole",
|
||||
"invalidTenant": "Tenant invalide",
|
||||
"invalidTenantHyphenDescription": "Le tenant que vous utilisez est invalide (commence ou se termine par '-').",
|
||||
"invalidTenantLengthDescription": "Le tenant que vous utilisez est trop long.",
|
||||
"invitedOneMember": "{{name}} a été invité(e)",
|
||||
"invitedThreePlusMembers": "{{name}} et {{count}} autres ont été invités",
|
||||
"invitedTwoMembers": "{{first}} et {{second}} ont été invités",
|
||||
@@ -795,7 +786,6 @@
|
||||
"newDeviceAction": "Utiliser",
|
||||
"newDeviceAudioTitle": "Nouveau périphérique audio détecté",
|
||||
"newDeviceCameraTitle": "Nouvelle caméra détectée",
|
||||
"nextToSpeak": "Vous êtes le prochain à prendre la parole",
|
||||
"noiseSuppressionDesktopAudioDescription": "La suppression de bruit ne peut pas être activée en même temps que la partage audio du système, veuillez le désactiver et réessayer.",
|
||||
"noiseSuppressionFailedTitle": "Échec du démarrage de la suppression de bruit",
|
||||
"noiseSuppressionStereoDescription": "La suppression de bruit d’une source stéréo n’est pas encore supportée.",
|
||||
@@ -830,7 +820,6 @@
|
||||
"videoUnmuteBlockedDescription": "Le rétablissement de la vidéo a été bloqué temporairement en raison de limites système.",
|
||||
"videoUnmuteBlockedTitle": "Rétablissement de la caméra bloqué !",
|
||||
"viewLobby": "Voir la salle d'attente",
|
||||
"viewParticipants": "Voir les participants",
|
||||
"viewVisitors": "Voir les visiteurs",
|
||||
"waitingParticipants": "{{waitingParticipants}} personnes",
|
||||
"waitingVisitors": "Visiteurs en attente dans la file : {{waitingVisitors}}",
|
||||
@@ -850,8 +839,6 @@
|
||||
"breakoutRooms": "Salles annexes",
|
||||
"goLive": "Passer en direct",
|
||||
"invite": "Inviter quelqu'un",
|
||||
"lowerAllHands": "Abaisser toutes les mains",
|
||||
"lowerHand": "Abaisser la main",
|
||||
"moreModerationActions": "Options de modération supplémentaires",
|
||||
"moreModerationControls": "Options de modération supplémentaires",
|
||||
"moreParticipantOptions": "Options supplémentaires pour les participants",
|
||||
@@ -888,7 +875,6 @@
|
||||
"submit": "Envoyer"
|
||||
},
|
||||
"by": "Par {{ name }}",
|
||||
"closeButton": "Fermer le sondage",
|
||||
"create": {
|
||||
"addOption": "Ajouter une option",
|
||||
"answerPlaceholder": "Option {{index}}",
|
||||
@@ -928,11 +914,9 @@
|
||||
"configuringDevices": "Configuration des appareils…",
|
||||
"connectedWithAudioQ": "Êtes-vous connecté avec le microphone ?",
|
||||
"connection": {
|
||||
"failed": "Le test de connexion a échoué !",
|
||||
"good": "Votre connexion Internet est bonne !",
|
||||
"nonOptimal": "Votre connexion n'est pas optimale",
|
||||
"poor": "Vous avez une mauvaise connexion",
|
||||
"running": "Exécution du test de connexion…"
|
||||
"poor": "Vous avez une mauvaise connexion"
|
||||
},
|
||||
"connectionDetails": {
|
||||
"audioClipping": "Attendez vous à ce que votre son soit coupé.",
|
||||
@@ -941,7 +925,6 @@
|
||||
"goodQuality": "Impressionnant ! La qualité de vos médias sera excellente",
|
||||
"noMediaConnectivity": "Nous n'avons pas pu trouver un moyen d'établir une connectivité multimédia pour ce test. Cela est généralement causé par un pare-feu ou un NAT.",
|
||||
"noVideo": "Attendez vous à ce que votre qualité vidéo soit très mauvaise.",
|
||||
"testFailed": "Le test de connexion a rencontré des problèmes inattendus, mais cela pourrait ne pas affecter votre expérience.",
|
||||
"undetectable": "Si vous ne parvenez toujours pas à passer des appels dans le navigateur, nous vous recommandons de vous assurer que vos haut-parleurs, microphone et caméra sont correctement configurés, que vous avez accordé à votre navigateur les droits d'utiliser votre microphone et votre caméra et que la version de votre navigateur est à jour. Si vous rencontrez toujours des difficultés pour appeler, vous devez contacter le développeur de l'application Web.",
|
||||
"veryPoorConnection": "Attendez vous à ce que la qualité de votre appel soit très mauvaise",
|
||||
"videoFreezing": "Attendez vous à ce que votre vidéo saute, soit noire, et pixelisée.",
|
||||
@@ -1057,7 +1040,6 @@
|
||||
"onBy": "{{name}} a démarré l'enregistrement",
|
||||
"onlyRecordSelf": "Enregistrer seulement mon audio et ma vidéo.",
|
||||
"pending": "Préparation de l'enregistrement de la réunion…",
|
||||
"policyError": "Vous avez essayé de démarrer un enregistrement trop rapidement. Veuillez réessayer plus tard !",
|
||||
"recordAudioAndVideo": "Enregistrer l'audio et la vidéo",
|
||||
"recordTranscription": "Enregistrer la transcription",
|
||||
"saveLocalRecording": "Sauvegarder l’enregistrement local (Beta)",
|
||||
@@ -1106,7 +1088,6 @@
|
||||
"desktopShareWarning": "Vous devez repartager l'écran pour que ces paramètres soient utilisés.",
|
||||
"devices": "Périphériques",
|
||||
"followMe": "Tout le monde me suit",
|
||||
"followMeRecorder": "L'enregistreur me suit",
|
||||
"framesPerSecond": "images par seconde",
|
||||
"incomingMessage": "un message arrive",
|
||||
"language": "Langue",
|
||||
@@ -1253,7 +1234,6 @@
|
||||
"lobbyButton": "Activer / Désactiver le mode salle d'attente",
|
||||
"localRecording": "Activer / Désactiver les contrôles d'enregistrement local",
|
||||
"lockRoom": "Activer / Désactiver le mot de passe de la réunion",
|
||||
"love": "Cœur",
|
||||
"lowerHand": "Baisser la main",
|
||||
"moreActions": "Activer / Désactiver le menu d'actions supplémentaires",
|
||||
"moreActionsMenu": "Menu d'actions supplémentaires",
|
||||
@@ -1271,7 +1251,6 @@
|
||||
"privateMessage": "Envoyer un message privé",
|
||||
"profile": "Éditer votre profil",
|
||||
"raiseHand": "Lever la main",
|
||||
"react": "Réactions aux messages",
|
||||
"reactions": "Réactions",
|
||||
"reactionsMenu": "Ouvrir / fermer le menu réactions",
|
||||
"recording": "Activer / Désactiver l'enregistrement",
|
||||
@@ -1343,7 +1322,6 @@
|
||||
"lobbyButtonEnable": "Activer le mode salle d'attente / contrôle des participant(e)s",
|
||||
"login": "Connexion",
|
||||
"logout": "Déconnexion",
|
||||
"love": "Cœur",
|
||||
"lowerYourHand": "Baisser la main",
|
||||
"moreActions": "Plus d'actions",
|
||||
"moreOptions": "Plus d'options",
|
||||
@@ -1369,7 +1347,6 @@
|
||||
"raiseYourHand": "Lever la main",
|
||||
"reactionBoo": "Envoyer réaction huer",
|
||||
"reactionClap": "Envoyer réaction applaudir",
|
||||
"reactionHeart": "Envoyer une réaction en forme de cœur",
|
||||
"reactionLaugh": "Envoyer réaction rire",
|
||||
"reactionLike": "Envoyer réaction approuver",
|
||||
"reactionSilence": "Envoyer réaction silence",
|
||||
@@ -1403,7 +1380,7 @@
|
||||
"transcribing": {
|
||||
"ccButtonTooltip": "Activer / Désactiver les sous-titres",
|
||||
"expandedLabel": "La transcription est actuellement activée",
|
||||
"failed": "La transcription a échoué",
|
||||
"failedToStart": "Échec de démarrage de la transcription",
|
||||
"labelToolTip": "La transcription de la réunion est en cours",
|
||||
"sourceLanguageDesc": "Actuellement, la langue de la réunion est sélectionnée à <b>{{sourceLanguage}}</b>. <br/> Vous pouvez la changer à partir de ",
|
||||
"sourceLanguageHere": "ici",
|
||||
@@ -1504,15 +1481,10 @@
|
||||
},
|
||||
"visitors": {
|
||||
"chatIndicator": "(visiteur)",
|
||||
"joinMeeting": {
|
||||
"description": "Vous êtes actuellement un observateur dans cette conférence.",
|
||||
"raiseHand": "Levez la main",
|
||||
"title": "Rejoindre la réunion",
|
||||
"wishToSpeak": "Si vous souhaitez prendre la parole, veuillez lever la main ci-dessous et attendre l'approbation du modérateur."
|
||||
},
|
||||
"labelTooltip": "Nombre de Visiteurs: {{count}}",
|
||||
"labelTooltip": "Nombre de Visiteurs",
|
||||
"notification": {
|
||||
"demoteDescription": "Envoyé ici par {{actor}}, levez la main pour participer",
|
||||
"description": "Pour participer lever la main.",
|
||||
"noMainParticipantsDescription": "Un participant doit démarrer la réunion. Veuillez réessayer dans un moment.",
|
||||
"noMainParticipantsTitle": "Cette réunion n'a pas encore commencé.",
|
||||
"noVisitorLobby": "Vous ne pouvez pas rejoindre tant qu'une salle d'attente est activée pour la réunion.",
|
||||
|
||||
@@ -334,7 +334,6 @@
|
||||
"kickParticipantButton": "Izraidīt",
|
||||
"kickParticipantDialog": "Vai esat pārliecināti, ka vēlaties izraidīt šo dalībnieku?",
|
||||
"kickParticipantTitle": "Izraidīt šo dalībnieku?",
|
||||
"kickSystemTitle": "Ak! Jūs izraidīja no sapulces",
|
||||
"kickTitle": "Ak! {{participantDisplayName}} izraidīja jūs no sapulces",
|
||||
"linkMeeting": "Sasaistīt sapulci",
|
||||
"linkMeetingTitle": "Sasaistīt sapulci ar Salesforce",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -410,7 +410,6 @@
|
||||
"sendPrivateMessageTitle": "私信回复?",
|
||||
"serviceUnavailable": "服务不可用",
|
||||
"sessTerminated": "通话已结束",
|
||||
"sessTerminatedReason": "会议已经结束",
|
||||
"sessionRestarted": "由于连接问题,呼叫重新启动。",
|
||||
"shareAudio": "继续",
|
||||
"shareAudioTitle": "如何分享音频",
|
||||
|
||||
@@ -307,8 +307,8 @@
|
||||
"contactSupport": "Contact support",
|
||||
"copied": "Copied",
|
||||
"copy": "Copy",
|
||||
"demoteParticipantDialog": "Are you sure you want to move this participant to viewer?",
|
||||
"demoteParticipantTitle": "Move to viewer",
|
||||
"demoteParticipantDialog": "Are you sure you want to move this participant to visitor?",
|
||||
"demoteParticipantTitle": "Move to visitor",
|
||||
"dismiss": "Dismiss",
|
||||
"displayNameRequired": "Hi! What’s your name?",
|
||||
"done": "Done",
|
||||
@@ -831,9 +831,9 @@
|
||||
"videoUnmuteBlockedTitle": "Camera unmute and desktop sharing blocked!",
|
||||
"viewLobby": "View lobby",
|
||||
"viewParticipants": "View participants",
|
||||
"viewVisitors": "View viewers",
|
||||
"viewVisitors": "View visitors",
|
||||
"waitingParticipants": "{{waitingParticipants}} people",
|
||||
"waitingVisitors": "Viewers waiting in queue: {{waitingVisitors}}",
|
||||
"waitingVisitors": "Visitors waiting in queue: {{waitingVisitors}}",
|
||||
"waitingVisitorsTitle": "The meeting is not live yet!",
|
||||
"whiteboardLimitDescription": "Please save your progress, as the user limit will soon be reached and the whiteboard will close.",
|
||||
"whiteboardLimitTitle": "Whiteboard usage"
|
||||
@@ -870,7 +870,7 @@
|
||||
"participantsList": "Meeting participants ({{count}})",
|
||||
"visitorInQueue": " (waiting {{count}})",
|
||||
"visitorRequests": " (requests {{count}})",
|
||||
"visitors": "Viewers {{count}}",
|
||||
"visitors": "Visitors {{count}}",
|
||||
"waitingLobby": "Waiting in lobby ({{count}})"
|
||||
},
|
||||
"search": "Search participants",
|
||||
@@ -1083,7 +1083,7 @@
|
||||
"about": "You can add a $t(lockRoomPassword) to your meeting. Participants will need to provide the $t(lockRoomPassword) before they are allowed to join the meeting.",
|
||||
"aboutReadOnly": "Moderator participants can add a $t(lockRoomPassword) to the meeting. Participants will need to provide the $t(lockRoomPassword) before they are allowed to join the meeting.",
|
||||
"insecureRoomNameWarningNative": "The room name is unsafe. Unwanted participants may join your meeting. {{recommendAction}} Learn more about securing your meeting ",
|
||||
"insecureRoomNameWarningWeb": "The room name is unsafe. Unwanted participants may join your meeting. {{recommendAction}} Learn more about securing your meeting <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">here</a>.",
|
||||
"insecureRoomNameWarningWeb": "The room name is unsafe. Unwanted participants may join your meeting. {{recommendAction}} Learn more about securing you meeting <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">here</a>.",
|
||||
"title": "Security Options",
|
||||
"unsafeRoomActions": {
|
||||
"meeting": "Consider securing your meeting using the security button.",
|
||||
@@ -1183,7 +1183,6 @@
|
||||
"fearful": "Fearful",
|
||||
"happy": "Happy",
|
||||
"hours": "{{count}}h",
|
||||
"labelTooltip": "Number of participants: {{count}}",
|
||||
"minutes": "{{count}}m",
|
||||
"name": "Name",
|
||||
"neutral": "Neutral",
|
||||
@@ -1452,7 +1451,7 @@
|
||||
},
|
||||
"videothumbnail": {
|
||||
"connectionInfo": "Connection Info",
|
||||
"demote": "Move to viewer",
|
||||
"demote": "Move to visitor",
|
||||
"domute": "Mute",
|
||||
"domuteOthers": "Mute everyone else",
|
||||
"domuteVideo": "Disable camera",
|
||||
@@ -1504,21 +1503,21 @@
|
||||
"webAssemblyWarningDescription": "WebAssembly disabled or not supported by this browser"
|
||||
},
|
||||
"visitors": {
|
||||
"chatIndicator": "(viewer)",
|
||||
"chatIndicator": "(visitor)",
|
||||
"joinMeeting": {
|
||||
"description": "You're currently a viewer in this conference.",
|
||||
"description": "You're currently an observer in this conference.",
|
||||
"raiseHand": "Raise your hand",
|
||||
"title": "Joining meeting",
|
||||
"wishToSpeak": "If you wish to speak, please raise your hand below and wait for the moderator's approval."
|
||||
},
|
||||
"labelTooltip": "Number of viewers: {{count}}",
|
||||
"labelTooltip": "Number of visitors: {{count}}",
|
||||
"notification": {
|
||||
"demoteDescription": "Sent here by {{actor}}, raise your hand to participate",
|
||||
"noMainParticipantsDescription": "A participant needs to start the meeting. Please try again in a bit.",
|
||||
"noMainParticipantsTitle": "This meeting hasn’t started yet.",
|
||||
"noVisitorLobby": "You cannot join while there is a lobby enabled for the meeting.",
|
||||
"notAllowedPromotion": "A participant needs to allow your request first.",
|
||||
"title": "You are a viewer in the meeting"
|
||||
"title": "You are a visitor in the meeting"
|
||||
},
|
||||
"waitingMessage": "You'll join the meeting as soon as it is live!"
|
||||
},
|
||||
|
||||
@@ -590,7 +590,7 @@ function initCommands() {
|
||||
* @param { string } arg.title - Notification title.
|
||||
* @param { string } arg.description - Notification description.
|
||||
* @param { string } arg.uid - Optional unique identifier for the notification.
|
||||
* @param { string } arg.type - Notification type, either `error`, `normal`, `success` or `warning`.
|
||||
* @param { string } arg.type - Notification type, either `error`, `info`, `normal`, `success` or `warning`.
|
||||
* Defaults to "normal" if not provided.
|
||||
* @param { string } arg.timeout - Timeout type, either `short`, `medium`, `long` or `sticky`.
|
||||
* Defaults to "short" if not provided.
|
||||
@@ -851,8 +851,6 @@ function initCommands() {
|
||||
'overwrite-config': config => {
|
||||
const whitelistedConfig = getWhitelistedJSON('config', config);
|
||||
|
||||
logger.info(`Overwriting config with: ${JSON.stringify(whitelistedConfig)}`);
|
||||
|
||||
APP.store.dispatch(overwriteConfig(whitelistedConfig));
|
||||
},
|
||||
'toggle-virtual-background': () => {
|
||||
@@ -1573,8 +1571,8 @@ class API {
|
||||
formattedArgument += `${arg.toString()}: ${arg.stack}`;
|
||||
} else if (typeof arg === 'object') {
|
||||
// NOTE: The non-enumerable properties of the objects wouldn't be included in the string after
|
||||
// JSON.stringify. For example Map instance will be translated to '{}'. So I think we have to eventually
|
||||
// do something better for parsing the arguments. But since this option for stringify is part of the
|
||||
// JSON.strigify. For example Map instance will be translated to '{}'. So I think we have to eventually
|
||||
// do something better for parsing the arguments. But since this option for strigify is part of the
|
||||
// public interface and I think it could be useful in some cases I will it for now.
|
||||
try {
|
||||
formattedArgument += JSON.stringify(arg);
|
||||
|
||||
96
modules/API/external/external_api.js
vendored
96
modules/API/external/external_api.js
vendored
@@ -194,6 +194,80 @@ function changeParticipantNumber(APIInstance, number) {
|
||||
APIInstance._numberOfParticipants += number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the URL for the iframe.
|
||||
*
|
||||
* @param {string} domain - The domain name of the server that hosts the
|
||||
* conference.
|
||||
* @param {string} [options] - Another optional parameters.
|
||||
* @param {Object} [options.configOverwrite] - Object containing configuration
|
||||
* options defined in config.js to be overridden.
|
||||
* @param {Object} [options.interfaceConfigOverwrite] - Object containing
|
||||
* configuration options defined in interface_config.js to be overridden.
|
||||
* @param {string} [options.jwt] - The JWT token if needed by jitsi-meet for
|
||||
* authentication.
|
||||
* @param {string} [options.lang] - The meeting's default language.
|
||||
* @param {string} [options.roomName] - The name of the room to join.
|
||||
* @returns {string} The URL.
|
||||
*/
|
||||
function generateURL(domain, options = {}) {
|
||||
return urlObjectToString({
|
||||
...options,
|
||||
url: `https://${domain}/#jitsi_meet_external_api_id=${id}`
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the arguments passed to the constructor. If the old format is used
|
||||
* the function translates the arguments to the new format.
|
||||
*
|
||||
* @param {Array} args - The arguments to be parsed.
|
||||
* @returns {Object} JS object with properties.
|
||||
*/
|
||||
function parseArguments(args) {
|
||||
if (!args.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const firstArg = args[0];
|
||||
|
||||
switch (typeof firstArg) {
|
||||
case 'string': // old arguments format
|
||||
case 'undefined': {
|
||||
// Not sure which format but we are trying to parse the old
|
||||
// format because if the new format is used everything will be undefined
|
||||
// anyway.
|
||||
const [
|
||||
roomName,
|
||||
width,
|
||||
height,
|
||||
parentNode,
|
||||
configOverwrite,
|
||||
interfaceConfigOverwrite,
|
||||
jwt,
|
||||
onload,
|
||||
lang
|
||||
] = args;
|
||||
|
||||
return {
|
||||
roomName,
|
||||
width,
|
||||
height,
|
||||
parentNode,
|
||||
configOverwrite,
|
||||
interfaceConfigOverwrite,
|
||||
jwt,
|
||||
onload,
|
||||
lang
|
||||
};
|
||||
}
|
||||
case 'object': // new arguments format
|
||||
return args[0];
|
||||
default:
|
||||
throw new Error('Can\'t parse the arguments!');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute valid values for height and width. If a number is specified it's
|
||||
* treated as pixel units. If the value is expressed in px, em, pt or
|
||||
@@ -262,7 +336,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
* @param {string} [options.release] - The key used for specifying release if enabled on the backend.
|
||||
* @param {string} [options.sandbox] - Sandbox directive for the created iframe, if desired.
|
||||
*/
|
||||
constructor(domain, options = {}) {
|
||||
constructor(domain, ...args) {
|
||||
super();
|
||||
const {
|
||||
roomName = '',
|
||||
@@ -271,22 +345,21 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
parentNode = document.body,
|
||||
configOverwrite = {},
|
||||
interfaceConfigOverwrite = {},
|
||||
jwt,
|
||||
lang,
|
||||
onload,
|
||||
jwt = undefined,
|
||||
lang = undefined,
|
||||
onload = undefined,
|
||||
invitees,
|
||||
iceServers,
|
||||
devices,
|
||||
userInfo,
|
||||
e2eeKey,
|
||||
release,
|
||||
sandbox
|
||||
} = options;
|
||||
sandbox = ''
|
||||
} = parseArguments(args);
|
||||
const localStorageContent = jitsiLocalStorage.getItem('jitsiLocalStorage');
|
||||
|
||||
this._parentNode = parentNode;
|
||||
|
||||
this._url = urlObjectToString({
|
||||
this._url = generateURL(domain, {
|
||||
configOverwrite,
|
||||
iceServers,
|
||||
interfaceConfigOverwrite,
|
||||
@@ -298,8 +371,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
appData: {
|
||||
localStorageContent
|
||||
},
|
||||
release,
|
||||
url: `https://${domain}/#jitsi_meet_external_api_id=${id}`
|
||||
release
|
||||
});
|
||||
|
||||
this._createIFrame(height, width, sandbox);
|
||||
@@ -1241,10 +1313,6 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
* Returns the state of availability electron share screen via external api.
|
||||
*
|
||||
* @returns {Promise}
|
||||
*
|
||||
* TODO: should be removed after we make sure that all Electron clients use only versions
|
||||
* after with the legacy SS suport was removed from the electron SDK. If we remove it now the SS for Electron
|
||||
* clients with older versions wont work.
|
||||
*/
|
||||
_isNewElectronScreensharingSupported() {
|
||||
return this._transport.sendRequest({
|
||||
|
||||
5903
package-lock.json
generated
5903
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
51
package.json
51
package.json
@@ -26,13 +26,13 @@
|
||||
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.19/jitsi-excalidraw-0.0.19.tgz",
|
||||
"@jitsi/js-utils": "2.2.1",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
"@jitsi/rnnoise-wasm": "0.2.0",
|
||||
"@jitsi/rnnoise-wasm": "0.1.0",
|
||||
"@jitsi/rtcstats": "9.5.1",
|
||||
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
|
||||
"@microsoft/microsoft-graph-client": "3.0.1",
|
||||
"@mui/material": "5.12.1",
|
||||
"@react-native-async-storage/async-storage": "1.23.1",
|
||||
"@react-native-clipboard/clipboard": "1.14.3",
|
||||
"@react-native-clipboard/clipboard": "1.14.1",
|
||||
"@react-native-community/netinfo": "11.1.0",
|
||||
"@react-native-community/slider": "4.4.3",
|
||||
"@react-native-google-signin/google-signin": "10.1.0",
|
||||
@@ -68,7 +68,7 @@
|
||||
"js-md5": "0.6.1",
|
||||
"js-sha512": "0.8.0",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1908.0.0+2a5d7fcc/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet#release-8302",
|
||||
"lodash-es": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -76,7 +76,6 @@
|
||||
"optional-require": "1.0.3",
|
||||
"pixelmatch": "5.3.0",
|
||||
"promise.allsettled": "1.0.4",
|
||||
"promise.withresolvers": "1.0.3",
|
||||
"punycode": "2.3.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
@@ -135,17 +134,15 @@
|
||||
"@babel/plugin-transform-private-methods": "7.25.9",
|
||||
"@babel/preset-env": "7.25.9",
|
||||
"@babel/preset-react": "7.25.9",
|
||||
"@jitsi/eslint-config": "5.0.9",
|
||||
"@jitsi/eslint-config": "4.1.10",
|
||||
"@react-native/metro-config": "0.75.4",
|
||||
"@stylistic/eslint-plugin": "2.12.1",
|
||||
"@types/amplitude-js": "8.16.5",
|
||||
"@types/audioworklet": "0.0.29",
|
||||
"@types/dom-screen-wake-lock": "1.0.1",
|
||||
"@types/jasmine": "5.1.4",
|
||||
"@types/js-md5": "0.4.3",
|
||||
"@types/jsonwebtoken": "9.0.7",
|
||||
"@types/lodash-es": "4.17.12",
|
||||
"@types/minimatch": "5.1.2",
|
||||
"@types/mocha": "10.0.10",
|
||||
"@types/moment-duration-format": "2.2.6",
|
||||
"@types/offscreencanvas": "2019.7.2",
|
||||
"@types/pixelmatch": "5.2.5",
|
||||
@@ -163,25 +160,25 @@
|
||||
"@types/w3c-image-capture": "1.0.6",
|
||||
"@types/w3c-web-hid": "1.0.3",
|
||||
"@types/zxcvbn": "4.4.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.19.1",
|
||||
"@typescript-eslint/parser": "8.19.1",
|
||||
"@wdio/allure-reporter": "9.4.3",
|
||||
"@wdio/cli": "9.4.3",
|
||||
"@wdio/globals": "9.4.3",
|
||||
"@wdio/junit-reporter": "9.4.3",
|
||||
"@wdio/local-runner": "9.4.3",
|
||||
"@wdio/mocha-framework": "9.4.3",
|
||||
"@typescript-eslint/eslint-plugin": "5.59.5",
|
||||
"@typescript-eslint/parser": "5.59.5",
|
||||
"@wdio/allure-reporter": "9.2.14",
|
||||
"@wdio/cli": "9.4.1",
|
||||
"@wdio/globals": "9.4.1",
|
||||
"@wdio/jasmine-framework": "9.4.1",
|
||||
"@wdio/junit-reporter": "9.2.14",
|
||||
"@wdio/local-runner": "9.4.1",
|
||||
"babel-loader": "9.1.0",
|
||||
"babel-plugin-optional-require": "0.3.1",
|
||||
"circular-dependency-plugin": "5.2.0",
|
||||
"clean-css-cli": "4.3.0",
|
||||
"css-loader": "6.8.1",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-plugin-import": "2.31.0",
|
||||
"eslint-plugin-jsdoc": "50.6.1",
|
||||
"eslint-plugin-react": "7.37.3",
|
||||
"eslint-plugin-react-native": "5.0.0",
|
||||
"eslint-plugin-typescript-sort-keys": "3.3.0",
|
||||
"eslint": "8.40.0",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-jsdoc": "46.2.6",
|
||||
"eslint-plugin-react": "7.32.2",
|
||||
"eslint-plugin-react-native": "4.0.0",
|
||||
"eslint-plugin-typescript-sort-keys": "2.3.0",
|
||||
"jetifier": "1.6.4",
|
||||
"jsonwebtoken": "9.0.2",
|
||||
"metro-react-native-babel-preset": "0.77.0",
|
||||
@@ -192,9 +189,9 @@
|
||||
"style-loader": "3.3.1",
|
||||
"traverse": "0.6.6",
|
||||
"ts-loader": "9.4.2",
|
||||
"typescript": "5.7.2",
|
||||
"typescript": "5.0.4",
|
||||
"unorm": "1.6.0",
|
||||
"webdriverio": "9.4.3",
|
||||
"webdriverio": "9.4.1",
|
||||
"webpack": "5.95.0",
|
||||
"webpack-bundle-analyzer": "4.4.2",
|
||||
"webpack-cli": "5.1.4",
|
||||
@@ -204,7 +201,7 @@
|
||||
"@xmldom/xmldom": "0.8.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.0.0",
|
||||
"node": ">=20.0.0",
|
||||
"npm": ">=10.0.0"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
@@ -223,11 +220,9 @@
|
||||
"tsc-test:native": "tsc --project tsconfig.native.json --listFilesOnly | grep -v node_modules | grep web",
|
||||
"start": "make dev",
|
||||
"test": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.conf.ts",
|
||||
"test-single": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.conf.ts --spec",
|
||||
"test-ff": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.firefox.conf.ts",
|
||||
"test-dev": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.dev.conf.ts",
|
||||
"test-grid": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.grid.conf.ts",
|
||||
"test-grid-single": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.grid.conf.ts --spec"
|
||||
"test-grid": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.grid.conf.ts"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "17.0.14",
|
||||
|
||||
@@ -69,7 +69,7 @@ cd ios && pod install && cd ..
|
||||
|
||||
## Android
|
||||
|
||||
- In your build.gradle have at least `minSdkVersion = 26`
|
||||
- In your build.gradle have at least `minSdkVersion = 24`
|
||||
- In `android/app/src/debug/AndroidManifest.xml` and `android/app/src/main/AndroidManifest.xml`, under the `</application>` tag, include
|
||||
```xml
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import static android.Manifest.permission.POST_NOTIFICATIONS;
|
||||
import static android.Manifest.permission.RECORD_AUDIO;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.facebook.react.ReactActivity;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
import com.facebook.react.modules.core.PermissionListener;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* This class implements a ReactModule and it's
|
||||
* responsible for launching/aborting a service when a conference is in progress.
|
||||
*/
|
||||
@ReactModule(name = JMOngoingConferenceModule.NAME)
|
||||
class JMOngoingConferenceModule extends ReactContextBaseJavaModule {
|
||||
|
||||
public static final String NAME = "JMOngoingConference";
|
||||
|
||||
private static final int PERMISSIONS_REQUEST_CODE = (int) (Math.random() * Short.MAX_VALUE);
|
||||
|
||||
public JMOngoingConferenceModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void launch() {
|
||||
Context context = getReactApplicationContext();
|
||||
ReactActivity reactActivity = (ReactActivity) getCurrentActivity();
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
JMOngoingConferenceService.launch(context);
|
||||
|
||||
JitsiMeetLogger.i(NAME + " launch");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PermissionListener listener = new PermissionListener() {
|
||||
@Override
|
||||
public boolean onRequestPermissionsResult(int i, String[] strings, int[] results) {
|
||||
JitsiMeetLogger.i(NAME + " Permission callback received");
|
||||
|
||||
if (results == null || results.length == 0) {
|
||||
JitsiMeetLogger.w(NAME + " Permission results are null or empty");
|
||||
return true;
|
||||
}
|
||||
|
||||
int counter = 0;
|
||||
for (int result : results) {
|
||||
if (result == PackageManager.PERMISSION_GRANTED) {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
JitsiMeetLogger.i(NAME + " Permissions granted: " + counter + "/" + results.length);
|
||||
|
||||
if (counter == results.length) {
|
||||
JitsiMeetLogger.i(NAME + " All permissions granted, launching service");
|
||||
JMOngoingConferenceService.launch(context);
|
||||
} else {
|
||||
JitsiMeetLogger.w(NAME + " Not all permissions were granted");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
JitsiMeetLogger.i(NAME + " Checking Tiramisu permissions");
|
||||
|
||||
List<String> permissionsList = new ArrayList<>();
|
||||
|
||||
permissionsList.add(POST_NOTIFICATIONS);
|
||||
permissionsList.add(RECORD_AUDIO);
|
||||
|
||||
String[] permissionsArray = new String[ permissionsList.size() ];
|
||||
permissionsArray = permissionsList.toArray( permissionsArray );
|
||||
|
||||
try {
|
||||
JitsiMeetLogger.i(NAME + " Requesting permissions: " + Arrays.toString(permissionsArray));
|
||||
reactActivity.requestPermissions(permissionsArray, PERMISSIONS_REQUEST_CODE, listener);
|
||||
} catch (Exception e) {
|
||||
JitsiMeetLogger.e(e, NAME + " Error requesting permissions");
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void abort() {
|
||||
Context context = getReactApplicationContext();
|
||||
JMOngoingConferenceService.abort(context);
|
||||
|
||||
JitsiMeetLogger.i(NAME + " abort");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.Service;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import android.content.pm.ServiceInfo;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* This class implements an Android {@link Service}, a foreground one specifically, and it's
|
||||
* responsible for presenting an ongoing notification when a conference is in progress.
|
||||
* The service will help keep the app running while in the background.
|
||||
*
|
||||
* See: https://developer.android.com/guide/components/services
|
||||
*/
|
||||
public class JMOngoingConferenceService extends Service {
|
||||
private static final String TAG = JMOngoingConferenceService.class.getSimpleName();
|
||||
|
||||
static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
|
||||
|
||||
public static void launch(Context context) {
|
||||
try {
|
||||
RNOngoingNotification.createOngoingConferenceNotificationChannel(context);
|
||||
JitsiMeetLogger.i(TAG + " Notification channel creation completed");
|
||||
} catch (Exception e) {
|
||||
JitsiMeetLogger.e(e, TAG + " Error creating notification channel");
|
||||
}
|
||||
|
||||
Intent intent = new Intent(context, JMOngoingConferenceService.class);
|
||||
|
||||
try {
|
||||
context.startForegroundService(intent);
|
||||
JitsiMeetLogger.i(TAG + " Starting foreground service");
|
||||
} catch (RuntimeException e) {
|
||||
// Avoid crashing due to ForegroundServiceStartNotAllowedException (API level 31).
|
||||
// See: https://developer.android.com/guide/components/foreground-services#background-start-restrictions
|
||||
JitsiMeetLogger.w(TAG + " Ongoing conference service not started", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void abort(Context context) {
|
||||
Intent intent = new Intent(context, JMOngoingConferenceService.class);
|
||||
context.stopService(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
JitsiMeetLogger.i(TAG + " onCreate called");
|
||||
|
||||
try {
|
||||
Notification notification = RNOngoingNotification.buildOngoingConferenceNotification(this);
|
||||
JitsiMeetLogger.i(TAG + " Notification build result: " + (notification != null));
|
||||
|
||||
if (notification == null) {
|
||||
stopSelf();
|
||||
JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null");
|
||||
} else {
|
||||
JitsiMeetLogger.i(TAG + " Starting service in foreground with notification");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK | ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE);
|
||||
} else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
|
||||
startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK);
|
||||
} else {
|
||||
startForeground(NOTIFICATION_ID, notification);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
JitsiMeetLogger.e(e, TAG + " Error in onCreate");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ public class JitsiMeetReactNativePackage implements ReactPackage {
|
||||
new AndroidSettingsModule(reactContext),
|
||||
new AppInfoModule(reactContext),
|
||||
new AudioModeModule(reactContext),
|
||||
new JMOngoingConferenceModule(reactContext),
|
||||
new JavaScriptSandboxModule(reactContext),
|
||||
new LocaleDetector(reactContext),
|
||||
new LogBridgeModule(reactContext),
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class for creating the ongoing notification which is used with
|
||||
* {@link JMOngoingConferenceService}. It allows the user to easily get back to the app
|
||||
* and to hangup from within the notification itself.
|
||||
*/
|
||||
class RNOngoingNotification {
|
||||
private static final String TAG = RNOngoingNotification.class.getSimpleName();
|
||||
|
||||
static final String RN_ONGOING_CONFERENCE_CHANNEL_ID = "OngoingConferenceChannel";
|
||||
|
||||
static void createOngoingConferenceNotificationChannel(Context context) {
|
||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Service.NOTIFICATION_SERVICE);
|
||||
NotificationChannel channel = notificationManager.getNotificationChannel(RN_ONGOING_CONFERENCE_CHANNEL_ID);
|
||||
|
||||
if (channel != null) {
|
||||
JitsiMeetLogger.i(TAG + " Notification channel already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
channel = new NotificationChannel(
|
||||
RN_ONGOING_CONFERENCE_CHANNEL_ID,
|
||||
context.getString(R.string.ongoing_notification_channel_name),
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
);
|
||||
|
||||
channel.enableVibration(true);
|
||||
channel.setShowBadge(true);
|
||||
channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
|
||||
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
JitsiMeetLogger.i(TAG + " Notification channel created with importance: " + channel.getImportance());
|
||||
}
|
||||
|
||||
static Notification buildOngoingConferenceNotification(Context context) {
|
||||
if (context == null) {
|
||||
JitsiMeetLogger.w(TAG + " Cannot create notification: no current context");
|
||||
return null;
|
||||
}
|
||||
|
||||
JitsiMeetLogger.i(TAG + " Creating notification with context: " + context);
|
||||
|
||||
// Creating an intent to launch app's main activity
|
||||
Intent intent = context.getPackageManager()
|
||||
.getLaunchIntentForPackage(context.getPackageName());
|
||||
assert intent != null;
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
|
||||
// Creating PendingIntent
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
0,
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
|
||||
);
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, RN_ONGOING_CONFERENCE_CHANNEL_ID);
|
||||
|
||||
builder
|
||||
.setCategory(NotificationCompat.CATEGORY_CALL)
|
||||
.setContentTitle(context.getString(R.string.ongoing_notification_title))
|
||||
.setContentText(context.getString(R.string.ongoing_notification_text))
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setOngoing(true)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setUsesChronometer(true)
|
||||
.setAutoCancel(false)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setSmallIcon(context.getResources().getIdentifier("ic_notification", "drawable", context.getPackageName()))
|
||||
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
|
||||
.setContentIntent(pendingIntent);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,6 @@
|
||||
"moment-duration-format": "0.0.0",
|
||||
"optional-require": "0.0.0",
|
||||
"promise.allsettled": "0.0.0",
|
||||
"promise.withresolvers": "0.0.0",
|
||||
"punycode": "0.0.0",
|
||||
"react-emoji-render": "0.0.0",
|
||||
"react-i18next": "0.0.0",
|
||||
@@ -59,6 +58,7 @@
|
||||
"peerDependencies": {
|
||||
"@amplitude/react-native": "0.0.0",
|
||||
"@giphy/react-native-sdk": "0.0.0",
|
||||
"@react-native/metro-config": "*",
|
||||
"@react-native-async-storage/async-storage": "0.0.0",
|
||||
"@react-native-clipboard/clipboard": "0.0.0",
|
||||
"@react-native-community/netinfo": "0.0.0",
|
||||
|
||||
22
react-native-sdk/update_sdk_dependencies.js
vendored
22
react-native-sdk/update_sdk_dependencies.js
vendored
@@ -1,13 +1,9 @@
|
||||
const fs = require('fs');
|
||||
const semver = require('semver');
|
||||
|
||||
const packageJSON = require('../package.json');
|
||||
|
||||
const SDKPackageJSON = require('./package.json');
|
||||
|
||||
// Skip checking these.
|
||||
const skipDeps = [ 'react', 'react-native' ];
|
||||
|
||||
/**
|
||||
* Merges the dependency versions from the root package.json with the dependencies of the SDK package.json.
|
||||
*/
|
||||
@@ -22,21 +18,15 @@ function mergeDependencyVersions() {
|
||||
|
||||
// Updates SDK peer dependencies.
|
||||
for (const key in packageJSON.dependencies) {
|
||||
if (SDKPackageJSON.peerDependencies.hasOwnProperty(key) && !skipDeps.includes(key)) {
|
||||
SDKPackageJSON.peerDependencies[key] = packageJSON.dependencies[key];
|
||||
if (SDKPackageJSON.peerDependencies.hasOwnProperty(key)) {
|
||||
|
||||
// Updates all peer dependencies except react and react-native.
|
||||
if (key !== 'react' && key !== 'react-native') {
|
||||
SDKPackageJSON.peerDependencies[key] = packageJSON.dependencies[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set RN peer dependency.
|
||||
const rnVersion = semver.parse(packageJSON.dependencies['react-native']);
|
||||
|
||||
if (!rnVersion) {
|
||||
throw new Error('failed to parse React Native version');
|
||||
}
|
||||
|
||||
// In RN the "major" version is the Semver minor.
|
||||
SDKPackageJSON.peerDependencies['react-native'] = `~0.${rnVersion.minor}.0`;
|
||||
|
||||
// Updates SDK overrides dependencies.
|
||||
for (const key in packageJSON.overrides) {
|
||||
if (SDKPackageJSON.overrides.hasOwnProperty(key)) {
|
||||
|
||||
@@ -14,14 +14,24 @@ module.exports = {
|
||||
project: [ './tsconfig.web.json', './tsconfig.native.json' ]
|
||||
},
|
||||
rules: {
|
||||
// TODO: Remove these and fix the warnings
|
||||
'@typescript-eslint/no-unsafe-function-type': 0,
|
||||
'@typescript-eslint/no-wrapper-object-types': 0,
|
||||
|
||||
'@typescript-eslint/no-require-imports': 0
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
'selector': 'interface',
|
||||
'format': [ 'PascalCase' ],
|
||||
'custom': {
|
||||
'regex': '^I[A-Z]',
|
||||
'match': true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
'rules': {
|
||||
// XXX remove this eventually.
|
||||
'react/jsx-indent-props': 0
|
||||
},
|
||||
'settings': {
|
||||
'react': {
|
||||
'version': 'detect'
|
||||
|
||||
@@ -4,10 +4,8 @@ import ReactDOM from 'react-dom';
|
||||
import AlwaysOnTop from './AlwaysOnTop';
|
||||
|
||||
// Render the main/root Component.
|
||||
/* eslint-disable-next-line react/no-deprecated */
|
||||
ReactDOM.render(<AlwaysOnTop />, document.getElementById('react'));
|
||||
|
||||
window.addEventListener(
|
||||
'beforeunload',
|
||||
/* eslint-disable-next-line react/no-deprecated */
|
||||
() => ReactDOM.unmountComponentAtNode(document.getElementById('react') ?? document.body));
|
||||
|
||||
@@ -311,7 +311,7 @@ export function createInviteDialogEvent(
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function createNetworkInfoEvent({ isOnline, networkType, details }:
|
||||
{ details?: Object; isOnline: boolean; networkType?: string; }) {
|
||||
{ details?: Object; isOnline: boolean; networkType?: string; }) {
|
||||
const attributes: {
|
||||
details?: Object;
|
||||
isOnline: boolean;
|
||||
|
||||
@@ -158,3 +158,4 @@ export function maybeRedirectToTokenAuthUrl(
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,9 +27,11 @@ export interface IProps {
|
||||
*/
|
||||
export class AbstractApp<P extends IProps = IProps> extends BaseApp<P> {
|
||||
/**
|
||||
* The deferred for the initialization {{promise, resolve, reject}}.
|
||||
* The deferred for the initialisation {{promise, resolve, reject}}.
|
||||
*/
|
||||
_init: PromiseWithResolvers<any>;
|
||||
_init: {
|
||||
promise: Promise<any>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the app.
|
||||
|
||||
@@ -140,7 +140,10 @@ function _getWebWelcomePageRoute(state: IReduxState) {
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
function _getEmptyRoute(): { component: React.ReactNode; href?: string; } {
|
||||
function _getEmptyRoute(): {
|
||||
component: React.ReactNode;
|
||||
href?: string;
|
||||
} {
|
||||
return {
|
||||
component: BlankPage,
|
||||
href: undefined
|
||||
|
||||
@@ -113,7 +113,8 @@ function _isMaybeSplitBrainError(getState: IStore['getState'], action: AnyAction
|
||||
const { error } = action;
|
||||
const isShardChangedError = error
|
||||
&& error.message === 'item-not-found'
|
||||
&& error.details?.shard_changed;
|
||||
&& error.details
|
||||
&& error.details.shard_changed;
|
||||
|
||||
if (isShardChangedError) {
|
||||
const state = getState();
|
||||
|
||||
@@ -38,6 +38,7 @@ import '../jaas/reducer';
|
||||
import '../large-video/reducer';
|
||||
import '../lobby/reducer';
|
||||
import '../notifications/reducer';
|
||||
import '../overlay/reducer';
|
||||
import '../participants-pane/reducer';
|
||||
import '../polls/reducer';
|
||||
import '../polls-history/reducer';
|
||||
|
||||
@@ -57,6 +57,7 @@ import { INoAudioSignalState } from '../no-audio-signal/reducer';
|
||||
import { INoiseDetectionState } from '../noise-detection/reducer';
|
||||
import { INoiseSuppressionState } from '../noise-suppression/reducer';
|
||||
import { INotificationsState } from '../notifications/reducer';
|
||||
import { IOverlayState } from '../overlay/reducer';
|
||||
import { IParticipantsPaneState } from '../participants-pane/reducer';
|
||||
import { IPollsState } from '../polls/reducer';
|
||||
import { IPollsHistoryState } from '../polls-history/reducer';
|
||||
@@ -146,6 +147,7 @@ export interface IReduxState {
|
||||
'features/noise-detection': INoiseDetectionState;
|
||||
'features/noise-suppression': INoiseSuppressionState;
|
||||
'features/notifications': INotificationsState;
|
||||
'features/overlay': IOverlayState;
|
||||
'features/participants-pane': IParticipantsPaneState;
|
||||
'features/polls': IPollsState;
|
||||
'features/polls-history': IPollsHistoryState;
|
||||
|
||||
@@ -121,7 +121,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
if (isTokenAuthEnabled(config)
|
||||
&& config.tokenAuthUrlAutoRedirect
|
||||
&& state['features/base/jwt'].jwt) {
|
||||
// auto redirect is turned on and we have successfully logged in
|
||||
// auto redirect is turned on and we have succesfully logged in
|
||||
// let's mark that
|
||||
dispatch(setTokenAuthUrlSuccess(true));
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import PersistenceRegistry from '../../redux/PersistenceRegistry';
|
||||
import ReducerRegistry from '../../redux/ReducerRegistry';
|
||||
import StateListenerRegistry from '../../redux/StateListenerRegistry';
|
||||
import SoundCollection from '../../sounds/components/SoundCollection';
|
||||
import { createDeferred } from '../../util/helpers';
|
||||
import { appWillMount, appWillUnmount } from '../actions';
|
||||
import logger from '../logger';
|
||||
|
||||
@@ -45,7 +46,9 @@ export default class BaseApp<P> extends Component<P, IState> {
|
||||
/**
|
||||
* The deferred for the initialisation {{promise, resolve, reject}}.
|
||||
*/
|
||||
_init: PromiseWithResolvers<any>;
|
||||
_init: {
|
||||
promise: Promise<any>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes a new {@code BaseApp} instance.
|
||||
@@ -76,7 +79,7 @@ export default class BaseApp<P> extends Component<P, IState> {
|
||||
* @see {@link #_initStorage}
|
||||
* @type {Promise}
|
||||
*/
|
||||
this._init = Promise.withResolvers();
|
||||
this._init = createDeferred<void>();
|
||||
|
||||
try {
|
||||
await this._initStorage();
|
||||
|
||||
@@ -248,7 +248,8 @@ function _conferenceFailed({ dispatch, getState }: IStore, next: Function, actio
|
||||
}
|
||||
|
||||
!error.recoverable
|
||||
&& conference?.leave(CONFERENCE_LEAVE_REASONS.UNRECOVERABLE_ERROR).catch((reason: Error) => {
|
||||
&& conference
|
||||
&& conference.leave(CONFERENCE_LEAVE_REASONS.UNRECOVERABLE_ERROR).catch((reason: Error) => {
|
||||
// Even though we don't care too much about the failure, it may be
|
||||
// good to know that it happen, so log it (on the info level).
|
||||
logger.info('JitsiConference.leave() rejected with:', reason);
|
||||
@@ -429,7 +430,7 @@ function _connectionFailed({ dispatch, getState }: IStore, next: Function, actio
|
||||
} as INotificationProps;
|
||||
|
||||
const { locationURL = { href: '' } as URL } = getState()['features/base/connection'];
|
||||
const { tenant = '' } = parseURIString(locationURL.href) || {};
|
||||
const { tenant } = parseURIString(locationURL.href) || {};
|
||||
|
||||
if (tenant.startsWith('-') || tenant.endsWith('-')) {
|
||||
notificationProps.descriptionKey = 'notify.invalidTenantHyphenDescription';
|
||||
@@ -550,7 +551,7 @@ function _pinParticipant({ getState }: IStore, next: Function, action: AnyAction
|
||||
const actionName = id ? ACTION_PINNED : ACTION_UNPINNED;
|
||||
const local
|
||||
= participantById?.local
|
||||
|| (!id && pinnedParticipant?.local);
|
||||
|| (!id && pinnedParticipant && pinnedParticipant.local);
|
||||
let participantIdForEvent;
|
||||
|
||||
if (local) {
|
||||
|
||||
@@ -495,7 +495,7 @@ function _conferenceJoined(state: IConferenceState, { conference }: { conference
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _conferenceLeftOrWillLeave(state: IConferenceState, { conference, type }:
|
||||
{ conference: IJitsiConference; type: string; }) {
|
||||
{ conference: IJitsiConference; type: string; }) {
|
||||
const nextState = { ...state };
|
||||
|
||||
// The redux action CONFERENCE_LEFT is the last time that we should be
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { ToolbarButton } from '../../toolbox/types';
|
||||
import { ILoggingConfig } from '../logging/types';
|
||||
import { DesktopSharingSourceType } from '../tracks/types';
|
||||
|
||||
type ButtonsWithNotifyClick = 'camera' |
|
||||
'chat' |
|
||||
@@ -217,10 +215,6 @@ export interface IConfig {
|
||||
hideAutoAssignButton?: boolean;
|
||||
hideJoinRoomButton?: boolean;
|
||||
};
|
||||
bridgeChannel?: {
|
||||
ignoreDomain?: string;
|
||||
preferSctp?: boolean;
|
||||
};
|
||||
buttonsWithNotifyClick?: Array<ButtonsWithNotifyClick | {
|
||||
key: ButtonsWithNotifyClick;
|
||||
preventExecution: boolean;
|
||||
@@ -281,15 +275,11 @@ export interface IConfig {
|
||||
max?: number;
|
||||
min?: number;
|
||||
};
|
||||
desktopSharingSources?: Array<DesktopSharingSourceType>;
|
||||
dialInConfCodeUrl?: string;
|
||||
dialInNumbersUrl?: string;
|
||||
dialOutAuthUrl?: string;
|
||||
dialOutRegionUrl?: string;
|
||||
disable1On1Mode?: boolean | null;
|
||||
disableAEC?: boolean;
|
||||
disableAGC?: boolean;
|
||||
disableAP?: boolean;
|
||||
disableAddingBackgroundImages?: boolean;
|
||||
disableAudioLevels?: boolean;
|
||||
disableBeforeUnloadHandlers?: boolean;
|
||||
@@ -304,13 +294,11 @@ export interface IConfig {
|
||||
disableJoinLeaveSounds?: boolean;
|
||||
disableLocalVideoFlip?: boolean;
|
||||
disableModeratorIndicator?: boolean;
|
||||
disableNS?: boolean;
|
||||
disablePolls?: boolean;
|
||||
disableProfile?: boolean;
|
||||
disableReactions?: boolean;
|
||||
disableReactionsModeration?: boolean;
|
||||
disableRecordAudioNotification?: boolean;
|
||||
disableRemoteControl?: boolean;
|
||||
disableRemoteMute?: boolean;
|
||||
disableRemoveRaisedHandOnFocus?: boolean;
|
||||
disableResponsiveTiles?: boolean;
|
||||
@@ -328,7 +316,6 @@ export interface IConfig {
|
||||
disableVirtualBackground?: boolean;
|
||||
disabledNotifications?: Array<string>;
|
||||
disabledSounds?: Array<Sounds>;
|
||||
displayJids?: boolean;
|
||||
doNotFlipLocalVideo?: boolean;
|
||||
doNotStoreRoom?: boolean;
|
||||
dropbox?: {
|
||||
@@ -358,6 +345,7 @@ export interface IConfig {
|
||||
maxMessagesPerSecond?: number;
|
||||
numRequests?: number;
|
||||
};
|
||||
enableAutomaticUrlCopy?: boolean;
|
||||
enableCalendarIntegration?: boolean;
|
||||
enableClosePage?: boolean;
|
||||
enableDisplayNameInStats?: boolean;
|
||||
@@ -371,7 +359,6 @@ export interface IConfig {
|
||||
enableOpusRed?: boolean;
|
||||
enableRemb?: boolean;
|
||||
enableSaveLogs?: boolean;
|
||||
enableTalkWhileMuted?: boolean;
|
||||
enableTcc?: boolean;
|
||||
enableWebHIDFeature?: boolean;
|
||||
enableWelcomePage?: boolean;
|
||||
@@ -385,6 +372,7 @@ export interface IConfig {
|
||||
faceCenteringThreshold?: number;
|
||||
};
|
||||
feedbackPercentage?: number;
|
||||
fileRecordingsEnabled?: boolean;
|
||||
fileRecordingsServiceEnabled?: boolean;
|
||||
fileRecordingsServiceSharingEnabled?: boolean;
|
||||
filmstrip?: {
|
||||
@@ -394,11 +382,11 @@ export interface IConfig {
|
||||
disabled?: boolean;
|
||||
minParticipantCountForTopPanel?: number;
|
||||
};
|
||||
firefox_fake_device?: string;
|
||||
flags?: {
|
||||
ssrcRewritingEnabled: boolean;
|
||||
};
|
||||
focusUserJid?: string;
|
||||
forceTurnRelay?: boolean;
|
||||
gatherStats?: boolean;
|
||||
giphy?: {
|
||||
displayMode?: 'all' | 'tile' | 'chat';
|
||||
@@ -438,7 +426,6 @@ export interface IConfig {
|
||||
};
|
||||
iAmRecorder?: boolean;
|
||||
iAmSipGateway?: boolean;
|
||||
ignoreStartMuted?: boolean;
|
||||
inviteAppName?: string | null;
|
||||
inviteServiceCallFlowsUrl?: string;
|
||||
inviteServiceUrl?: string;
|
||||
@@ -471,7 +458,6 @@ export interface IConfig {
|
||||
};
|
||||
localSubject?: string;
|
||||
locationURL?: URL;
|
||||
logging?: ILoggingConfig;
|
||||
mainToolbarButtons?: Array<Array<string>>;
|
||||
maxFullResolutionParticipants?: number;
|
||||
microsoftApiApplicationClientID?: string;
|
||||
@@ -493,7 +479,6 @@ export interface IConfig {
|
||||
enabled?: boolean;
|
||||
iceTransportPolicy?: string;
|
||||
mobileCodecPreferenceOrder?: Array<string>;
|
||||
mobileScreenshareCodec?: string;
|
||||
stunServers?: Array<{ urls: string; }>;
|
||||
};
|
||||
participantMenuButtonsWithNotifyClick?: Array<string | ParticipantMenuButtonsWithNotifyClick | {
|
||||
@@ -586,9 +571,7 @@ export interface IConfig {
|
||||
subject?: string;
|
||||
testing?: {
|
||||
assumeBandwidth?: boolean;
|
||||
debugAudioLevels?: boolean;
|
||||
dumpTranscript?: boolean;
|
||||
failICE?: boolean;
|
||||
noAutoPlayVideo?: boolean;
|
||||
p2pTestMode?: boolean;
|
||||
skipInterimTranscriptions?: boolean;
|
||||
@@ -636,13 +619,6 @@ export interface IConfig {
|
||||
mobileCodecPreferenceOrder?: Array<string>;
|
||||
persist?: boolean;
|
||||
};
|
||||
visitors?: {
|
||||
enableMediaOnPromote?: {
|
||||
audio?: boolean;
|
||||
video?: boolean;
|
||||
};
|
||||
queueService: string;
|
||||
};
|
||||
watchRTCConfigParams?: IWatchRTCConfiguration;
|
||||
webhookProxyUrl?: string;
|
||||
webrtcIceTcpDisable?: boolean;
|
||||
|
||||
@@ -22,7 +22,6 @@ export default [
|
||||
'apiLogLevels',
|
||||
'avgRtpStatsN',
|
||||
'backgroundAlpha',
|
||||
'brandingRoomAlias',
|
||||
'breakoutRooms',
|
||||
'bridgeChannel',
|
||||
'buttonsWithNotifyClick',
|
||||
@@ -78,6 +77,9 @@ export default [
|
||||
'connectionIndicators',
|
||||
'constraints',
|
||||
'customToolbarButtons',
|
||||
'brandingRoomAlias',
|
||||
'debug',
|
||||
'debugAudioLevels',
|
||||
'deeplinking.disabled',
|
||||
'deeplinking.desktop.enabled',
|
||||
'defaultLocalDisplayName',
|
||||
@@ -97,6 +99,7 @@ export default [
|
||||
'disabledSounds',
|
||||
'disableFilmstripAutohiding',
|
||||
'disableInitialGUM',
|
||||
'disableHPF',
|
||||
'disableInviteFunctions',
|
||||
'disableIncomingMessageSound',
|
||||
'disableJoinLeaveSounds',
|
||||
@@ -145,9 +148,14 @@ export default [
|
||||
'enableNoAudioDetection',
|
||||
'enableNoisyMicDetection',
|
||||
'enableTcc',
|
||||
'enableAutomaticUrlCopy',
|
||||
'etherpad_base',
|
||||
'faceLandmarks',
|
||||
'failICE',
|
||||
'feedbackPercentage',
|
||||
'fileRecordingsEnabled',
|
||||
'filmstrip',
|
||||
'firefox_fake_device',
|
||||
'flags',
|
||||
'forceTurnRelay',
|
||||
'gatherStats',
|
||||
@@ -164,8 +172,10 @@ export default [
|
||||
'hideAddRoomButton',
|
||||
'hideEmailInSettings',
|
||||
'hideLobbyButton',
|
||||
'hosts',
|
||||
'iAmRecorder',
|
||||
'iAmSipGateway',
|
||||
'iceTransportPolicy',
|
||||
'ignoreStartMuted',
|
||||
'inviteAppName',
|
||||
'liveStreaming.enabled',
|
||||
@@ -181,12 +191,7 @@ export default [
|
||||
'notificationTimeouts',
|
||||
'openSharedDocumentOnJoin',
|
||||
'opusMaxAverageBitrate',
|
||||
'p2p.backToP2PDelay',
|
||||
'p2p.codecPreferenceOrder',
|
||||
'p2p.enabled',
|
||||
'p2p.iceTransportPolicy',
|
||||
'p2p.mobileCodecPreferenceOrder',
|
||||
'p2p.mobileScreenshareCodec',
|
||||
'p2p',
|
||||
'participantMenuButtonsWithNotifyClick',
|
||||
'participantsPane',
|
||||
'pcStatsInterval',
|
||||
@@ -228,17 +233,7 @@ export default [
|
||||
'useTurnUdp',
|
||||
'videoQuality',
|
||||
'visitors.enableMediaOnPromote',
|
||||
'watchRTCConfigParams.allowBrowserLogCollection',
|
||||
'watchRTCConfigParams.collectionInterval',
|
||||
'watchRTCConfigParams.console',
|
||||
'watchRTCConfigParams.debug',
|
||||
'watchRTCConfigParams.keys',
|
||||
'watchRTCConfigParams.logGetStats',
|
||||
'watchRTCConfigParams.rtcApiKey',
|
||||
'watchRTCConfigParams.rtcPeerId',
|
||||
'watchRTCConfigParams.rtcRoomId',
|
||||
'watchRTCConfigParams.rtcTags',
|
||||
'watchRTCConfigParams.rtcToken',
|
||||
'watchRTCConfigParams',
|
||||
'webrtcIceTcpDisable',
|
||||
'webrtcIceUdpDisable',
|
||||
'whiteboard.enabled'
|
||||
|
||||
@@ -89,7 +89,7 @@ export function _setDeeplinkingDefaults(deeplinking: IDeeplinkingConfig) {
|
||||
android.downloadLink = android.downloadLink
|
||||
|| 'https://play.google.com/store/apps/details?id=org.jitsi.meet';
|
||||
android.appPackage = android.appPackage || 'org.jitsi.meet';
|
||||
android.fDroidUrl = android.fDroidUrl || 'https://f-droid.org/packages/org.jitsi.meet/';
|
||||
android.fDroidUrl = android.fDroidUrl || 'https://f-droid.org/en/packages/org.jitsi.meet/';
|
||||
if (android.dynamicLink) {
|
||||
android.dynamicLink.apn = android.dynamicLink.apn || 'org.jitsi.meet';
|
||||
android.dynamicLink.appCode = android.dynamicLink.appCode || 'w2atb';
|
||||
|
||||
@@ -22,12 +22,15 @@ export default [
|
||||
'DISABLE_DOMINANT_SPEAKER_INDICATOR',
|
||||
'DISABLE_FOCUS_INDICATOR',
|
||||
'DISABLE_PRIVATE_MESSAGES',
|
||||
'DISABLE_RINGING',
|
||||
'DISABLE_TRANSCRIPTION_SUBTITLES',
|
||||
'DISABLE_VIDEO_BACKGROUND',
|
||||
'DISPLAY_WELCOME_PAGE_CONTENT',
|
||||
'ENABLE_DIAL_OUT',
|
||||
'ENABLE_FEEDBACK_ANIMATION',
|
||||
'FILM_STRIP_MAX_HEIGHT',
|
||||
'GENERATE_ROOMNAMES_ON_WELCOME_PAGE',
|
||||
'HIDE_INVITE_MORE_HEADER',
|
||||
'INDICATOR_FONT_SIZES',
|
||||
'INITIAL_TOOLBAR_TIMEOUT',
|
||||
'LANG_DETECTION',
|
||||
|
||||
@@ -63,6 +63,7 @@ export interface IConfigState extends IConfig {
|
||||
analysis?: {
|
||||
obfuscateRoomName?: boolean;
|
||||
};
|
||||
disableRemoteControl?: boolean;
|
||||
error?: Error;
|
||||
oldConfig?: {
|
||||
bosh?: string;
|
||||
@@ -74,6 +75,13 @@ export interface IConfigState extends IConfig {
|
||||
p2p?: object;
|
||||
websocket?: string;
|
||||
};
|
||||
visitors?: {
|
||||
enableMediaOnPromote?: {
|
||||
audio?: boolean;
|
||||
video?: boolean;
|
||||
};
|
||||
queueService: string;
|
||||
};
|
||||
}
|
||||
|
||||
ReducerRegistry.register<IConfigState>('features/base/config', (state = _getInitialState(), action): IConfigState => {
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
/**
|
||||
* Prefixes of devices that will be filtered from the device list.
|
||||
*
|
||||
* NOTE: It seems that the filtered devices can't be set
|
||||
* NOTE: Currently we filter only 'Microsoft Teams Audio Device' virtual device. It seems that it can't be set
|
||||
* as default device on the OS level and this use case is not handled in the code. If we add more device prefixes that
|
||||
* can be default devices we should make sure to handle the default device use case.
|
||||
*/
|
||||
export const DEVICE_LABEL_PREFIXES_TO_IGNORE = [
|
||||
'Microsoft Teams Audio Device',
|
||||
'ZoomAudioDevice'
|
||||
];
|
||||
export const DEVICE_LABEL_PREFIXES_TO_IGNORE = [ 'Microsoft Teams Audio Device' ];
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
OPEN_SHEET
|
||||
} from './actionTypes';
|
||||
import { isDialogOpen } from './functions';
|
||||
import logger from './logger';
|
||||
|
||||
/**
|
||||
* Signals Dialog to close its dialog.
|
||||
@@ -24,8 +23,6 @@ import logger from './logger';
|
||||
* }}
|
||||
*/
|
||||
export function hideDialog(component?: ComponentType<any>) {
|
||||
logger.info(`Hide dialog: ${getComponentDisplayName(component)}`);
|
||||
|
||||
return {
|
||||
type: HIDE_DIALOG,
|
||||
component
|
||||
@@ -58,8 +55,6 @@ export function hideSheet() {
|
||||
* }}
|
||||
*/
|
||||
export function openDialog(component: ComponentType<any>, componentProps?: Object) {
|
||||
logger.info(`Open dialog: ${getComponentDisplayName(component)}`);
|
||||
|
||||
return {
|
||||
type: OPEN_DIALOG,
|
||||
component,
|
||||
@@ -106,21 +101,3 @@ export function toggleDialog(component: ComponentType<any>, componentProps?: Obj
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a printable name for a dialog component.
|
||||
*
|
||||
* @param {Object} component - The component to extract the name for.
|
||||
*
|
||||
* @returns {string} The display name.
|
||||
*/
|
||||
function getComponentDisplayName(component?: ComponentType<any>) {
|
||||
if (!component) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const name = component.displayName ?? component.name ?? 'Component';
|
||||
|
||||
return name.replace('withI18nextTranslation(Connect(', '') // dialogs with translations
|
||||
.replace('))', ''); // dialogs with translations suffix
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
? action.value
|
||||
: store.getState()['features/dynamic-branding'];
|
||||
|
||||
if (language && labels?.[language]) {
|
||||
if (language && labels && labels[language]) {
|
||||
changeLanguageBundle(language, labels[language])
|
||||
.catch(err => {
|
||||
logger.log('Error setting dynamic language bundle', err);
|
||||
|
||||
@@ -237,7 +237,7 @@ function _undoOverwriteLocalParticipant(
|
||||
* }}
|
||||
*/
|
||||
function _user2participant({ avatar, avatarUrl, email, id, name, 'hidden-from-recorder': hiddenFromRecorder }:
|
||||
{ avatar?: string; avatarUrl?: string; email: string; 'hidden-from-recorder': string | boolean;
|
||||
{ avatar?: string; avatarUrl?: string; email: string; 'hidden-from-recorder': string | boolean;
|
||||
id: string; name: string; }) {
|
||||
const participant: {
|
||||
avatarURL?: string;
|
||||
|
||||
@@ -25,6 +25,10 @@ export function createLocalTrack(type: string, deviceId: string | null, timeout?
|
||||
JitsiMeetJS.createLocalTracks({
|
||||
cameraDeviceId: deviceId,
|
||||
devices: [ type ],
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
firefox_fake_device:
|
||||
window.config?.firefox_fake_device,
|
||||
micDeviceId: deviceId,
|
||||
timeout,
|
||||
...additionalOptions
|
||||
|
||||
@@ -5,11 +5,10 @@ import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
import { equals, set } from '../redux/functions';
|
||||
|
||||
import { SET_LOGGING_CONFIG, SET_LOG_COLLECTOR } from './actionTypes';
|
||||
import { ILoggingConfig, LogLevel } from './types';
|
||||
|
||||
const DEFAULT_LOGGING_CONFIG: ILoggingConfig = {
|
||||
const DEFAULT_LOGGING_CONFIG = {
|
||||
// default log level for the app and lib-jitsi-meet
|
||||
defaultLogLevel: 'trace',
|
||||
defaultLogLevel: 'trace' as LogLevel,
|
||||
|
||||
// Option to disable LogCollector (which stores the logs)
|
||||
// disableLogCollector: true,
|
||||
@@ -17,8 +16,8 @@ const DEFAULT_LOGGING_CONFIG: ILoggingConfig = {
|
||||
loggers: {
|
||||
// The following are too verbose in their logging with the
|
||||
// {@link #defaultLogLevel}:
|
||||
'modules/RTC/TraceablePeerConnection.js': 'info',
|
||||
'modules/xmpp/strophe.util.js': 'log'
|
||||
'modules/RTC/TraceablePeerConnection.js': 'info' as LogLevel,
|
||||
'modules/xmpp/strophe.util.js': 'log' as LogLevel
|
||||
}
|
||||
};
|
||||
|
||||
@@ -40,11 +39,11 @@ const DEFAULT_STATE = {
|
||||
|
||||
// Reduce default verbosity on mobile, it kills performance.
|
||||
if (navigator.product === 'ReactNative') {
|
||||
const RN_LOGGERS: { [key: string]: LogLevel; } = {
|
||||
'modules/sdp/SDPUtil.js': 'info',
|
||||
'modules/xmpp/ChatRoom.js': 'warn',
|
||||
'modules/xmpp/JingleSessionPC.js': 'info',
|
||||
'modules/xmpp/strophe.jingle.js': 'info'
|
||||
const RN_LOGGERS = {
|
||||
'modules/sdp/SDPUtil.js': 'info' as LogLevel,
|
||||
'modules/xmpp/ChatRoom.js': 'warn' as LogLevel,
|
||||
'modules/xmpp/JingleSessionPC.js': 'info' as LogLevel,
|
||||
'modules/xmpp/strophe.jingle.js': 'info' as LogLevel
|
||||
};
|
||||
|
||||
DEFAULT_STATE.config.loggers = {
|
||||
@@ -53,8 +52,16 @@ if (navigator.product === 'ReactNative') {
|
||||
};
|
||||
}
|
||||
|
||||
type LogLevel = 'trace' | 'log' | 'info' | 'warn' | 'error';
|
||||
|
||||
export interface ILoggingState {
|
||||
config: ILoggingConfig;
|
||||
config: {
|
||||
defaultLogLevel: LogLevel;
|
||||
disableLogCollector?: boolean;
|
||||
loggers: {
|
||||
[key: string]: LogLevel;
|
||||
};
|
||||
};
|
||||
logCollector?: {
|
||||
flush: () => void;
|
||||
start: () => void;
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
export type LogLevel = 'trace' | 'log' | 'info' | 'warn' | 'error';
|
||||
|
||||
export interface ILoggingConfig {
|
||||
defaultLogLevel?: LogLevel;
|
||||
disableLogCollector?: boolean;
|
||||
loggers?: {
|
||||
[key: string]: LogLevel;
|
||||
};
|
||||
}
|
||||
@@ -228,7 +228,7 @@ class AudioTrack extends Component<IProps> {
|
||||
* @returns {void}
|
||||
*/
|
||||
_detachTrack(track?: ITrack) {
|
||||
if (this._ref?.current && track?.jitsiTrack) {
|
||||
if (this._ref?.current && track && track.jitsiTrack) {
|
||||
clearTimeout(this._playTimeout);
|
||||
this._playTimeout = undefined;
|
||||
track.jitsiTrack.detach(this._ref.current);
|
||||
|
||||
@@ -358,7 +358,7 @@ class Video extends Component<IProps> {
|
||||
* @returns {void}
|
||||
*/
|
||||
_detachTrack(videoTrack?: Partial<ITrack>) {
|
||||
if (this._videoElement && videoTrack?.jitsiTrack) {
|
||||
if (this._videoElement && videoTrack && videoTrack.jitsiTrack) {
|
||||
videoTrack.jitsiTrack.detach(this._videoElement);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@ export const MEDIA_TYPE: {
|
||||
AUDIO: MediaType;
|
||||
SCREENSHARE: MediaType;
|
||||
VIDEO: MediaType;
|
||||
} = {
|
||||
AUDIO: 'audio',
|
||||
SCREENSHARE: 'screenshare',
|
||||
VIDEO: 'video'
|
||||
};
|
||||
} = {
|
||||
AUDIO: 'audio',
|
||||
SCREENSHARE: 'screenshare',
|
||||
VIDEO: 'video'
|
||||
};
|
||||
|
||||
|
||||
/* eslint-disable no-bitwise */
|
||||
|
||||
@@ -3,6 +3,7 @@ import { AnyAction, combineReducers } from 'redux';
|
||||
import { CONFERENCE_FAILED, CONFERENCE_LEFT } from '../conference/actionTypes';
|
||||
import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
import { TRACK_REMOVED } from '../tracks/actionTypes';
|
||||
import { DefferedPromise, createDeferred } from '../util/helpers';
|
||||
|
||||
import {
|
||||
GUM_PENDING,
|
||||
@@ -92,18 +93,17 @@ function _audio(state: IAudioState = _AUDIO_INITIAL_MEDIA_STATE, action: AnyActi
|
||||
// initial track creation haven't been started we would wait for it to finish before starting to join the room.
|
||||
// NOTE: The previous implementation was using the GUM promise from conference.init. But it turned out that connect
|
||||
// may finish even before conference.init is executed.
|
||||
const DEFAULT_INITIAL_PROMISE_STATE = Promise.withResolvers<IInitialGUMPromiseResult>();
|
||||
const DEFAULT_INITIAL_PROMISE_STATE = createDeferred<IInitialGUMPromiseResult>();
|
||||
|
||||
/**
|
||||
* Reducer for the common properties in media state.
|
||||
* Reducer fot the common properties in media state.
|
||||
*
|
||||
* @param {ICommonState} state - Common media state.
|
||||
* @param {Object} action - Action object.
|
||||
* @param {string} action.type - Type of action.
|
||||
* @returns {ICommonState}
|
||||
*/
|
||||
function _initialGUMPromise(
|
||||
state: PromiseWithResolvers<IInitialGUMPromiseResult> | null = DEFAULT_INITIAL_PROMISE_STATE,
|
||||
function _initialGUMPromise(state: DefferedPromise<IInitialGUMPromiseResult> | null = DEFAULT_INITIAL_PROMISE_STATE,
|
||||
action: AnyAction) {
|
||||
if (action.type === SET_INITIAL_GUM_PROMISE) {
|
||||
return action.promise ?? null;
|
||||
@@ -294,7 +294,7 @@ interface IVideoState {
|
||||
|
||||
export interface IMediaState {
|
||||
audio: IAudioState;
|
||||
initialGUMPromise: PromiseWithResolvers<IInitialGUMPromiseResult> | null;
|
||||
initialGUMPromise: DefferedPromise<IInitialGUMPromiseResult> | null;
|
||||
screenshare: IScreenshareState;
|
||||
video: IVideoState;
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ export function participantJoined(participant: IParticipant) {
|
||||
// conference. The following check is really necessary because a
|
||||
// JitsiConference may have moved into leaving but may still manage to
|
||||
// sneak a PARTICIPANT_JOINED in if its leave is delayed for any purpose
|
||||
// (which is not outrageous given that leaving involves network
|
||||
// (which is not outragous given that leaving involves network
|
||||
// requests.)
|
||||
const stateFeaturesBaseConference
|
||||
= getState()['features/base/conference'];
|
||||
|
||||
@@ -15,6 +15,7 @@ import i18next from '../i18n/i18next';
|
||||
import { MEDIA_TYPE, MediaType, VIDEO_TYPE } from '../media/constants';
|
||||
import { toState } from '../redux/functions';
|
||||
import { getScreenShareTrack, isLocalTrackMuted } from '../tracks/functions.any';
|
||||
import { createDeferred } from '../util/helpers';
|
||||
|
||||
import {
|
||||
JIGASI_PARTICIPANT_ICON,
|
||||
@@ -126,7 +127,7 @@ export function getActiveSpeakersToBeDisplayed(stateful: IStateful) {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function getFirstLoadableAvatarUrl(participant: IParticipant, store: IStore) {
|
||||
const deferred: any = Promise.withResolvers();
|
||||
const deferred: any = createDeferred();
|
||||
const fullPromise = deferred.promise
|
||||
.then(() => _getFirstLoadableAvatarUrl(participant, store))
|
||||
.then((result: any) => {
|
||||
|
||||
@@ -52,7 +52,7 @@ StateListenerRegistry.register(
|
||||
|
||||
/**
|
||||
* Compares the old and new screenshare lists provided and creates/removes the virtual screenshare participant
|
||||
* tiles accordingly.
|
||||
* tiles accodingly.
|
||||
*
|
||||
* @param {Array<string>} oldScreenshareSourceNames - List of old screenshare source names.
|
||||
* @param {Array<string>} newScreenshareSourceNames - Current list of screenshare source names.
|
||||
|
||||
@@ -340,7 +340,9 @@ class Popover extends Component<IProps, IState> {
|
||||
_onTouchStart(event: TouchEvent) {
|
||||
if (this.props.visible
|
||||
&& !this.props.overflowDrawer
|
||||
&& !this._contextMenuRef?.contains?.(event.target as Node)
|
||||
&& this._contextMenuRef
|
||||
&& this._contextMenuRef.contains
|
||||
&& !this._contextMenuRef.contains(event.target as Node)
|
||||
&& !this._containerRef?.current?.contains(event.target as Node)) {
|
||||
this._onHideDialog();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import clsx from 'clsx';
|
||||
import React, { ReactNode, useEffect, useRef, useState } from 'react';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
@@ -11,7 +11,6 @@ import { isButtonEnabled } from '../../../../toolbox/functions.web';
|
||||
import { getConferenceName } from '../../../conference/functions';
|
||||
import { PREMEETING_BUTTONS, THIRD_PARTY_PREJOIN_BUTTONS } from '../../../config/constants';
|
||||
import { withPixelLineHeight } from '../../../styles/functions.web';
|
||||
import Tooltip from '../../../tooltip/components/Tooltip';
|
||||
import { isPreCallTestEnabled } from '../../functions';
|
||||
|
||||
import ConnectionStatus from './ConnectionStatus';
|
||||
@@ -161,20 +160,15 @@ const useStyles = makeStyles()(theme => {
|
||||
display: 'none'
|
||||
}
|
||||
},
|
||||
roomNameContainer: {
|
||||
width: '100%',
|
||||
textAlign: 'center',
|
||||
marginBottom: theme.spacing(4)
|
||||
},
|
||||
|
||||
roomName: {
|
||||
...withPixelLineHeight(theme.typography.heading5),
|
||||
color: theme.palette.text01,
|
||||
display: 'inline-block',
|
||||
marginBottom: theme.spacing(4),
|
||||
overflow: 'hidden',
|
||||
textAlign: 'center',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
maxWidth: '100%',
|
||||
width: '100%'
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -201,19 +195,6 @@ const PreMeetingScreen = ({
|
||||
backgroundSize: 'cover'
|
||||
} : {};
|
||||
|
||||
const roomNameRef = useRef<HTMLSpanElement | null>(null);
|
||||
const [ isOverflowing, setIsOverflowing ] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (roomNameRef.current) {
|
||||
const element = roomNameRef.current;
|
||||
const elementStyles = window.getComputedStyle(element);
|
||||
const elementWidth = Math.floor(parseFloat(elementStyles.width));
|
||||
|
||||
setIsOverflowing(element.scrollWidth > elementWidth + 1);
|
||||
}
|
||||
}, [ _roomName ]);
|
||||
|
||||
return (
|
||||
<div className = { clsx('premeeting-screen', classes.container, className) }>
|
||||
<div style = { style }>
|
||||
@@ -225,22 +206,8 @@ const PreMeetingScreen = ({
|
||||
{title}
|
||||
</h1>
|
||||
{_roomName && (
|
||||
<span className = { classes.roomNameContainer }>
|
||||
{isOverflowing ? (
|
||||
<Tooltip content = { _roomName }>
|
||||
<span
|
||||
className = { classes.roomName }
|
||||
ref = { roomNameRef }>
|
||||
{_roomName}
|
||||
</span>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<span
|
||||
className = { classes.roomName }
|
||||
ref = { roomNameRef }>
|
||||
{_roomName}
|
||||
</span>
|
||||
)}
|
||||
<span className = { classes.roomName }>
|
||||
{_roomName}
|
||||
</span>
|
||||
)}
|
||||
{children}
|
||||
@@ -292,4 +259,3 @@ function mapStateToProps(state: IReduxState, ownProps: Partial<IProps>) {
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(PreMeetingScreen);
|
||||
|
||||
|
||||
@@ -227,14 +227,14 @@ class MeetingsList extends Component<IProps> {
|
||||
<Container
|
||||
className = { rootClassName }
|
||||
key = { index }
|
||||
onClick = { onPress }
|
||||
tabIndex = { 0 }>
|
||||
onClick = { onPress }>
|
||||
<Container className = 'right-column'>
|
||||
<Text
|
||||
className = 'title'
|
||||
onClick = { onPress }
|
||||
onKeyPress = { onKeyPress }
|
||||
role = 'button'>
|
||||
role = 'button'
|
||||
tabIndex = { 0 }>
|
||||
{ title }
|
||||
</Text>
|
||||
{
|
||||
|
||||
@@ -41,8 +41,8 @@ export function formatURLText(text = '') {
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
// This will be the case for invalid URLs or URLs without a host (emails for example). In this case due to
|
||||
// the issue with PunycodeJS that truncates parts of the text when there is '@' we split the text by '@'
|
||||
// This will be the case for invalid URLs or URLs without a host (emails for example). In this case beacuse
|
||||
// of the issue with PunycodeJS that truncates parts of the text when there is '@' we split the text by '@'
|
||||
// and use punycode for every separate part to prevent homograph attacks.
|
||||
result = text.split('@').map(punycode.toASCII)
|
||||
.join('@');
|
||||
@@ -59,7 +59,7 @@ export function formatURLText(text = '') {
|
||||
*/
|
||||
export function getSupportUrl(stateful: IStateful) {
|
||||
|
||||
// TODO: Once overwriting through interface config is completely gone we should think of a way to be able to set
|
||||
// TODO: Once overwriting trough interface config is completelly gone we should think of a way to be able to set
|
||||
// the value in the branding and not return the default value from interface config.
|
||||
return toState(stateful)['features/dynamic-branding'].supportUrl || interfaceConfig?.SUPPORT_URL;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ declare let __DEV__: any;
|
||||
/**
|
||||
* Mixed type of the element (subtree) config. If it's a {@code boolean} (and is
|
||||
* {@code true}), we persist the entire subtree. If it's an {@code Object}, we
|
||||
* persist a filtered subtree based on the properties of the config object.
|
||||
* perist a filtered subtree based on the properties of the config object.
|
||||
*/
|
||||
declare type ElementConfig = boolean | Object;
|
||||
|
||||
|
||||
@@ -96,8 +96,8 @@ class StateListenerRegistry {
|
||||
* @returns {void}
|
||||
*/
|
||||
_listener({ prevSelections, store }: {
|
||||
prevSelections: Map<SelectorListener, any>;
|
||||
store: Store<any, any>;
|
||||
prevSelections: Map<SelectorListener, any>;
|
||||
store: Store<any, any>;
|
||||
}) {
|
||||
for (const selectorListener of this._selectorListeners) {
|
||||
const prevSelection = prevSelections.get(selectorListener);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { setAspectRatio, setReducedUI } from './actions';
|
||||
|
||||
|
||||
/**
|
||||
* Middleware that handles window dimension changes and updates the aspect ratio and
|
||||
* Middleware that handles widnow dimension changes and updates the aspect ratio and
|
||||
* reduced UI modes accordingly.
|
||||
*
|
||||
* @param {Store} store - The redux store.
|
||||
|
||||
@@ -375,7 +375,7 @@ export default class AbstractButton<P extends IProps, S = any> extends Component
|
||||
|
||||
// blur after click to release focus from button to allow PTT.
|
||||
// @ts-ignore
|
||||
e?.currentTarget?.blur?.();
|
||||
e?.currentTarget?.blur && e.currentTarget.blur();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -86,16 +86,12 @@ export function createDesiredLocalTracks(...desiredTypes: any) {
|
||||
dispatch(destroyLocalDesktopTrackIfExists());
|
||||
|
||||
if (desiredTypes.length === 0) {
|
||||
const { startSilent } = state['features/base/config'];
|
||||
const { video } = state['features/base/media'];
|
||||
|
||||
if (!startSilent) {
|
||||
// Always create the audio track early, even if it will be muted.
|
||||
// This fixes a timing issue when adding the track to the conference which
|
||||
// manifests primarily on iOS 15.
|
||||
// Unless we are silent, of course.
|
||||
desiredTypes.push(MEDIA_TYPE.AUDIO);
|
||||
}
|
||||
// XXX: Always create the audio track early, even if it will be muted.
|
||||
// This fixes a timing issue when adding the track to the conference which
|
||||
// manifests primarily on iOS 15.
|
||||
desiredTypes.push(MEDIA_TYPE.AUDIO);
|
||||
|
||||
// XXX When the app is coming into the foreground from the
|
||||
// background in order to handle a URL, it may realize the new
|
||||
@@ -838,16 +834,6 @@ export function toggleCamera() {
|
||||
const localVideoTrack = getLocalVideoTrack(tracks)?.jitsiTrack;
|
||||
const currentFacingMode = localVideoTrack.getCameraFacingMode();
|
||||
const { localFlipX } = state['features/base/settings'];
|
||||
|
||||
/**
|
||||
* FIXME: Ideally, we should be dispatching {@code replaceLocalTrack} here,
|
||||
* but it seems to not trigger the re-rendering of the local video on Chrome;
|
||||
* could be due to a plan B vs unified plan issue. Therefore, we use the legacy
|
||||
* method defined in conference.js that manually takes care of updating the local
|
||||
* video as well.
|
||||
*/
|
||||
await APP.conference.useVideoStream(null);
|
||||
|
||||
const targetFacingMode = currentFacingMode === CAMERA_FACING_MODE.USER
|
||||
? CAMERA_FACING_MODE.ENVIRONMENT
|
||||
: CAMERA_FACING_MODE.USER;
|
||||
@@ -857,7 +843,6 @@ export function toggleCamera() {
|
||||
|
||||
const newVideoTrack = await createLocalTrack('video', null, null, { facingMode: targetFacingMode });
|
||||
|
||||
// FIXME: See above.
|
||||
await APP.conference.useVideoStream(newVideoTrack);
|
||||
dispatch(replaceLocalTrack(localVideoTrack, newVideoTrack));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -359,7 +359,8 @@ export function createInitialAVTracks(options: ICreateInitialTracksOptions, reco
|
||||
return (dispatch: IStore['dispatch'], _getState: IStore['getState']) => {
|
||||
const {
|
||||
devices,
|
||||
timeout
|
||||
timeout,
|
||||
firePermissionPromptIsShownEvent
|
||||
} = options;
|
||||
|
||||
dispatch(gumPending(devices, IGUMPendingState.PENDING_UNMUTE));
|
||||
@@ -399,14 +400,16 @@ export function createInitialAVTracks(options: ICreateInitialTracksOptions, reco
|
||||
if (devices.includes(MEDIA_TYPE.AUDIO)) {
|
||||
gUMPromises.push(createLocalTracksF({
|
||||
devices: [ MEDIA_TYPE.AUDIO ],
|
||||
timeout
|
||||
timeout,
|
||||
firePermissionPromptIsShownEvent
|
||||
}));
|
||||
}
|
||||
|
||||
if (devices.includes(MEDIA_TYPE.VIDEO)) {
|
||||
gUMPromises.push(createLocalTracksF({
|
||||
devices: [ MEDIA_TYPE.VIDEO ],
|
||||
timeout
|
||||
timeout,
|
||||
firePermissionPromptIsShownEvent
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,10 @@ export * from './functions.any';
|
||||
* and/or 'video'.
|
||||
* @param {string|null} [options.micDeviceId] - Microphone device id or
|
||||
* {@code undefined} to use app's settings.
|
||||
* @param {number|undefined} [options.timeout] - A timeout for JitsiMeetJS.createLocalTracks used to create the tracks.
|
||||
* @param {number|undefined} [oprions.timeout] - A timeout for JitsiMeetJS.createLocalTracks used to create the tracks.
|
||||
* @param {boolean} [options.firePermissionPromptIsShownEvent] - Whether lib-jitsi-meet
|
||||
* should check for a {@code getUserMedia} permission prompt and fire a
|
||||
* corresponding event.
|
||||
* @param {IStore} store - The redux store in the context of which the function
|
||||
* is to execute and from which state such as {@code config} is to be retrieved.
|
||||
* @returns {Promise<JitsiLocalTrack[]>}
|
||||
|
||||
@@ -31,7 +31,10 @@ export * from './functions.any';
|
||||
* and/or 'video'.
|
||||
* @param {string|null} [options.micDeviceId] - Microphone device id or
|
||||
* {@code undefined} to use app's settings.
|
||||
* @param {number|undefined} [options.timeout] - A timeout for JitsiMeetJS.createLocalTracks used to create the tracks.
|
||||
* @param {number|undefined} [oprions.timeout] - A timeout for JitsiMeetJS.createLocalTracks used to create the tracks.
|
||||
* @param {boolean} [options.firePermissionPromptIsShownEvent] - Whether lib-jitsi-meet
|
||||
* should check for a {@code getUserMedia} permission prompt and fire a
|
||||
* corresponding event.
|
||||
* @param {IStore} store - The redux store in the context of which the function
|
||||
* is to execute and from which state such as {@code config} is to be retrieved.
|
||||
* @param {boolean} recordTimeMetrics - If true time metrics will be recorded.
|
||||
@@ -42,6 +45,7 @@ export function createLocalTracksF(options: ITrackOptions = {}, store?: IStore,
|
||||
const {
|
||||
desktopSharingSourceDevice,
|
||||
desktopSharingSources,
|
||||
firePermissionPromptIsShownEvent,
|
||||
timeout
|
||||
} = options;
|
||||
|
||||
@@ -60,6 +64,7 @@ export function createLocalTracksF(options: ITrackOptions = {}, store?: IStore,
|
||||
|
||||
const {
|
||||
desktopSharingFrameRate,
|
||||
firefox_fake_device, // eslint-disable-line camelcase
|
||||
resolution
|
||||
} = state['features/base/config'];
|
||||
const constraints = options.constraints ?? state['features/base/config'].constraints;
|
||||
@@ -85,6 +90,8 @@ export function createLocalTracksF(options: ITrackOptions = {}, store?: IStore,
|
||||
devices: options.devices?.slice(0),
|
||||
effects,
|
||||
facingMode: options.facingMode || getCameraFacingMode(state),
|
||||
firefox_fake_device, // eslint-disable-line camelcase
|
||||
firePermissionPromptIsShownEvent,
|
||||
micDeviceId,
|
||||
resolution,
|
||||
timeout
|
||||
@@ -139,6 +146,7 @@ export function createPrejoinTracks() {
|
||||
if (requestedAudio || requestedVideo) {
|
||||
tryCreateLocalTracks = createLocalTracksF({
|
||||
devices: initialDevices,
|
||||
firePermissionPromptIsShownEvent: true,
|
||||
timeout
|
||||
}, APP.store)
|
||||
.catch(async (err: Error) => {
|
||||
@@ -155,6 +163,7 @@ export function createPrejoinTracks() {
|
||||
if (requestedAudio) {
|
||||
gUMPromises.push(createLocalTracksF({
|
||||
devices: [ MEDIA_TYPE.AUDIO ],
|
||||
firePermissionPromptIsShownEvent: true,
|
||||
timeout
|
||||
}));
|
||||
}
|
||||
@@ -162,6 +171,7 @@ export function createPrejoinTracks() {
|
||||
if (requestedVideo) {
|
||||
gUMPromises.push(createLocalTracksF({
|
||||
devices: [ MEDIA_TYPE.VIDEO ],
|
||||
firePermissionPromptIsShownEvent: true,
|
||||
timeout
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -12,9 +12,10 @@ export interface ITrackOptions {
|
||||
};
|
||||
};
|
||||
desktopSharingSourceDevice?: string;
|
||||
desktopSharingSources?: Array<DesktopSharingSourceType>;
|
||||
desktopSharingSources?: string[];
|
||||
devices?: string[];
|
||||
facingMode?: string;
|
||||
firePermissionPromptIsShownEvent?: boolean;
|
||||
micDeviceId?: string | null;
|
||||
timeout?: number;
|
||||
}
|
||||
@@ -67,16 +68,15 @@ export interface IToggleScreenSharingOptions {
|
||||
shareOptions: IShareOptions;
|
||||
}
|
||||
|
||||
export type DesktopSharingSourceType = 'screen' | 'window';
|
||||
|
||||
export interface IShareOptions {
|
||||
desktopSharingSourceDevice?: string;
|
||||
desktopSharingSources?: Array<DesktopSharingSourceType>;
|
||||
desktopSharingSources?: string[];
|
||||
desktopStream?: any;
|
||||
}
|
||||
|
||||
export interface ICreateInitialTracksOptions {
|
||||
devices: Array<MediaType>;
|
||||
firePermissionPromptIsShownEvent?: boolean;
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ const IconButton: React.FC<IIconButtonProps> = ({
|
||||
underlayColor = { underlayColor }>
|
||||
<Icon
|
||||
color = { color }
|
||||
size = { size ?? 20 }
|
||||
size = { 20 || size }
|
||||
src = { src } />
|
||||
</TouchableHighlight>
|
||||
);
|
||||
|
||||
@@ -244,9 +244,9 @@ const ContextMenu = ({
|
||||
list: Element | null,
|
||||
currentFocus: Element | null,
|
||||
traversalFunction: (
|
||||
list: Element | null,
|
||||
currentFocus: Element | null
|
||||
) => Element | null
|
||||
list: Element | null,
|
||||
currentFocus: Element | null
|
||||
) => Element | null
|
||||
) => {
|
||||
let wrappedOnce = false;
|
||||
let nextFocus = traversalFunction(list, currentFocus);
|
||||
|
||||
@@ -141,7 +141,7 @@ const useStyles = makeStyles()(theme => {
|
||||
});
|
||||
|
||||
interface IObject {
|
||||
[key: string]: unknown;
|
||||
[key: string]: string | string[] | boolean | number | number[] | {} | undefined;
|
||||
}
|
||||
|
||||
export interface IDialogTab<P> {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user