Compare commits

..

2 Commits

Author SHA1 Message Date
damencho
4f0f8ea019 fix(tests): Skip iframeAPI if it is disabled. 2025-02-26 14:35:11 -06:00
damencho
444f4a7abc feat(tests): Adds an option for an access jwt token.
Used only for the first participant joining/creating the room.
2025-02-25 09:17:58 -06:00
792 changed files with 8213 additions and 17046 deletions

View File

@@ -17,8 +17,3 @@ react/features/face-landmarks/resources/*
# Not worth it.
actionTypes.ts
# It's not complete until all files are copied at build time.
react-native-sdk/
*.d.ts

View File

@@ -1,5 +1,6 @@
module.exports = {
extends: [
'extends': [
'@jitsi/eslint-config'
]
],
'ignorePatterns': [ '*.d.ts' ]
};

View File

@@ -18,7 +18,7 @@ jobs:
npm -v
- name: Get changed files
id: changed-files
uses: jitsi/changed-files@main
uses: tj-actions/changed-files@v41
- name: Get changed lang files
id: lang-files
run: echo "all=$(echo "${{ steps.changed-files.outputs.all_changed_files }}" | grep -oE 'lang\/\S+' | tr '\n' ' ')" >> "$GITHUB_OUTPUT"

View File

@@ -1,20 +1,14 @@
# Follow Our Updated Guide to See How You Can Contribute
**Hello there! 👋**
Hello there! 👋
We're thrilled that you're eager to contribute to **Jitsi Meet! ❤️**
We're thrilled that you're eager to contribute to Jitsi Meet! ❤️
Your interest in improving our platform means a lot to us. To ensure your contributions align seamlessly with our goals and processes, we've recently updated our guide. This guide will provide you with clear instructions on how to get involved effectively.
### 📖 Get Started
Ready to get started? Head over to our [Jitsi Meet Handbook](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-contributing/) and let's make **Jitsi Meet** even better together!
### 💬 Join the Discussion
Have questions or need help? Join our community discussions on the [Jitsi Forum](https://community.jitsi.org/) where contributors and maintainers can assist you.
Ready to get started? Head over to our [Jitsi Meet Handbook](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-contributing/) and let's make Jitsi Meet even better together!
### ❗Additional Note
Before sending us your code, double-check that it meets our coding standards. You can do this by running a command: `npm run lint`. If there are any issues, don't worry! You can fix them by running: `npm run lint-fix`. Once your code passes these checks, feel free to submit your pull request.
**Happy coding!**
Happy coding!

View File

@@ -1,6 +1,6 @@
# <p align="center">Jitsi Meet</p>
TEST Jitsi Meet is a set of Open Source projects which empower users to use and deploy
Jitsi Meet is a set of Open Source projects which empower users to use and deploy
video conferencing platforms with state-of-the-art video quality and features.
<hr />

View File

@@ -1 +0,0 @@
OK

View File

@@ -42,7 +42,6 @@ android {
debug {
buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${googleServicesEnabled}"
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
applicationIdSuffix ".debug"
}
release {
// Uncomment the following line for singing a test release build.
@@ -83,8 +82,10 @@ dependencies {
// Firebase
// - Crashlytics
// - Dynamic Links
implementation 'com.google.firebase:firebase-analytics:21.3.0'
implementation 'com.google.firebase:firebase-crashlytics:18.4.3'
implementation 'com.google.firebase:firebase-dynamic-links:21.1.0'
}
implementation project(':sdk')

View File

@@ -4,6 +4,7 @@ import android.net.Uri;
import android.util.Log;
import com.google.firebase.crashlytics.FirebaseCrashlytics;
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks;
import org.jitsi.meet.sdk.JitsiMeet;
import org.jitsi.meet.sdk.JitsiMeetActivity;
@@ -21,6 +22,18 @@ final class GoogleServicesHelper {
Log.d(activity.getClass().getSimpleName(), "Initializing Google Services");
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(!JitsiMeet.isCrashReportingDisabled(activity));
FirebaseDynamicLinks.getInstance().getDynamicLink(activity.getIntent())
.addOnSuccessListener(activity, pendingDynamicLinkData -> {
Uri dynamicLink = null;
if (pendingDynamicLinkData != null) {
dynamicLink = pendingDynamicLinkData.getLink();
}
if (dynamicLink != null) {
activity.join(dynamicLink.toString());
}
});
}
}
}

View File

@@ -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);
}

View File

@@ -44,6 +44,9 @@ dependencies {
api "com.facebook.react:react-android:$rootProject.ext.rnVersion"
api "com.facebook.react:hermes-android:$rootProject.ext.rnVersion"
//noinspection GradleDynamicVersion
implementation 'org.webkit:android-jsc:+'
implementation 'com.facebook.fresco:animated-gif:2.5.0'
implementation 'com.dropbox.core:dropbox-core-sdk:4.0.1'
implementation 'com.jakewharton.timber:timber:5.0.1'
@@ -86,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'
}

View File

@@ -3,6 +3,12 @@ package org.jitsi.meet.sdk;
import android.content.Intent;
import android.os.Bundle;
import com.facebook.react.bridge.WritableNativeMap;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
import java.util.HashMap;
/**
* Wraps the name and extra data for events that were broadcasted locally.
*/
@@ -10,21 +16,57 @@ public class BroadcastAction {
private static final String TAG = BroadcastAction.class.getSimpleName();
private final Type type;
private final Bundle data;
private final HashMap<String, Object> data;
public BroadcastAction(Intent intent) {
this.type = Type.buildTypeFromAction(intent.getAction());
this.data = intent.getExtras();
this.data = buildDataFromBundle(intent.getExtras());
}
public Type getType() {
return this.type;
}
public Bundle getData() {
public HashMap<String, Object> getData() {
return this.data;
}
public WritableNativeMap getDataAsWritableNativeMap() {
WritableNativeMap nativeMap = new WritableNativeMap();
for (String key : this.data.keySet()) {
try {
if (this.data.get(key) instanceof Boolean) {
nativeMap.putBoolean(key, (Boolean) this.data.get(key));
} else if (this.data.get(key) instanceof Integer) {
nativeMap.putInt(key, (Integer) this.data.get(key));
} else if (this.data.get(key) instanceof Double) {
nativeMap.putDouble(key, (Double) this.data.get(key));
} else if (this.data.get(key) instanceof String) {
nativeMap.putString(key, (String) this.data.get(key));
} else {
throw new Exception("Unsupported extra data type");
}
} catch (Exception e) {
JitsiMeetLogger.w(TAG + " invalid extra data in event", e);
}
}
return nativeMap;
}
private static HashMap<String, Object> buildDataFromBundle(Bundle bundle) {
HashMap<String, Object> map = new HashMap<>();
if (bundle != null) {
for (String key : bundle.keySet()) {
map.put(key, bundle.get(key));
}
}
return map;
}
enum Type {
SET_AUDIO_MUTED("org.jitsi.meet.SET_AUDIO_MUTED"),
HANG_UP("org.jitsi.meet.HANG_UP"),
@@ -40,9 +82,7 @@ public class BroadcastAction {
SHOW_NOTIFICATION("org.jitsi.meet.SHOW_NOTIFICATION"),
HIDE_NOTIFICATION("org.jitsi.meet.HIDE_NOTIFICATION"),
START_RECORDING("org.jitsi.meet.START_RECORDING"),
STOP_RECORDING("org.jitsi.meet.STOP_RECORDING"),
OVERWRITE_CONFIG("org.jitsi.meet.OVERWRITE_CONFIG"),
SEND_CAMERA_FACING_MODE_MESSAGE("org.jitsi.meet.SEND_CAMERA_FACING_MODE_MESSAGE");
STOP_RECORDING("org.jitsi.meet.STOP_RECORDING");
private final String action;

View File

@@ -91,9 +91,7 @@ public class BroadcastEvent {
VIDEO_MUTED_CHANGED("org.jitsi.meet.VIDEO_MUTED_CHANGED"),
READY_TO_CLOSE("org.jitsi.meet.READY_TO_CLOSE"),
TRANSCRIPTION_CHUNK_RECEIVED("org.jitsi.meet.TRANSCRIPTION_CHUNK_RECEIVED"),
CUSTOM_BUTTON_PRESSED("org.jitsi.meet.CUSTOM_BUTTON_PRESSED"),
CONFERENCE_UNIQUE_ID_SET("org.jitsi.meet.CONFERENCE_UNIQUE_ID_SET"),
RECORDING_STATUS_CHANGED("org.jitsi.meet.RECORDING_STATUS_CHANGED");
CUSTOM_BUTTON_PRESSED("org.jitsi.meet.CUSTOM_BUTTON_PRESSED");
private static final String CONFERENCE_BLURRED_NAME = "CONFERENCE_BLURRED";
private static final String CONFERENCE_FOCUSED_NAME = "CONFERENCE_FOCUSED";
@@ -112,8 +110,6 @@ public class BroadcastEvent {
private static final String READY_TO_CLOSE_NAME = "READY_TO_CLOSE";
private static final String TRANSCRIPTION_CHUNK_RECEIVED_NAME = "TRANSCRIPTION_CHUNK_RECEIVED";
private static final String CUSTOM_BUTTON_PRESSED_NAME = "CUSTOM_BUTTON_PRESSED";
private static final String CONFERENCE_UNIQUE_ID_SET_NAME = "CONFERENCE_UNIQUE_ID_SET";
private static final String RECORDING_STATUS_CHANGED_NAME = "RECORDING_STATUS_CHANGED";
private final String action;
@@ -170,10 +166,6 @@ public class BroadcastEvent {
return TRANSCRIPTION_CHUNK_RECEIVED;
case CUSTOM_BUTTON_PRESSED_NAME:
return CUSTOM_BUTTON_PRESSED;
case CONFERENCE_UNIQUE_ID_SET_NAME:
return CONFERENCE_UNIQUE_ID_SET;
case RECORDING_STATUS_CHANGED_NAME:
return RECORDING_STATUS_CHANGED;
}
return null;

View File

@@ -139,19 +139,4 @@ public class BroadcastIntentHelper {
return intent;
}
public static Intent buildOverwriteConfigIntent(Bundle config) {
Intent intent = new Intent(BroadcastAction.Type.OVERWRITE_CONFIG.getAction());
intent.putExtra("config", config);
return intent;
}
public static Intent buildSendCameraFacingModeMessageIntent(String to, String facingMode) {
Intent intent = new Intent(BroadcastAction.Type.SEND_CAMERA_FACING_MODE_MESSAGE.getAction());
intent.putExtra("to", to);
intent.putExtra("facingMode", facingMode);
return intent;
}
}

View File

@@ -3,9 +3,6 @@ package org.jitsi.meet.sdk;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import com.facebook.react.bridge.Arguments;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
@@ -31,14 +28,7 @@ public class BroadcastReceiver extends android.content.BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
BroadcastAction action = new BroadcastAction(intent);
String actionName = action.getType().getAction();
Bundle data = action.getData();
// For actions without data bundle (like hangup), we create an empty map
// instead of attempting to convert a null bundle to avoid crashes.
if (data != null) {
ReactInstanceManagerHolder.emitEvent(actionName, Arguments.fromBundle(data));
} else {
ReactInstanceManagerHolder.emitEvent(actionName, Arguments.createMap());
}
ReactInstanceManagerHolder.emitEvent(actionName, action.getDataAsWritableNativeMap());
}
}

View File

@@ -101,8 +101,6 @@ class ExternalAPIModule extends ReactContextBaseJavaModule {
constants.put("HIDE_NOTIFICATION", BroadcastAction.Type.HIDE_NOTIFICATION.getAction());
constants.put("START_RECORDING", BroadcastAction.Type.START_RECORDING.getAction());
constants.put("STOP_RECORDING", BroadcastAction.Type.STOP_RECORDING.getAction());
constants.put("OVERWRITE_CONFIG", BroadcastAction.Type.OVERWRITE_CONFIG.getAction());
constants.put("SEND_CAMERA_FACING_MODE_MESSAGE", BroadcastAction.Type.SEND_CAMERA_FACING_MODE_MESSAGE.getAction());
return constants;
}

View File

@@ -272,16 +272,8 @@ public class JitsiMeetActivity extends AppCompatActivity
// }
// protected void onCustomButtonPressed(HashMap<String, Object> extraData) {
// JitsiMeetLogger.i("Custom button pressed: " + extraData);
// }
// protected void onConferenceUniqueIdSet(HashMap<String, Object> extraData) {
// JitsiMeetLogger.i("Conference unique id set: " + extraData);
// }
// protected void onRecordingStatusChanged(HashMap<String, Object> extraData) {
// JitsiMeetLogger.i("Recording status changed: " + extraData);
// }
// JitsiMeetLogger.i("Custom button pressed: " + extraData);
// }
// Activity lifecycle methods
//
@@ -366,18 +358,12 @@ public class JitsiMeetActivity extends AppCompatActivity
case READY_TO_CLOSE:
onReadyToClose();
break;
// case TRANSCRIPTION_CHUNK_RECEIVED:
// onTranscriptionChunkReceived(event.getData());
// break;
// case CUSTOM_BUTTON_PRESSED:
// onCustomButtonPressed(event.getData());
// break;
// case CONFERENCE_UNIQUE_ID_SET:
// onConferenceUniqueIdSet(event.getData());
// break;
// case RECORDING_STATUS_CHANGED:
// onRecordingStatusChanged(event.getData());
// break;
// case TRANSCRIPTION_CHUNK_RECEIVED:
// onTranscriptionChunkReceived(event.getData());
// break;
// case CUSTOM_BUTTON_PRESSED:
// onCustomButtonPressed(event.getData());
// break;
}
}
}

View File

@@ -33,9 +33,10 @@ import org.jitsi.meet.sdk.log.JitsiMeetLogger;
public class JitsiMeetView extends FrameLayout {
/**
* Background color. Should match the background color set in JS.
* Background color used by {@code BaseReactView} and the React Native root
* view.
*/
private static final int BACKGROUND_COLOR = 0xFF040404;
private static final int BACKGROUND_COLOR = 0xFF111111;
/**
* React Native root view.

View File

@@ -1,84 +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 android.media.MediaCodecInfo;
import androidx.annotation.Nullable;
import com.oney.WebRTCModule.webrtcutils.SoftwareVideoDecoderFactoryProxy;
import org.webrtc.EglBase;
import org.webrtc.HardwareVideoDecoderFactory;
import org.webrtc.JitsiPlatformVideoDecoderFactory;
import org.webrtc.Predicate;
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 VideoDecoderFactory platformSoftwareVideoDecoderFactory;
/**
* Predicate to filter out the AV1 hardware decoder, as we've seen decoding issues with it.
*/
private static final String GOOGLE_AV1_DECODER = "c2.google.av1";
private static final Predicate<MediaCodecInfo> hwCodecPredicate = arg -> {
// Filter out the Google AV1 codec.
return !arg.getName().startsWith(GOOGLE_AV1_DECODER);
};
private static final Predicate<MediaCodecInfo> swCodecPredicate = arg -> {
// Noop, just making sure we can customize it easily if needed.
return true;
};
/**
* Create decoder factory using default hardware decoder factory.
*/
public JitsiVideoDecoderFactory(@Nullable EglBase.Context eglContext) {
this.hardwareVideoDecoderFactory = new HardwareVideoDecoderFactory(eglContext, hwCodecPredicate);
this.platformSoftwareVideoDecoderFactory = new JitsiPlatformVideoDecoderFactory(eglContext, swCodecPredicate);
}
@Override
public @Nullable VideoDecoder createDecoder(VideoCodecInfo codecType) {
VideoDecoder softwareDecoder = softwareVideoDecoderFactory.createDecoder(codecType);
final VideoDecoder hardwareDecoder = hardwareVideoDecoderFactory.createDecoder(codecType);
if (softwareDecoder == 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()));
supportedCodecInfos.addAll(Arrays.asList(platformSoftwareVideoDecoderFactory.getSupportedCodecs()));
return supportedCodecInfos.toArray(new VideoCodecInfo[supportedCodecInfos.size()]);
}
}

View File

@@ -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);
}
}

View File

@@ -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()

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2018 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.
*/
package org.webrtc;
import android.media.MediaCodecInfo;
import androidx.annotation.Nullable;
/** Factory for Android platform software VideoDecoders. */
public class JitsiPlatformVideoDecoderFactory extends MediaCodecVideoDecoderFactory {
/**
* Default allowed predicate.
*/
private static final Predicate<MediaCodecInfo> defaultAllowedPredicate =
codecInfo -> {
// We only want to use the platform software codecs.
return MediaCodecUtils.isSoftwareOnly(codecInfo);
};
/**
* Creates a PlatformSoftwareVideoDecoderFactory that supports surface texture rendering.
*
* @param sharedContext The textures generated will be accessible from this context. May be null,
* this disables texture support.
*/
public JitsiPlatformVideoDecoderFactory(@Nullable EglBase.Context sharedContext) {
super(sharedContext, defaultAllowedPredicate);
}
public JitsiPlatformVideoDecoderFactory(@Nullable EglBase.Context sharedContext, @Nullable Predicate<MediaCodecInfo> codecAllowedPredicate) {
super(sharedContext, codecAllowedPredicate == null ? defaultAllowedPredicate : codecAllowedPredicate.and(defaultAllowedPredicate));
}
}

View File

@@ -3,7 +3,7 @@ rootProject.name = 'jitsi-meet'
include ':app', ':sdk'
include ':react-native-amplitude'
project(':react-native-amplitude').projectDir = new File(rootProject.projectDir, '../node_modules/@amplitude/analytics-react-native/android')
project(':react-native-amplitude').projectDir = new File(rootProject.projectDir, '../node_modules/@amplitude/react-native/android')
include ':react-native-async-storage'
project(':react-native-async-storage').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-async-storage/async-storage/android')
include ':react-native-background-timer'

