mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-01-10 08:40:18 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f0f8ea019 | ||
|
|
444f4a7abc |
@@ -30,12 +30,9 @@ import android.view.KeyEvent;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.oney.WebRTCModule.WebRTCModuleOptions;
|
||||
|
||||
import org.jitsi.meet.sdk.JitsiMeet;
|
||||
import org.jitsi.meet.sdk.JitsiMeetActivity;
|
||||
import org.jitsi.meet.sdk.JitsiMeetConferenceOptions;
|
||||
import org.webrtc.Logging;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
@@ -82,10 +79,6 @@ public class MainActivity extends JitsiMeetActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
JitsiMeet.showSplashScreen(this);
|
||||
|
||||
WebRTCModuleOptions options = WebRTCModuleOptions.getInstance();
|
||||
options.loggingSeverity = Logging.Severity.LS_ERROR;
|
||||
|
||||
super.onCreate(null);
|
||||
}
|
||||
|
||||
|
||||
@@ -89,11 +89,9 @@ dependencies {
|
||||
implementation project(':react-native-splash-screen')
|
||||
implementation project(':react-native-svg')
|
||||
implementation project(':react-native-video')
|
||||
implementation project(':react-native-webrtc')
|
||||
implementation project(':react-native-webview')
|
||||
|
||||
// Use `api` here so consumers can use WebRTCModuleOptions.
|
||||
api project(':react-native-webrtc')
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
}
|
||||
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
/*
|
||||
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.oney.WebRTCModule.webrtcutils.SoftwareVideoDecoderFactoryProxy;
|
||||
|
||||
import org.webrtc.EglBase;
|
||||
import org.webrtc.HardwareVideoDecoderFactory;
|
||||
import org.webrtc.PlatformSoftwareVideoDecoderFactory;
|
||||
import org.webrtc.VideoCodecInfo;
|
||||
import org.webrtc.VideoDecoder;
|
||||
import org.webrtc.VideoDecoderFactory;
|
||||
import org.webrtc.VideoDecoderFallback;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
/**
|
||||
* Custom decoder factory which uses HW decoders and falls back to SW.
|
||||
*/
|
||||
public class JitsiVideoDecoderFactory implements VideoDecoderFactory {
|
||||
private final VideoDecoderFactory hardwareVideoDecoderFactory;
|
||||
private final VideoDecoderFactory softwareVideoDecoderFactory = new SoftwareVideoDecoderFactoryProxy();
|
||||
private final @Nullable VideoDecoderFactory platformSoftwareVideoDecoderFactory;
|
||||
|
||||
/**
|
||||
* Create decoder factory using default hardware decoder factory.
|
||||
*/
|
||||
public JitsiVideoDecoderFactory(@Nullable EglBase.Context eglContext) {
|
||||
this.hardwareVideoDecoderFactory = new HardwareVideoDecoderFactory(eglContext);
|
||||
this.platformSoftwareVideoDecoderFactory = new PlatformSoftwareVideoDecoderFactory(eglContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create decoder factory using explicit hardware decoder factory.
|
||||
*/
|
||||
JitsiVideoDecoderFactory(VideoDecoderFactory hardwareVideoDecoderFactory) {
|
||||
this.hardwareVideoDecoderFactory = hardwareVideoDecoderFactory;
|
||||
this.platformSoftwareVideoDecoderFactory = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable VideoDecoder createDecoder(VideoCodecInfo codecType) {
|
||||
VideoDecoder softwareDecoder = softwareVideoDecoderFactory.createDecoder(codecType);
|
||||
final VideoDecoder hardwareDecoder = hardwareVideoDecoderFactory.createDecoder(codecType);
|
||||
if (softwareDecoder == null && platformSoftwareVideoDecoderFactory != null) {
|
||||
softwareDecoder = platformSoftwareVideoDecoderFactory.createDecoder(codecType);
|
||||
}
|
||||
if (hardwareDecoder != null && softwareDecoder != null) {
|
||||
// Both hardware and software supported, wrap it in a software fallback
|
||||
return new VideoDecoderFallback(
|
||||
/* fallback= */ softwareDecoder, /* primary= */ hardwareDecoder);
|
||||
}
|
||||
return hardwareDecoder != null ? hardwareDecoder : softwareDecoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VideoCodecInfo[] getSupportedCodecs() {
|
||||
LinkedHashSet<VideoCodecInfo> supportedCodecInfos = new LinkedHashSet<>();
|
||||
|
||||
supportedCodecInfos.addAll(Arrays.asList(softwareVideoDecoderFactory.getSupportedCodecs()));
|
||||
supportedCodecInfos.addAll(Arrays.asList(hardwareVideoDecoderFactory.getSupportedCodecs()));
|
||||
if (platformSoftwareVideoDecoderFactory != null) {
|
||||
supportedCodecInfos.addAll(
|
||||
Arrays.asList(platformSoftwareVideoDecoderFactory.getSupportedCodecs()));
|
||||
}
|
||||
|
||||
return supportedCodecInfos.toArray(new VideoCodecInfo[supportedCodecInfos.size()]);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.oney.WebRTCModule.webrtcutils.H264AndSoftwareVideoEncoderFactory;
|
||||
|
||||
import org.webrtc.EglBase;
|
||||
|
||||
/**
|
||||
* Custom encoder factory which uses HW for H.264 and SW for everything else.
|
||||
*/
|
||||
public class JitsiVideoEncoderFactory extends H264AndSoftwareVideoEncoderFactory {
|
||||
public JitsiVideoEncoderFactory(@Nullable EglBase.Context eglContext) {
|
||||
super(eglContext);
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -32,10 +32,12 @@ import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
import com.oney.WebRTCModule.EglUtils;
|
||||
import com.oney.WebRTCModule.WebRTCModuleOptions;
|
||||
import com.oney.WebRTCModule.webrtcutils.H264AndSoftwareVideoDecoderFactory;
|
||||
import com.oney.WebRTCModule.webrtcutils.H264AndSoftwareVideoEncoderFactory;
|
||||
|
||||
import org.devio.rn.splashscreen.SplashScreenModule;
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
import org.webrtc.EglBase;
|
||||
import org.webrtc.Logging;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
@@ -124,31 +126,31 @@ class ReactInstanceManagerHolder {
|
||||
// AmplitudeReactNativePackage
|
||||
try {
|
||||
Class<?> amplitudePackageClass = Class.forName("com.amplitude.reactnative.AmplitudeReactNativePackage");
|
||||
Constructor<?> constructor = amplitudePackageClass.getConstructor();
|
||||
Constructor constructor = amplitudePackageClass.getConstructor();
|
||||
packages.add((ReactPackage)constructor.newInstance());
|
||||
} catch (Exception e) {
|
||||
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
|
||||
JitsiMeetLogger.d(TAG, "Not loading AmplitudeReactNativePackage");
|
||||
Log.d(TAG, "Not loading AmplitudeReactNativePackage");
|
||||
}
|
||||
|
||||
// GiphyReactNativeSdkPackage
|
||||
try {
|
||||
Class<?> giphyPackageClass = Class.forName("com.giphyreactnativesdk.GiphyReactNativeSdkPackage");
|
||||
Constructor<?> constructor = giphyPackageClass.getConstructor();
|
||||
Constructor constructor = giphyPackageClass.getConstructor();
|
||||
packages.add((ReactPackage)constructor.newInstance());
|
||||
} catch (Exception e) {
|
||||
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
|
||||
JitsiMeetLogger.d(TAG, "Not loading GiphyReactNativeSdkPackage");
|
||||
Log.d(TAG, "Not loading GiphyReactNativeSdkPackage");
|
||||
}
|
||||
|
||||
// RNGoogleSignInPackage
|
||||
try {
|
||||
Class<?> googlePackageClass = Class.forName("com.reactnativegooglesignin.RNGoogleSigninPackage");
|
||||
Constructor<?> constructor = googlePackageClass.getConstructor();
|
||||
Constructor constructor = googlePackageClass.getConstructor();
|
||||
packages.add((ReactPackage)constructor.newInstance());
|
||||
} catch (Exception e) {
|
||||
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
|
||||
JitsiMeetLogger.d(TAG, "Not loading RNGoogleSignInPackage");
|
||||
Log.d(TAG, "Not loading RNGoogleSignInPackage");
|
||||
}
|
||||
|
||||
return packages;
|
||||
@@ -167,7 +169,7 @@ class ReactInstanceManagerHolder {
|
||||
= ReactInstanceManagerHolder.getReactInstanceManager();
|
||||
|
||||
if (reactInstanceManager != null) {
|
||||
@SuppressLint("VisibleForTests") ReactContext reactContext
|
||||
ReactContext reactContext
|
||||
= reactInstanceManager.getCurrentReactContext();
|
||||
|
||||
if (reactContext != null) {
|
||||
@@ -190,7 +192,7 @@ class ReactInstanceManagerHolder {
|
||||
*/
|
||||
static <T extends NativeModule> T getNativeModule(
|
||||
Class<T> nativeModuleClass) {
|
||||
@SuppressLint("VisibleForTests") ReactContext reactContext
|
||||
ReactContext reactContext
|
||||
= reactInstanceManager != null
|
||||
? reactInstanceManager.getCurrentReactContext() : null;
|
||||
|
||||
@@ -217,18 +219,15 @@ class ReactInstanceManagerHolder {
|
||||
|
||||
// Initialize the WebRTC module options.
|
||||
WebRTCModuleOptions options = WebRTCModuleOptions.getInstance();
|
||||
options.enableMediaProjectionService = true;
|
||||
if (options.videoDecoderFactory == null || options.videoEncoderFactory == null) {
|
||||
EglBase.Context eglContext = EglUtils.getRootEglBaseContext();
|
||||
if (options.videoDecoderFactory == null) {
|
||||
options.videoDecoderFactory = new JitsiVideoDecoderFactory(eglContext);
|
||||
}
|
||||
if (options.videoEncoderFactory == null) {
|
||||
options.videoEncoderFactory = new JitsiVideoEncoderFactory(eglContext);
|
||||
}
|
||||
}
|
||||
|
||||
JitsiMeetLogger.d(TAG, "initializing RN");
|
||||
EglBase.Context eglContext = EglUtils.getRootEglBaseContext();
|
||||
|
||||
options.videoDecoderFactory = new H264AndSoftwareVideoDecoderFactory(eglContext);
|
||||
options.videoEncoderFactory = new H264AndSoftwareVideoEncoderFactory(eglContext);
|
||||
options.enableMediaProjectionService = true;
|
||||
// options.loggingSeverity = Logging.Severity.LS_INFO;
|
||||
|
||||
Log.d(TAG, "initializing RN with Activity");
|
||||
|
||||
reactInstanceManager
|
||||
= ReactInstanceManager.builder()
|
||||
|
||||
@@ -2278,10 +2278,8 @@ export default {
|
||||
* @param {boolean} [requestFeedback=false] if user feedback should be
|
||||
* @param {string} [hangupReason] the reason for leaving the meeting
|
||||
* requested
|
||||
* @param {boolean} [notifyOnConferenceTermination] whether to notify
|
||||
* the user on conference termination
|
||||
*/
|
||||
hangup(requestFeedback = false, hangupReason, notifyOnConferenceTermination) {
|
||||
hangup(requestFeedback = false, hangupReason) {
|
||||
APP.store.dispatch(disableReceiver());
|
||||
|
||||
this._stopProxyConnection();
|
||||
@@ -2300,7 +2298,7 @@ export default {
|
||||
|
||||
if (requestFeedback) {
|
||||
const feedbackDialogClosed = (feedbackResult = {}) => {
|
||||
if (!feedbackResult.wasDialogShown && hangupReason && notifyOnConferenceTermination) {
|
||||
if (!feedbackResult.wasDialogShown && hangupReason) {
|
||||
return APP.store.dispatch(
|
||||
openLeaveReasonDialog(hangupReason)).then(() => feedbackResult);
|
||||
}
|
||||
|
||||
@@ -393,9 +393,6 @@ var config = {
|
||||
// // showPrejoinWarning: true,
|
||||
// // If true, the notification for recording start will display a link to download the cloud recording.
|
||||
// // showRecordingLink: true,
|
||||
// // If true, mutes audio and video when a recording begins and displays a dialog
|
||||
// // explaining the effect of unmuting.
|
||||
// // requireConsent: true,
|
||||
// },
|
||||
|
||||
// recordingService: {
|
||||
@@ -755,9 +752,6 @@ var config = {
|
||||
// and microsoftApiApplicationClientID
|
||||
// enableCalendarIntegration: false,
|
||||
|
||||
// Whether to notify when the conference is terminated because it was destroyed.
|
||||
// notifyOnConferenceDestruction: true,
|
||||
|
||||
// The client id for the google APIs used for the calendar integration, youtube livestreaming, etc.
|
||||
// googleApiApplicationClientID: '<client_id>',
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
overflow-y: auto;
|
||||
flex-grow: 1;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
|
||||
.meetings-list-empty {
|
||||
text-align: center;
|
||||
|
||||
@@ -75,12 +75,9 @@ $welcomePageHeaderBackground: linear-gradient(0deg, rgba(0, 0, 0, 0.2), rgba(0,
|
||||
$welcomePageHeaderBackgroundPosition: center;
|
||||
$welcomePageHeaderBackgroundRepeat: none;
|
||||
$welcomePageHeaderBackgroundSize: cover;
|
||||
$welcomePageHeaderPadding: 1rem;
|
||||
$welcomePageHeaderPaddingBottom: 15px;
|
||||
$welcomePageHeaderTitleMaxWidth: initial;
|
||||
$welcomePageHeaderTextAlign: center;
|
||||
$welcomePageButtonBg: #0074E0;
|
||||
$welcomePageButtonHoverBg: #4687ED;
|
||||
$welcomePageButtonFocusOutline: #00225A;
|
||||
|
||||
$welcomePageHeaderContainerMarginTop: 104px;
|
||||
$welcomePageHeaderContainerDisplay: flex;
|
||||
|
||||
@@ -18,7 +18,7 @@ body.welcome-page {
|
||||
background-position: $welcomePageHeaderBackgroundPosition;
|
||||
background-repeat: $welcomePageHeaderBackgroundRepeat;
|
||||
background-size: $welcomePageHeaderBackgroundSize;
|
||||
padding: $welcomePageHeaderPadding;
|
||||
padding-bottom: $welcomePageHeaderPaddingBottom;
|
||||
background-color: #131519;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
@@ -219,18 +219,14 @@ body.welcome-page {
|
||||
.welcome-page-button {
|
||||
border: 0;
|
||||
font-size: 14px;
|
||||
background: $welcomePageButtonBg;
|
||||
background: #0074E0;
|
||||
border-radius: 3px;
|
||||
color: #FFFFFF;
|
||||
cursor: pointer;
|
||||
padding: 16px 20px;
|
||||
transition: all 0.2s;
|
||||
&:focus-within {
|
||||
outline: auto 2px $welcomePageButtonFocusOutline;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $welcomePageButtonHoverBg;
|
||||
&:focus-within {
|
||||
outline: auto 2px #022e61;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +264,8 @@ body.welcome-page {
|
||||
|
||||
&.without-content {
|
||||
.welcome-card {
|
||||
max-width: 100dvw;
|
||||
min-width: 500px;
|
||||
max-width: 580px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -157,6 +157,7 @@
|
||||
4EB0603B260E09D000F524C5 /* SampleUploader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SampleUploader.swift; sourceTree = "<group>"; };
|
||||
4EC49B8625BED71300E76218 /* ReplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReplayKit.framework; path = System/Library/Frameworks/ReplayKit.framework; sourceTree = SDKROOT; };
|
||||
5C1BE20ECD5DEEB48FED90B5 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
6132EF172BDFF13200BBE14D /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = ../PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
756FCE06C08D9B947653C98A /* Pods-JitsiMeet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.debug.xcconfig"; path = "Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
B3B083EB1D4955FF0069CEE7 /* app.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = app.entitlements; sourceTree = "<group>"; };
|
||||
D6152FF9E9F7B0E86F70A21D /* libPods-JitsiMeet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-JitsiMeet.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -301,6 +302,7 @@
|
||||
0BEA5C351F7B8F73000D0AB4 /* WatchKit extension */,
|
||||
4EB06025260E026600F524C5 /* JitsiMeetBroadcast Extension */,
|
||||
CDD71F5E1157E9F283DF92A8 /* Pods */,
|
||||
6132EF172BDFF13200BBE14D /* PrivacyInfo.xcprivacy */,
|
||||
5C1BE20ECD5DEEB48FED90B5 /* PrivacyInfo.xcprivacy */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
|
||||
@@ -145,6 +145,7 @@
|
||||
4ED4FFF12721B9B90074E620 /* JitsiAudioSession.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiAudioSession.h; sourceTree = "<group>"; };
|
||||
4ED4FFF22721B9B90074E620 /* JitsiAudioSession.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JitsiAudioSession.m; sourceTree = "<group>"; };
|
||||
4ED4FFF52721BAE10074E620 /* JitsiAudioSession+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiAudioSession+Private.h"; sourceTree = "<group>"; };
|
||||
6132EF172BDFF13200BBE14D /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = ../PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
86389F55993FAAF6AEB3FA3E /* Pods-JitsiMeetSDKLite.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeetSDKLite.release.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeetSDKLite/Pods-JitsiMeetSDKLite.release.xcconfig"; sourceTree = "<group>"; };
|
||||
891FE43DAD30BC8976683100 /* Pods-JitsiMeetSDK.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeetSDK.release.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeetSDK/Pods-JitsiMeetSDK.release.xcconfig"; sourceTree = "<group>"; };
|
||||
8F48C340DE0D91D1012976C5 /* Pods-JitsiMeetSDKLite.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeetSDKLite.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeetSDKLite/Pods-JitsiMeetSDKLite.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
@@ -230,6 +231,7 @@
|
||||
0BD906E61EC0C00300C8C18E /* Products */,
|
||||
0BCA49681EC4BBE500B793EE /* Resources */,
|
||||
0BD906E71EC0C00300C8C18E /* src */,
|
||||
6132EF172BDFF13200BBE14D /* PrivacyInfo.xcprivacy */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
|
||||
@@ -18,6 +18,11 @@
|
||||
|
||||
static NSString * const sendEventNotificationName = @"org.jitsi.meet.SendEvent";
|
||||
|
||||
typedef NS_ENUM(NSInteger, RecordingMode) {
|
||||
RecordingModeFile,
|
||||
RecordingModeStream
|
||||
};
|
||||
|
||||
@interface ExternalAPI : RCTEventEmitter<RCTBridgeModule>
|
||||
|
||||
- (void)sendHangUp;
|
||||
@@ -33,7 +38,7 @@ static NSString * const sendEventNotificationName = @"org.jitsi.meet.SendEvent";
|
||||
- (void)toggleCamera;
|
||||
- (void)showNotification:(NSString*)appearance :(NSString*)description :(NSString*)timeout :(NSString*)title :(NSString*)uid;
|
||||
- (void)hideNotification:(NSString*)uid;
|
||||
- (void)startRecording:(NSString*)mode :(NSString*)dropboxToken :(BOOL)shouldShare :(NSString*)rtmpStreamKey :(NSString*)rtmpBroadcastID :(NSString*)youtubeStreamKey :(NSString*)youtubeBroadcastID :(NSDictionary*)extraMetadata :(BOOL)transcription;
|
||||
- (void)stopRecording:(NSString*)mode :(BOOL)transcription;
|
||||
- (void)startRecording:(RecordingMode)mode :(NSString*)dropboxToken :(BOOL)shouldShare :(NSString*)rtmpStreamKey :(NSString*)rtmpBroadcastID :(NSString*)youtubeStreamKey :(NSString*)youtubeBroadcastID :(NSDictionary*)extraMetadata :(BOOL)transcription;
|
||||
- (void)stopRecording:(RecordingMode)mode :(BOOL)transcription;
|
||||
|
||||
@end
|
||||
|
||||
@@ -38,7 +38,7 @@ static NSString * const stopRecordingAction = @"org.jitsi.meet.STOP_RECORDING";
|
||||
static NSMapTable<NSString*, void (^)(NSArray* participantsInfo)> *participantInfoCompletionHandlers;
|
||||
|
||||
__attribute__((constructor))
|
||||
static void initializeViewsMap(void) {
|
||||
static void initializeViewsMap() {
|
||||
participantInfoCompletionHandlers = [NSMapTable strongToStrongObjectsMapTable];
|
||||
}
|
||||
|
||||
@@ -210,9 +210,21 @@ RCT_EXPORT_METHOD(sendEvent:(NSString *)name
|
||||
[self sendEventWithName:hideNotificationAction body:data];
|
||||
}
|
||||
|
||||
- (void)startRecording:(NSString*)mode :(NSString*)dropboxToken :(BOOL)shouldShare :(NSString*)rtmpStreamKey :(NSString*)rtmpBroadcastID :(NSString*)youtubeStreamKey :(NSString*)youtubeBroadcastID :(NSDictionary*)extraMetadata :(BOOL)transcription {
|
||||
static inline NSString *RecordingModeToString(RecordingMode mode) {
|
||||
switch (mode) {
|
||||
case RecordingModeFile:
|
||||
return @"file";
|
||||
case RecordingModeStream:
|
||||
return @"stream";
|
||||
default:
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)startRecording:(RecordingMode)mode :(NSString*)dropboxToken :(BOOL)shouldShare :(NSString*)rtmpStreamKey :(NSString*)rtmpBroadcastID :(NSString*)youtubeStreamKey :(NSString*)youtubeBroadcastID :(NSDictionary*)extraMetadata :(BOOL)transcription {
|
||||
NSString *modeString = RecordingModeToString(mode);
|
||||
NSDictionary *data = @{
|
||||
@"mode": mode,
|
||||
@"mode": modeString,
|
||||
@"dropboxToken": dropboxToken,
|
||||
@"shouldShare": @(shouldShare),
|
||||
@"rtmpStreamKey": rtmpStreamKey,
|
||||
@@ -226,9 +238,10 @@ RCT_EXPORT_METHOD(sendEvent:(NSString *)name
|
||||
[self sendEventWithName:startRecordingAction body:data];
|
||||
}
|
||||
|
||||
- (void)stopRecording:(NSString*)mode :(BOOL)transcription {
|
||||
- (void)stopRecording:(RecordingMode)mode :(BOOL)transcription {
|
||||
NSString *modeString = RecordingModeToString(mode);
|
||||
NSDictionary *data = @{
|
||||
@"mode": mode,
|
||||
@"mode": modeString,
|
||||
@"transcription": @(transcription)
|
||||
};
|
||||
|
||||
|
||||
@@ -21,10 +21,7 @@
|
||||
#import "JitsiMeetConferenceOptions.h"
|
||||
#import "JitsiMeetViewDelegate.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, RecordingMode) {
|
||||
RecordingModeFile,
|
||||
RecordingModeStream
|
||||
};
|
||||
typedef NS_ENUM(NSInteger, RecordingMode);
|
||||
|
||||
@interface JitsiMeetView : UIView
|
||||
|
||||
|
||||
@@ -30,11 +30,6 @@
|
||||
*/
|
||||
static NSString *const PiPEnabledFeatureFlag = @"pip.enabled";
|
||||
|
||||
/**
|
||||
* Forward declarations.
|
||||
*/
|
||||
static NSString *recordingModeToString(RecordingMode mode);
|
||||
|
||||
|
||||
@implementation JitsiMeetView {
|
||||
/**
|
||||
@@ -158,15 +153,15 @@ static NSString *recordingModeToString(RecordingMode mode);
|
||||
[externalAPI hideNotification:uid];
|
||||
}
|
||||
|
||||
- (void)startRecording:(RecordingMode)mode :(NSString *)dropboxToken :(BOOL)shouldShare :(NSString *)rtmpStreamKey :(NSString *)rtmpBroadcastID :(NSString *)youtubeStreamKey :(NSString *)youtubeBroadcastID :(NSDictionary *)extraMetadata :(BOOL)transcription {
|
||||
- (void)startRecording:(RecordingMode)mode :(NSString *)dropboxToken :(BOOL)shouldShare :(NSString *)rtmpStreamKey :(NSString *)rtmpBroadcastID :(NSString *)youtubeStreamKey :(NSString *)youtubeBroadcastID :(NSString *)extraMetadata :(BOOL)transcription {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI startRecording:recordingModeToString(mode) :dropboxToken :shouldShare :rtmpStreamKey :rtmpBroadcastID :youtubeStreamKey :youtubeBroadcastID :extraMetadata :transcription];
|
||||
[externalAPI startRecording:mode :dropboxToken :shouldShare :rtmpStreamKey :rtmpBroadcastID :youtubeStreamKey :youtubeBroadcastID :extraMetadata :transcription];
|
||||
}
|
||||
|
||||
- (void)stopRecording:(RecordingMode)mode :(BOOL)transcription {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI stopRecording:recordingModeToString(mode) :transcription];
|
||||
}
|
||||
[externalAPI stopRecording:mode :transcription];
|
||||
}
|
||||
|
||||
#pragma mark Private methods
|
||||
|
||||
@@ -262,14 +257,3 @@ static NSString *recordingModeToString(RecordingMode mode);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static NSString *recordingModeToString(RecordingMode mode) {
|
||||
switch (mode) {
|
||||
case RecordingModeFile:
|
||||
return @"file";
|
||||
case RecordingModeStream:
|
||||
return @"stream";
|
||||
default:
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
"mr": "मराठी",
|
||||
"nb": "Norsk bokmål",
|
||||
"nl": "Nederlands",
|
||||
"no": "Norsk",
|
||||
"oc": "Occitan",
|
||||
"pl": "Polski",
|
||||
"pt": "Português",
|
||||
|
||||
@@ -70,14 +70,14 @@
|
||||
"breakoutList": "Breakout-Liste",
|
||||
"buttonLabel": "Breakout-Räume",
|
||||
"defaultName": "Breakout-Raum #{{index}}",
|
||||
"hideParticipantList": "Personenliste ausblenden",
|
||||
"hideParticipantList": "Teilnehmerliste ausblenden",
|
||||
"mainRoom": "Hauptraum",
|
||||
"notifications": {
|
||||
"joined": "Breakout-Raum \"{{name}}\" betreten",
|
||||
"joinedMainRoom": "Hauptraum betreten",
|
||||
"joinedTitle": "Breakout-Räume"
|
||||
},
|
||||
"showParticipantList": "Personenliste anzeigen",
|
||||
"showParticipantList": "Teilnehmerliste anzeigen",
|
||||
"title": "Breakout-Räume"
|
||||
},
|
||||
"calendarSync": {
|
||||
@@ -89,7 +89,7 @@
|
||||
"notSignedIn": "Ein Fehler ist während der Authentifizierung zur Anzeige von Kalenderterminen aufgetreten. Prüfen Sie Ihre Kalendereinstellungen oder versuchen Sie, sich erneut anzumelden."
|
||||
},
|
||||
"join": "Teilnehmen",
|
||||
"joinTooltip": "An Konferenz teilnehmen",
|
||||
"joinTooltip": "Am Konferenz teilnehmen",
|
||||
"nextMeeting": "Nächste Konferenz",
|
||||
"noEvents": "Es gibt keine bevorstehenden Termine.",
|
||||
"ongoingMeeting": "Laufende Konferenz",
|
||||
@@ -363,18 +363,18 @@
|
||||
"muteEveryoneDialogModerationOn": "Die Anwesenden können eine Anfrage zum Sprechen jederzeit senden.",
|
||||
"muteEveryoneElseDialog": "Einmal stummgeschaltet, können Sie deren Stummschaltung nicht mehr beenden, aber sie können ihre Stummschaltung jederzeit selbst beenden.",
|
||||
"muteEveryoneElseTitle": "Alle außer {{whom}} stummschalten?",
|
||||
"muteEveryoneElsesVideoDialog": "Sobald die Kamera für alle anderen Personen deaktiviert ist, können Sie diese nicht wieder für alle einschalten, die anderen Personen können ihre Kamera aber jederzeit wieder einschalten.",
|
||||
"muteEveryoneElsesVideoDialog": "Sobald die Kamera deaktiviert ist, können Sie sie nicht wieder aktivieren, die Teilnehmer können dies aber jederzeit wieder ändern.",
|
||||
"muteEveryoneElsesVideoTitle": "Die Kamera von allen außer {{whom}} ausschalten?",
|
||||
"muteEveryoneSelf": "sich selbst",
|
||||
"muteEveryoneStartMuted": "Alle beginnen von jetzt an stummgeschaltet",
|
||||
"muteEveryoneTitle": "Alle stummschalten?",
|
||||
"muteEveryonesVideoDialog": "Sind Sie sicher, dass Sie die Kamera von allen Personen deaktivieren möchten? Sie können dies nicht wieder rückgängig machen, jede Personen kann ihre Kamera aber jederzeit wieder einschalten.",
|
||||
"muteEveryonesVideoDialog": "Sind Sie sicher, dass Sie die Kamera von allen Teilnehmern deaktivieren möchten? Sie können sie nicht wieder aktivieren, die Teilnehmer können dies aber jederzeit wieder ändern.",
|
||||
"muteEveryonesVideoDialogModerationOn": "Die Anwesenden können jederzeit eine Anfrage senden, um ihre Kamera einzuschalten.",
|
||||
"muteEveryonesVideoDialogOk": "deaktivieren",
|
||||
"muteEveryonesVideoTitle": "Die Kamera von allen anderen ausschalten?",
|
||||
"muteParticipantBody": "Sie können die Stummschaltung anderer Personen nicht aufheben, aber eine Person kann ihre eigene Stummschaltung jederzeit beenden.",
|
||||
"muteParticipantButton": "Stummschalten",
|
||||
"muteParticipantsVideoBody": "Sie können die Kamera nicht wieder einschalten, die Person kann ihre Kamera aber jederzeit wieder einschalten.",
|
||||
"muteParticipantsVideoBody": "Sie können die Kamera nicht wieder aktivieren, die Teilnehmer können dies aber jederzeit wieder ändern.",
|
||||
"muteParticipantsVideoBodyModerationOn": "Sie können die Kamera nicht wieder aktivieren und die Person selbst auch nicht.",
|
||||
"muteParticipantsVideoButton": "Kamera ausschalten",
|
||||
"muteParticipantsVideoDialog": "Wollen Sie die Kamera dieser Person wirklich deaktivieren? Sie können die Kamera nicht wieder aktivieren, die Person kann dies aber jederzeit selbst tun.",
|
||||
@@ -562,7 +562,7 @@
|
||||
"inviteTextiOSPhone": "Nutzen Sie folgende Nummer um via Telefon teilzunehmen: {{number}},,{{conferenceID}}#. Wenn Sie nach einer anderen Einwahlnummer suchen, finden Sie die vollständige Liste hier: {{didUrl}}.",
|
||||
"inviteURLFirstPartGeneral": "Sie wurden zur Teilnahme an einer Konferenz eingeladen.",
|
||||
"inviteURLFirstPartPersonal": "{{name}} lädt Sie zu einer Konferenz ein.\n",
|
||||
"inviteURLSecondPart": "\nAn Konferenz teilnehmen:\n{{url}}\n",
|
||||
"inviteURLSecondPart": "\nAm Konferenz teilnehmen:\n{{url}}\n",
|
||||
"label": "Einwahlinformationen",
|
||||
"liveStreamURL": "Livestream:",
|
||||
"moreNumbers": "Weitere Telefonnummern",
|
||||
@@ -642,7 +642,6 @@
|
||||
"on": "Livestream",
|
||||
"onBy": "{{name}} startete den Livestream",
|
||||
"pending": "Livestream wird gestartet …",
|
||||
"policyError": "Sie haben den Livestream zu schnell gestartet. Bitte versuchen Sie es später noch einmal!",
|
||||
"serviceName": "Livestreaming-Dienst",
|
||||
"sessionAlreadyActive": "Diese Konferenz wird bereits als Livestream übertragen.",
|
||||
"signIn": "Mit Google anmelden",
|
||||
@@ -743,7 +742,7 @@
|
||||
"connectedOneMember": "{{name}} nimmt an der Konferenz teil",
|
||||
"connectedThreePlusMembers": "{{name}} und {{count}} andere Personen nehmen an der Konferenz teil",
|
||||
"connectedTwoMembers": "{{first}} und {{second}} nehmen an der Konferenz teil",
|
||||
"connectionFailed": "Verbindung fehlgeschlagen. Bitte versuchen Sie es später noch einmal!",
|
||||
"connectionFailed": "Verbindung fehlgeschlagen. Bitte versuchen Sie es später noch einmal.",
|
||||
"dataChannelClosed": "Schlechte Videoqualität",
|
||||
"dataChannelClosedDescription": "Die Steuerungsverbindung (Bridge Channel) wurde unterbrochen, daher ist die Videoqulität auf die schlechteste Stufe limitiert.",
|
||||
"dataChannelClosedDescriptionWithAudio": "Die Steuerungsverbindung (Bridge Channel) wurde unterbrochen, daher können Video- und Tonprobleme auftreten.",
|
||||
@@ -758,9 +757,9 @@
|
||||
"gifsMenu": "GIPHY",
|
||||
"groupTitle": "Benachrichtigungen",
|
||||
"hostAskedUnmute": "Die Moderation bittet Sie, das Mikrofon zu aktivieren",
|
||||
"invalidTenant": "Ungültiger Mandant",
|
||||
"invalidTenantHyphenDescription": "Der gewählte Mandantenname ist ungültig (beginnt oder endet mit '-').",
|
||||
"invalidTenantLengthDescription": "Der gewählte Mandantenname ist zu lang.",
|
||||
"invalidTenant": "Ungültiger Tenant",
|
||||
"invalidTenantHyphenDescription": "Der von Ihnen genutzte Tenantname ist unfültig (beginnt oder endet mit '-').",
|
||||
"invalidTenantLengthDescription": "Der von Ihnen genutzte Tenantname ist zu lang.",
|
||||
"invitedOneMember": "{{name}} wurde eingeladen",
|
||||
"invitedThreePlusMembers": "{{name}} und {{count}} andere wurden eingeladen",
|
||||
"invitedTwoMembers": "{{first}} und {{second}} wurden eingeladen",
|
||||
@@ -1060,7 +1059,7 @@
|
||||
"onBy": "{{name}} startete die Aufnahme",
|
||||
"onlyRecordSelf": "Nur eigenes Kamerabild und Ton aufzeichnen",
|
||||
"pending": "Aufzeichnung der Konferenz wird vorbereitet…",
|
||||
"policyError": "Sie haben die Aufzeichnung zu schnell gestartet. Bitte versuchen Sie es später noch einmal.",
|
||||
"policyError": "Sie haben die Aufzeichnung zu früh gestartet. Bitte versuchen Sie es später noch einmal.",
|
||||
"recordAudioAndVideo": "Kamera und Ton aufzeichnen",
|
||||
"recordTranscription": "Transkription aufzeichnen",
|
||||
"saveLocalRecording": "Aufzeichnung lokal abspeichern",
|
||||
@@ -1083,10 +1082,10 @@
|
||||
"pullToRefresh": "Ziehen, um zu aktualisieren"
|
||||
},
|
||||
"security": {
|
||||
"about": "Sie können Ihre Konferenz mit einem Passwort sichern. Personen müssen dieses eingeben, bevor sie an der Sitzung teilnehmen dürfen.",
|
||||
"about": "Sie können Ihre Konferenz mit einem Passwort sichern. Teilnehmer müssen dieses eingeben, bevor sie an der Sitzung teilnehmen dürfen.",
|
||||
"aboutReadOnly": "Mit Moderationsrechten kann die Konferenz mit einem Passwort gesichert werden. Personen müssen dieses eingeben, bevor sie an der Sitzung teilnehmen dürfen.",
|
||||
"insecureRoomNameWarningNative": "Der Raumname ist unsicher. Unerwünschte Personen könnten Ihrer Konferenz beitreten. {{recommendAction}} Lernen Sie mehr über die Absicherung Ihrer Konferenz ",
|
||||
"insecureRoomNameWarningWeb": "Der Raumname ist unsicher. Unerwünschte Personen könnten Ihrer Konferenz beitreten {{recommendAction}} Lernen Sie <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">hier</a> mehr über die Absicherung Ihrer Konferenz.",
|
||||
"insecureRoomNameWarningNative": "Der Raumname ist unsicher. Unerwünschte Teilnehmer könnten Ihrer Konferenz beitreten. {{recommendAction}} Lernen Sie mehr über die Absicherung Ihrer Konferenz ",
|
||||
"insecureRoomNameWarningWeb": "Der Raumname ist unsicher. Unerwünschte Teilnehmer könnten Ihrer Konferenz beitreten {{recommendAction}} Lernen Sie <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">hier</a> mehr über die Absicherung Ihrer Konferenz.",
|
||||
"title": "Sicherheitsoptionen",
|
||||
"unsafeRoomActions": {
|
||||
"meeting": "Erwägen Sie die Absicherung Ihrer Konferenz über den Sicherheits-Button.",
|
||||
@@ -1186,7 +1185,6 @@
|
||||
"fearful": "Ängstlich",
|
||||
"happy": "Fröhlich",
|
||||
"hours": "{{count}} Std. ",
|
||||
"labelTooltip": "Anzahl der Personen: {{count}}",
|
||||
"minutes": "{{count}} Min. ",
|
||||
"name": "Name",
|
||||
"neutral": "Neutral",
|
||||
|
||||
1584
lang/main-no.json
1584
lang/main-no.json
File diff suppressed because it is too large
Load Diff
@@ -263,7 +263,6 @@
|
||||
"Remove": "Remove",
|
||||
"Share": "Share",
|
||||
"Submit": "Submit",
|
||||
"Understand": "I understand",
|
||||
"WaitForHostMsg": "The conference has not yet started because no moderators have yet arrived. If you'd like to become a moderator please log-in. Otherwise, please wait.",
|
||||
"WaitForHostNoAuthMsg": "The conference has not yet started because no moderators have yet arrived. Please wait.",
|
||||
"WaitingForHostButton": "Wait for moderator",
|
||||
@@ -394,8 +393,6 @@
|
||||
"recentlyUsedObjects": "Your recently used objects",
|
||||
"recording": "Recording",
|
||||
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Not possible while a live stream is active",
|
||||
"recordingInProgressDescription": "This meeting is being recorded. Your audio and video have been muted. If you choose to unmute, you consent to being recorded.",
|
||||
"recordingInProgressTitle": "Recording in progress",
|
||||
"rejoinNow": "Rejoin now",
|
||||
"remoteControlAllowedMessage": "{{user}} accepted your remote control request!",
|
||||
"remoteControlDeniedMessage": "{{user}} rejected your remote control request!",
|
||||
|
||||
10
package-lock.json
generated
10
package-lock.json
generated
@@ -62,7 +62,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/v1919.0.0+d4a47d0e/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1915.0.0+6e9b9c01/lib-jitsi-meet.tgz",
|
||||
"lodash-es": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -16909,8 +16909,8 @@
|
||||
},
|
||||
"node_modules/lib-jitsi-meet": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1919.0.0+d4a47d0e/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-0/rTgoaaXwKs4J2+MY4HYh/VbZg3gjNHInhAz+smZGlWsJB8H2qkSNVU0HcTI7WG5LzrzkX4c/eTVpkq8ljLJw==",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1915.0.0+6e9b9c01/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-erPBz93xzWDIvW9EdvSfiraHFi0TMo1W68zxe7rKvIQWX1DCjmKxWKnxdq5WirSD7MXwoSIxgdX4PB7Wz3aTmg==",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@@ -37637,8 +37637,8 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1919.0.0+d4a47d0e/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-0/rTgoaaXwKs4J2+MY4HYh/VbZg3gjNHInhAz+smZGlWsJB8H2qkSNVU0HcTI7WG5LzrzkX4c/eTVpkq8ljLJw==",
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1915.0.0+6e9b9c01/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-erPBz93xzWDIvW9EdvSfiraHFi0TMo1W68zxe7rKvIQWX1DCjmKxWKnxdq5WirSD7MXwoSIxgdX4PB7Wz3aTmg==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "2.2.1",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
|
||||
@@ -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/v1919.0.0+d4a47d0e/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1915.0.0+6e9b9c01/lib-jitsi-meet.tgz",
|
||||
"lodash-es": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
|
||||
@@ -4,7 +4,7 @@ import { JitsiConferenceErrors } from '../lib-jitsi-meet';
|
||||
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
|
||||
import { CONFERENCE_FAILED } from './actionTypes';
|
||||
import { conferenceLeft } from './actions.native';
|
||||
import { conferenceLeft } from './actions';
|
||||
import { TRIGGER_READY_TO_CLOSE_REASONS } from './constants';
|
||||
|
||||
import './middleware.any';
|
||||
@@ -15,20 +15,10 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
|
||||
switch (action.type) {
|
||||
case CONFERENCE_FAILED: {
|
||||
const { getState } = store;
|
||||
const state = getState();
|
||||
const { notifyOnConferenceDestruction = true } = state['features/base/config'];
|
||||
|
||||
if (error?.name !== JitsiConferenceErrors.CONFERENCE_DESTROYED) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!notifyOnConferenceDestruction) {
|
||||
dispatch(conferenceLeft(action.conference));
|
||||
dispatch(appNavigate(undefined));
|
||||
break;
|
||||
}
|
||||
|
||||
const [ reason ] = error.params;
|
||||
|
||||
const reasonKey = Object.keys(TRIGGER_READY_TO_CLOSE_REASONS)[
|
||||
|
||||
@@ -122,14 +122,12 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
}
|
||||
|
||||
if (errorName === JitsiConferenceErrors.CONFERENCE_DESTROYED) {
|
||||
const state = getState();
|
||||
const { notifyOnConferenceDestruction = true } = state['features/base/config'];
|
||||
const [ reason ] = action.error.params;
|
||||
const titlekey = Object.keys(TRIGGER_READY_TO_CLOSE_REASONS)[
|
||||
Object.values(TRIGGER_READY_TO_CLOSE_REASONS).indexOf(reason)
|
||||
];
|
||||
|
||||
dispatch(hangup(true, i18next.t(titlekey) || reason, notifyOnConferenceDestruction));
|
||||
dispatch(hangup(true, i18next.t(titlekey) || reason));
|
||||
}
|
||||
|
||||
releaseScreenLock();
|
||||
|
||||
@@ -486,7 +486,6 @@ export interface IConfig {
|
||||
short?: number;
|
||||
};
|
||||
notifications?: Array<string>;
|
||||
notifyOnConferenceDestruction?: boolean;
|
||||
openSharedDocumentOnJoin?: boolean;
|
||||
opusMaxAverageBitrate?: number;
|
||||
p2p?: {
|
||||
@@ -543,7 +542,6 @@ export interface IConfig {
|
||||
recordingSharingUrl?: string;
|
||||
recordings?: {
|
||||
recordAudioAndVideo?: boolean;
|
||||
requireConsent?: boolean;
|
||||
showPrejoinWarning?: boolean;
|
||||
showRecordingLink?: boolean;
|
||||
suggestRecording?: boolean;
|
||||
|
||||
@@ -182,7 +182,6 @@ export default [
|
||||
'mouseMoveCallbackInterval',
|
||||
'notifications',
|
||||
'notificationTimeouts',
|
||||
'notifyOnConferenceDestruction',
|
||||
'openSharedDocumentOnJoin',
|
||||
'opusMaxAverageBitrate',
|
||||
'p2p.backToP2PDelay',
|
||||
@@ -206,10 +205,7 @@ export default [
|
||||
'remoteVideoMenu',
|
||||
'roomPasswordNumberOfDigits',
|
||||
'readOnlyName',
|
||||
'recordings.recordAudioAndVideo',
|
||||
'recordings.showPrejoinWarning',
|
||||
'recordings.showRecordingLink',
|
||||
'recordings.suggestRecording',
|
||||
'recordings',
|
||||
'replaceParticipant',
|
||||
'resolution',
|
||||
'screenshotCapture',
|
||||
|
||||
@@ -62,11 +62,9 @@ export function connect(id?: string, password?: string) {
|
||||
* @param {boolean} [requestFeedback] - Whether to attempt showing a
|
||||
* request for call feedback.
|
||||
* @param {string} [feedbackTitle] - The feedback title.
|
||||
* @param {boolean} [notifyOnConferenceTermination] - Whether to notify
|
||||
* the user on conference termination.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function hangup(requestFeedback = false, feedbackTitle?: string, notifyOnConferenceTermination?: boolean) {
|
||||
export function hangup(requestFeedback = false, feedbackTitle?: string) {
|
||||
// XXX For web based version we use conference hanging up logic from the old app.
|
||||
return async (dispatch: IStore['dispatch']) => {
|
||||
if (LocalRecordingManager.isRecordingLocally()) {
|
||||
@@ -82,6 +80,6 @@ export function hangup(requestFeedback = false, feedbackTitle?: string, notifyOn
|
||||
});
|
||||
}
|
||||
|
||||
return APP.conference.hangup(requestFeedback, feedbackTitle, notifyOnConferenceTermination);
|
||||
return APP.conference.hangup(requestFeedback, feedbackTitle);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -36,11 +36,6 @@ interface IProps extends AbstractProps, WithTranslation {
|
||||
*/
|
||||
descriptionKey?: string | { key: string; params: string; };
|
||||
|
||||
/**
|
||||
* Whether the cancel button is hidden.
|
||||
*/
|
||||
isCancelHidden?: Boolean;
|
||||
|
||||
/**
|
||||
* Whether or not the nature of the confirm button is destructive.
|
||||
*/
|
||||
@@ -105,7 +100,6 @@ class ConfirmDialog extends AbstractDialog<IProps> {
|
||||
cancelLabel,
|
||||
children,
|
||||
confirmLabel,
|
||||
isCancelHidden,
|
||||
isConfirmDestructive,
|
||||
isConfirmHidden,
|
||||
t,
|
||||
@@ -127,12 +121,10 @@ class ConfirmDialog extends AbstractDialog<IProps> {
|
||||
}
|
||||
{ this._renderDescription() }
|
||||
{ children }
|
||||
{
|
||||
!isCancelHidden && <Dialog.Button
|
||||
label = { t(cancelLabel || 'dialog.confirmNo') }
|
||||
onPress = { this._onCancel }
|
||||
style = { styles.dialogButton } />
|
||||
}
|
||||
<Dialog.Button
|
||||
label = { t(cancelLabel || 'dialog.confirmNo') }
|
||||
onPress = { this._onCancel }
|
||||
style = { styles.dialogButton } />
|
||||
{
|
||||
!isConfirmHidden && <Dialog.Button
|
||||
label = { t(confirmLabel || 'dialog.confirmYes') }
|
||||
|
||||
@@ -4,12 +4,6 @@
|
||||
*/
|
||||
export const ADD_PEOPLE_ENABLED = 'add-people.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if the audio device button should be displayed.
|
||||
* Default: enabled (true).
|
||||
*/
|
||||
export const AUDIO_DEVICE_BUTTON_ENABLED = 'audio-device-button.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if the SDK should not require the audio focus.
|
||||
* Used by apps that do not use Jitsi audio.
|
||||
@@ -245,16 +239,10 @@ export const SETTINGS_ENABLED = 'settings.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if tile view feature should be enabled.
|
||||
* Default: enabled(true).
|
||||
* Default: enabled.
|
||||
*/
|
||||
export const TILE_VIEW_ENABLED = 'tile-view.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if the toggle camera button should be enabled
|
||||
* Default: enabled(true).
|
||||
*/
|
||||
export const TOGGLE_CAMERA_BUTTON_ENABLED = 'toggle-camera-button.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if the toolbox should be always be visible
|
||||
* Default: disabled (false).
|
||||
|
||||
@@ -15,11 +15,6 @@ interface IProps {
|
||||
*/
|
||||
gifEnabled: boolean;
|
||||
|
||||
/**
|
||||
* Message decoration for screen reader.
|
||||
*/
|
||||
screenReaderHelpText?: string;
|
||||
|
||||
/**
|
||||
* The body of the message.
|
||||
*/
|
||||
@@ -96,18 +91,10 @@ class Message extends Component<IProps> {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { screenReaderHelpText } = this.props;
|
||||
|
||||
return (
|
||||
<p>
|
||||
{ screenReaderHelpText && (
|
||||
<span className = 'sr-only'>
|
||||
{screenReaderHelpText}
|
||||
</span>
|
||||
) }
|
||||
|
||||
<>
|
||||
{ this._processMessage() }
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,9 +254,7 @@ const ChatMessage = ({
|
||||
function _renderTimestamp() {
|
||||
return (
|
||||
<div className = { cx('timestamp', classes.timestamp) }>
|
||||
<p>
|
||||
{getFormattedTimestamp(message)}
|
||||
</p>
|
||||
{getFormattedTimestamp(message)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -287,17 +285,15 @@ const ChatMessage = ({
|
||||
<div
|
||||
className = { classes.reactionItem }
|
||||
key = { reaction }>
|
||||
<p>
|
||||
<span>{reaction}</span>
|
||||
<span>{participants.size}</span>
|
||||
</p>
|
||||
<span>{reaction}</span>
|
||||
<span>{participants.size}</span>
|
||||
<div className = { classes.participantList }>
|
||||
{Array.from(participants).map(participantId => (
|
||||
<p
|
||||
<div
|
||||
className = { classes.participant }
|
||||
key = { participantId }>
|
||||
{state && getParticipantDisplayName(state, participantId)}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -315,12 +311,12 @@ const ChatMessage = ({
|
||||
visible = { isReactionsOpen }>
|
||||
<div className = { classes.reactionBox }>
|
||||
{reactionsArray.slice(0, numReactionsDisplayed).map(({ reaction }, index) =>
|
||||
<p key = { index }>{reaction}</p>
|
||||
<span key = { index }>{reaction}</span>
|
||||
)}
|
||||
{reactionsArray.length > numReactionsDisplayed && (
|
||||
<p className = { classes.reactionCount }>
|
||||
<span className = { classes.reactionCount }>
|
||||
+{totalReactions - numReactionsDisplayed}
|
||||
</p>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</Popover>
|
||||
@@ -356,13 +352,14 @@ const ChatMessage = ({
|
||||
<div className = { cx('messagecontent', classes.messageContent) }>
|
||||
{showDisplayName && _renderDisplayName()}
|
||||
<div className = { cx('usermessage', classes.userMessage) }>
|
||||
<Message
|
||||
screenReaderHelpText = { message.displayName === message.recipient
|
||||
? t<string>('chat.messageAccessibleTitleMe')
|
||||
: t<string>('chat.messageAccessibleTitle', {
|
||||
<span className = 'sr-only'>
|
||||
{message.displayName === message.recipient
|
||||
? t('chat.messageAccessibleTitleMe')
|
||||
: t('chat.messageAccessibleTitle', {
|
||||
user: message.displayName
|
||||
}) }
|
||||
text = { getMessageText(message) } />
|
||||
})}
|
||||
</span>
|
||||
<Message text = { getMessageText(message) } />
|
||||
{(message.privateMessage || (message.lobbyChat && !knocking))
|
||||
&& _renderPrivateNotice()}
|
||||
<div className = { classes.chatMessageFooter }>
|
||||
|
||||
@@ -15,7 +15,6 @@ import { connect, useDispatch } from 'react-redux';
|
||||
import { appNavigate } from '../../../app/actions.native';
|
||||
import { IReduxState, IStore } from '../../../app/types';
|
||||
import { CONFERENCE_BLURRED, CONFERENCE_FOCUSED } from '../../../base/conference/actionTypes';
|
||||
import { isDisplayNameVisible } from '../../../base/config/functions.native';
|
||||
import { FULLSCREEN_ENABLED } from '../../../base/flags/constants';
|
||||
import { getFeatureFlag } from '../../../base/flags/functions';
|
||||
import Container from '../../../base/react/components/native/Container';
|
||||
@@ -101,11 +100,6 @@ interface IProps extends AbstractProps {
|
||||
*/
|
||||
_fullscreenEnabled: boolean;
|
||||
|
||||
/**
|
||||
* The indicator which determines if the display name is visible.
|
||||
*/
|
||||
_isDisplayNameVisible: boolean;
|
||||
|
||||
/**
|
||||
* The indicator which determines if the participants pane is open.
|
||||
*/
|
||||
@@ -370,7 +364,6 @@ class Conference extends AbstractConference<IProps, State> {
|
||||
_aspectRatio,
|
||||
_connecting,
|
||||
_filmstripVisible,
|
||||
_isDisplayNameVisible,
|
||||
_largeVideoParticipantId,
|
||||
_reducedUI,
|
||||
_shouldDisplayTileView,
|
||||
@@ -427,12 +420,10 @@ class Conference extends AbstractConference<IProps, State> {
|
||||
|
||||
{
|
||||
_shouldDisplayTileView
|
||||
|| (_isDisplayNameVisible && (
|
||||
<Container style = { styles.displayNameContainer }>
|
||||
<DisplayNameLabel
|
||||
participantId = { _largeVideoParticipantId } />
|
||||
</Container>
|
||||
))
|
||||
|| <Container style = { styles.displayNameContainer }>
|
||||
<DisplayNameLabel
|
||||
participantId = { _largeVideoParticipantId } />
|
||||
</Container>
|
||||
}
|
||||
|
||||
{ !_shouldDisplayTileView && <LonelyMeetingExperience /> }
|
||||
@@ -586,7 +577,6 @@ function _mapStateToProps(state: IReduxState, _ownProps: any) {
|
||||
_connecting: isConnecting(state),
|
||||
_filmstripVisible: isFilmstripVisible(state),
|
||||
_fullscreenEnabled: getFeatureFlag(state, FULLSCREEN_ENABLED, true),
|
||||
_isDisplayNameVisible: isDisplayNameVisible(state),
|
||||
_isParticipantsPaneOpen: isOpen,
|
||||
_largeVideoParticipantId: state['features/large-video'].participantId,
|
||||
_pictureInPictureEnabled: isPipEnabled(state),
|
||||
|
||||
@@ -82,7 +82,6 @@ class LonelyMeetingExperience extends PureComponent<IProps> {
|
||||
render() {
|
||||
const {
|
||||
_inviteOthersControl,
|
||||
_isAddPeopleFeatureEnabled,
|
||||
_isInBreakoutRoom,
|
||||
_isInviteFunctionsDisabled,
|
||||
_isLonelyMeeting,
|
||||
@@ -90,7 +89,7 @@ class LonelyMeetingExperience extends PureComponent<IProps> {
|
||||
} = this.props;
|
||||
const { color, shareDialogVisible } = _inviteOthersControl;
|
||||
|
||||
if (!_isLonelyMeeting || !_isAddPeopleFeatureEnabled) {
|
||||
if (!_isLonelyMeeting) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,17 +4,13 @@ import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { getConferenceName, getConferenceTimestamp } from '../../../base/conference/functions';
|
||||
import {
|
||||
AUDIO_DEVICE_BUTTON_ENABLED,
|
||||
CONFERENCE_TIMER_ENABLED,
|
||||
TOGGLE_CAMERA_BUTTON_ENABLED
|
||||
} from '../../../base/flags/constants';
|
||||
import { CONFERENCE_TIMER_ENABLED } from '../../../base/flags/constants';
|
||||
import { getFeatureFlag } from '../../../base/flags/functions';
|
||||
import AudioDeviceToggleButton from '../../../mobile/audio-mode/components/AudioDeviceToggleButton';
|
||||
import PictureInPictureButton from '../../../mobile/picture-in-picture/components/PictureInPictureButton';
|
||||
import ParticipantsPaneButton from '../../../participants-pane/components/native/ParticipantsPaneButton';
|
||||
import { isParticipantsPaneEnabled } from '../../../participants-pane/functions';
|
||||
import { isRoomNameEnabled } from '../../../prejoin/functions.native';
|
||||
import { isRoomNameEnabled } from '../../../prejoin/functions';
|
||||
import ToggleCameraButton from '../../../toolbox/components/native/ToggleCameraButton';
|
||||
import { isToolboxVisible } from '../../../toolbox/functions.native';
|
||||
import ConferenceTimer from '../ConferenceTimer';
|
||||
@@ -25,11 +21,6 @@ import styles from './styles';
|
||||
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
* Whether the audio device button should be displayed.
|
||||
*/
|
||||
_audioDeviceButtonEnabled: boolean;
|
||||
|
||||
/**
|
||||
* Whether displaying the current conference timer is enabled or not.
|
||||
*/
|
||||
@@ -56,11 +47,6 @@ interface IProps {
|
||||
*/
|
||||
_roomNameEnabled: boolean;
|
||||
|
||||
/**
|
||||
* Whether the toggle camera button should be displayed.
|
||||
*/
|
||||
_toggleCameraButtonEnabled: boolean;
|
||||
|
||||
/**
|
||||
* True if the navigation bar should be visible.
|
||||
*/
|
||||
@@ -109,18 +95,12 @@ const TitleBar = (props: IProps) => {
|
||||
{/* eslint-disable-next-line react/jsx-no-bind */}
|
||||
<Labels createOnPress = { props._createOnPress } />
|
||||
</View>
|
||||
{
|
||||
props._toggleCameraButtonEnabled
|
||||
&& <View style = { styles.titleBarButtonContainer }>
|
||||
<ToggleCameraButton styles = { styles.titleBarButton } />
|
||||
</View>
|
||||
}
|
||||
{
|
||||
props._audioDeviceButtonEnabled
|
||||
&& <View style = { styles.titleBarButtonContainer }>
|
||||
<AudioDeviceToggleButton styles = { styles.titleBarButton } />
|
||||
</View>
|
||||
}
|
||||
<View style = { styles.titleBarButtonContainer }>
|
||||
<ToggleCameraButton styles = { styles.titleBarButton } />
|
||||
</View>
|
||||
<View style = { styles.titleBarButtonContainer }>
|
||||
<AudioDeviceToggleButton styles = { styles.titleBarButton } />
|
||||
</View>
|
||||
{
|
||||
_isParticipantsPaneEnabled
|
||||
&& <View style = { styles.titleBarButtonContainer }>
|
||||
@@ -143,13 +123,11 @@ function _mapStateToProps(state: IReduxState) {
|
||||
const startTimestamp = getConferenceTimestamp(state);
|
||||
|
||||
return {
|
||||
_audioDeviceButtonEnabled: getFeatureFlag(state, AUDIO_DEVICE_BUTTON_ENABLED, true),
|
||||
_conferenceTimerEnabled:
|
||||
Boolean(getFeatureFlag(state, CONFERENCE_TIMER_ENABLED, true) && !hideConferenceTimer && startTimestamp),
|
||||
_isParticipantsPaneEnabled: isParticipantsPaneEnabled(state),
|
||||
_meetingName: getConferenceName(state),
|
||||
_roomNameEnabled: isRoomNameEnabled(state),
|
||||
_toggleCameraButtonEnabled: getFeatureFlag(state, TOGGLE_CAMERA_BUTTON_ENABLED, true),
|
||||
_visible: isToolboxVisible(state)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { appNavigate } from '../app/actions.native';
|
||||
import { KICKED_OUT } from '../base/conference/actionTypes';
|
||||
import { conferenceLeft } from '../base/conference/actions.native';
|
||||
import { conferenceLeft } from '../base/conference/actions';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
|
||||
import { notifyKickedOut } from './actions.native';
|
||||
|
||||
@@ -35,8 +35,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
|
||||
dispatch(hangup(true,
|
||||
participantDisplayName ? i18next.t('dialog.kickTitle', { participantDisplayName })
|
||||
: i18next.t('dialog.kickSystemTitle'),
|
||||
true));
|
||||
: i18next.t('dialog.kickSystemTitle')));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -158,7 +158,6 @@ export interface IDynamicBrandingState {
|
||||
logoImageUrl: string;
|
||||
muiBrandedTheme?: boolean;
|
||||
premeetingBackground: string;
|
||||
requireRecordingConsent?: boolean;
|
||||
sharedVideoAllowedURLDomains?: Array<string>;
|
||||
showGiphyIntegration?: boolean;
|
||||
supportUrl?: string;
|
||||
@@ -187,7 +186,6 @@ ReducerRegistry.register<IDynamicBrandingState>(STORE_NAME, (state = DEFAULT_STA
|
||||
premeetingBackground,
|
||||
sharedVideoAllowedURLDomains,
|
||||
showGiphyIntegration,
|
||||
requireRecordingConsent,
|
||||
supportUrl,
|
||||
virtualBackgrounds
|
||||
} = action.value;
|
||||
@@ -207,7 +205,6 @@ ReducerRegistry.register<IDynamicBrandingState>(STORE_NAME, (state = DEFAULT_STA
|
||||
premeetingBackground,
|
||||
sharedVideoAllowedURLDomains,
|
||||
showGiphyIntegration,
|
||||
requireRecordingConsent,
|
||||
supportUrl,
|
||||
customizationFailed: false,
|
||||
customizationReady: true,
|
||||
|
||||
@@ -4,7 +4,6 @@ import { connect } from 'react-redux';
|
||||
// @ts-expect-error
|
||||
import VideoLayout from '../../../../modules/UI/videolayout/VideoLayout';
|
||||
import { IReduxState, IStore } from '../../app/types';
|
||||
import { isDisplayNameVisible } from '../../base/config/functions.web';
|
||||
import { VIDEO_TYPE } from '../../base/media/constants';
|
||||
import { getLocalParticipant } from '../../base/participants/functions';
|
||||
import Watermarks from '../../base/react/components/web/Watermarks';
|
||||
@@ -59,11 +58,6 @@ interface IProps {
|
||||
*/
|
||||
_isChatOpen: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not the display name is visible.
|
||||
*/
|
||||
_isDisplayNameVisible: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not the local screen share is on large-video.
|
||||
*/
|
||||
@@ -197,7 +191,6 @@ class LargeVideo extends Component<IProps> {
|
||||
const {
|
||||
_displayScreenSharingPlaceholder,
|
||||
_isChatOpen,
|
||||
_isDisplayNameVisible,
|
||||
_noAutoPlayVideo,
|
||||
_showDominantSpeakerBadge,
|
||||
_whiteboardEnabled
|
||||
@@ -250,12 +243,7 @@ class LargeVideo extends Component<IProps> {
|
||||
</div>
|
||||
{ interfaceConfig.DISABLE_TRANSCRIPTION_SUBTITLES
|
||||
|| <Captions /> }
|
||||
{
|
||||
_isDisplayNameVisible
|
||||
&& (
|
||||
_showDominantSpeakerBadge && <StageParticipantNameLabel />
|
||||
)
|
||||
}
|
||||
{_showDominantSpeakerBadge && <StageParticipantNameLabel />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -380,7 +368,6 @@ function _mapStateToProps(state: IReduxState) {
|
||||
_displayScreenSharingPlaceholder: Boolean(isLocalScreenshareOnLargeVideo && !seeWhatIsBeingShared && !isOnSpot),
|
||||
_hideSelfView: getHideSelfView(state),
|
||||
_isChatOpen: isChatOpen,
|
||||
_isDisplayNameVisible: isDisplayNameVisible(state),
|
||||
_isScreenSharing: Boolean(isLocalScreenshareOnLargeVideo),
|
||||
_largeVideoParticipantId: largeVideoParticipant?.id ?? '',
|
||||
_localParticipantId: localParticipantId ?? '',
|
||||
|
||||
@@ -68,16 +68,12 @@ function _toDateString(itemDate: number, t: Function) {
|
||||
const dateInMs = date.getTime();
|
||||
const now = new Date();
|
||||
const todayInMs = new Date().setHours(0, 0, 0, 0);
|
||||
const yesterday = new Date();
|
||||
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
yesterday.setHours(0, 0, 0, 0);
|
||||
const yesterdayInMs = yesterday.getTime();
|
||||
const yesterdayInMs = todayInMs - 86400000; // 1 day = 86400000ms
|
||||
|
||||
if (dateInMs >= todayInMs) {
|
||||
return m.fromNow();
|
||||
} else if (dateInMs >= yesterdayInMs) {
|
||||
return `${t('dateUtils.yesterday')}, ${m.format('h:mm A')}`;
|
||||
return t('dateUtils.yesterday');
|
||||
} else if (date.getFullYear() !== now.getFullYear()) {
|
||||
// We only want to include the year in the date if its not the current
|
||||
// year.
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export { default as StartRecordingDialog } from './native/StartRecordingDialog';
|
||||
export { default as RecordingConsentDialog } from './native/RecordingConsentDialog';
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export { default as StartRecordingDialog } from './web/StartRecordingDialog';
|
||||
export { default as RecordingConsentDialog } from './web/RecordingConsentDialog';
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import ConfirmDialog from '../../../../base/dialog/components/native/ConfirmDialog';
|
||||
import { setAudioUnmutePermissions, setVideoUnmutePermissions } from '../../../../base/media/actions';
|
||||
|
||||
/**
|
||||
* Component that renders the dialog for explicit consent for recordings.
|
||||
*
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
export default function RecordingConsentDialog() {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const consent = useCallback(() => {
|
||||
dispatch(setAudioUnmutePermissions(false, true));
|
||||
dispatch(setVideoUnmutePermissions(false, true));
|
||||
|
||||
return true;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ConfirmDialog
|
||||
confirmLabel = { 'dialog.Understand' }
|
||||
descriptionKey = { 'dialog.recordingInProgressDescription' }
|
||||
isCancelHidden = { true }
|
||||
onSubmit = { consent }
|
||||
title = { 'dialog.recordingInProgressTitle' } />
|
||||
);
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { setAudioUnmutePermissions, setVideoUnmutePermissions } from '../../../../base/media/actions';
|
||||
import Dialog from '../../../../base/ui/components/web/Dialog';
|
||||
|
||||
/**
|
||||
* Component that renders the dialog for explicit consent for recordings.
|
||||
*
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
export default function RecordingConsentDialog() {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const consent = useCallback(() => {
|
||||
dispatch(setAudioUnmutePermissions(false, true));
|
||||
dispatch(setVideoUnmutePermissions(false, true));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
cancel = {{ hidden: true }}
|
||||
disableBackdropClose = { true }
|
||||
ok = {{ translationKey: 'dialog.Understand' }}
|
||||
onSubmit = { consent }
|
||||
titleKey = 'dialog.recordingInProgressTitle'>
|
||||
<div>
|
||||
{t('dialog.recordingInProgressDescription')}
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -437,26 +437,3 @@ export function isLiveStreamingButtonVisible({
|
||||
}) {
|
||||
return !isInBreakoutRoom && liveStreamingEnabled && liveStreamingAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the RecordingConsentDialog should be displayed.
|
||||
*
|
||||
* @param {any} recorderSession - The recorder session.
|
||||
* @param {IReduxState} state - The Redux state.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function shouldRequireRecordingConsent(recorderSession: any, state: IReduxState) {
|
||||
const { requireRecordingConsent } = state['features/dynamic-branding'] || {};
|
||||
const { requireConsent } = state['features/base/config'].recordings || {};
|
||||
|
||||
if (!requireConsent && !requireRecordingConsent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!recorderSession.getInitiator()
|
||||
|| recorderSession.getStatus() === JitsiRecordingConstants.status.OFF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return recorderSession.getInitiator() !== getLocalParticipant(state)?.id;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,13 @@
|
||||
import { batch } from 'react-redux';
|
||||
|
||||
import { createRecordingEvent } from '../analytics/AnalyticsEvents';
|
||||
import { sendAnalytics } from '../analytics/functions';
|
||||
import { IStore } from '../app/types';
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes';
|
||||
import { CONFERENCE_JOIN_IN_PROGRESS } from '../base/conference/actionTypes';
|
||||
import { getCurrentConference } from '../base/conference/functions';
|
||||
import { openDialog } from '../base/dialog/actions';
|
||||
import JitsiMeetJS, {
|
||||
JitsiConferenceEvents,
|
||||
JitsiRecordingConstants
|
||||
} from '../base/lib-jitsi-meet';
|
||||
import {
|
||||
setAudioMuted,
|
||||
setAudioUnmutePermissions,
|
||||
setVideoMuted,
|
||||
setVideoUnmutePermissions
|
||||
} from '../base/media/actions';
|
||||
import { MEDIA_TYPE } from '../base/media/constants';
|
||||
import { PARTICIPANT_UPDATED } from '../base/participants/actionTypes';
|
||||
import { updateLocalRecordingStatus } from '../base/participants/actions';
|
||||
@@ -46,7 +37,6 @@ import {
|
||||
showStoppedRecordingNotification,
|
||||
updateRecordingSessionData
|
||||
} from './actions';
|
||||
import { RecordingConsentDialog } from './components/Recording';
|
||||
import LocalRecordingManager from './components/Recording/LocalRecordingManager';
|
||||
import {
|
||||
LIVE_STREAMING_OFF_SOUND_ID,
|
||||
@@ -59,7 +49,6 @@ import {
|
||||
getResourceId,
|
||||
getSessionById,
|
||||
registerRecordingAudioFiles,
|
||||
shouldRequireRecordingConsent,
|
||||
unregisterRecordingAudioFiles
|
||||
} from './functions';
|
||||
import logger from './logger';
|
||||
@@ -112,11 +101,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
(recorderSession: any) => {
|
||||
if (recorderSession) {
|
||||
recorderSession.getID() && dispatch(updateRecordingSessionData(recorderSession));
|
||||
if (recorderSession.getError()) {
|
||||
_showRecordingErrorNotification(recorderSession, dispatch, getState);
|
||||
} else {
|
||||
_showExplicitConsentDialog(recorderSession, dispatch, getState);
|
||||
}
|
||||
recorderSession.getError() && _showRecordingErrorNotification(recorderSession, dispatch, getState);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -405,25 +390,3 @@ function _showRecordingErrorNotification(session: any, dispatch: IStore['dispatc
|
||||
APP.API.notifyRecordingStatusChanged(false, mode, error, isRecorderTranscriptionsRunning(getState()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutes audio and video and displays the RecordingConsentDialog when the conditions are met.
|
||||
*
|
||||
* @param {any} recorderSession - The recording session.
|
||||
* @param {Function} dispatch - The Redux dispatch function.
|
||||
* @param {Function} getState - The Redux getState function.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _showExplicitConsentDialog(recorderSession: any, dispatch: IStore['dispatch'], getState: IStore['getState']) {
|
||||
if (!shouldRequireRecordingConsent(recorderSession, getState())) {
|
||||
return;
|
||||
}
|
||||
|
||||
batch(() => {
|
||||
dispatch(setAudioUnmutePermissions(true, true));
|
||||
dispatch(setVideoUnmutePermissions(true, true));
|
||||
dispatch(setAudioMuted(true));
|
||||
dispatch(setVideoMuted(true));
|
||||
dispatch(openDialog(RecordingConsentDialog));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -200,14 +200,8 @@ end
|
||||
|
||||
-- Managing breakout rooms
|
||||
|
||||
function create_breakout_room(orig_room, subject)
|
||||
local main_room, main_room_jid = get_main_room(orig_room.jid);
|
||||
|
||||
if orig_room ~= main_room then
|
||||
module:log('warn', 'Invalid create breakout room request for %s', orig_room.jid);
|
||||
return;
|
||||
end
|
||||
|
||||
function create_breakout_room(room_jid, subject)
|
||||
local main_room, main_room_jid = get_main_room(room_jid);
|
||||
local breakout_room_jid = uuid_gen() .. '@' .. breakout_rooms_muc_component_config;
|
||||
|
||||
if not main_room._data.breakout_rooms then
|
||||
@@ -225,18 +219,13 @@ function create_breakout_room(orig_room, subject)
|
||||
broadcast_breakout_rooms(main_room_jid);
|
||||
end
|
||||
|
||||
function destroy_breakout_room(orig_room, room_jid, message)
|
||||
function destroy_breakout_room(room_jid, message)
|
||||
local main_room, main_room_jid = get_main_room(room_jid);
|
||||
|
||||
if room_jid == main_room_jid then
|
||||
return;
|
||||
end
|
||||
|
||||
if orig_room ~= main_room then
|
||||
module:log('warn', 'Invalid destroy breakout room request for %s', orig_room.jid);
|
||||
return;
|
||||
end
|
||||
|
||||
local breakout_room = breakout_rooms_muc_service.get_room_from_jid(room_jid);
|
||||
|
||||
if breakout_room then
|
||||
@@ -255,18 +244,13 @@ function destroy_breakout_room(orig_room, room_jid, message)
|
||||
end
|
||||
|
||||
|
||||
function rename_breakout_room(orig_room, room_jid, name)
|
||||
function rename_breakout_room(room_jid, name)
|
||||
local main_room, main_room_jid = get_main_room(room_jid);
|
||||
|
||||
if room_jid == main_room_jid then
|
||||
return;
|
||||
end
|
||||
|
||||
if orig_room ~= main_room then
|
||||
module:log('warn', 'Invalid rename breakout room request for %s', orig_room.jid);
|
||||
return;
|
||||
end
|
||||
|
||||
if main_room then
|
||||
if main_room._data.breakout_rooms then
|
||||
main_room._data.breakout_rooms[room_jid] = name;
|
||||
@@ -338,25 +322,18 @@ function on_message(event)
|
||||
end
|
||||
|
||||
if message.attr.type == JSON_TYPE_ADD_BREAKOUT_ROOM then
|
||||
create_breakout_room(room, message.attr.subject);
|
||||
create_breakout_room(room.jid, message.attr.subject);
|
||||
return true;
|
||||
elseif message.attr.type == JSON_TYPE_REMOVE_BREAKOUT_ROOM then
|
||||
destroy_breakout_room(room, message.attr.breakoutRoomJid);
|
||||
destroy_breakout_room(message.attr.breakoutRoomJid);
|
||||
return true;
|
||||
elseif message.attr.type == JSON_TYPE_RENAME_BREAKOUT_ROOM then
|
||||
rename_breakout_room(room, message.attr.breakoutRoomJid, message.attr.subject);
|
||||
rename_breakout_room(message.attr.breakoutRoomJid, message.attr.subject);
|
||||
return true;
|
||||
elseif message.attr.type == JSON_TYPE_MOVE_TO_ROOM_REQUEST then
|
||||
local participant_jid = message.attr.participantJid;
|
||||
local target_room_jid = message.attr.roomJid;
|
||||
|
||||
if not room._data.breakout_rooms or not (
|
||||
room._data.breakout_rooms[target_room_jid] or target_room_jid == internal_room_jid_match_rewrite(room.jid))
|
||||
then
|
||||
module:log('warn', 'Invalid breakout room %s for %s', target_room_jid, room.jid);
|
||||
return false
|
||||
end
|
||||
|
||||
local json_msg, error = json.encode({
|
||||
type = BREAKOUT_ROOMS_IDENTITY_TYPE,
|
||||
event = JSON_TYPE_MOVE_TO_ROOM_REQUEST,
|
||||
@@ -365,7 +342,6 @@ function on_message(event)
|
||||
|
||||
if not json_msg then
|
||||
module:log('error', 'skip sending request room:%s error:%s', room.jid, error);
|
||||
return false
|
||||
end
|
||||
|
||||
send_json_msg(participant_jid, json_msg)
|
||||
@@ -515,7 +491,7 @@ function on_main_room_destroyed(event)
|
||||
end
|
||||
|
||||
for breakout_room_jid in pairs(main_room._data.breakout_rooms or {}) do
|
||||
destroy_breakout_room(main_room, breakout_room_jid, event.reason)
|
||||
destroy_breakout_room(breakout_room_jid, event.reason)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
# If there is a tenant in the URL it must end with a slash (e.g. "https://alpha.jitsi.net/sometenant/")
|
||||
#BASE_URL=
|
||||
|
||||
# Room name suffix to use when creating new room names
|
||||
# ROOM_NAME_SUFFIX=
|
||||
|
||||
# To be able to match a domain to a specific address
|
||||
# The format is "MAP example.com 1.2.3.4"
|
||||
#RESOLVER_RULES=
|
||||
@@ -18,8 +15,8 @@
|
||||
# The path to the browser video capture file
|
||||
#VIDEO_CAPTURE_FILE=tests/resources/FourPeople_1280x720_30.y4m
|
||||
|
||||
# The tenant used when executing the iframeAPI tests, will override any tenant from BASE_URL if any
|
||||
#IFRAME_TENANT=
|
||||
# The path to the helper iframe page that will be used for the iframeAPI tests
|
||||
#IFRAME_PAGE_BASE=
|
||||
|
||||
# The grid host url (https://mygrid.com/wd/hub)
|
||||
#GRID_HOST_URL=
|
||||
|
||||
@@ -60,30 +60,6 @@ export class Participant {
|
||||
analytics: {
|
||||
disabled: true
|
||||
},
|
||||
|
||||
// if there is a video file to play, use deployment config,
|
||||
// otherwise use lower resolution to avoid high CPU usage
|
||||
constraints: process.env.VIDEO_CAPTURE_FILE ? undefined : {
|
||||
video: {
|
||||
height: {
|
||||
ideal: 360,
|
||||
max: 360,
|
||||
min: 180
|
||||
},
|
||||
|
||||
// @ts-ignore
|
||||
width: {
|
||||
ideal: 640,
|
||||
max: 640,
|
||||
min: 320
|
||||
},
|
||||
frameRate: {
|
||||
max: 30
|
||||
}
|
||||
}
|
||||
},
|
||||
resolution: process.env.VIDEO_CAPTURE_FILE ? undefined : 360,
|
||||
|
||||
requireDisplayName: false,
|
||||
testing: {
|
||||
testMode: true
|
||||
@@ -219,9 +195,7 @@ export class Participant {
|
||||
// @ts-ignore
|
||||
url = `${this.driver.iframePageBase}${url}&domain="${baseUrl.host}"&room="${ctx.roomName}"`;
|
||||
|
||||
if (process.env.IFRAME_TENANT) {
|
||||
url = `${url}&tenant="${process.env.IFRAME_TENANT}"`;
|
||||
} else if (baseUrl.pathname.length > 1) {
|
||||
if (baseUrl.pathname.length > 1) {
|
||||
// remove leading slash
|
||||
url = `${url}&tenant="${baseUrl.pathname.substring(1)}"`;
|
||||
}
|
||||
@@ -232,15 +206,8 @@ export class Participant {
|
||||
|
||||
await this.driver.setTimeout({ 'pageLoad': 30000 });
|
||||
|
||||
let urlToLoad = url.startsWith('/') ? url.substring(1) : url;
|
||||
|
||||
if (options.forceGenerateToken && !ctx.iframeAPI && ctx.isJaasAvailable() && process.env.IFRAME_TENANT) {
|
||||
// This to enables tests like invite, which can force using the jaas auth instead of the provided token
|
||||
urlToLoad = `/${process.env.IFRAME_TENANT}/${urlToLoad}`;
|
||||
}
|
||||
|
||||
// drop the leading '/' so we can use the tenant if any
|
||||
await this.driver.url(urlToLoad);
|
||||
await this.driver.url(url.startsWith('/') ? url.substring(1) : url);
|
||||
|
||||
await this.waitForPageToLoad();
|
||||
|
||||
|
||||
@@ -168,8 +168,7 @@ async function joinTheModeratorAsP1(ctx: IContext, options?: IJoinOptions) {
|
||||
if (!options?.skipFirstModerator) {
|
||||
// we prioritize the access token when iframe is not used and private key is set,
|
||||
// otherwise if private key is not specified we use the access token if set
|
||||
if (process.env.JWT_ACCESS_TOKEN && (!ctx.jwtPrivateKeyPath || !ctx.iframeAPI
|
||||
|| !options?.forceGenerateToken)) {
|
||||
if (process.env.JWT_ACCESS_TOKEN && (!ctx.jwtPrivateKeyPath || !ctx.iframeAPI)) {
|
||||
token = process.env.JWT_ACCESS_TOKEN;
|
||||
} else if (ctx.jwtPrivateKeyPath) {
|
||||
token = getModeratorToken(p1DisplayName);
|
||||
|
||||
@@ -7,7 +7,6 @@ export type IContext = {
|
||||
conferenceJid: string;
|
||||
dialInPin: string;
|
||||
iframeAPI: boolean;
|
||||
isJaasAvailable: () => boolean;
|
||||
jwtKid: string;
|
||||
jwtPrivateKeyPath: string;
|
||||
keepAlive: Array<any>;
|
||||
@@ -34,12 +33,6 @@ export type IJoinOptions = {
|
||||
*/
|
||||
displayName?: string;
|
||||
|
||||
/**
|
||||
* When joining the first participant and jwt singing material is available and a provided token
|
||||
* is available, prefer generating a new token for the first participant.
|
||||
*/
|
||||
forceGenerateToken?: boolean;
|
||||
|
||||
/**
|
||||
* Whether to skip setting display name.
|
||||
*/
|
||||
|
||||
@@ -25,6 +25,6 @@ export default class LobbyScreen extends PreMeetingScreen {
|
||||
* Waits for lobby screen to load.
|
||||
*/
|
||||
waitForLoading(): Promise<void> {
|
||||
return this.participant.driver.$('.lobby-screen').waitForDisplayed({ timeout: 6000 });
|
||||
return this.participant.driver.$('.lobby-screen').waitForDisplayed({ timeout: 4000 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ export default class PasswordDialog extends BaseDialog {
|
||||
timeoutMsg: 'Password dialog not found'
|
||||
});
|
||||
await input.waitForDisplayed();
|
||||
await input.waitForStable();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,7 +44,7 @@ export default abstract class PreMeetingScreen extends BasePageObject {
|
||||
return this.participant.driver.waitUntil(
|
||||
() => this.isLobbyRoomJoined(),
|
||||
{
|
||||
timeout: 6_000, // 6 seconds
|
||||
timeout: 3_000, // 3 seconds
|
||||
timeoutMsg: `Timeout waiting to join lobby for ${this.participant.name}`
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ensureTwoParticipants } from '../../helpers/participants';
|
||||
|
||||
describe('Audio only', () => {
|
||||
it('joining the meeting', () => ensureTwoParticipants(ctx));
|
||||
it('joining the meeting', () => ensureTwoParticipants(ctx, { skipFirstModerator: true }));
|
||||
|
||||
/**
|
||||
* Enables audio only mode for p1 and verifies that the other participant sees participant1 as video muted.
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ensureOneParticipant, ensureTwoParticipants, joinSecondParticipant } from '../../helpers/participants';
|
||||
import type SecurityDialog from '../../pageobjects/SecurityDialog';
|
||||
|
||||
/**
|
||||
* 1. Lock the room (make sure the image changes to locked)
|
||||
@@ -42,7 +41,7 @@ describe('Lock Room', () => {
|
||||
await p2.getToolbar().clickSecurityButton();
|
||||
await p2SecurityDialog.waitForDisplay();
|
||||
|
||||
await waitForRoomLockState(p2SecurityDialog, true);
|
||||
expect(await p2SecurityDialog.isLocked()).toBe(true);
|
||||
});
|
||||
|
||||
it('unlock room', async () => {
|
||||
@@ -64,7 +63,7 @@ describe('Lock Room', () => {
|
||||
await p2.getToolbar().clickSecurityButton();
|
||||
await p2SecurityDialog.waitForDisplay();
|
||||
|
||||
await waitForRoomLockState(p2SecurityDialog, false);
|
||||
expect(await p2SecurityDialog.isLocked()).toBe(false);
|
||||
|
||||
await p2SecurityDialog.clickCloseButton();
|
||||
});
|
||||
@@ -80,11 +79,11 @@ describe('Lock Room', () => {
|
||||
await p2.getToolbar().clickSecurityButton();
|
||||
await p2SecurityDialog.waitForDisplay();
|
||||
|
||||
await waitForRoomLockState(p2SecurityDialog, true);
|
||||
expect(await p2SecurityDialog.isLocked()).toBe(true);
|
||||
|
||||
await participant1UnlockRoom();
|
||||
|
||||
await waitForRoomLockState(p2SecurityDialog, false);
|
||||
expect(await p2SecurityDialog.isLocked()).toBe(false);
|
||||
});
|
||||
it('unlock after participant enter wrong password', async () => {
|
||||
// P1 locks the room. Participant tries to enter using wrong password.
|
||||
@@ -118,7 +117,7 @@ describe('Lock Room', () => {
|
||||
await p2.getToolbar().clickSecurityButton();
|
||||
await p2SecurityDialog.waitForDisplay();
|
||||
|
||||
await waitForRoomLockState(p2SecurityDialog, false);
|
||||
expect(await p2SecurityDialog.isLocked()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -134,7 +133,7 @@ async function participant1LockRoom() {
|
||||
await p1.getToolbar().clickSecurityButton();
|
||||
await p1SecurityDialog.waitForDisplay();
|
||||
|
||||
await waitForRoomLockState(p1SecurityDialog, false);
|
||||
expect(await p1SecurityDialog.isLocked()).toBe(false);
|
||||
|
||||
await p1SecurityDialog.addPassword(ctx.roomKey);
|
||||
|
||||
@@ -143,7 +142,7 @@ async function participant1LockRoom() {
|
||||
await p1.getToolbar().clickSecurityButton();
|
||||
await p1SecurityDialog.waitForDisplay();
|
||||
|
||||
await waitForRoomLockState(p1SecurityDialog, true);
|
||||
expect(await p1SecurityDialog.isLocked()).toBe(true);
|
||||
|
||||
await p1SecurityDialog.clickCloseButton();
|
||||
}
|
||||
@@ -160,22 +159,13 @@ async function participant1UnlockRoom() {
|
||||
|
||||
await p1SecurityDialog.removePassword();
|
||||
|
||||
await waitForRoomLockState(p1SecurityDialog, false);
|
||||
await p1.driver.waitUntil(
|
||||
async () => !await p1SecurityDialog.isLocked(),
|
||||
{
|
||||
timeout: 3_000, // 3 seconds
|
||||
timeoutMsg: `Timeout waiting for the room to unlock for ${p1.name}.`
|
||||
}
|
||||
);
|
||||
|
||||
await p1SecurityDialog.clickCloseButton();
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the room to be locked or unlocked.
|
||||
* @param securityDialog
|
||||
* @param locked
|
||||
*/
|
||||
function waitForRoomLockState(securityDialog: SecurityDialog, locked: boolean) {
|
||||
return securityDialog.participant.driver.waitUntil(
|
||||
async () => await securityDialog.isLocked() === locked,
|
||||
{
|
||||
timeout: 3_000, // 3 seconds
|
||||
timeoutMsg: `Timeout waiting for the room to unlock for ${securityDialog.participant.name}.`
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -77,11 +77,6 @@ describe('AVModeration', () => {
|
||||
});
|
||||
|
||||
it('hangup and change moderator', async () => {
|
||||
// no moderator switching if jaas is available
|
||||
if (ctx.isJaasAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Promise.all([ ctx.p2.hangup(), ctx.p3.hangup() ]);
|
||||
|
||||
await ensureThreeParticipants(ctx);
|
||||
|
||||
@@ -10,7 +10,10 @@ const HASH = '38f014e4b7dde0f64f8157d26a8c812e';
|
||||
describe('Avatar', () => {
|
||||
it('setup the meeting', () =>
|
||||
ensureTwoParticipants(ctx, {
|
||||
skipDisplayName: true
|
||||
skipDisplayName: true,
|
||||
|
||||
// no default avatar if we have used to join a token with an avatar and no option to set it
|
||||
skipFirstModerator: true
|
||||
})
|
||||
);
|
||||
|
||||
@@ -201,7 +204,8 @@ describe('Avatar', () => {
|
||||
await p1.hangup();
|
||||
|
||||
await ensureTwoParticipants(ctx, {
|
||||
skipDisplayName: true
|
||||
skipDisplayName: true,
|
||||
skipFirstModerator: true
|
||||
});
|
||||
p1 = ctx.p1;
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ describe('BreakoutRooms', () => {
|
||||
|
||||
await p1.driver.waitUntil(
|
||||
async () => await p1BreakoutRooms.getRoomsCount() === 1, {
|
||||
timeout: 3000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'No breakout room added for p1'
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ describe('BreakoutRooms', () => {
|
||||
// second participant should also see one breakout room
|
||||
await p2.driver.waitUntil(
|
||||
async () => await p2.getBreakoutRooms().getRoomsCount() === 1, {
|
||||
timeout: 3000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'No breakout room seen by p2'
|
||||
});
|
||||
});
|
||||
@@ -54,7 +54,7 @@ describe('BreakoutRooms', () => {
|
||||
// there should be one breakout room
|
||||
await p1.driver.waitUntil(
|
||||
async () => await p1BreakoutRooms.getRoomsCount() === 1, {
|
||||
timeout: 3000,
|
||||
timeout: 1000,
|
||||
timeoutMsg: 'No breakout room seen by p1'
|
||||
});
|
||||
|
||||
@@ -80,7 +80,7 @@ describe('BreakoutRooms', () => {
|
||||
|
||||
return list[0].name === MAIN_ROOM_NAME;
|
||||
}, {
|
||||
timeout: 5000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'P1 did not join breakout room'
|
||||
});
|
||||
|
||||
@@ -95,7 +95,7 @@ describe('BreakoutRooms', () => {
|
||||
|
||||
return list[0].participantCount === 1;
|
||||
}, {
|
||||
timeout: 3000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'P2 is not seeing p1 in the breakout room'
|
||||
});
|
||||
});
|
||||
@@ -122,7 +122,7 @@ describe('BreakoutRooms', () => {
|
||||
|
||||
return list[0].name !== MAIN_ROOM_NAME;
|
||||
}, {
|
||||
timeout: 5000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'P1 did not leave breakout room'
|
||||
});
|
||||
|
||||
@@ -137,7 +137,7 @@ describe('BreakoutRooms', () => {
|
||||
|
||||
return list[0].participantCount === 0;
|
||||
}, {
|
||||
timeout: 3000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'P2 is seeing p1 in the breakout room'
|
||||
});
|
||||
});
|
||||
@@ -152,14 +152,14 @@ describe('BreakoutRooms', () => {
|
||||
// there should be no breakout rooms
|
||||
await p1.driver.waitUntil(
|
||||
async () => await p1BreakoutRooms.getRoomsCount() === 0, {
|
||||
timeout: 3000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'Breakout room was not removed for p1'
|
||||
});
|
||||
|
||||
// the second participant should also see no breakout rooms
|
||||
await p2.driver.waitUntil(
|
||||
async () => await p2.getBreakoutRooms().getRoomsCount() === 0, {
|
||||
timeout: 3000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'Breakout room was not removed for p2'
|
||||
});
|
||||
});
|
||||
@@ -176,7 +176,7 @@ describe('BreakoutRooms', () => {
|
||||
// there should be two breakout rooms
|
||||
await p1.driver.waitUntil(
|
||||
async () => await p1BreakoutRooms.getRoomsCount() === 2, {
|
||||
timeout: 3000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'Breakout room was not created by p1'
|
||||
});
|
||||
|
||||
@@ -198,7 +198,7 @@ describe('BreakoutRooms', () => {
|
||||
|
||||
return list[0].participantCount === 1 && list[1].participantCount === 1;
|
||||
}, {
|
||||
timeout: 5000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'P1 did not auto assigned participants to breakout rooms'
|
||||
});
|
||||
|
||||
@@ -220,7 +220,7 @@ describe('BreakoutRooms', () => {
|
||||
return list[0].participantCount === 1 && list[1].participantCount === 1
|
||||
&& (list[0].name === MAIN_ROOM_NAME || list[1].name === MAIN_ROOM_NAME);
|
||||
}, {
|
||||
timeout: 3000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'P2 is not seeing p1 in the main room'
|
||||
});
|
||||
});
|
||||
@@ -244,7 +244,7 @@ describe('BreakoutRooms', () => {
|
||||
|
||||
return list[0].participantCount === 1 && list[1].participantCount === 1;
|
||||
}, {
|
||||
timeout: 3000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'P1 is not seeing two breakout rooms'
|
||||
});
|
||||
|
||||
@@ -266,7 +266,7 @@ describe('BreakoutRooms', () => {
|
||||
|
||||
return list[0].participantCount === 0 || list[1].participantCount === 0;
|
||||
}, {
|
||||
timeout: 5000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'P1 is not seeing an empty breakout room'
|
||||
});
|
||||
|
||||
@@ -305,7 +305,7 @@ describe('BreakoutRooms', () => {
|
||||
|
||||
return list[0].participantCount + list[1].participantCount === 1;
|
||||
}, {
|
||||
timeout: 3000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: `${p.name} is not seeing an empty breakout room and one with one participant`
|
||||
});
|
||||
|
||||
@@ -335,7 +335,7 @@ describe('BreakoutRooms', () => {
|
||||
await p1.driver.waitUntil(
|
||||
async () => await p1BreakoutRooms.getRoomsCount() === 1
|
||||
&& (await p1BreakoutRooms.getRooms())[0].participantCount === 0, {
|
||||
timeout: 3000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'No breakout room added for p1'
|
||||
});
|
||||
|
||||
@@ -353,7 +353,7 @@ describe('BreakoutRooms', () => {
|
||||
|
||||
return list[0].participantCount === 1;
|
||||
}, {
|
||||
timeout: 5000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'P1 is not seeing p2 in the breakout room'
|
||||
});
|
||||
});
|
||||
@@ -373,7 +373,7 @@ describe('BreakoutRooms', () => {
|
||||
|
||||
return list[0].participantCount === 1;
|
||||
}, {
|
||||
timeout: 3000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'P1 is not seeing p2 in the breakout room'
|
||||
});
|
||||
|
||||
@@ -419,7 +419,7 @@ describe('BreakoutRooms', () => {
|
||||
|
||||
return list[0].name === myNewRoomName;
|
||||
}, {
|
||||
timeout: 3000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'The breakout room was not renamed for p1'
|
||||
});
|
||||
|
||||
@@ -441,7 +441,7 @@ describe('BreakoutRooms', () => {
|
||||
|
||||
return list[0].participantCount === 0;
|
||||
}, {
|
||||
timeout: 3000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'The breakout room not found or not empty for p1'
|
||||
});
|
||||
|
||||
@@ -471,7 +471,7 @@ describe('BreakoutRooms', () => {
|
||||
|
||||
return list[0].participantCount === 1;
|
||||
}, {
|
||||
timeout: 5000,
|
||||
timeout: 2000,
|
||||
timeoutMsg: 'The breakout room was not rename for p1'
|
||||
});
|
||||
|
||||
|
||||
@@ -195,10 +195,6 @@ describe('Lobby', () => {
|
||||
});
|
||||
|
||||
it('change of moderators in lobby', async () => {
|
||||
// no moderator switching if jaas is available
|
||||
if (ctx.isJaasAvailable()) {
|
||||
return;
|
||||
}
|
||||
await hangupAllParticipants();
|
||||
|
||||
await ensureTwoParticipants(ctx);
|
||||
@@ -226,11 +222,11 @@ describe('Lobby', () => {
|
||||
|
||||
// here the important check is whether the moderator sees the knocking participant
|
||||
await enterLobby(p2, false);
|
||||
|
||||
await hangupAllParticipants();
|
||||
});
|
||||
|
||||
it('shared password', async () => {
|
||||
await hangupAllParticipants();
|
||||
|
||||
await ensureTwoParticipants(ctx);
|
||||
|
||||
const { p1 } = ctx;
|
||||
@@ -244,7 +240,7 @@ describe('Lobby', () => {
|
||||
|
||||
expect(await p1SecurityDialog.isLocked()).toBe(false);
|
||||
|
||||
const roomPasscode = String(Math.trunc(Math.random() * 1_000_000));
|
||||
const roomPasscode = String(Math.random() * 1_000);
|
||||
|
||||
await p1SecurityDialog.addPassword(roomPasscode);
|
||||
|
||||
@@ -287,10 +283,6 @@ describe('Lobby', () => {
|
||||
});
|
||||
|
||||
it('moderator leaves while lobby enabled', async () => {
|
||||
// no moderator switching if jaas is available
|
||||
if (ctx.isJaasAvailable()) {
|
||||
return;
|
||||
}
|
||||
const { p1, p2, p3 } = ctx;
|
||||
|
||||
await p3.hangup();
|
||||
@@ -310,7 +302,7 @@ describe('Lobby', () => {
|
||||
});
|
||||
|
||||
it('reject and approve in pre-join', async () => {
|
||||
await hangupAllParticipants();
|
||||
await ctx.p2.hangup();
|
||||
|
||||
await ensureTwoParticipants(ctx);
|
||||
await enableLobby();
|
||||
|
||||
@@ -188,15 +188,17 @@ describe('StartMuted', () => {
|
||||
}
|
||||
};
|
||||
|
||||
await ensureOneParticipant(ctx, options);
|
||||
await joinSecondParticipant(ctx, {
|
||||
configOverwrite: {
|
||||
p2p: {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
skipInMeetingChecks: true
|
||||
});
|
||||
await Promise.all([
|
||||
ensureOneParticipant(ctx, options),
|
||||
joinSecondParticipant(ctx, {
|
||||
configOverwrite: {
|
||||
p2p: {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
skipInMeetingChecks: true
|
||||
})
|
||||
]);
|
||||
|
||||
const { p1, p2 } = ctx;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ensureOneParticipant } from '../../helpers/participants';
|
||||
import { isDialInEnabled } from '../helpers/DialIn';
|
||||
|
||||
describe('Invite', () => {
|
||||
it('join participant', () => ensureOneParticipant(ctx, { forceGenerateToken: true }));
|
||||
it('join participant', () => ensureOneParticipant(ctx));
|
||||
|
||||
it('url displayed', async () => {
|
||||
const { p1 } = ctx;
|
||||
|
||||
@@ -194,7 +194,7 @@ export const config: WebdriverIO.MultiremoteConfig = {
|
||||
|
||||
// setup keepalive
|
||||
globalAny.ctx.keepAlive.push(setInterval(async () => {
|
||||
await bInstance.execute(() => console.log(`${new Date().toISOString()} keep-alive`));
|
||||
await bInstance.execute(() => console.log('keep-alive'));
|
||||
}, 20_000));
|
||||
|
||||
if (bInstance.isFirefox) {
|
||||
@@ -208,13 +208,8 @@ export const config: WebdriverIO.MultiremoteConfig = {
|
||||
}));
|
||||
|
||||
globalAny.ctx.roomName = `jitsimeettorture-${crypto.randomUUID()}`;
|
||||
if (process.env.ROOM_NAME_SUFFIX) {
|
||||
globalAny.ctx.roomName += `_${process.env.ROOM_NAME_SUFFIX.trim()}`;
|
||||
}
|
||||
|
||||
globalAny.ctx.jwtPrivateKeyPath = process.env.JWT_PRIVATE_KEY_PATH;
|
||||
globalAny.ctx.jwtKid = process.env.JWT_KID;
|
||||
globalAny.ctx.isJaasAvailable = () => globalAny.ctx.jwtKid?.startsWith('vpaas-magic-cookie-');
|
||||
},
|
||||
|
||||
after() {
|
||||
|
||||
Reference in New Issue
Block a user