26
app.js
View File

@@ -10,32 +10,6 @@ import '@matrix-org/olm';
import 'focus-visible';
/*
* Safari polyfill for createImageBitmap
* https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap
*
* Support source image types: Canvas.
*/
if (!('createImageBitmap' in window)) {
window.createImageBitmap = function(data) {
return new Promise((resolve, reject) => {
let dataURL;
if (data instanceof HTMLCanvasElement) {
dataURL = data.toDataURL();
} else {
reject(new Error('createImageBitmap does not handle the provided image source type'));
}
const img = document.createElement('img');
img.addEventListener('load', () => {
resolve(img);
});
img.src = dataURL;
});
};
}
// We need to setup the jitsi-local-storage as early as possible so that we can start using it.
// NOTE: If jitsi-local-storage is used before the initial setup is performed this will break the use case when we use
// the local storage from the parent page when the localStorage is disabled. Also the setup is relying that

View File

@@ -89,7 +89,7 @@ import {
setVideoMuted,
setVideoUnmutePermissions
} from './react/features/base/media/actions';
import { MEDIA_TYPE, VIDEO_MUTISM_AUTHORITY, VIDEO_TYPE } from './react/features/base/media/constants';
import { MEDIA_TYPE, VIDEO_TYPE } from './react/features/base/media/constants';
import {
getStartWithAudioMuted,
getStartWithVideoMuted,
@@ -131,6 +131,7 @@ import {
createLocalTracksF,
getLocalJitsiAudioTrack,
getLocalJitsiVideoTrack,
getLocalTracks,
getLocalVideoTrack,
isLocalTrackMuted,
isUserInteractionRequiredForUnmute
@@ -205,6 +206,23 @@ function sendData(command, value) {
room.sendCommand(command, { value });
}
/**
* Mute or unmute local audio stream if it exists.
* @param {boolean} muted - if audio stream should be muted or unmuted.
*/
function muteLocalAudio(muted) {
APP.store.dispatch(setAudioMuted(muted));
}
/**
* Mute or unmute local video stream if it exists.
* @param {boolean} muted if video stream should be muted or unmuted.
*
*/
function muteLocalVideo(muted) {
APP.store.dispatch(setVideoMuted(muted));
}
/**
* A queue for the async replaceLocalTrack action so that multiple audio
* replacements cannot happen simultaneously. This solves the issue where
@@ -583,7 +601,7 @@ export default {
const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(initialOptions, true);
tryCreateLocalTracks.then(tr => {
tryCreateLocalTracks.then(async tr => {
const createLocalTracksEnd = window.performance.now();
connectionTimes['conference.init.createLocalTracks.end'] = createLocalTracksEnd;
@@ -691,10 +709,11 @@ export default {
* Simulates toolbar button click for audio mute. Used by shortcuts and API.
*
* @param {boolean} mute true for mute and false for unmute.
* @param {boolean} [showUI] when set to false will not display any error
* dialogs in case of media permissions error.
* @returns {Promise}
*/
async muteAudio(mute) {
async muteAudio(mute, showUI = true) {
const state = APP.store.getState();
if (!mute
@@ -713,7 +732,47 @@ export default {
return;
}
await APP.store.dispatch(setAudioMuted(mute, true));
// Not ready to modify track's state yet
if (!this._localTracksInitialized) {
// This will only modify base/media.audio.muted which is then synced
// up with the track at the end of local tracks initialization.
muteLocalAudio(mute);
this.updateAudioIconEnabled();
return;
} else if (this.isLocalAudioMuted() === mute) {
// NO-OP
return;
}
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
if (!localAudio && !mute) {
const maybeShowErrorDialog = error => {
showUI && APP.store.dispatch(notifyMicError(error));
};
APP.store.dispatch(gumPending([ MEDIA_TYPE.AUDIO ], IGUMPendingState.PENDING_UNMUTE));
await createLocalTracksF({ devices: [ 'audio' ] })
.then(([ audioTrack ]) => audioTrack)
.catch(error => {
maybeShowErrorDialog(error);
// Rollback the audio muted status by using null track
return null;
})
.then(async audioTrack => {
await this._maybeApplyAudioMixerEffect(audioTrack);
return this.useAudioStream(audioTrack);
})
.finally(() => {
APP.store.dispatch(gumPending([ MEDIA_TYPE.AUDIO ], IGUMPendingState.NONE));
});
} else {
muteLocalAudio(mute);
}
},
/**
@@ -743,9 +802,10 @@ export default {
/**
* Simulates toolbar button click for video mute. Used by shortcuts and API.
* @param mute true for mute and false for unmute.
* @param {boolean} [showUI] when set to false will not display any error
* dialogs in case of media permissions error.
*/
muteVideo(mute) {
muteVideo(mute, showUI = true) {
if (this.videoSwitchInProgress) {
logger.warn('muteVideo - unable to perform operations while video switch is in progress');
@@ -766,7 +826,60 @@ export default {
return;
}
APP.store.dispatch(setVideoMuted(mute, VIDEO_MUTISM_AUTHORITY.USER, true));
// If not ready to modify track's state yet adjust the base/media
if (!this._localTracksInitialized) {
// This will only modify base/media.video.muted which is then synced
// up with the track at the end of local tracks initialization.
muteLocalVideo(mute);
this.setVideoMuteStatus();
return;
} else if (this.isLocalVideoMuted() === mute) {
// NO-OP
return;
}
const localVideo = getLocalJitsiVideoTrack(state);
if (!localVideo && !mute && !this.isCreatingLocalTrack) {
const maybeShowErrorDialog = error => {
showUI && APP.store.dispatch(notifyCameraError(error));
};
this.isCreatingLocalTrack = true;
APP.store.dispatch(gumPending([ MEDIA_TYPE.VIDEO ], IGUMPendingState.PENDING_UNMUTE));
// Try to create local video if there wasn't any.
// This handles the case when user joined with no video
// (dismissed screen sharing screen or in audio only mode), but
// decided to add it later on by clicking on muted video icon or
// turning off the audio only mode.
//
// FIXME when local track creation is moved to react/redux
// it should take care of the use case described above
createLocalTracksF({ devices: [ 'video' ] })
.then(([ videoTrack ]) => videoTrack)
.catch(error => {
// FIXME should send some feedback to the API on error ?
maybeShowErrorDialog(error);
// Rollback the video muted status by using null track
return null;
})
.then(videoTrack => {
logger.debug(`muteVideo: calling useVideoStream for track: ${videoTrack}`);
return this.useVideoStream(videoTrack);
})
.finally(() => {
this.isCreatingLocalTrack = false;
APP.store.dispatch(gumPending([ MEDIA_TYPE.VIDEO ], IGUMPendingState.NONE));
});
} else {
// FIXME show error dialog if it fails (should be handled by react)
muteLocalVideo(mute);
}
},
/**
@@ -947,14 +1060,6 @@ export default {
downloadJSON(logs, filename);
},
/**
* Download app state, a function that can be called from console while debugging.
* @param filename (optional) specify target filename
*/
saveState(filename = 'meet-state.json') {
downloadJSON(APP.store.getState(), filename);
},
/**
* Exposes a Command(s) API on this instance. It is necessitated by (1) the
* desire to keep room private to this instance and (2) the need of other
@@ -1443,6 +1548,7 @@ export default {
}
APP.store.dispatch(localParticipantRoleChanged(role));
APP.API.notifyUserRoleChanged(id, role);
} else {
APP.store.dispatch(participantRoleChanged(id, role));
}
@@ -1716,6 +1822,35 @@ export default {
onStartMutedPolicyChanged(audio, video));
}
);
room.on(JitsiConferenceEvents.STARTED_MUTED, () => {
const audioMuted = room.isStartAudioMuted();
const videoMuted = room.isStartVideoMuted();
const localTracks = getLocalTracks(APP.store.getState()['features/base/tracks']);
const promises = [];
APP.store.dispatch(setAudioMuted(audioMuted));
APP.store.dispatch(setVideoMuted(videoMuted));
// Remove the tracks from the peerconnection.
for (const track of localTracks) {
// Always add the track on Safari because of a known issue where audio playout doesn't happen
// if the user joins audio and video muted, i.e., if there is no local media capture.
if (audioMuted && track.jitsiTrack?.getType() === MEDIA_TYPE.AUDIO && !browser.isWebKitBased()) {
promises.push(this.useAudioStream(null));
}
if (videoMuted && track.jitsiTrack?.getType() === MEDIA_TYPE.VIDEO) {
promises.push(this.useVideoStream(null));
}
}
Promise.allSettled(promises)
.then(() => {
APP.store.dispatch(showNotification({
titleKey: 'notify.mutedTitle',
descriptionKey: 'notify.muted'
}, NOTIFICATION_TIMEOUT_TYPE.SHORT));
});
});
room.on(
JitsiConferenceEvents.DATA_CHANNEL_OPENED, () => {
@@ -1753,16 +1888,6 @@ export default {
}, timeout);
}
);
room.on(JitsiConferenceEvents.PERMISSIONS_RECEIVED, p => {
const localParticipant = getLocalParticipant(APP.store.getState());
APP.store.dispatch(participantUpdated({
id: localParticipant.id,
local: true,
features: p
}));
});
},
/**
@@ -1927,7 +2052,8 @@ export default {
_initDeviceList(setDeviceListChangeHandler = false) {
const { mediaDevices } = JitsiMeetJS;
if (mediaDevices.isDeviceChangeAvailable()) {
if (mediaDevices.isDeviceListAvailable()
&& mediaDevices.isDeviceChangeAvailable()) {
if (setDeviceListChangeHandler) {
this.deviceChangeListener = devices =>
window.setTimeout(() => this._onDeviceListChanged(devices), 0);
@@ -2152,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();
@@ -2174,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);
}

View File

@@ -49,9 +49,7 @@ var config = {
bosh: 'https://jitsi-meet.example.com/' + subdir + 'http-bind',
// Websocket URL (XMPP)
websocket: 'wss://jitsi-meet.example.com/' + subdir + 'xmpp-websocket',
// websocketKeepAliveUrl: 'https://jitsi-meet.example.com/' + subdir + '_unlock',
// websocket: 'wss://jitsi-meet.example.com/' + subdir + 'xmpp-websocket',
// Whether BOSH should be preferred over WebSocket if both are configured.
// preferBosh: false,
@@ -89,9 +87,6 @@ var config = {
// Enables use of getDisplayMedia in electron
// electronUseGetDisplayMedia: false,
// Enables AV1 codec for FF. Note: By default it is disabled.
// enableAV1ForFF: false,
// Enables the use of the codec selection API supported by the browsers .
// enableCodecSelectionAPI: false,
@@ -128,9 +123,6 @@ var config = {
// Disables the reactions moderation feature.
// disableReactionsModeration: false,
// Disables the reactions in chat feature.
// disableReactionsInChat: false,
// Disables polls feature.
// disablePolls: false,
@@ -401,13 +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,
// // If true consent will be skipped for users who are already in the meeting.
// // skipConsentInMeeting: true,
// // Link for the recording consent dialog's "Learn more" link.
// // consentLearnMoreLink: 'https://jitsi.org/meet/consent',
// },
// recordingService: {
@@ -505,15 +490,6 @@ var config = {
// // Enables automatic request of subtitles when transcriber is present in the meeting, uses the default
// // language that is set
// autoCaptionOnTranscribe: false,
//
// // Disables everything related to closed captions - the tab in the chat area, the button in the menu,
// // subtitles on stage and the "Show subtitles on stage" checkbox in the settings.
// // Note: Starting transcriptions from the recording dialog will still work.
// disableClosedCaptions: false,
// // Whether to invite jigasi when backend transcriptions are enabled (asyncTranscription is true in metadata).
// // By default, we invite it.
// inviteJigasiOnBackendTranscribing: true,
// },
// Misc
@@ -539,7 +515,7 @@ var config = {
// videoQuality: {
//
// // Provides a way to set the codec preference on desktop based endpoints.
// codecPreferenceOrder: [ 'AV1', 'VP9', 'VP8', 'H264' ],
// codecPreferenceOrder: [ 'VP9', 'VP8', 'H264', 'AV1' ],
//
// // Provides a way to set the codec for screenshare.
// screenshareCodec: 'AV1',
@@ -616,7 +592,7 @@ 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', 'AV1' ],
// mobileCodecPreferenceOrder: [ 'VP8', 'VP9', 'H264' ],
// },
// Notification timeouts
@@ -625,7 +601,6 @@ var config = {
// medium: 5000,
// long: 10000,
// extraLong: 60000,
// sticky: 0,
// },
// // Options for the recording limit notification.
@@ -777,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>',
@@ -843,7 +815,8 @@ var config = {
// some other values in config.js to be enabled. Also, the "profile" button will
// not display for users with a JWT.
// Notes:
// - it's possible to reorder the buttons in the maintoolbar by changing the order of the mainToolbarButtons
// - it's impossible to choose which buttons go in the "More actions" menu
// - it's impossible to control the placement of buttons
// - 'desktop' controls the "Share your screen" button
// - if `toolbarButtons` is undefined, we fallback to enabling all buttons on the UI
// toolbarButtons: [
@@ -1094,10 +1067,10 @@ var config = {
// Provides a way to set the codec preference on mobile devices, both on RN and mobile browser based
// endpoints.
// mobileCodecPreferenceOrder: [ 'H264', 'VP8', 'VP9', 'AV1' ],
// mobileCodecPreferenceOrder: [ 'H264', 'VP8', 'VP9' ],
//
// Provides a way to set the codec preference on desktop based endpoints.
// codecPreferenceOrder: [ 'AV1', 'VP9', 'VP8', 'H264 ],
// codecPreferenceOrder: [ 'VP9', 'VP8', 'H264 ],
// Provides a way to set the codec for screenshare.
// screenshareCodec: 'AV1',
@@ -1273,6 +1246,9 @@ var config = {
// disableDeepLinking: false,
// The deeplinking config.
// For information about the properties of
// deeplinking.[ios/android].dynamicLink check:
// https://firebase.google.com/docs/dynamic-links/create-manually
// deeplinking: {
//
// // The desktop deeplinking config, disabled by default.
@@ -1301,6 +1277,13 @@ var config = {
// appScheme: 'org.jitsi.meet',
// // Custom URL for downloading ios mobile app.
// downloadLink: 'https://itunes.apple.com/us/app/jitsi-meet/id1165103905',
// dynamicLink: {
// apn: 'org.jitsi.meet',
// appCode: 'w2atb',
// customDomain: undefined,
// ibi: 'com.atlassian.JitsiMeet.ios',
// isi: '1165103905'
// }
// },
// // The android deeplinking config.
@@ -1313,6 +1296,13 @@ var config = {
// // Android app package name.
// appPackage: 'org.jitsi.meet',
// fDroidUrl: 'https://f-droid.org/en/packages/org.jitsi.meet/',
// dynamicLink: {
// apn: 'org.jitsi.meet',
// appCode: 'w2atb',
// customDomain: undefined,
// ibi: 'com.atlassian.JitsiMeet.ios',
// isi: '1165103905'
// }
// }
// },
@@ -1360,11 +1350,18 @@ var config = {
// disableKick: true,
// // If set to true the 'Grant moderator' button will be disabled.
// disableGrantModerator: true,
// // If set to 'all' the 'Private chat' button will be disabled for all participants.
// // If set to 'allow-moderator-chat' the 'Private chat' button will be available for chats with moderators.
// disablePrivateChat: 'all' | 'allow-moderator-chat',
// // If set to true the 'Send private message' button will be disabled.
// disablePrivateChat: true,
// },
// Endpoint that enables support for salesforce integration with in-meeting resource linking
// This is required for:
// listing the most recent records - salesforceUrl/records/recents
// searching records - salesforceUrl/records?text=${text}
// retrieving record details - salesforceUrl/records/${id}?type=${type}
// and linking the meeting - salesforceUrl/sessions/${sessionId}/records/${id}
//
// salesforceUrl: 'https://api.example.com/',
// If set to true all muting operations of remote participants will be disabled.
// disableRemoteMute: true,
@@ -1375,12 +1372,8 @@ var config = {
The config file should be in JSON.
None of the fields are mandatory and the response must have the shape:
{
// Whether participant can only send group chat message if `send-groupchat` feature is enabled in jwt.
groupChatRequiresPermission: false,
// Whether participant can only create polls if `create-polls` feature is enabled in jwt.
pollCreationRequiresPermission: false,
// The domain url to apply (will replace the domain in the sharing conference link/embed section)
inviteDomain: 'example-company.org',
inviteDomain: 'example-company.org,
// The hex value for the colour used as background
backgroundColor: '#fff',
// The url for the image used as background
@@ -1389,13 +1382,6 @@ var config = {
logoClickUrl: 'https://example-company.org',
// The url used for the image used as logo
logoImageUrl: 'https://example.com/logo-img.png',
// Endpoint that enables support for salesforce integration with in-meeting resource linking
// This is required for:
// listing the most recent records - salesforceUrl/records/recents
// searching records - salesforceUrl/records?text=${text}
// retrieving record details - salesforceUrl/records/${id}?type=${type}
// and linking the meeting - salesforceUrl/sessions/${sessionId}/records/${id}
// salesforceUrl: 'https://api.example.com/',
// Overwrite for pool of background images for avatars
avatarBackgrounds: ['url(https://example.com/avatar-background-1.png)', '#FFF'],
// The lobby/prejoin screen background
@@ -1575,11 +1561,6 @@ var config = {
// You can enable tokenAuthUrlAutoRedirect which will detect that you have logged in successfully before
// and will automatically redirect to the token service to get the token for the meeting.
// tokenAuthUrlAutoRedirect: false
// An option to respect the context.tenant jwt field compared to the current tenant from the url
// tokenRespectTenant: false,
// An option to get for user info (name, picture, email) in the token outside the user context.
// Can be used with Firebase tokens.
// tokenGetUserInfoOutOfContext: false,
// You can put an array of values to target different entity types in the invite dialog.
// Valid values are "phone", "room", "sip", "user", "videosipgw" and "email"
@@ -1880,16 +1861,6 @@ var config = {
// If true remove the tint foreground on focused user camera in filmstrip
// disableCameraTintForeground: false,
// File sharign service.
// fileSharing: {
// // The URL of the file sharing service API. See resources/file-sharing.yaml for more details.
// apiUrl: 'https://example.com',
// // Whether the file sharing service is enabled or not.
// enabled: true,
// // Maximum file size limit (-1 value disables any file size limit check)
// maxFileSize: 50,
// },
};
// Set the default values for JaaS customers

View File

@@ -4,12 +4,12 @@
text-align: center;
h2 {
font-size: 3rem;
font-size: 48px;
color : #f2f2f2;
}
&__message {
font-size: 1.5rem;
font-size: 24px;
margin-top: 20px;
}
}

View File

@@ -28,7 +28,7 @@ body {
margin: 0px;
width: 100%;
height: 100%;
font-size: 0.75rem;
font-size: 12px;
font-weight: 400;
overflow: hidden;
color: #F1F1F1;
@@ -111,7 +111,7 @@ form {
height: $watermarkHeight;
background-size: contain;
background-repeat: no-repeat;
z-index: $watermarkZ;
z-index: $zindex2;
}
.leftwatermark {
@@ -139,10 +139,10 @@ form {
position: absolute;
left: 25;
bottom: 7;
font-size: 0.875rem;
font-size: 11pt;
color: rgba(255,255,255,.50);
text-decoration: none;
z-index: $watermarkZ;
z-index: 100;
}
/**

View File

@@ -11,9 +11,9 @@
#chatconversation {
box-sizing: border-box;
flex: 1;
font-size: 0.75rem;
font-size: 10pt;
height: calc(100% - 10px);
line-height: 1.25rem;
line-height: 20px;
overflow: auto;
padding: 16px;
text-align: left;
@@ -72,7 +72,7 @@
#nickname {
text-align: center;
color: #9d9d9d;
font-size: 1rem;
font-size: 16px;
margin: auto 0;
padding: 0 16px;
@@ -86,7 +86,7 @@
}
label {
line-height: 1.5rem;
line-height: 24px;
}
}
@@ -98,7 +98,7 @@
}
.chatmessage .usermessage {
font-size: 1rem;
font-size: 16px;
}
}
@@ -124,7 +124,7 @@
}
#smileys {
font-size: 1.625rem;
font-size: 20pt;
margin: auto;
cursor: pointer;
}
@@ -141,8 +141,34 @@
left: 0;
}
.smileys-panel {
bottom: 100%;
box-sizing: border-box;
background-color: rgba(0, 0, 0, .6) !important;
height: auto;
display: flex;
overflow: hidden;
position: absolute;
width: calc(#{$sidebarWidth} - 32px);
margin-bottom: 5px;
margin-left: -5px;
/**
* CSS transitions do not apply for auto dimensions. So to produce the css
* accordion effect for showing and hiding the smiley-panel, while allowing
* for variable panel, height, use a very large max-height and animate off
* of that.
*/
transition: max-height 0.3s;
#smileysContainer {
background-color: $chatBackgroundColor;
border-top: 1px solid #A4B8D1;
}
}
#smileysContainer .smiley {
font-size: 1.625rem;
font-size: 20pt;
}
.smileyContainer {
@@ -193,8 +219,8 @@
box-sizing: border-box;
color: #fff;
font-weight: 600;
font-size: 1.5rem;
line-height: 2rem;
font-size: 24px;
line-height: 32px;
.jitsi-icon {
cursor: pointer;

View File

@@ -34,8 +34,8 @@
}
&__checkbox-label {
font-size: 0.875rem;
line-height: 1.125rem;
font-size: 14px;
line-height: 18px;
display: flex;
align-items: center;
letter-spacing: -0.006em;
@@ -51,8 +51,8 @@
}
&__text-container {
font-size: 0.875rem;
line-height: 1.125rem;
font-size: 14px;
line-height: 18px;
display: flex;
align-items: center;
letter-spacing: -0.006em;
@@ -84,8 +84,8 @@
&__button-text {
font-weight: 600;
font-size: 0.875rem;
line-height: 2.5rem;
font-size: 14px;
line-height: 40px;
text-align: center;
letter-spacing: -0.006em;
color: #FFFFFF;

View File

@@ -10,7 +10,7 @@
margin: 17px 0;
padding-bottom: 17px;
color: #ffffff;
font-size: 1.25rem;
font-size: 21px;
letter-spacing: 0.3px;
border-bottom: 1px solid lighten(#FFFFFF, 10%);
}
@@ -19,12 +19,12 @@
color: #ffffff;
display: block;
margin-top: 22px;
font-size: 1rem;
font-size: 16px;
}
&__icon {
margin: 0 10px;
font-size: 3.125rem;
font-size: 50px;
}
}

View File

@@ -1,14 +1,14 @@
.meetings-list {
font-size: 0.875rem;
font-size: 14px;
color: #253858;
line-height: 1.25rem;
line-height: 20px;
text-align: left;
text-overflow: ellipsis;
display: flex;
flex-direction: column;
position: relative;
overflow-y: auto;
flex-grow: 1;
overflow: auto;
width: 100%;
.meetings-list-empty {
text-align: center;
@@ -20,8 +20,8 @@
.description {
color: #2f3237;
font-size: 0.875rem;
line-height: 1.125rem;
font-size: 14px;
line-height: 18px;
margin-bottom: 16px;
max-width: 436px;
}
@@ -37,8 +37,8 @@
color: #0163FF;
cursor: pointer;
display: flex;
font-size: 0.875rem;
line-height: 1.125rem;
font-size: 14px;
line-height: 18px;
margin: 24px 0 32px 0;
}
@@ -101,17 +101,17 @@
}
.title {
font-size: 0.75rem;
font-size: 12px;
font-weight: 600;
line-height: 1rem;
line-height: 16px;
margin-bottom: 4px;
}
.subtitle {
color: #5E6D7A;
font-weight: normal;
font-size: 0.75rem;
line-height: 1rem;
font-size: 12px;
line-height: 16px;
}
@@ -174,12 +174,4 @@
}
}
}
@media (max-width: 1024px) { /* Targets iPads and smaller devices */
.item {
.delete-meeting {
display: block !important;
}
}
}
}

View File

@@ -1,7 +1,7 @@
%navigate-section-list-text {
width: 100%;
font-size: 0.875rem;
line-height: 1.25rem;
font-size: 14px;
line-height: 20px;
color: $welcomePageTitleColor;
text-align: left;
font-family: 'open_sanslight', Helvetica, sans-serif;
@@ -52,7 +52,7 @@
.navigate-section-tile-body {
@extend %navigate-section-list-tile-text;
font-weight: normal;
line-height: 1.5rem;
line-height: 24px;
}
.navigate-section-list-tile-info {
flex: 1;
@@ -61,7 +61,7 @@
.navigate-section-tile-title {
@extend %navigate-section-list-tile-text;
font-weight: bold;
line-height: 1.5rem;
line-height: 24px;
}
.navigate-section-section-header {
@extend %navigate-section-list-text;

View File

@@ -4,3 +4,9 @@
border-radius: 3px;
}
}
.mobile-browser.shift-right {
.participants_pane {
z-index: -1;
}
}

View File

@@ -8,8 +8,8 @@
&__text {
text-align: center;
font-size: 0.875rem;
line-height: 1.25rem;
font-size: 14px;
line-height: 21px;
font-weight: 300;
}
}

View File

@@ -55,7 +55,7 @@
span.emoji {
width: 40px;
height: 40px;
font-size: 1.375rem;
font-size: 22px;
display: flex;
align-items: center;
justify-content: center;
@@ -63,7 +63,7 @@
@for $i from 1 through 12 {
&.increase-#{$i}{
font-size: calc(1.25rem + #{$i}px);
font-size: calc(20px + #{$i}px);
}
}
}
@@ -96,8 +96,8 @@
span.text {
font-style: normal;
font-weight: 600;
font-size: 0.875rem;
line-height: 1.5rem;
font-size: 14px;
line-height: 24px;
margin-left: 8px;
}
}
@@ -132,8 +132,8 @@ $reactionCount: 20;
.reaction-emoji {
position: absolute;
font-size: 1.5rem;
line-height: 2rem;
font-size: 24px;
line-height: 32px;
width: 32px;
height: 32px;
top: 0;

View File

@@ -12,7 +12,7 @@
.recording-title {
display: inline-flex;
align-items: center;
font-size: 0.875rem;
font-size: 14px;
margin-left: 16px;
max-width: 70%;
@@ -35,8 +35,8 @@
.local-recording-warning {
margin-top: 8px;
display: block;
font-size: 0.875rem;
line-height: 1.25rem;
font-size: 14px;
line-height: 20px;
padding: 8px 16px;
&.text {
@@ -126,7 +126,7 @@
.recording-info-title {
display: inline-flex;
font-size: 0.875rem;
font-size: 14px;
width: 290px
}
@@ -150,7 +150,7 @@
/**
* Set font-size to be consistent with Atlaskit FieldText.
*/
font-size: 0.875rem;
font-size: 14px;
.broadcast-dropdown {
text-align: left;
@@ -194,6 +194,6 @@
.warning-text {
color:#FFD740;
font-size: 0.75rem;
font-size: 12px;
}
}

View File

@@ -2,7 +2,7 @@
width: 30%;
margin: 20% auto;
text-align: center;
font-size: 1.5rem;
font-size: 24px;
.thanks-msg {
border-bottom: 1px solid #FFFFFF;
@@ -10,16 +10,16 @@
padding-right: 30px;
p {
margin: 30px auto;
font-size: 1.5rem;
line-height: 1.5rem;
font-size: 24px;
line-height: 24px;
}
}
.hint-msg {
p {
margin: 26px auto;
font-weight: 600;
font-size: 1rem;
line-height: 1.125rem;
font-size: 16px;
line-height: 18px;
.hint-msg__holder{
font-weight: 200;
}
@@ -33,7 +33,7 @@
}
.forbidden-msg {
p {
font-size: 1rem;
font-size: 16px;
margin-top: 15px;
}
}

View File

@@ -70,7 +70,7 @@ input[type="reset"] {
body {
color: #333;
font-family: Arial, sans-serif;
font-size: 0.875rem;
font-size: 14px;
line-height: 1.42857142857143;
}
/* International Font Stacks*/
@@ -113,7 +113,7 @@ pre:first-child {
/* Headings: desired line height in px / font size = unitless line height */
h1 {
color: #333;
font-size: 2rem;
font-size: 32px;
font-weight: normal;
line-height: 1.25;
text-transform: none;
@@ -121,7 +121,7 @@ h1 {
}
h2 {
color: #333;
font-size: 1.5rem;
font-size: 24px;
font-weight: normal;
line-height: 1.25;
text-transform: none;
@@ -129,14 +129,14 @@ h2 {
}
h3 {
color: #333;
font-size: 1.25rem;
font-size: 20px;
font-weight: normal;
line-height: 1.5;
text-transform: none;
margin: 30px 0 0 0;
}
h4 {
font-size: 1rem;
font-size: 16px;
font-weight: bold;
line-height: 1.25;
text-transform: none;
@@ -144,7 +144,7 @@ h4 {
}
h5 {
color: #333;
font-size: 0.875rem;
font-size: 14px;
font-weight: bold;
line-height: 1.42857143;
text-transform: none;
@@ -152,7 +152,7 @@ h5 {
}
h6 {
color: #707070;
font-size: 0.75rem;
font-size: 12px;
font-weight: bold;
line-height: 1.66666667;
text-transform: uppercase;
@@ -179,7 +179,7 @@ h5 + h6 {
/* Other typographical elements */
small {
color: #707070;
font-size: 0.75rem;
font-size: 12px;
line-height: 1.33333333333333;
}
code,

View File

@@ -4,7 +4,7 @@
#enter_room {
.welcome-page-button {
font-size: 1rem;
font-size: 16px;
left: 0;
text-align: center;
width: 100%;
@@ -53,10 +53,25 @@
}
.welcome-footer-row-block {
display: flex;
flex-direction: column;
gap:12px;
align-items: center;
display: block;
}
}
}
.desktop-browser {
&.shift-right {
@media only screen and (max-width: $verySmallScreen + $sidebarWidth) {
#videoResolutionLabel {
display: none;
}
.vertical-filmstrip .filmstrip {
display: none;
}
.chrome-extension-banner {
display: none;
}
}
}
}

View File

@@ -9,9 +9,9 @@
// Do not inherit the font-family from the toolbar button, because it's an
// icon style.
font-family: $baseFontFamily;
font-size: 0.5rem;
font-size: 9px;
font-weight: 700;
line-height: 0.75rem;
line-height: 13px;
min-width: 13px;
overflow: hidden;
text-align: center;
@@ -69,8 +69,8 @@
.badge-round {
bottom: -5px;
font-size: 0.75rem;
line-height: 1.25rem;
font-size: 12px;
line-height: 20px;
min-width: 20px;
pointer-events: none;
position: absolute;

View File

@@ -22,6 +22,7 @@ $newToolbarSizeWithPadding: calc(#{$newToolbarSize} + 24px);
* Chat
*/
$chatBackgroundColor: #131519;
$sidebarWidth: 315px;
/**
* Misc.
@@ -37,8 +38,6 @@ $zindex1: 1;
$zindex2: 2;
$zindex3: 3;
$toolbarZ: 250;
$watermarkZ: 253;
// Place filmstrip videos over toolbar in order
// to make connection info visible.
$filmstripVideosZ: $toolbarZ + 1;
@@ -49,11 +48,11 @@ $filmstripVideosZ: $toolbarZ + 1;
$primaryUnsupportedBrowserButtonBgColor: #0052CC;
$unsupportedBrowserButtonBgColor: rgba(9, 30, 66, 0.04);
$unsupportedBrowserTextColor: #4a4a4a;
$unsupportedBrowserTextSmallFontSize: 1rem;
$unsupportedBrowserTextSmallFontSize: 17px;
$unsupportedBrowserTitleColor: #fff;
$unsupportedBrowserTitleFontSize: 1.5rem;
$unsupportedBrowserTitleFontSize: 24px;
$unsupportedDesktopBrowserTextColor: rgba(255, 255, 255, 0.7);
$unsupportedDesktopBrowserTextFontSize: 1.25rem;
$unsupportedDesktopBrowserTextFontSize: 21px;
/**
* The size of the default watermark.
@@ -76,19 +75,16 @@ $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;
$welcomePageHeaderContainerMargin: $welcomePageHeaderContainerMarginTop auto 0;
$welcomePageHeaderTextTitleMarginBottom: 0;
$welcomePageHeaderTextTitleFontSize: 2.625rem;
$welcomePageHeaderTextTitleFontSize: 42px;
$welcomePageHeaderTextTitleFontWeight: normal;
$welcomePageHeaderTextTitleLineHeight: 50px;
$welcomePageHeaderTextTitleOpacity: 1;

View File

@@ -160,7 +160,7 @@
}
#alwaysOnTop .displayname {
font-size: 0.875rem;
font-size: 15px;
position: inherit;
width: 100%;
left: 0px;
@@ -294,7 +294,7 @@
width: auto;
z-index: $zindex2;
font-weight: 600;
font-size: 0.875rem;
font-size: 14px;
text-align: center;
color: #FFF;
left: 50%;
@@ -340,7 +340,7 @@
.presence-label {
color: #fff;
font-size: 0.75rem;
font-size: 12px;
font-weight: 100;
left: 0;
margin: 0 auto;

View File

@@ -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;
@@ -53,9 +53,9 @@ body.welcome-page {
.header-text-subtitle {
color: #fff;
font-size: 1.25rem;
font-size: 20px;
font-weight: 600;
line-height: 1.625rem;
line-height: 26px;
margin: 16px 0 32px 0;
text-align: $welcomePageHeaderTextAlign;
@@ -64,7 +64,7 @@ body.welcome-page {
.not-allow-title-character-div {
color: #f03e3e;
background-color: #fff;
font-size: 0.75rem;
font-size: 12px;
font-weight: 600;
margin: 10px 0px 5px 0px;
text-align: $welcomePageHeaderTextAlign;
@@ -147,7 +147,7 @@ body.welcome-page {
display: inline-block;
height: 50px;
width: 100%;
font-size: 0.875rem;
font-size: 14px;
padding-left: 10px;
&.focus-visible {
@@ -172,7 +172,7 @@ body.welcome-page {
}
.tab-container {
font-size: 1rem;
font-size: 16px;
position: relative;
text-align: left;
display: $welcomePageTabContainerDisplay;
@@ -191,8 +191,8 @@ body.welcome-page {
background-color: #c7ddff;
border-radius: 6px;
color: #0163FF;
font-size: 0.875rem;
line-height: 1.125rem;
font-size: 14px;
line-height: 18px;
margin: 4px;
display: $welcomePageTabButtonsDisplay;
@@ -218,19 +218,15 @@ body.welcome-page {
.welcome-page-button {
border: 0;
font-size: 0.875rem;
background: $welcomePageButtonBg;
font-size: 14px;
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;
}
}
@@ -246,7 +242,7 @@ body.welcome-page {
* {
cursor: pointer;
font-size: 2rem;
font-size: 32px;
}
.toolbox-icon {
@@ -268,7 +264,8 @@ body.welcome-page {
&.without-content {
.welcome-card {
max-width: 100dvw;
min-width: 500px;
max-width: 580px;
}
}
@@ -349,6 +346,6 @@ body.welcome-page {
.welcome-footer-row-1-text {
max-width: 200px;
text-align: center;
margin-right: 16px;
}
}

View File

@@ -91,3 +91,15 @@
}
}
}
.shift-right .remote-videos > div {
/**
* Max-width corresponding to the ASPECT_RATIO_BREAKPOINT from features/filmstrip/constants,
* from which we subtract the chat size.
*/
@media only screen and (max-width: calc(500px + #{$sidebarWidth})) {
video {
object-fit: cover;
}
}
}

View File

@@ -20,7 +20,7 @@
width: 28px;
i {
line-height: 1.75rem;
line-height: 28px;
margin: auto;
}
}
@@ -35,7 +35,7 @@
padding-left: 10px;
i {
line-height: 1.25rem;
line-height: 20px;
margin: auto;
}
}

View File

@@ -1,7 +1,7 @@
.info-dialog {
cursor: default;
display: flex;
font-size: 0.875rem;
font-size: 14px;
.info-dialog-column {
margin-right: 10px;
@@ -53,8 +53,8 @@
max-width: 334px;
width: 100%;
margin-top: 20px;
font-size: 0.75rem;
line-height: 1.5rem;
font-size: 12px;
line-height: 24px;
border-collapse: collapse;
* {
@@ -107,7 +107,7 @@
box-sizing: border-box;
display: flex;
flex-direction: column;
font-size: 0.75rem;
font-size: 12px;
max-height: 100%;
overflow: auto;
padding: 15pt;

View File

@@ -1,8 +1,8 @@
.invite-more {
&-dialog {
color: #fff;
font-size: 0.875rem;
line-height: 1.5rem;
font-size: 15px;
line-height: 24px;
&.separator {
margin: 24px 0 24px -20px;

View File

@@ -1,5 +1,5 @@
.share-screen-warn-dialog {
font-size: 0.875rem;
font-size: 14px;
.separator-line {
margin: 24px 0 24px -20px;

View File

@@ -1,15 +1,15 @@
.security {
&-dialog {
color: #fff;
font-size: 0.875rem;
line-height: 1.5rem;
font-size: 15px;
line-height: 24px;
&.password-section {
display: flex;
flex-direction: column;
.description {
font-size: 0.75rem;
font-size: 13px;
}
.password {
@@ -24,7 +24,7 @@
button {
cursor: pointer;
text-decoration: none;
font-size: 0.875rem;
font-size: 14px;
color: #6FB1EA;
}

View File

@@ -1,7 +1,7 @@
.lobby-screen {
font-size: 1rem;
font-size: 16px;
font-weight: 400;
line-height: 1.625rem;
line-height: 26px;
&-content {
align-items: center;
@@ -43,7 +43,7 @@
flex-direction: column;
.description {
font-size: 0.75rem;
font-size: 13px;
}
.control-row {
@@ -53,7 +53,7 @@
margin-top: 15px;
label {
font-size: 0.875rem;
font-size: 14px;
font-weight: bold;
}
}
@@ -191,9 +191,9 @@
.title {
flex: 1;
color: #fff;
font-size: 1.25rem;
font-size: 20px;
font-weight: 600;
line-height: 1.75rem;
line-height: 28px;
letter-spacing: -1.2%;
}
}
@@ -214,8 +214,8 @@
border-radius: 6px;
box-sizing: border-box;
color: white;
font-size: 0.75rem;
line-height: 1rem;
font-size: 12px;
line-height: 16px;
margin-bottom: 16px;
margin-top: -8px;
padding: 4px;

View File

@@ -5,9 +5,9 @@
color: #fff;
cursor: pointer;
display: inline-block;
font-size: 0.875rem;
font-size: 14px;
font-weight: 600;
line-height: 1.5rem;
line-height: 24px;
margin-bottom: 16px;
padding: 7px 16px;
position: relative;
@@ -26,7 +26,7 @@
&.text {
width: auto;
font-size: 0.75rem;
font-size: 13px;
margin: 0;
padding: 0;
}
@@ -98,7 +98,7 @@
}
.action-btn {
font-size: 1rem;
font-size: 16px;
margin-bottom: 8px;
padding: 11px 16px;
}

View File

@@ -1,13 +1,13 @@
.reload_overlay_title {
display: block;
font-size: 1rem;
line-height: 1.25rem;
font-size: 16px;
line-height: 20px;
}
.reload_overlay_text {
display: block;
font-size: 0.75rem;
line-height: 1.875rem;
font-size: 12px;
line-height: 30px;
}
#reloadProgressBar {

View File

@@ -34,12 +34,12 @@
&__status{
margin-top: 15px;
font-size: 0.875rem;
line-height: 1.25rem;
font-size: 14px;
line-height: 20px;
}
&__name {
font-size: 1.5rem;
line-height: 2rem;
font-size: 24px;
line-height: 32px;
}
}

View File

@@ -8,7 +8,7 @@
cursor: pointer;
display: inline-flex;
font-family: Roboto, arial, sans-serif;
font-size: 0.875rem;
font-size: 14px;
padding: 1px;
.google-cta {
@@ -17,7 +17,7 @@
/**
* Hack the line height for vertical centering of text.
*/
line-height: 2rem;
line-height: 32px;
margin: 0 15px;
}

View File

@@ -17,8 +17,8 @@
.microsoft-cta {
display: inline-block;
color: #5E5E5E;
font-size: 0.875rem;
line-height: 2.5rem;
font-size: 15px;
line-height: 41px;
}
.microsoft-logo {

4
debian/control vendored
View File

@@ -34,7 +34,7 @@ Description: Configuration for web serving of Jitsi Meet
Package: jitsi-meet-prosody
Architecture: all
Depends: openssl, prosody (>= 0.12.0) | prosody-trunk | prosody-0.12 | prosody-13.0, lua-sec, lua-basexx, lua-luaossl, lua-cjson, lua-inspect
Depends: openssl, prosody (>= 0.11.7) | prosody-trunk | prosody-0.12 | prosody-0.11, lua-sec, lua-basexx, lua-luaossl, lua-cjson, lua-inspect
Replaces: jitsi-meet-tokens
Description: Prosody configuration for Jitsi Meet
Jitsi Meet is a WebRTC JavaScript application that uses Jitsi
@@ -48,7 +48,7 @@ Description: Prosody configuration for Jitsi Meet
Package: jitsi-meet-tokens
Architecture: all
Depends: ${misc:Depends}, prosody-trunk | prosody-0.12 | prosody-13.0 | prosody (>= 0.12.0), jitsi-meet-prosody
Depends: ${misc:Depends}, prosody-trunk | prosody-0.11 | prosody-0.12 | prosody (>= 0.11.7), jitsi-meet-prosody
Description: Prosody token authentication plugin for Jitsi Meet
Package: jitsi-meet-turnserver

View File

@@ -131,6 +131,16 @@ case "$1" in
fi
fi
if [ "$PROSODY_CREATE_JICOFO_USER" = "true" ]; then
# create 'focus@auth.domain' prosody user
prosodyctl register $JICOFO_AUTH_USER $JICOFO_AUTH_DOMAIN $JICOFO_AUTH_PASSWORD
# trigger a restart
PROSODY_CONFIG_PRESENT="false"
fi
# creates the user if it does not exist
echo -e "$JVB_SECRET\n$JVB_SECRET" | prosodyctl adduser jvb@$JICOFO_AUTH_DOMAIN > /dev/null || true
# Check whether prosody config has the internal muc, if not add it,
# as we are migrating configs
if [ -f $PROSODY_HOST_CONFIG ] && ! grep -q "internal.$JICOFO_AUTH_DOMAIN" $PROSODY_HOST_CONFIG; then
@@ -174,12 +184,6 @@ case "$1" in
PROSODY_CONFIG_PRESENT="false"
fi
# Since prosody 13 admins are not automatically room owners and we expect that for jicofo
if ! grep -q -- 'component_admins_as_room_owners = ' $PROSODY_HOST_CONFIG ;then
sed -i "1s/^/component_admins_as_room_owners = true\n/" $PROSODY_HOST_CONFIG
PROSODY_CONFIG_PRESENT="false"
fi
JAAS_HOST_CONFIG="/etc/prosody/conf.avail/jaas.cfg.lua"
if [ "${JAAS_INPUT}" = "true" ] && [ ! -f $JAAS_HOST_CONFIG ]; then
sed -i "s/enabled = false -- Jitsi meet components/enabled = true -- Jitsi meet components/g" $PROSODY_HOST_CONFIG
@@ -203,6 +207,9 @@ case "$1" in
fi
fi
# Make sure the focus@auth user's roster includes the proxy component (this is idempotent)
prosodyctl mod_roster_command subscribe focus.$JVB_HOSTNAME $JICOFO_AUTH_USER@$JICOFO_AUTH_DOMAIN
if [ ! -f /var/lib/prosody/$JVB_HOSTNAME.crt ]; then
# prosodyctl takes care for the permissions
# echo for using all default values
@@ -245,29 +252,6 @@ case "$1" in
if [ "$PROSODY_CONFIG_PRESENT" = "false" ]; then
invoke-rc.d prosody restart || true
# give it some time to warm up
sleep 10
if [ "$PROSODY_CREATE_JICOFO_USER" = "true" ]; then
# create 'focus@auth.domain' prosody user
echo -e "$JICOFO_AUTH_PASSWORD\n$JICOFO_AUTH_PASSWORD" | prosodyctl adduser $JICOFO_AUTH_USER@$JICOFO_AUTH_DOMAIN > /dev/null || true
# trigger a restart
PROSODY_CONFIG_PRESENT="false"
fi
# creates the user if it does not exist
echo -e "$JVB_SECRET\n$JVB_SECRET" | prosodyctl adduser jvb@$JICOFO_AUTH_DOMAIN > /dev/null || true
# Make sure the focus@auth user's roster includes the proxy component (this is idempotent)
prosodyctl mod_roster_command subscribe focus.$JVB_HOSTNAME $JICOFO_AUTH_USER@$JICOFO_AUTH_DOMAIN
# To make sure the roster command is loaded
# Once we have https://issues.prosody.im/1908 we can start using prosodyctl shell roster subscribe
# and drop the wait and the prosody restart
sleep 1
invoke-rc.d prosody restart || true
# In case we had updated the certificates and restarted prosody, let's restart and the bridge and jicofo if possible
if [ -d /run/systemd/system ] && [ "$CERT_ADDED_TO_TRUST" = "true" ]; then
systemctl restart jitsi-videobridge2.service >/dev/null || true

View File

@@ -1,6 +1,3 @@
-- We need this for prosody 13.0
component_admins_as_room_owners = true
plugin_paths = { "/usr/share/jitsi-meet/prosody-plugins/" }
-- domain mapper options, must at least have domain base set to use the mapper
@@ -15,7 +12,6 @@ external_services = {
cross_domain_bosh = false;
consider_bosh_secure = true;
consider_websocket_secure = true;
-- https_ports = { }; -- Remove this line to prevent listening on port 5284
-- by default prosody 0.12 sends cors headers, if you want to disable it uncomment the following (the config is available on 0.12.1)
@@ -39,11 +35,6 @@ unlimited_jids = {
"jvb@auth.jitmeet.example.com"
}
-- https://prosody.im/doc/modules/mod_smacks
smacks_max_unacked_stanzas = 5;
smacks_hibernation_time = 60;
smacks_max_old_sessions = 1;
VirtualHost "jitmeet.example.com"
authentication = "jitsi-anonymous" -- do not delete me
-- Properties below are modified by jitsi-meet-tokens package config
@@ -58,21 +49,26 @@ VirtualHost "jitmeet.example.com"
key = "/etc/prosody/certs/jitmeet.example.com.key";
certificate = "/etc/prosody/certs/jitmeet.example.com.crt";
}
av_moderation_component = "avmoderation.jitmeet.example.com"
speakerstats_component = "speakerstats.jitmeet.example.com"
end_conference_component = "endconference.jitmeet.example.com"
-- we need bosh
modules_enabled = {
"bosh";
"websocket";
"smacks";
"ping"; -- Enable mod_ping
"speakerstats";
"external_services";
"features_identity";
"conference_duration";
"end_conference";
"muc_lobby_rooms";
"muc_breakout_rooms";
"av_moderation";
"room_metadata";
}
c2s_require_encryption = false
lobby_muc = "lobby.jitmeet.example.com"
breakout_rooms_muc = "breakout.jitmeet.example.com"
room_metadata_component = "metadata.jitmeet.example.com"
main_muc = "conference.jitmeet.example.com"
-- muc_lobby_whitelist = { "recorder.jitmeet.example.com" } -- Here we can whitelist jibri to enter lobby enabled rooms
@@ -128,13 +124,6 @@ VirtualHost "auth.jitmeet.example.com"
authentication = "internal_hashed"
smacks_hibernation_time = 15;
VirtualHost "recorder.jitmeet.example.com"
modules_enabled = {
"smacks";
}
authentication = "internal_hashed"
smacks_max_old_sessions = 2000;
-- Proxy to jicofo's user JID, so that it doesn't have to register as a component.
Component "focus.jitmeet.example.com" "client_proxy"
target_address = "focusUser@auth.jitmeet.example.com"
@@ -148,9 +137,6 @@ Component "endconference.jitmeet.example.com" "end_conference"
Component "avmoderation.jitmeet.example.com" "av_moderation_component"
muc_component = "conference.jitmeet.example.com"
Component "filesharing.jitmeet.example.com" "filesharing_component"
muc_component = "conference.jitmeet.example.com"
Component "lobby.jitmeet.example.com" "muc"
storage = "memory"
restrict_room_creation = true

View File

@@ -150,12 +150,6 @@ server {
# alias /usr/share/jitsi-meet/load-test/libs/$1;
#}
location = /_unlock {
add_header 'Access-Control-Allow-Origin' '*';
add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains';
add_header "Cache-Control" "no-cache, no-store";
}
location ~ ^/conference-request/v1(\/.*)?$ {
proxy_pass http://127.0.0.1:8888/conference-request/v1$1;
add_header "Cache-Control" "no-cache, no-store";

View File

@@ -36,7 +36,7 @@
Component: JitsiMeetJS.app.entryPoints.APP
})
const isEmbedded = () => {
const inIframe = () => {
try {
return window.self !== window.top;
} catch (e) {
@@ -45,7 +45,7 @@
};
const isElectron = navigator.userAgent.includes('Electron');
const shouldRegisterWorker = !isElectron && !isEmbedded() && 'serviceWorker' in navigator;
const shouldRegisterWorker = !isElectron && !inIframe() && 'serviceWorker' in navigator;
if (shouldRegisterWorker) {
navigator.serviceWorker

View File

@@ -192,6 +192,17 @@ var interfaceConfig = {
// NATIVE_APP_NAME: 'Jitsi Meet',
/**
* Specify Firebase dynamic link properties for the mobile apps.
*/
// MOBILE_DYNAMIC_LINK: {
// APN: 'org.jitsi.meet',
// APP_CODE: 'w2atb',
// CUSTOM_DOMAIN: undefined,
// IBI: 'com.atlassian.JitsiMeet.ios',
// ISI: '1165103905'
// },
/**
* Hide the logo on the deep linking pages.
*/

View File

@@ -19,6 +19,7 @@ target 'JitsiMeet' do
pod 'Firebase/Analytics', '~> 8.0'
pod 'Firebase/Crashlytics', '~> 8.0'
pod 'Firebase/DynamicLinks', '~> 8.0'
end
target 'JitsiMeetSDK' do
@@ -96,7 +97,4 @@ post_install do |installer|
config.build_settings['OTHER_SWIFT_FLAGS'] = '$(inherited) -no-verify-emitted-module-interface'
end
end
# Patch SocketRocket to support TLS 1.3
%x(patch Pods/SocketRocket/SocketRocket/SRSecurityPolicy.m -N < patches/ws-tls13.diff)
end

View File

@@ -1,11 +1,15 @@
PODS:
- amplitude-react-native (1.4.13):
- Amplitude (8.18.0):
- AnalyticsConnector (~> 1.0.0)
- amplitude-react-native (2.17.3):
- Amplitude (= 8.18.0)
- React-Core
- AppAuth (1.7.6):
- AppAuth/Core (= 1.7.6)
- AppAuth/ExternalUserAgent (= 1.7.6)
- AppAuth/Core (1.7.6)
- AppAuth/ExternalUserAgent (1.7.6):
- AnalyticsConnector (1.0.3)
- AppAuth (1.7.5):
- AppAuth/Core (= 1.7.5)
- AppAuth/ExternalUserAgent (= 1.7.5)
- AppAuth/Core (1.7.5)
- AppAuth/ExternalUserAgent (1.7.5):
- AppAuth/Core
- boost (1.84.0)
- CocoaLumberjack (3.7.4):
@@ -23,6 +27,9 @@ PODS:
- Firebase/Crashlytics (8.15.0):
- Firebase/CoreOnly
- FirebaseCrashlytics (~> 8.15.0)
- Firebase/DynamicLinks (8.15.0):
- Firebase/CoreOnly
- FirebaseDynamicLinks (~> 8.15.0)
- FirebaseAnalytics (8.15.0):
- FirebaseAnalytics/AdIdSupport (= 8.15.0)
- FirebaseCore (~> 8.0)
@@ -57,6 +64,8 @@ PODS:
- GoogleUtilities/Environment (~> 7.7)
- nanopb (~> 2.30908.0)
- PromisesObjC (< 3.0, >= 1.2)
- FirebaseDynamicLinks (8.15.0):
- FirebaseCore (~> 8.0)
- FirebaseInstallations (8.15.0):
- FirebaseCore (~> 8.0)
- GoogleUtilities/Environment (~> 7.7)
@@ -132,18 +141,18 @@ PODS:
- hermes-engine (0.75.5):
- hermes-engine/Pre-built (= 0.75.5)
- hermes-engine/Pre-built (0.75.5)
- JitsiWebRTC (124.0.2)
- libwebp (1.5.0):
- libwebp/demux (= 1.5.0)
- libwebp/mux (= 1.5.0)
- libwebp/sharpyuv (= 1.5.0)
- libwebp/webp (= 1.5.0)
- libwebp/demux (1.5.0):
- JitsiWebRTC (124.0.1)
- libwebp (1.3.2):
- libwebp/demux (= 1.3.2)
- libwebp/mux (= 1.3.2)
- libwebp/sharpyuv (= 1.3.2)
- libwebp/webp (= 1.3.2)
- libwebp/demux (1.3.2):
- libwebp/webp
- libwebp/mux (1.5.0):
- libwebp/mux (1.3.2):
- libwebp/demux
- libwebp/sharpyuv (1.5.0)
- libwebp/webp (1.5.0):
- libwebp/sharpyuv (1.3.2)
- libwebp/webp (1.3.2):
- libwebp/sharpyuv
- nanopb (2.30908.0):
- nanopb/decode (= 2.30908.0)
@@ -1782,13 +1791,14 @@ PODS:
- Yoga (0.0.0)
DEPENDENCIES:
- "amplitude-react-native (from `../node_modules/@amplitude/analytics-react-native`)"
- "amplitude-react-native (from `../node_modules/@amplitude/react-native`)"
- boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`)
- CocoaLumberjack (= 3.7.4)
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
- Firebase/Analytics (~> 8.0)
- Firebase/Crashlytics (~> 8.0)
- Firebase/DynamicLinks (~> 8.0)
- fmt (from `../node_modules/react-native/third-party-podspecs/fmt.podspec`)
- "giphy-react-native-sdk (from `../node_modules/@giphy/react-native-sdk`)"
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
@@ -1879,6 +1889,8 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- Amplitude
- AnalyticsConnector
- AppAuth
- CocoaLumberjack
- Firebase
@@ -1886,6 +1898,7 @@ SPEC REPOS:
- FirebaseCore
- FirebaseCoreDiagnostics
- FirebaseCrashlytics
- FirebaseDynamicLinks
- FirebaseInstallations
- Giphy
- GoogleAppMeasurement
@@ -1904,7 +1917,7 @@ SPEC REPOS:
EXTERNAL SOURCES:
amplitude-react-native:
:path: "../node_modules/@amplitude/analytics-react-native"
:path: "../node_modules/@amplitude/react-native"
boost:
:podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec"
DoubleConversion:
@@ -2082,8 +2095,10 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/yoga"
SPEC CHECKSUMS:
amplitude-react-native: d0039a3ce502eb441ba818af1b8c8ba710ef16e7
AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73
Amplitude: 184def4f87aa26f94a93a7faa334e06b1cae704d
amplitude-react-native: 6b7a1d30627233fe6f03741109831561d0a5f69c
AnalyticsConnector: a53214d38ae22734c6266106c0492b37832633a9
AppAuth: 501c04eda8a8d11f179dbe8637b7a91bb7e5d2fa
boost: 4cb898d0bf20404aab1850c656dcea009429d6c1
CocoaLumberjack: 543c79c114dadc3b1aba95641d8738b06b05b646
DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5
@@ -2093,6 +2108,7 @@ SPEC CHECKSUMS:
FirebaseCore: 5743c5785c074a794d35f2fff7ecc254a91e08b1
FirebaseCoreDiagnostics: 92e07a649aeb66352b319d43bdd2ee3942af84cb
FirebaseCrashlytics: feb07e4e9187be3c23c6a846cce4824e5ce2dd0b
FirebaseDynamicLinks: 1dc816ef789c5adac6fede0b46d11478175c70e4
FirebaseInstallations: 40bd9054049b2eae9a2c38ef1c3dd213df3605cd
fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120
Giphy: 83628960ed04e1c3428ff1b4fb2b027f65e82f50
@@ -2105,8 +2121,8 @@ SPEC CHECKSUMS:
GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
hermes-engine: c9fe5870af65876125fdbbf833071b6f329db30d
JitsiWebRTC: b47805ab5668be38e7ee60e2258f49badfe8e1d0
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
JitsiWebRTC: d0ae5fd6a81e771bfd82c2ee6c6bb542ebd65ee8
libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
ObjectiveDropboxOfficial: fe206ce8c0bc49976c249d472db7fdbc53ebbd53
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
@@ -2193,6 +2209,6 @@ SPEC CHECKSUMS:
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
Yoga: 1dd9dabb9df8fe08f12cd522eae04a2da0e252eb
PODFILE CHECKSUM: 8ff981f2324fa4b013b6690257898dcd2be9d3c3
PODFILE CHECKSUM: 8a3e5d019861b37d4159f2d178cc534be3ac528c
COCOAPODS: 1.16.2

View File

@@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
0B412F1F1EDEE6E800B1A0A6 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B412F1E1EDEE6E800B1A0A6 /* ViewController.m */; };
0B412F211EDEE95300B1A0A6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0B412F201EDEE95300B1A0A6 /* Main.storyboard */; };
0B5418471F7C5D8C00A2DD86 /* MeetingRowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B5418461F7C5D8C00A2DD86 /* MeetingRowController.swift */; };
0B7001701F7C51CC005944F4 /* InCallController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B70016F1F7C51CC005944F4 /* InCallController.swift */; };
0BEA5C291F7B8F73000D0AB4 /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0BEA5C271F7B8F73000D0AB4 /* Interface.storyboard */; };
@@ -17,8 +19,10 @@
0BEA5C3B1F7B8F73000D0AB4 /* ComplicationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BEA5C3A1F7B8F73000D0AB4 /* ComplicationController.swift */; };
0BEA5C3D1F7B8F73000D0AB4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0BEA5C3C1F7B8F73000D0AB4 /* Assets.xcassets */; };
0BEA5C411F7B8F73000D0AB4 /* JitsiMeetCompanion.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 0BEA5C251F7B8F73000D0AB4 /* JitsiMeetCompanion.app */; };
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
2681BB562C7A0B42CFBA6719 /* libPods-JitsiMeet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D6152FF9E9F7B0E86F70A21D /* libPods-JitsiMeet.a */; };
361974E2A13624D7735D619D /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 5C1BE20ECD5DEEB48FED90B5 /* PrivacyInfo.xcprivacy */; };
4341A9062CF0D63200940D93 /* hermes.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4341A9052CF0D63200940D93 /* hermes.xcframework */; };
@@ -30,8 +34,7 @@
4EB0603C260E09D000F524C5 /* SocketConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB06039260E09D000F524C5 /* SocketConnection.swift */; };
4EB0603D260E09D000F524C5 /* DarwinNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB0603A260E09D000F524C5 /* DarwinNotificationCenter.swift */; };
4EB0603E260E09D000F524C5 /* SampleUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB0603B260E09D000F524C5 /* SampleUploader.swift */; };
DEA0B7122D7EF16E0062A9F6 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEA0B7112D7EF16E0062A9F6 /* ViewController.swift */; };
DEA0B7142D7EF7590062A9F6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEA0B7132D7EF7590062A9F6 /* AppDelegate.swift */; };
DE4C456121DE1E4E00EA0709 /* FIRUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = DE4C455F21DE1E4E00EA0709 /* FIRUtilities.m */; };
DEA9F289258A6EA800D4CD74 /* JitsiMeetSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DEA9F288258A6EA800D4CD74 /* JitsiMeetSDK.framework */; };
DEA9F28A258A6EA800D4CD74 /* JitsiMeetSDK.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DEA9F288258A6EA800D4CD74 /* JitsiMeetSDK.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
DED016F128ECBC9D009D5E8D /* WebRTC.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = DED016F028ECBC9D009D5E8D /* WebRTC.xcframework */; };
@@ -118,8 +121,12 @@
/* Begin PBXFileReference section */
0B26BE6D1EC5BC3C00EEFB41 /* JitsiMeet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = JitsiMeet.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0B412F1D1EDEE6E800B1A0A6 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
0B412F1E1EDEE6E800B1A0A6 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
0B412F201EDEE95300B1A0A6 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
0B5418461F7C5D8C00A2DD86 /* MeetingRowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingRowController.swift; sourceTree = "<group>"; };
0B70016F1F7C51CC005944F4 /* InCallController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InCallController.swift; sourceTree = "<group>"; };
0BBD021F212EB69D00CCB19F /* Types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Types.h; sourceTree = "<group>"; };
0BD6B4361EF82A6B00D1F4CD /* WebRTC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebRTC.framework; path = "../../node_modules/react-native-webrtc/ios/WebRTC.framework"; sourceTree = "<group>"; };
0BEA5C251F7B8F73000D0AB4 /* JitsiMeetCompanion.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JitsiMeetCompanion.app; sourceTree = BUILT_PRODUCTS_DIR; };
0BEA5C281F7B8F73000D0AB4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Interface.storyboard; sourceTree = "<group>"; };
@@ -132,9 +139,12 @@
0BEA5C3C1F7B8F73000D0AB4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
0BEA5C3E1F7B8F73000D0AB4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* jitsi-meet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "jitsi-meet.app"; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
3E0F4ED943C0B12BE77F6B45 /* Pods-JitsiMeet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.release.xcconfig"; path = "Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.release.xcconfig"; sourceTree = "<group>"; };
4341A9052CF0D63200940D93 /* hermes.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = hermes.xcframework; path = "../Pods/hermes-engine/destroot/Library/Frameworks/universal/hermes.xcframework"; sourceTree = "<group>"; };
4E90F93F2632D1AB001102D4 /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = "<group>"; };
@@ -147,12 +157,13 @@
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; };
DE050388256E904600DEE3A5 /* WebRTC.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = WebRTC.xcframework; path = "../../node_modules/react-native-webrtc/apple/WebRTC.xcframework"; sourceTree = "<group>"; };
DEA0B7112D7EF16E0062A9F6 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
DEA0B7132D7EF7590062A9F6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
DE4C455F21DE1E4E00EA0709 /* FIRUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRUtilities.m; sourceTree = "<group>"; };
DE4C456021DE1E4E00EA0709 /* FIRUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FIRUtilities.h; sourceTree = "<group>"; };
DEA9F288258A6EA800D4CD74 /* JitsiMeetSDK.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = JitsiMeetSDK.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DED016F028ECBC9D009D5E8D /* WebRTC.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = WebRTC.xcframework; path = ../Pods/JitsiWebRTC/WebRTC.xcframework; sourceTree = "<group>"; };
DEFDBBDB25656E3B00344B23 /* WebRTC.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = WebRTC.xcframework; path = "../../node_modules/react-native-webrtc/ios/WebRTC.xcframework"; sourceTree = "<group>"; };
@@ -247,11 +258,18 @@
13B07FAE1A68108700A75B9A /* src */ = {
isa = PBXGroup;
children = (
DEA0B7132D7EF7590062A9F6 /* AppDelegate.swift */,
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.m */,
DE4C456021DE1E4E00EA0709 /* FIRUtilities.h */,
DE4C455F21DE1E4E00EA0709 /* FIRUtilities.m */,
13B07FB51A68108700A75B9A /* Images.xcassets */,
13B07FB61A68108700A75B9A /* Info.plist */,
13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
DEA0B7112D7EF16E0062A9F6 /* ViewController.swift */,
13B07FB71A68108700A75B9A /* main.m */,
0B412F201EDEE95300B1A0A6 /* Main.storyboard */,
0BBD021F212EB69D00CCB19F /* Types.h */,
0B412F1D1EDEE6E800B1A0A6 /* ViewController.h */,
0B412F1E1EDEE6E800B1A0A6 /* ViewController.m */,
);
path = src;
sourceTree = "<group>";
@@ -284,6 +302,7 @@
0BEA5C351F7B8F73000D0AB4 /* WatchKit extension */,
4EB06025260E026600F524C5 /* JitsiMeetBroadcast Extension */,
CDD71F5E1157E9F283DF92A8 /* Pods */,
6132EF172BDFF13200BBE14D /* PrivacyInfo.xcprivacy */,
5C1BE20ECD5DEEB48FED90B5 /* PrivacyInfo.xcprivacy */,
);
indentWidth = 2;
@@ -416,7 +435,6 @@
ProvisioningStyle = Automatic;
};
13B07F861A680F5B00A75B9A = {
LastSwiftMigration = 1620;
SystemCapabilities = {
com.apple.SafariKeychain = {
enabled = 1;
@@ -474,6 +492,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0B412F211EDEE95300B1A0A6 /* Main.storyboard in Resources */,
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
361974E2A13624D7735D619D /* PrivacyInfo.xcprivacy in Resources */,
@@ -539,7 +558,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "#if test \"$PRODUCT_BUNDLE_IDENTIFIER\" = \"com.atlassian.JitsiMeet.ios\"; then\n# ENTITLEMENTS_PLIST=\"$PROJECT_DIR/app.entitlements\"\n# \n# /usr/libexec/PlistBuddy -c \"Add :com.apple.developer.avfoundation.multitasking-camera-access bool 1\" $ENTITLEMENTS_PLIST\n#fi\n";
shellScript = "if test \"$PRODUCT_BUNDLE_IDENTIFIER\" = \"com.atlassian.JitsiMeet.ios\"; then\n ENTITLEMENTS_PLIST=\"$PROJECT_DIR/app.entitlements\"\n \n /usr/libexec/PlistBuddy -c \"Add :com.apple.developer.avfoundation.multitasking-camera-access bool 1\" $ENTITLEMENTS_PLIST\nfi\n";
};
69BC5020DBE393B56BD76636 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
@@ -641,8 +660,10 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DEA0B7122D7EF16E0062A9F6 /* ViewController.swift in Sources */,
DEA0B7142D7EF7590062A9F6 /* AppDelegate.swift in Sources */,
0B412F1F1EDEE6E800B1A0A6 /* ViewController.m in Sources */,
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
DE4C456121DE1E4E00EA0709 /* FIRUtilities.m in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -848,7 +869,6 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconDebug;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = app.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
@@ -873,8 +893,6 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
@@ -885,7 +903,6 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconRelease;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = app.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
@@ -909,7 +926,6 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;

23
ios/app/src/AppDelegate.h Normal file
View File

@@ -0,0 +1,23 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@end

139
ios/app/src/AppDelegate.m Normal file
View File

@@ -0,0 +1,139 @@
/*
* Copyright @ 2018-present 8x8, Inc.
* Copyright @ 2017-2018 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "AppDelegate.h"
#import "FIRUtilities.h"
#import "Types.h"
#import "ViewController.h"
@import Firebase;
@import JitsiMeetSDK;
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
JitsiMeet *jitsiMeet = [JitsiMeet sharedInstance];
#if 0
jitsiMeet.webRtcLoggingSeverity = WebRTCLoggingSeverityVerbose;
#endif
jitsiMeet.conferenceActivityType = JitsiMeetConferenceActivityType;
jitsiMeet.customUrlScheme = @"org.jitsi.meet";
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 = @"https://meet.jit.si/test0988test";
[builder setFeatureFlag:@"welcomepage.enabled" withBoolean:YES];
[builder setFeatureFlag:@"ios.screensharing.enabled" withBoolean:YES];
[builder setFeatureFlag:@"ios.recording.enabled" withBoolean:YES];
}];
[jitsiMeet application:application didFinishLaunchingWithOptions:launchOptions];
// Initialize Crashlytics and Firebase if a valid GoogleService-Info.plist file was provided.
if ([FIRUtilities appContainsRealServiceInfoPlist]) {
NSLog(@"Enabling Firebase");
[FIRApp configure];
// Crashlytics defaults to disabled with the FirebaseCrashlyticsCollectionEnabled Info.plist key.
[[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:![jitsiMeet isCrashReportingDisabled]];
}
ViewController *rootController = (ViewController *)self.window.rootViewController;
[jitsiMeet showSplashScreen:rootController.view];
return YES;
}
- (void) applicationWillTerminate:(UIApplication *)application {
NSLog(@"Application will terminate!");
// Try to leave the current meeting graceefully.
ViewController *rootController = (ViewController *)self.window.rootViewController;
[rootController terminate];
}
#pragma mark Linking delegate methods
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *restorableObjects))restorationHandler {
if ([FIRUtilities appContainsRealServiceInfoPlist]) {
// 1. Attempt to handle Universal Links through Firebase in order to support
// its Dynamic Links (which we utilize for the purposes of deferred deep
// linking).
BOOL handled
= [[FIRDynamicLinks dynamicLinks]
handleUniversalLink:userActivity.webpageURL
completion:^(FIRDynamicLink * _Nullable dynamicLink, NSError * _Nullable error) {
NSURL *firebaseUrl = [FIRUtilities extractURL:dynamicLink];
if (firebaseUrl != nil) {
userActivity.webpageURL = firebaseUrl;
[[JitsiMeet sharedInstance] application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
}];
if (handled) {
return handled;
}
}
// 2. Default to plain old, non-Firebase-assisted Universal Links.
return [[JitsiMeet sharedInstance] application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
// This shows up during a reload in development, skip it.
// https://github.com/firebase/firebase-ios-sdk/issues/233
if ([[url absoluteString] containsString:@"google/link/?dismiss=1&is_weak_match=1"]) {
return NO;
}
NSURL *openUrl = url;
if ([FIRUtilities appContainsRealServiceInfoPlist]) {
// Process Firebase Dynamic Links
FIRDynamicLink *dynamicLink = [[FIRDynamicLinks dynamicLinks] dynamicLinkFromCustomSchemeURL:url];
NSURL *firebaseUrl = [FIRUtilities extractURL:dynamicLink];
if (firebaseUrl != nil) {
openUrl = firebaseUrl;
}
}
return [[JitsiMeet sharedInstance] application:app
openURL:openUrl
options:options];
}
- (UIInterfaceOrientationMask)application:(UIApplication *)application
supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return [[JitsiMeet sharedInstance] application:application
supportedInterfaceOrientationsForWindow:window];
}
@end

View File

@@ -1,78 +0,0 @@
import UIKit
import Firebase
import JitsiMeetSDK
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
let jitsiMeet = JitsiMeet.sharedInstance()
// jitsiMeet.webRtcLoggingSeverity = .verbose
jitsiMeet.conferenceActivityType = "org.jitsi.JitsiMeet.ios.conference" // Must match the one defined in Info.plist{}
jitsiMeet.customUrlScheme = "org.jitsi.meet"
jitsiMeet.universalLinkDomains = ["meet.jit.si", "alpha.jitsi.net", "beta.meet.jit.si"]
jitsiMeet.defaultConferenceOptions = JitsiMeetConferenceOptions.fromBuilder { builder in
// For testing configOverrides a room needs to be set
// builder.room = "https://meet.jit.si/test0988test"
builder.setFeatureFlag("welcomepage.enabled", withBoolean: true)
builder.setFeatureFlag("ios.screensharing.enabled", withBoolean: true)
builder.setFeatureFlag("ios.recording.enabled", withBoolean: true)
}
jitsiMeet.application(application, didFinishLaunchingWithOptions: launchOptions ?? [:])
if self.appContainsRealServiceInfoPlist() {
print("Enabling Firebase")
FirebaseApp.configure()
Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(!jitsiMeet.isCrashReportingDisabled())
}
let vc = ViewController()
self.window?.rootViewController = vc
jitsiMeet.showSplashScreen(vc.view)
self.window?.makeKeyAndVisible()
return true
}
func applicationWillTerminate(_ application: UIApplication) {
print("Application will terminate!")
if let rootController = self.window?.rootViewController as? ViewController {
rootController.terminate()
}
}
// MARK: Linking delegate methods
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
return JitsiMeet.sharedInstance().application(application, continue: userActivity, restorationHandler: restorationHandler)
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
if url.absoluteString.contains("google/link/?dismiss=1&is_weak_match=1") {
return false
}
return JitsiMeet.sharedInstance().application(app, open: url, options: options)
}
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return JitsiMeet.sharedInstance().application(application, supportedInterfaceOrientationsFor: window)
}
}
// Firebase utilities
extension AppDelegate {
func appContainsRealServiceInfoPlist() -> Bool {
return InfoPlistUtil.containsRealServiceInfoPlist(in: Bundle.main)
}
}

View File

@@ -1,10 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="u7g-vg-A8m">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="xSm-U5-Hdu">
<objects>
<viewController id="u7g-vg-A8m" customClass="ViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="d40-fc-Y8P"/>
<viewControllerLayoutGuide type="bottom" id="1KD-Ho-g0H"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="QpR-jB-WOw" customClass="JitsiMeetView">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="ZIj-K3-jVH" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="28" y="138"/>
</scene>
</scenes>
</document>

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2017 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <Foundation/Foundation.h>
@import Firebase;
@interface FIRUtilities : NSObject
+ (BOOL)appContainsRealServiceInfoPlist;
+ (NSURL *_Nullable)extractURL: (FIRDynamicLink* _Nullable)dynamicLink;
@end

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2017 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "FIRUtilities.h"
@import JitsiMeetSDK;
@implementation FIRUtilities
+ (BOOL)appContainsRealServiceInfoPlist {
static BOOL containsRealServiceInfoPlist = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSBundle *bundle = [NSBundle mainBundle];
containsRealServiceInfoPlist = [InfoPlistUtil containsRealServiceInfoPlistInBundle:bundle];
});
return containsRealServiceInfoPlist;
}
+ (NSURL *)extractURL: (FIRDynamicLink*)dynamicLink {
NSURL *url = nil;
if (dynamicLink != nil) {
NSURL *dynamicLinkURL = dynamicLink.url;
if (dynamicLinkURL != nil
&& (dynamicLink.matchType == FIRDLMatchTypeUnique
|| dynamicLink.matchType == FIRDLMatchTypeDefault)) {
// Strong match, process it.
url = dynamicLinkURL;
}
}
return url;
}
@end

View File

@@ -88,6 +88,8 @@
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>

7
ios/app/src/Types.h Normal file
View File

@@ -0,0 +1,7 @@
#import <Foundation/Foundation.h>
// This must match what's defined in the NSUserActivityTypes array in the
// Info.plist file.
static NSString *const JitsiMeetConferenceActivityType
= @"org.jitsi.JitsiMeet.ios.conference";

View File

@@ -0,0 +1,24 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@import UIKit;
@import JitsiMeetSDK;
@interface ViewController : UIViewController<JitsiMeetViewDelegate>
- (void)terminate;
@end

View File

@@ -0,0 +1,149 @@
/*
* Copyright @ 2017-present 8x8, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@import CoreSpotlight;
@import MobileCoreServices;
@import Intents; // Needed for NSUserActivity suggestedInvocationPhrase
@import JitsiMeetSDK;
#import "Types.h"
#import "ViewController.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
JitsiMeetView *view = (JitsiMeetView *) self.view;
view.delegate = self;
[view join:[[JitsiMeet sharedInstance] getInitialConferenceOptions]];
}
// JitsiMeetViewDelegate
- (void)_onJitsiMeetViewDelegateEvent:(NSString *)name
withData:(NSDictionary *)data {
NSLog(
@"[%s:%d] JitsiMeetViewDelegate %@ %@",
__FILE__, __LINE__, name, data);
#if DEBUG
NSAssert(
[NSThread isMainThread],
@"JitsiMeetViewDelegate %@ method invoked on a non-main thread",
name);
#endif
}
- (void)conferenceJoined:(NSDictionary *)data {
[self _onJitsiMeetViewDelegateEvent:@"CONFERENCE_JOINED" withData:data];
// Register a NSUserActivity for this conference so it can be invoked as a
// Siri shortcut.
NSUserActivity *userActivity
= [[NSUserActivity alloc] initWithActivityType:JitsiMeetConferenceActivityType];
NSString *urlStr = data[@"url"];
NSURL *url = [NSURL URLWithString:urlStr];
NSString *conference = [url.pathComponents lastObject];
userActivity.title = [NSString stringWithFormat:@"Join %@", conference];
userActivity.suggestedInvocationPhrase = @"Join my Jitsi meeting";
userActivity.userInfo = @{@"url": urlStr};
[userActivity setEligibleForSearch:YES];
[userActivity setEligibleForPrediction:YES];
[userActivity setPersistentIdentifier:urlStr];
// Subtitle
CSSearchableItemAttributeSet *attributes
= [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString *)kUTTypeItem];
attributes.contentDescription = urlStr;
userActivity.contentAttributeSet = attributes;
self.userActivity = userActivity;
[userActivity becomeCurrent];
}
- (void)conferenceTerminated:(NSDictionary *)data {
[self _onJitsiMeetViewDelegateEvent:@"CONFERENCE_TERMINATED" withData:data];
}
- (void)conferenceWillJoin:(NSDictionary *)data {
[self _onJitsiMeetViewDelegateEvent:@"CONFERENCE_WILL_JOIN" withData:data];
}
// - (void)customButtonPressed:(NSDictionary *)data {
// [self _onJitsiMeetViewDelegateEvent:@"CUSTOM_BUTTON_PRESSED" withData:data];
// }
#if 0
- (void)enterPictureInPicture:(NSDictionary *)data {
[self _onJitsiMeetViewDelegateEvent:@"ENTER_PICTURE_IN_PICTURE" withData:data];
}
#endif
- (void)readyToClose:(NSDictionary *)data {
[self _onJitsiMeetViewDelegateEvent:@"READY_TO_CLOSE" withData:data];
}
// - (void)transcriptionChunkReceived:(NSDictionary *)data {
// [self _onJitsiMeetViewDelegateEvent:@"TRANSCRIPTION_CHUNK_RECEIVED" withData:data];
// }
- (void)participantJoined:(NSDictionary *)data {
NSLog(@"%@%@", @"Participant joined: ", data[@"participantId"]);
}
- (void)participantLeft:(NSDictionary *)data {
NSLog(@"%@%@", @"Participant left: ", data[@"participantId"]);
}
- (void)audioMutedChanged:(NSDictionary *)data {
NSLog(@"%@%@", @"Audio muted changed: ", data[@"muted"]);
}
- (void)endpointTextMessageReceived:(NSDictionary *)data {
NSLog(@"%@%@", @"Endpoint text message received: ", data);
}
- (void)screenShareToggled:(NSDictionary *)data {
NSLog(@"%@%@", @"Screen share toggled: ", data);
}
- (void)chatMessageReceived:(NSDictionary *)data {
NSLog(@"%@%@", @"Chat message received: ", data);
}
- (void)chatToggled:(NSDictionary *)data {
NSLog(@"%@%@", @"Chat toggled: ", data);
}
- (void)videoMutedChanged:(NSDictionary *)data {
NSLog(@"%@%@", @"Video muted changed: ", data[@"muted"]);
}
#pragma mark - Helpers
- (void)terminate {
JitsiMeetView *view = (JitsiMeetView *) self.view;
[view leave];
}
@end

View File

@@ -1,94 +0,0 @@
/*
* Copyright @ 2025-present 8x8, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import CoreSpotlight
import Intents
import MobileCoreServices
import UIKit
import JitsiMeetSDK
@objcMembers
class ViewController: UIViewController {
override func loadView() {
let jitsiView = JitsiMeetView(frame: UIScreen.main.bounds)
self.view = jitsiView
}
override func viewDidLoad() {
super.viewDidLoad()
guard let view = self.view as? JitsiMeetView else { return }
view.delegate = self
view.join(JitsiMeet.sharedInstance().getInitialConferenceOptions())
}
// MARK: - Helper Methods
func terminate() {
guard let view = self.view as? JitsiMeetView else { return }
view.leave()
}
}
extension ViewController: @preconcurrency JitsiMeetViewDelegate {
// MARK: - Private Helper Methods
private func onJitsiMeetViewDelegateEvent(_ name: String, withData data: [AnyHashable: Any]?) {
NSLog("[%@:%d] JitsiMeetViewDelegate %@ %@", #file, #line, name, data ?? [:])
#if DEBUG
assert(Thread.isMainThread, "JitsiMeetViewDelegate \(name) method invoked on a non-main thread")
#endif
}
// MARK: - JitsiMeetViewDelegate
func conferenceJoined(_ data: [AnyHashable: Any]) {
onJitsiMeetViewDelegateEvent("CONFERENCE_JOINED", withData: data)
// Register a NSUserActivity for this conference so it can be invoked as a Siri shortcut.
// Must match the one defined in Info.plist
let userActivity = NSUserActivity(activityType: "org.jitsi.JitsiMeet.ios.conference")
if let urlStr = data["url"] as? String,
let url = URL(string: urlStr),
let conference = url.pathComponents.last {
userActivity.title = "Join \(conference)"
userActivity.suggestedInvocationPhrase = "Join my Jitsi meeting"
userActivity.userInfo = ["url": urlStr]
userActivity.isEligibleForSearch = true
userActivity.isEligibleForPrediction = true
userActivity.persistentIdentifier = urlStr
// Subtitle
let attributes = CSSearchableItemAttributeSet(contentType: UTType.item)
attributes.contentDescription = urlStr
userActivity.contentAttributeSet = attributes
self.userActivity = userActivity
userActivity.becomeCurrent()
}
}
func ready(toClose data: [AnyHashable: Any]) {
onJitsiMeetViewDelegateEvent("READY_TO_CLOSE", withData: data)
}
}

28
ios/app/src/main.m Normal file
View File

@@ -0,0 +1,28 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(
argc, argv,
nil,
NSStringFromClass([AppDelegate class]));
}
}

View File

@@ -1,15 +0,0 @@
diff --git a/SocketRocket/SRSecurityPolicy.m b/SocketRocket/SRSecurityPolicy.m
index 3759d26e..271477e8 100644
--- a/SocketRocket/SRSecurityPolicy.m
+++ b/SocketRocket/SRSecurityPolicy.m
@@ -56,8 +56,8 @@ - (instancetype)init
- (void)updateSecurityOptionsInStream:(NSStream *)stream
{
- // Enforce TLS 1.2
- [stream setProperty:(__bridge id)CFSTR("kCFStreamSocketSecurityLevelTLSv1_2") forKey:(__bridge id)kCFStreamPropertySocketSecurityLevel];
+ // Enforce TLS >= 1.2
+ [stream setProperty:(__bridge id)kCFStreamSocketSecurityLevelNegotiatedSSL forKey:(__bridge id)kCFStreamPropertySocketSecurityLevel];
// Validate certificate chain for this stream if enabled.
NSDictionary<NSString *, id> *sslOptions = @{ (__bridge NSString *)kCFStreamSSLValidatesCertificateChain : @(self.certificateChainValidationEnabled) };

View File

@@ -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>";
};
@@ -869,7 +871,6 @@
baseConfigurationReference = 09A78016288AF50ACD28A10D /* Pods-JitsiMeetSDK.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
@@ -893,6 +894,8 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_INSTALL_OBJC_HEADER = NO;
SWIFT_OBJC_INTERFACE_HEADER_NAME = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -904,7 +907,6 @@
baseConfigurationReference = 891FE43DAD30BC8976683100 /* Pods-JitsiMeetSDK.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
@@ -928,6 +930,8 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_INSTALL_OBJC_HEADER = NO;
SWIFT_OBJC_INTERFACE_HEADER_NAME = "";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
@@ -938,7 +942,6 @@
baseConfigurationReference = 8F48C340DE0D91D1012976C5 /* Pods-JitsiMeetSDKLite.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
@@ -967,6 +970,8 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_INSTALL_OBJC_HEADER = NO;
SWIFT_OBJC_INTERFACE_HEADER_NAME = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -978,7 +983,6 @@
baseConfigurationReference = 86389F55993FAAF6AEB3FA3E /* Pods-JitsiMeetSDKLite.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
@@ -1007,6 +1011,8 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_INSTALL_OBJC_HEADER = NO;
SWIFT_OBJC_INTERFACE_HEADER_NAME = "";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};

View File

@@ -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,9 +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)overwriteConfig:(NSDictionary*)config;
- (void)sendCameraFacingModeMessage:(NSString*)to :(NSString*)facingMode;
- (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

View File

@@ -32,15 +32,13 @@ static NSString * const showNotificationAction = @"org.jitsi.meet.SHOW_NOTIFICAT
static NSString * const hideNotificationAction = @"org.jitsi.meet.HIDE_NOTIFICATION";
static NSString * const startRecordingAction = @"org.jitsi.meet.START_RECORDING";
static NSString * const stopRecordingAction = @"org.jitsi.meet.STOP_RECORDING";
static NSString * const overwriteConfigAction = @"org.jitsi.meet.OVERWRITE_CONFIG";
static NSString * const sendCameraFacingModeMessageAction = @"org.jitsi.meet.SEND_CAMERA_FACING_MODE_MESSAGE";
@implementation ExternalAPI
static NSMapTable<NSString*, void (^)(NSArray* participantsInfo)> *participantInfoCompletionHandlers;
__attribute__((constructor))
static void initializeViewsMap(void) {
static void initializeViewsMap() {
participantInfoCompletionHandlers = [NSMapTable strongToStrongObjectsMapTable];
}
@@ -62,9 +60,7 @@ RCT_EXPORT_MODULE();
@"SHOW_NOTIFICATION": showNotificationAction,
@"HIDE_NOTIFICATION": hideNotificationAction,
@"START_RECORDING": startRecordingAction,
@"STOP_RECORDING": stopRecordingAction,
@"OVERWRITE_CONFIG": overwriteConfigAction,
@"SEND_CAMERA_FACING_MODE_MESSAGE": sendCameraFacingModeMessageAction
@"STOP_RECORDING": stopRecordingAction
};
};
@@ -94,9 +90,7 @@ RCT_EXPORT_MODULE();
showNotificationAction,
hideNotificationAction,
startRecordingAction,
stopRecordingAction,
overwriteConfigAction,
sendCameraFacingModeMessageAction
stopRecordingAction
];
}
@@ -216,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,
@@ -232,29 +238,13 @@ 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)
};
[self sendEventWithName:stopRecordingAction body:data];
}
- (void)overwriteConfig:(NSDictionary*)config {
NSDictionary *data = @{
@"config": config
};
[self sendEventWithName:overwriteConfigAction body:data];
}
- (void)sendCameraFacingModeMessage:(NSString*)to :(NSString*)facingMode {
NSDictionary *data = @{
@"to": to,
@"facingMode": facingMode
};
[self sendEventWithName:sendCameraFacingModeMessageAction body:data];
}
@end

View File

@@ -24,11 +24,15 @@
}
+ (void)activateWithAudioSession:(AVAudioSession *)session {
[self.rtcAudioSession audioSessionDidActivate:session];
if (!self.rtcAudioSession.useManualAudio) {
[self.rtcAudioSession audioSessionDidActivate:session];
}
}
+ (void)deactivateWithAudioSession:(AVAudioSession *)session {
[self.rtcAudioSession audioSessionDidDeactivate:session];
if (!self.rtcAudioSession.useManualAudio) {
[self.rtcAudioSession audioSessionDidDeactivate:session];
}
}
@end

View File

@@ -82,7 +82,7 @@ typedef NS_ENUM(NSInteger, WebRTCLoggingSeverity) {
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *_Nonnull)options;
- (UIInterfaceOrientationMask)application:(UIApplication *_Nonnull)application
supportedInterfaceOrientationsForWindow:(UIWindow *_Nullable)window;
supportedInterfaceOrientationsForWindow:(UIWindow *_Nonnull)window;
#pragma mark - Utility methods

View File

@@ -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
@@ -54,8 +51,7 @@ typedef NS_ENUM(NSInteger, RecordingMode) {
- (void)toggleCamera;
- (void)showNotification:(NSString * _Nonnull)appearance :(NSString * _Nullable)description :(NSString * _Nullable)timeout :(NSString * _Nullable)title :(NSString * _Nullable)uid;
- (void)hideNotification:(NSString * _Nullable)uid;
- (void)startRecording:(RecordingMode)mode :(NSString * _Nullable)dropboxToken :(BOOL)shouldShare :(NSString * _Nullable)rtmpStreamKey :(NSString * _Nullable)rtmpBroadcastID :(NSString * _Nullable)youtubeStreamKey :(NSString * _Nullable)youtubeBroadcastID :(NSDictionary * _Nullable)extraMetadata :(BOOL)transcription;
- (void)startRecording:(RecordingMode)mode :(NSString * _Nullable)dropboxToken :(BOOL)shouldShare :(NSString * _Nullable)rtmpStreamKey :(NSString * _Nullable)rtmpBroadcastID :(NSString * _Nullable)youtubeStreamKey :(NSString * _Nullable)youtubeBroadcastID :(NSString * _Nullable)extraMetadata :(BOOL)transcription;
- (void)stopRecording:(RecordingMode)mode :(BOOL)transcription;
- (void)overwriteConfig:(NSDictionary * _Nonnull)config;
- (void)sendCameraFacingModeMessage:(NSString * _Nonnull)to :(NSString * _Nullable)facingMode;
@end

View File

@@ -17,8 +17,6 @@
#include <mach/mach_time.h>
#import <UIKit/UIKit.h>
#import "ExternalAPI.h"
#import "JitsiMeet+Private.h"
#import "JitsiMeetConferenceOptions+Private.h"
@@ -27,43 +25,11 @@
#import "RNRootView.h"
#pragma mark UIColor helpers
@interface UIColor (Hex)
+ (UIColor *)colorWithHex:(uint32_t)hex;
+ (UIColor *)colorWithHex:(uint32_t)hex alpha:(CGFloat)alpha;
@end
@implementation UIColor (Hex)
+ (UIColor *)colorWithHex:(uint32_t)hex {
return [self colorWithHex:hex alpha:1.0];
}
+ (UIColor *)colorWithHex:(uint32_t)hex alpha:(CGFloat)alpha {
CGFloat red = ((hex >> 16) & 0xFF) / 255.0;
CGFloat green = ((hex >> 8) & 0xFF) / 255.0;
CGFloat blue = (hex & 0xFF) / 255.0;
return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}
@end
#pragma mark UIColor helpers end
/**
* Backwards compatibility: turn the boolean prop into a feature flag.
*/
static NSString *const PiPEnabledFeatureFlag = @"pip.enabled";
/**
* Forward declarations.
*/
static NSString *recordingModeToString(RecordingMode mode);
@implementation JitsiMeetView {
/**
@@ -99,8 +65,11 @@ static NSString *recordingModeToString(RecordingMode mode);
* - registers necessary observers
*/
- (void)doInitialize {
// Set a background color which matches the one used in JS.
self.backgroundColor = [UIColor colorWithHex:0x040404 alpha:1];
// Set a background color which is in accord with the JavaScript and Android
// parts of the application and causes less perceived visual flicker than
// the default background color.
self.backgroundColor
= [UIColor colorWithRed:.07f green:.07f blue:.07f alpha:1];
[self registerObservers];
}
@@ -184,25 +153,15 @@ static NSString *recordingModeToString(RecordingMode mode);
[externalAPI hideNotification:uid];
}
- (void)startRecording:(RecordingMode)mode :(NSString * _Nullable)dropboxToken :(BOOL)shouldShare :(NSString * _Nullable)rtmpStreamKey :(NSString * _Nullable)rtmpBroadcastID :(NSString * _Nullable)youtubeStreamKey :(NSString * _Nullable)youtubeBroadcastID :(NSDictionary * _Nullable)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];
}
- (void)overwriteConfig:(NSDictionary * _Nonnull)config {
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
[externalAPI overwriteConfig:config];
}
- (void)sendCameraFacingModeMessage:(NSString * _Nonnull)to :(NSString * _Nullable)facingMode {
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
[externalAPI sendCameraFacingModeMessage:to :facingMode];
}
[externalAPI stopRecording:mode :transcription];
}
#pragma mark Private methods
@@ -298,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;
}
}

View File

@@ -130,18 +130,4 @@
*/
- (void)customButtonPressed:(NSDictionary *)data;
/**
* Called when the unique identifier for conference has been set.
*
* The `data` dictionary contains a `sessionId` key.
*/
- (void)conferenceUniqueIdSet:(NSDictionary *)data;
/**
* Called when the recording status has changed.
*
* The `data` dictionary contains a `sessionData` key.
*/
- (void)recordingStatusChanged:(NSDictionary *)data;
@end

View File

@@ -39,7 +39,6 @@
"mr": "मराठी",
"nb": "Norsk bokmål",
"nl": "Nederlands",
"no": "Norsk",
"oc": "Occitan",
"pl": "Polski",
"pt": "Português",

View File

@@ -835,6 +835,7 @@
"or": "أو",
"premeeting": "ما قبل المُلتقى",
"screenSharingError": "خطأ في مشاركة الشاشة:",
"showScreen": "تفعيل واجهة ما قبل المُلتقى",
"startWithPhone": "البدء مع جهاز الصوت من الجوال",
"videoOnlyError": "خطأ في الفيديو:",
"videoTrackError": "لم نتمكن من إنشاء ملف الفيديو",
@@ -943,7 +944,6 @@
"title": "خيارات الأمان"
},
"settings": {
"audio": "الصوت",
"buttonLabel": "إعدادات",
"calendar": {
"about": "تُستعمَل الرزنامة {{appName}} المدمجة للوصل بأمان إلى رزنامتك، لذا بالإمكان معرفة الأحداث القادمة.",
@@ -967,7 +967,6 @@
"more": "المزيد",
"name": "الاسم",
"noDevice": "لا يوجد",
"notifications": "الإشعارات",
"participantJoined": "انضم مشارك",
"participantKnocking": "دخل المشارك في الردهة",
"participantLeft": "غادر المشارك",
@@ -978,15 +977,13 @@
"selectCamera": "الكاميرا",
"selectMic": "المايكروفون",
"selfView": "عرض ذاتي",
"shortcuts": "اختصارات لوحة المفاتيح",
"sounds": "اصوات",
"speakers": "المذياع (مكبر الصوت)",
"startAudioMuted": "بدء الجميع مكتومي الصوت",
"startReactionsMuted": "كتم رد فعل الصوت للجميع",
"startVideoMuted": "بدء الجميع دون فيديو",
"talkWhileMuted": "تحدث أثناء كتم الصوت",
"title": "الإعدادات",
"video": "الفيديو"
"title": "الإعدادات"
},
"settingsView": {
"advanced": "إعدادات متقدمة",

View File

@@ -842,6 +842,7 @@
"or": "o",
"premeeting": "Prereunió",
"screenSharingError": "Error en compartir la pantalla:",
"showScreen": "Activa la pantalla de prereunió",
"startWithPhone": "Comença amb àudio de telèfon",
"videoOnlyError": "Error del vídeo:",
"videoTrackError": "No s'ha pogut crear la pista de vídeo.",
@@ -915,7 +916,7 @@
"localRecordingStartWarningTitle": "Atura l'enregistrament per a desar-lo",
"localRecordingVideoStop": "Aturar el vídeo també aturarà l'enregistrament local. Segur que voleu continuar?",
"localRecordingVideoWarning": "Per a enregistrar el vostre vídeo, cal que ho feu en començar l'enregistrament",
"localRecordingWarning": "Assegureu-vos de triar la pestanya actual per a poder usar el vídeo i àudios correctes.",
"localRecordingWarning": "Assegureu-vos de triar la pestanya actual per a poder usar el vídeo i àudios correctes. L'enregistrament actualment està limitat a 1 GB. Això són, aproximadament, 100 minuts.",
"loggedIn": "Sessió iniciada com a {{userName}}",
"noStreams": "No s'ha detectat flux d'àudio ni vídeo.",
"off": "S'ha aturat l'enregistrament",

View File

@@ -976,6 +976,7 @@
"proceedAnyway": "Přesto pokračujte",
"recordingWarning": "Ostatní účastníci mohou tento hovor nahrávat",
"screenSharingError": "Chyba sdílení obrazovky:",
"showScreen": "Zapnout obrazovku před setkáním",
"startWithPhone": "Začít se zvukem přes telefon",
"unsafeRoomConsent": "Chápu rizika, chci se připojit k setkání",
"videoOnlyError": "Chyba videa:",
@@ -1046,7 +1047,7 @@
"localRecordingStartWarningTitle": "Zastavte záznam, abyste jej uložili",
"localRecordingVideoStop": "Zastavením videa se zastaví také místní nahrávání. Opravdu chcete pokračovat?",
"localRecordingVideoWarning": "Chcete-li nahrát video, musíte jej mít zapnutý při zahájení nahrávání",
"localRecordingWarning": "Ujistěte se, že jste vybrali aktuální kartu, abyste mohli použít správné video a zvuk.",
"localRecordingWarning": "Ujistěte se, že jste vybrali aktuální kartu, abyste mohli použít správné video a zvuk. Záznam je aktuálně omezen na 1GB, což je kolem 100 minut.",
"loggedIn": "Přihlášen/a jako {{userName}}",
"noMicPermission": "Kanál mikrofonu nelze vytvořit. Udělte prosím povolení k použití mikrofonu.",
"noStreams": "Nebyl zjištěn žádný audio nebo video stream.",
@@ -1110,7 +1111,7 @@
"incomingMessage": "Příchozí zpráva",
"language": "Jazyk",
"loggedIn": "Přihlášen/a jako {{name}}",
"maxStageParticipants": "Maximální počet účastníků, které lze připnout na hlavní pódium",
"maxStageParticipants": "Maximální počet účastníků, které lze připnout na hlavní pódium (EXPERIMENTÁLNÍ)",
"microphones": "Mikrofony",
"moderator": "Moderátor",
"moderatorOptions": "Možnosti moderátora",

View File

@@ -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",
@@ -122,9 +122,7 @@
"nickname": {
"popover": "Wähle einen Alias",
"title": "Geben Sie einen Alias zum Chatten ein",
"titleWithCC": "Geben Sie einen Alias zum Chatten und für Untertitel ein",
"titleWithPolls": "Geben Sie einen Alias zum Chatten und für Umfragen ein",
"titleWithPollsAndCC": "Geben Sie einen Alias zum Chatten, für Umfragen und Untertitel ein"
"titleWithPolls": "Geben Sie einen Alias zum Chatten ein"
},
"noMessagesMessage": "Es gibt noch keine Nachricht in dieser Konferenz. Starten Sie hier eine Unterhaltung!",
"privateNotice": "Private Nachricht an {{recipient}}",
@@ -133,13 +131,10 @@
"systemDisplayName": "System",
"tabs": {
"chat": "Chatten",
"closedCaptions": "Untertitel",
"polls": "Umfragen"
},
"title": "Chatten",
"titleWithCC": "Chatten und Untertitel",
"titleWithPolls": "Chatten und Umfragen",
"titleWithPollsAndCC": "Chatten, Umfragen und Untertitel",
"you": "Sie"
},
"chromeExtensionBanner": {
@@ -149,10 +144,6 @@
"dontShowAgain": "Hinweis nicht mehr anzeigen",
"installExtensionText": "Installieren Sie die Erweiterung für die Integration von Google Calendar und Office 365"
},
"closedCaptionsTab": {
"emptyState": "Die Untertitel sind verfügbar, sobald sie von der Moderation gestartet wurden",
"startClosedCaptionsButton": "Untertitel starten"
},
"connectingOverlay": {
"joiningRoom": "Eine Verbindung zu Ihrer Konferenz wird hergestellt…"
},
@@ -272,8 +263,6 @@
"Remove": "Entfernen",
"Share": "Teilen",
"Submit": "OK",
"Understand": "Verstanden, Stummschaltung beibehalten",
"UnderstandAndUnmute": "Verstanden, bitte Stummschaltung aufheben",
"WaitForHostMsg": "Die Konferenz wurde noch nicht gestartet. Falls Sie die Konferenz leiten, authentifizieren Sie sich bitte. Warten Sie andernfalls, bis die Konferenz gestartet wird.",
"WaitForHostNoAuthMsg": "Die Konferenz wurde noch nicht gestartet. Bitte warten Sie, bis die Konferenz gestartet wird.",
"WaitingForHostButton": "Auf Moderation warten",
@@ -310,7 +299,6 @@
"conferenceReloadMsg": "Wir versuchen das zu beheben. Verbinde in {{seconds}} Sekunden …",
"conferenceReloadTitle": "Leider ist etwas schiefgegangen.",
"confirm": "Bestätigen",
"confirmBack": "Zurück",
"confirmNo": "Nein",
"confirmYes": "Ja",
"connectError": "Oh! Es hat etwas nicht geklappt und der Konferenz konnte nicht beigetreten werden.",
@@ -348,7 +336,6 @@
"kickParticipantTitle": "Person entfernen?",
"kickSystemTitle": "Autsch! Sie wurden aus der Konferenz geworfen",
"kickTitle": "Autsch! {{participantDisplayName}} hat Sie aus der Konferenz geworfen",
"learnMore": "Mehr erfahren",
"linkMeeting": "Konferenz verlinken",
"linkMeetingTitle": "Konferenz mit Salesforce verlinken",
"liveStreaming": "Livestreaming",
@@ -376,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.",
@@ -406,10 +393,6 @@
"recentlyUsedObjects": "Ihre zuletzt verwendeten Objekte",
"recording": "Aufnahme",
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Während eines Livestreams nicht möglich",
"recordingInProgressDescription": "Diese Konferenz wird aufgezeichnet und von KI analysiert {{learnMore}}. Ihr Ton und Video ist deaktiviert, wenn Sie es aktivieren, stimmen Sie der Aufzeichnung zu.",
"recordingInProgressDescriptionFirstHalf": "Diese Konferenz wird aufgezeichnet und von KI analysiert",
"recordingInProgressDescriptionSecondHalf": ". Ihr Ton und Video ist deaktiviert, wenn Sie es aktivieren, stimmen Sie der Aufzeichnung zu.",
"recordingInProgressTitle": "Aufnahme läuft",
"rejoinNow": "Jetzt erneut beitreten",
"remoteControlAllowedMessage": "{{user}} hat die Anfrage zur Fernsteuerung angenommen!",
"remoteControlDeniedMessage": "{{user}} hat die Anfrage zur Fernsteuerung verweigert!",
@@ -579,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",
@@ -659,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",
@@ -760,14 +742,13 @@
"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.",
"dataChannelClosedWithAudio": "Ton- und Videoqualität können beeinträchtigt sein",
"disabledIframe": "Die Einbettung ist nur für Demo-Zwecke vorgesehen. Diese Konferenz wird in {{timeout}} Minuten beendet.",
"disabledIframeSecondaryNative": "Die Einbettung von {{domain}} ist nur für Demo-Zwecke vorgesehen. Diese Konferenz wird in {{timeout}} Minuten beendet.",
"disabledIframeSecondaryWeb": "Die Einbettung von {{domain}} ist nur für Demo-Zwecke vorgesehen. Diese Konferenz wird in {{timeout}} Minuten beendet. Bitte nutzen Sie <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi as a Service</a> für produktive Zwecke!",
"disabledIframeSecondary": "Die Einbettung von {{domain}} ist nur für Demo-Zwecke vorgesehen. Diese Konferenz wird in {{timeout}} Minuten beendet. Bitte nutzen Sie <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi as a Service</a> für produktive Zwecke!",
"disconnected": "getrennt",
"displayNotifications": "Benachrichtigungen anzeigen für",
"dontRemindMe": "Nicht erinnern",
@@ -776,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",
@@ -895,7 +876,6 @@
"waitingLobby": "In der Lobby ({{count}})"
},
"search": "Suche Anwesende",
"searchDescription": "Tippen Sie um die Anwesendenliste zu filtern",
"title": "Anwesende"
},
"passwordDigitsOnly": "Bis zu {{number}} Ziffern",
@@ -998,6 +978,7 @@
"proceedAnyway": "Trotzdem fortsetzen",
"recordingWarning": "Diese Konferenz wird möglicherweise von anderen Personen aufgezeichnet",
"screenSharingError": "Fehler bei Bildschirmfreigabe:",
"showScreen": "Konferenzvorschau aktivieren",
"startWithPhone": "Mit Telefonaudio starten",
"unsafeRoomConsent": "Ich verstehe das Risiko und möchte der Konferenz beitreten",
"videoOnlyError": "Videofehler:",
@@ -1068,7 +1049,7 @@
"localRecordingStartWarningTitle": "Aufzeichnung zum Speichern beenden",
"localRecordingVideoStop": "Wenn Sie ihre Kamera abschalten wird auch die Aufnahme beendet. Sind Sie sicher, dass Sie fortfahren möchten?",
"localRecordingVideoWarning": "Um Ihr eigenes Kamerabild aufzuzeichnen, müssen Sie Ihre Kamera beim Start der Aufnahme einschalten",
"localRecordingWarning": "Bitte prüfen Sie, dass das aktuelle Tab auswählen, um Bild und Ton aufzuzeichnen.",
"localRecordingWarning": "Bitte prüfen Sie, dass das aktuelle Tab auswählen, um Bild und Ton aufzuzeichnen. Die Länge der Aufzeichnung ist aktuell auf 1GB beschränkt, was ungefähr 100 Minuten entspricht.",
"loggedIn": "Als {{userName}} angemeldet",
"noMicPermission": "Zugriff auf Mikrofon fehlgeschlagen. Bitte erlauben Sie den Zugriff auf das Mikrofon.",
"noStreams": "Kein Ton oder Video erkannt.",
@@ -1078,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",
@@ -1101,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.",
@@ -1122,7 +1103,6 @@
"signedIn": "Momentan wird auf Kalendertermine von {{email}} zugegriffen. Klicken Sie auf die folgende Schaltfläche „Trennen“, um den Zugriff auf die Kalendertermine zu stoppen.",
"title": "Kalender"
},
"chatWithPermissions": "Chat mit Freigaben",
"desktopShareFramerate": "Framerate für Bildschirmfreigabe",
"desktopShareHighFpsWarning": "Eine höhere Framerate könnte sich auf Ihre Datenrate auswirken. Sie müssen die Bildschirmfreigabe neustarten, damit die Einstellung übernommen wird.",
"desktopShareWarning": "Sie müssen die Bildschirmfreigabe neustarten, damit die Einstellung übernommen wird.",
@@ -1152,7 +1132,6 @@
"selectMic": "Mikrofon",
"selfView": "Eigene Ansicht",
"shortcuts": "Tastaturkürzel",
"showSubtitlesOnStage": "Untertitel in Hauptansicht anzeigen",
"speakers": "Lautsprecher",
"startAudioMuted": "Alle Personen treten stummgeschaltet bei",
"startReactionsMuted": "Interaktionstöne für alle deaktivieren",
@@ -1206,13 +1185,11 @@
"fearful": "Ängstlich",
"happy": "Fröhlich",
"hours": "{{count}} Std. ",
"labelTooltip": "Anzahl der Personen: {{count}}",
"minutes": "{{count}} Min. ",
"name": "Name",
"neutral": "Neutral",
"sad": "Traurig",
"search": "Suche",
"searchDescription": "Tippen Sie um die Anwesendenliste zu filtern",
"searchHint": "Suche Anwesende",
"seconds": "{{count}} Sek.",
"speakerStats": "Sprechstatistik",
@@ -1249,7 +1226,6 @@
"closeChat": "Chat schließen",
"closeMoreActions": "„Weitere Einstellungen“ schließen",
"closeParticipantsPane": "Anwesendenliste schließen",
"closedCaptions": "Untertitel",
"collapse": "Einklappen",
"document": "Geteiltes Dokument schließen",
"documentClose": "Geteiltes Dokument schließen",
@@ -1292,7 +1268,7 @@
"muteGUMPending": "Verbinde Ihr Mikrofon",
"noiseSuppression": "Rauschunterdrückung",
"openChat": "Chat öffnen",
"participants": "Anwesenheitsliste öffnen. {{participantsCount}} anwesend",
"participants": "Anwesende",
"pip": "Bild-in-Bild-Modus ein-/ausschalten",
"privateMessage": "Private Nachricht senden",
"profile": "Profil bearbeiten",
@@ -1340,7 +1316,6 @@
"closeChat": "Chat schließen",
"closeParticipantsPane": "Anwesenheitsliste schließen",
"closeReactionsMenu": "Interaktionsmenü schließen",
"closedCaptions": "Untertitel",
"disableNoiseSuppression": "Rauschunterdrückung deaktivieren",
"disableReactionSounds": "Sie können die Interaktionstöne für diese Konferenz deaktivieren",
"documentClose": "Geteiltes Dokument schließen",
@@ -1431,18 +1406,14 @@
"ccButtonTooltip": "Untertitel ein-/ausschalten",
"expandedLabel": "Transkribieren ist derzeit eingeschaltet",
"failed": "Transkribieren fehlgeschlagen",
"labelTooltip": "Die Konferenz wird transkribiert",
"labelTooltipExtra": "Zusätzlich wird das Transkript später verfügbar sein.",
"openClosedCaptions": "Untertitel öffnen",
"original": "Original",
"labelToolTip": "Die Konferenz wird transkribiert",
"sourceLanguageDesc": "Aktuell ist die Sprache der Konferenz auf <b>{{sourceLanguage}}</b> eingestellt. <br/> Sie könne dies hier ",
"sourceLanguageHere": "ändern",
"start": "Anzeige der Untertitel starten",
"stop": "Anzeige der Untertitel stoppen",
"subtitles": "Untertitel",
"subtitlesOff": "Ausschalten",
"tr": "TR",
"translateTo": "Übersetzen in"
"tr": "TR"
},
"unpinParticipant": "{{participantName}} - Nicht mehr anheften",
"userMedia": {

View File

@@ -845,6 +845,7 @@
"or": "abo",
"premeeting": "naglěd",
"screenSharingError": "zmólenje pśi sobuźělenju monitora:",
"showScreen": "naglěd konferency aktiwěrowaś",
"startWithPhone": "zachopiś z telefonowym audio",
"videoOnlyError": "zmólenje wideo:",
"videoTrackError": "Sćažka wideo njejo mógła se załožyś.",
@@ -915,7 +916,7 @@
"localRecordingStartWarningTitle": "nagrawanje dokóńcowaś a zachowaś",
"localRecordingVideoStop": "Gaž kameru wušaltujośo, ga teke lokalne nagrawanje se dokóńcujo. Sćo-li napšawdu wěste, až to cośo?",
"localRecordingVideoWarning": "Aby bildu ze swójeje samskeje kamery nagrawali, musyśo swóju kameru na zachopjeńku nagrawanja zašaltowaś.",
"localRecordingWarning": "Pśespytujśo, lěc sćo aktuelnu kórtu wuzwólili, aby wideo a zuk nagrawali.",
"localRecordingWarning": "Pśespytujśo, lěc sćo aktuelnu kórtu wuzwólili, aby wideo a zuk nagrawali. Dłujkosć nagrawanja jo tuchylu na 1 GB wobgranicowana, což dosega za jadnab 100 minutow.",
"loggedIn": "ako {{userName}} zalogowany/-a",
"noMicPermission": "",
"noStreams": "Žeden zuk a žeden wideo njejo namakany.",

View File

@@ -862,6 +862,7 @@
"or": "ή",
"premeeting": "Προ σύσκεψη",
"screenSharingError": "Σφάλμα διαμοιρασμού οθόνης:",
"showScreen": "Ενεργοποίηση οθόνης προ σύσκεψης",
"startWithPhone": "Ξεκινήστε με ήχο τηλεφώνου",
"videoOnlyError": "Σφάλμα βίντεο:",
"videoTrackError": "Δεν ήταν δυνατή η δημιουργία κομματιού βίντεο.",
@@ -929,7 +930,7 @@
"localRecordingStartWarningTitle": "Σταματήστε τη καταγραφή για να την αποθηκεύσετε",
"localRecordingVideoStop": "Σταματώντας το βίντεο σας θα σταματήσει και η τοπική καταγραφή. Θέλετε να συνεχίσετε;",
"localRecordingVideoWarning": "Για να καταγράψετε το βίντεο σας πρέπει να είναι ήδη ενεργό όταν ξεκινήσει η καταγραφή",
"localRecordingWarning": "Βεβαιωθείτε ότι επιλέξατε τη τρέχουσα σελίδα ώστε να χρησιμοποιηθούν το σωστό βίντεο και ήχος.",
"localRecordingWarning": "Βεβαιωθείτε ότι επιλέξατε τη τρέχουσα σελίδα ώστε να χρησιμοποιηθούν το σωστό βίντεο και ήχος. Αυτή τη στιγμή η καταγραφή είναι μέχρι 1GB, περίπου 100 λεπτά.",
"loggedIn": "Συνδέθηκε ως {{userName}}",
"noMicPermission": "Δεν ήταν δυνατή η δημιουργία του κομματιού του μικροφώνου. Παρακαλώ δώστε την άδεια για χρήση του.",
"noStreams": "Δεν εντοπίστηκε ροή ήχου ή βίντεο.",
@@ -983,7 +984,7 @@
"incomingMessage": "Εισερχόμενο μήνυμα",
"language": "Γλώσσα",
"loggedIn": "Συνδέθηκε ως {{name}}",
"maxStageParticipants": "Μέγιστος αριθμός συμμετεχόντων που μπορούν να διατηρηθούν στην κύρια σκηνή",
"maxStageParticipants": "Μέγιστος αριθμός συμμετεχόντων που μπορούν να διατηρηθούν στην κύρια σκηνή (ΠΕΙΡΑΜΑΤΙΚΟ)",
"microphones": "Μικρόφωνα",
"moderator": "Συντονιστής",
"moderatorOptions": "Επιλογές συντονιστή",

View File

@@ -935,6 +935,7 @@
"premeeting": "Antaŭkunveno",
"proceedAnyway": "Daŭrigi",
"screenSharingError": "Eraro kun la ekrandividado:",
"showScreen": "Ebligu antaŭkunvenon ekranon",
"startWithPhone": "Komencu kun la telefona sono",
"unsafeRoomConsent": "Akceptu la riskojn, kaj daŭrigi",
"videoOnlyError": "Eraro kun la videaĵo:",
@@ -1006,7 +1007,7 @@
"localRecordingStartWarningTitle": "Ĉesigu la registradon por konservi ĝin.",
"localRecordingVideoStop": "Ĉesigi vian videaĵon ankaŭ ĉesos la lokan registradon. Ĉu vi certas, ke vi volas daŭrigi?",
"localRecordingVideoWarning": "Por registri vian videon, ŝaltu la kameraon antaŭ vi komencas la registradon.",
"localRecordingWarning": "Certigu, ke vi elektas la nunan langeton por uzi la ĝustajn filmetojn kaj sonojn.",
"localRecordingWarning": "Certigu, ke vi elektas la nunan langeton por uzi la ĝustajn filmetojn kaj sonojn. La registrado estas nuntempe limigita al 1GB, kio estas proksimume 100 minutoj.",
"loggedIn": "Ensalutinta kiel {{userName}}",
"noMicPermission": "Mikrofono ne povis esti uzata. Bonvole donu permeson uzi la mikrofonon.",
"noStreams": "Neniu aŭdio aŭ videofluo detektita.",
@@ -1069,7 +1070,7 @@
"incomingMessage": "Envena mesaĝo",
"language": "Lingvo",
"loggedIn": "Ensalutinta kiels {{name}}",
"maxStageParticipants": "Maksimuma nombro da partoprenantoj, kiuj povas esti alpinglitaj al la ĉefa scenejo",
"maxStageParticipants": "Maksimuma nombro da partoprenantoj, kiuj povas esti alpinglitaj al la ĉefa scenejo (EXPERIMENTA)",
"microphones": "Mikrofonoj",
"moderator": "Kunvenestro",
"moderatorOptions": "Kunvenestaj agordoj",

View File

@@ -886,6 +886,7 @@
"premeeting": "Pre-reunión",
"proceedAnyway": "Continuar de todos modos",
"screenSharingError": "Error al compartir pantalla:",
"showScreen": "Habilitar pantalla pre-reunión",
"startWithPhone": "Iniciar con audio de llamada telefónica",
"unsafeRoomConsent": "Comprendo los riesgos, quiero unirme a la reunión",
"videoOnlyError": "Error con el vídeo:",
@@ -957,7 +958,7 @@
"localRecordingStartWarningTitle": "Detenga la grabación para guardarla",
"localRecordingVideoStop": "Detener su video también detendrá la grabación local. ¿Está seguro de querer continuar?",
"localRecordingVideoWarning": "Para grabar su video debe tenerlo encendido al iniciar la grabación",
"localRecordingWarning": "Asegúrese de seleccionar la pestaña actual para usar el video y audio correctos.",
"localRecordingWarning": "Asegúrese de seleccionar la pestaña actual para usar el video y audio correctos. La grabación está actualmente limitada a 1GB, que son aproximadamente 100 minutos.",
"loggedIn": "Sesión iniciada como {{userName}}",
"noMicPermission": "No se pudo crear la pista de micrófono. Por favor otorgue permiso para usar el micrófono.",
"noStreams": "",

View File

@@ -759,6 +759,7 @@
"or": "o",
"premeeting": "Pre-reunión",
"screenSharingError": "Error al compartir pantalla:",
"showScreen": "Habilitar pantalla pre-reunión",
"startWithPhone": "Iniciar con audio de llamada telefónica",
"videoOnlyError": "Error con el video:",
"videoTrackError": "No se pudo crear la pista de video.",

View File

@@ -646,6 +646,7 @@
"or": "edo",
"premeeting": "Aurre-bilera",
"screenSharingError": "Errorea pantaila partekatzean:",
"showScreen": "Aktibatu bileraren aurreko pantaila",
"startWithPhone": "Telefono diearen audioarekin hasi",
"videoOnlyError": "Errorea bideoan:",
"videoTrackError": "Ezin izan da bideo pista sortu.",

View File

@@ -894,6 +894,7 @@
"premeeting": "پیش‌جلسه",
"proceedAnyway": "در هر صورت انجام شود",
"screenSharingError": "خطا در هم‌رسانی صفحه:",
"showScreen": "فعال‌سازی صفحهٔ پیش‌جلسه",
"startWithPhone": "شروع با صدای گوشی",
"unsafeRoomConsent": "من خطر احتمالی را درک می‌کنم؛ می‌خواهم به جلسه بپیوندم",
"videoOnlyError": "خطای ویدیو:",
@@ -1025,7 +1026,7 @@
"incomingMessage": "پیام ورودی",
"language": "زبان",
"loggedIn": "واردشده به عنوان {{name}}",
"maxStageParticipants": "بیشینه تعداد شرکت‌کنندگانی که می‌توانند به صحنه اصلی سنجاق شوند",
"maxStageParticipants": "بیشینه تعداد شرکت‌کنندگانی که می‌توانند به صحنه اصلی سنجاق شوند (<b>آزمایشی</b>)",
"microphones": "میکروفون‌ها",
"moderator": "مدیر",
"moderatorOptions": "گزینه‌های مدیر",

View File

@@ -976,6 +976,7 @@
"proceedAnyway": "Continuer quand même",
"recordingWarning": "D'autres participants peuvent enregistrer cet appel",
"screenSharingError": "Erreur de partage d'écran:",
"showScreen": "Activer l'écran de pré-séance",
"startWithPhone": "Commencez avec l'audio du téléphone",
"unsafeRoomConsent": "Je comprends les risques et je veux quand même rejoindre cette réunion",
"videoOnlyError": "Erreur vidéo:",
@@ -1046,7 +1047,7 @@
"localRecordingStartWarningTitle": "Arrêter lenregistrement pour le sauvegarder",
"localRecordingVideoStop": "Arrêter votre vidéo va aussi arrêter votre enregistrement local. Êtes-vous sûrs de vouloir continuer ?",
"localRecordingVideoWarning": "Pour enregistrer votre vidéo, vous devez avoir celle-ci active au moment de commencer lenregistrement.",
"localRecordingWarning": "Assurez-vous de sélectionner longlet courant pour utiliser le bon son et la bonne vidéo.",
"localRecordingWarning": "Assurez-vous de sélectionner longlet courant pour utiliser le bon son et la bonne vidéo. Lenregistrement est pour le moment limité à 1Go, soit approximativement 100 minutes.",
"loggedIn": "Connecté en tant que {{userName}}",
"noMicPermission": "La piste microphone ne peut pas être créée. Veuillez autoriser lutilisation du microphone.",
"noStreams": "Aucun flux audio ou vidéo détectés.",
@@ -1110,7 +1111,7 @@
"incomingMessage": "un message arrive",
"language": "Langue",
"loggedIn": "Connecté en tant que {{name}}",
"maxStageParticipants": "Nombre maximum de participants pouvant être épinglé sur laffichage principal",
"maxStageParticipants": "Nombre maximum de participants pouvant être épinglé sur laffichage principal (EXPÉRIMENTAL)",
"microphones": "Microphones",
"moderator": "Modérateur",
"moderatorOptions": "Options de modérateur",

View File

@@ -954,6 +954,7 @@
"premeeting": "Pré-séance",
"proceedAnyway": "Continuer quand même",
"screenSharingError": "Erreur de partage d'écran:",
"showScreen": "Activer l'écran de pré-séance",
"startWithPhone": "Commencez avec l'audio du téléphone",
"unsafeRoomConsent": "Je comprends les risques et je veux quand même rejoindre cette réunion",
"videoOnlyError": "Erreur vidéo:",
@@ -1025,7 +1026,7 @@
"localRecordingStartWarningTitle": "Arrêter lenregistrement pour le sauvegarder",
"localRecordingVideoStop": "Arrêter votre vidéo va aussi arrêter votre enregistrement local. Êtes-vous sûrs de vouloir continuer ?",
"localRecordingVideoWarning": "Pour enregistrer votre vidéo, vous devez avoir celle-ci active au moment de commencer lenregistrement.",
"localRecordingWarning": "Assurez-vous de sélectionner longlet courant pour utiliser le bon son et la bonne vidéo.",
"localRecordingWarning": "Assurez-vous de sélectionner longlet courant pour utiliser le bon son et la bonne vidéo. Lenregistrement est pour le moment limité à 1Go, soit approximativement 100 minutes.",
"loggedIn": "Connecté en tant que {{userName}}",
"noMicPermission": "La piste microphone ne peut pas être créée. Veuillez autoriser lutilisation du microphone.",
"noStreams": "Aucun flux audio ou vidéo détectés.",
@@ -1076,7 +1077,7 @@
"incomingMessage": "un message arrive",
"language": "Langue",
"loggedIn": "Connecté en tant que {{name}}",
"maxStageParticipants": "Nombre maximum de participants pouvant être épinglé sur laffichage principal",
"maxStageParticipants": "Nombre maximum de participants pouvant être épinglé sur laffichage principal (EXPÉRIMENTAL)",
"microphones": "Microphones",
"moderator": "Modérateur",
"moderatorOptions": "Options de modérateur",

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