Compare commits
57 Commits
track-op-q
...
6900
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
450da1a6df | ||
|
|
720d4555ab | ||
|
|
c764397994 | ||
|
|
0ad7b3db55 | ||
|
|
7e30053d51 | ||
|
|
0ad52a06ce | ||
|
|
82fd465819 | ||
|
|
561d0c9a10 | ||
|
|
3b8ad78a62 | ||
|
|
77e02a0994 | ||
|
|
965e7dc41d | ||
|
|
ad0ad31df9 | ||
|
|
2bb2a68e01 | ||
|
|
c441e8abca | ||
|
|
27754c8874 | ||
|
|
580f56010a | ||
|
|
4bad63e484 | ||
|
|
9cc41469d2 | ||
|
|
5077a33fcb | ||
|
|
e7078786e6 | ||
|
|
291370a263 | ||
|
|
32dbdf2e5c | ||
|
|
17b5009e63 | ||
|
|
d91f49ec88 | ||
|
|
7187530430 | ||
|
|
d3d442e4d2 | ||
|
|
294d2c9f6e | ||
|
|
12c002e015 | ||
|
|
9720b4858c | ||
|
|
9fae488070 | ||
|
|
0e47f72b5f | ||
|
|
298c4bd1e3 | ||
|
|
955367a157 | ||
|
|
c30d1e7479 | ||
|
|
cbbe58a1ec | ||
|
|
aef5328aeb | ||
|
|
f5ac1b6271 | ||
|
|
ca9f0a6788 | ||
|
|
e7c5ae5936 | ||
|
|
c43a319576 | ||
|
|
585c9aa0d2 | ||
|
|
768f10d966 | ||
|
|
704740969b | ||
|
|
d444a45f00 | ||
|
|
9fbbe05d6c | ||
|
|
3445c513ba | ||
|
|
6a4276b4c8 | ||
|
|
338b02a6b6 | ||
|
|
ef2631e95a | ||
|
|
226ef9f33d | ||
|
|
91ec5307ab | ||
|
|
fe0b7d3acc | ||
|
|
9533650594 | ||
|
|
d7bedb2e07 | ||
|
|
33e4da32e2 | ||
|
|
9a8a8ef7ad | ||
|
|
703ed731c8 |
7
.github/workflows/ci.yml
vendored
@@ -7,7 +7,7 @@ jobs:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
@@ -20,12 +20,11 @@ jobs:
|
||||
- name: Check if the git repository is clean
|
||||
run: $(exit $(git status --porcelain --untracked-files=no | head -255 | wc -l)) || (echo "Dirty git tree"; git diff; exit 1)
|
||||
- run: npm run lint:ci
|
||||
- run: for file in lang/*.json; do npx --yes jsonlint -q $file || exit 1; done
|
||||
linux-build:
|
||||
name: Build Frontend (Linux)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
@@ -36,7 +35,7 @@ jobs:
|
||||
name: Build Frontend (macOS)
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
@@ -141,7 +141,7 @@ react/features/sample/
|
||||
```
|
||||
|
||||
The middleware must be imported in `react/features/app/` specifically
|
||||
in `middlewares.any`, `middlewares.native.js` or `middlewares.web.js` where appropriate.
|
||||
in `middlewares.any.ts`, `middlewares.native.ts` or `middlewares.web.ts` where appropriate.
|
||||
Likewise for the reducer.
|
||||
|
||||
An `index.js` file must not be provided for exporting actions, action types and
|
||||
|
||||
|
Before Width: | Height: | Size: 659 B |
|
Before Width: | Height: | Size: 379 B |
|
Before Width: | Height: | Size: 960 B |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
@@ -81,6 +81,8 @@ public class JitsiMeetView extends FrameLayout {
|
||||
result.putBoolean(key, (Boolean)bValue);
|
||||
} else if (valueType.contentEquals("String")) {
|
||||
result.putString(key, (String)bValue);
|
||||
} else if (valueType.contentEquals("Integer")) {
|
||||
result.putInt(key, (int)bValue);
|
||||
} else if (valueType.contentEquals("Bundle")) {
|
||||
result.putBundle(key, mergeProps((Bundle)aValue, (Bundle)bValue));
|
||||
} else {
|
||||
|
||||
BIN
android/sdk/src/main/res/drawable-hdpi/ic_notification.png
Normal file
|
After Width: | Height: | Size: 699 B |
BIN
android/sdk/src/main/res/drawable-mdpi/ic_notification.png
Normal file
|
After Width: | Height: | Size: 406 B |
BIN
android/sdk/src/main/res/drawable-xhdpi/ic_notification.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
android/sdk/src/main/res/drawable-xxhdpi/ic_notification.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
android/sdk/src/main/res/drawable-xxxhdpi/ic_notification.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
1015
conference.js
101
config.js
@@ -79,11 +79,6 @@ var config = {
|
||||
// This is useful when the client runs on a host with limited resources.
|
||||
// noAutoPlayVideo: false,
|
||||
|
||||
// Whether to use fake constraints (height: 99999, width: 99999) when calling getDisplayMedia on
|
||||
// Chromium based browsers. This is intended as a workaround for
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=1056311
|
||||
// setScreenSharingResolutionConstraints: true,
|
||||
|
||||
// Enable callstats only for a percentage of users.
|
||||
// This takes a value between 0 and 100 which determines the probability for
|
||||
// the callstats to be enabled.
|
||||
@@ -262,17 +257,6 @@ var config = {
|
||||
// applied locally. FIXME: having these 2 options is confusing.
|
||||
// startWithVideoMuted: false,
|
||||
|
||||
// If set to true, prefer to use the H.264 video codec (if supported).
|
||||
// Note that it's not recommended to do this because simulcast is not
|
||||
// supported when using H.264. For 1-to-1 calls this setting is enabled by
|
||||
// default and can be toggled in the p2p section.
|
||||
// This option has been deprecated, use preferredCodec under videoQuality section instead.
|
||||
// preferH264: true,
|
||||
|
||||
// If set to true, disable H.264 video codec by stripping it out of the
|
||||
// SDP.
|
||||
// disableH264: false,
|
||||
|
||||
// Desktop sharing
|
||||
|
||||
// Optional desktop sharing frame rate options. Default value: min:5, max:5.
|
||||
@@ -434,12 +418,6 @@ var config = {
|
||||
// 90: 2,
|
||||
// },
|
||||
|
||||
// Provides a way to translate the legacy bridge signaling messages, 'LastNChangedEvent',
|
||||
// 'SelectedEndpointsChangedEvent' and 'ReceiverVideoConstraint' into the new 'ReceiverVideoConstraints' message
|
||||
// that invokes the new bandwidth allocation algorithm in the bridge which is described here
|
||||
// - https://github.com/jitsi/jitsi-videobridge/blob/master/doc/allocation.md.
|
||||
// useNewBandwidthAllocationStrategy: false,
|
||||
|
||||
// Specify the settings for video quality optimizations on the client.
|
||||
// videoQuality: {
|
||||
// // Provides a way to prevent a video codec from being negotiated on the JVB connection. The codec specified
|
||||
@@ -580,9 +558,19 @@ var config = {
|
||||
// Require users to always specify a display name.
|
||||
// requireDisplayName: true,
|
||||
|
||||
// DEPRECATED! Use 'welcomePage.disabled' instead.
|
||||
// Whether to use a welcome page or not. In case it's false a random room
|
||||
// will be joined when no room is specified.
|
||||
enableWelcomePage: true,
|
||||
// enableWelcomePage: true,
|
||||
|
||||
// Configs for welcome page.
|
||||
// welcomePage: {
|
||||
// // Whether to disable welcome page. In case it's disabled a random room
|
||||
// // will be joined when no room is specified.
|
||||
// disabled: false,
|
||||
// // If set,landing page will redirect to this URL.
|
||||
// customUrl: ''
|
||||
// },
|
||||
|
||||
// Disable app shortcuts that are registered upon joining a conference
|
||||
// disableShortcuts: false,
|
||||
@@ -701,7 +689,6 @@ var config = {
|
||||
// 'chat',
|
||||
// 'closedcaptions',
|
||||
// 'desktop',
|
||||
// 'dock-iframe',
|
||||
// 'download',
|
||||
// 'embedmeeting',
|
||||
// 'etherpad',
|
||||
@@ -729,7 +716,6 @@ var config = {
|
||||
// 'stats',
|
||||
// 'tileview',
|
||||
// 'toggle-camera',
|
||||
// 'undock-iframe',
|
||||
// 'videoquality',
|
||||
// 'whiteboard',
|
||||
// ],
|
||||
@@ -915,18 +901,10 @@ var config = {
|
||||
// If not set, the effective value is 'all'.
|
||||
// iceTransportPolicy: 'all',
|
||||
|
||||
// If set to true, it will prefer to use H.264 for P2P calls (if H.264
|
||||
// is supported). This setting is deprecated, use preferredCodec instead.
|
||||
// preferH264: true,
|
||||
|
||||
// Provides a way to set the video codec preference on the p2p connection. Acceptable
|
||||
// codec values are 'VP8', 'VP9' and 'H264'.
|
||||
// preferredCodec: 'H264',
|
||||
|
||||
// If set to true, disable H.264 video codec by stripping it out of the
|
||||
// SDP. This setting is deprecated, use disabledCodec instead.
|
||||
// disableH264: false,
|
||||
|
||||
// Provides a way to prevent a video codec from being negotiated on the p2p connection.
|
||||
// disabledCodec: '',
|
||||
|
||||
@@ -1083,10 +1061,67 @@ var config = {
|
||||
// use only.
|
||||
// _desktopSharingSourceDevice: 'sample-id-or-label',
|
||||
|
||||
// DEPRECATED! Use deeplinking.disabled instead.
|
||||
// If true, any checks to handoff to another application will be prevented
|
||||
// and instead the app will continue to display in the current browser.
|
||||
// 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.
|
||||
// desktop: {
|
||||
// appName: 'Jitsi Meet'
|
||||
// },
|
||||
// // If true, any checks to handoff to another application will be prevented
|
||||
// // and instead the app will continue to display in the current browser.
|
||||
// disabled: false,
|
||||
|
||||
// // whether to hide the logo on the deep linking pages.
|
||||
// hideLogo: false,
|
||||
|
||||
// // whether to show deeplinking image.
|
||||
// showImage: false,
|
||||
|
||||
// // The ios deeplinking config.
|
||||
// ios: {
|
||||
// appName: 'Jitsi Meet',
|
||||
// // Specify mobile app scheme for opening the app from the mobile browser.
|
||||
// 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.
|
||||
// android: {
|
||||
// appName: 'Jitsi Meet',
|
||||
// // Specify mobile app scheme for opening the app from the mobile browser.
|
||||
// appScheme: 'org.jitsi.meet',
|
||||
// // Custom URL for downloading android mobile app.
|
||||
// downloadLink: 'https://play.google.com/store/apps/details?id=org.jitsi.meet',
|
||||
// // 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'
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
|
||||
// A property to disable the right click context menu for localVideo
|
||||
// the menu has option to flip the locally seen video for local presentations
|
||||
// disableLocalVideoFlip: false,
|
||||
|
||||
@@ -126,6 +126,12 @@ form {
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.leftwatermarknomargin {
|
||||
background-position: center left;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.rightwatermark {
|
||||
right: 32px;
|
||||
top: 32px;
|
||||
|
||||
@@ -170,8 +170,9 @@ $welcomePageHeaderPaddingBottom: 0px;
|
||||
$welcomePageHeaderTitleMaxWidth: initial;
|
||||
$welcomePageHeaderTextAlign: center;
|
||||
|
||||
$welcomePageHeaderContainerMarginTop: 104px;
|
||||
$welcomePageHeaderContainerDisplay: flex;
|
||||
$welcomePageHeaderContainerMargin: 104px 32px 0 32px;
|
||||
$welcomePageHeaderContainerMargin: $welcomePageHeaderContainerMarginTop auto 0;
|
||||
|
||||
$welcomePageHeaderTextTitleMarginBottom: 0;
|
||||
$welcomePageHeaderTextTitleFontSize: 42px;
|
||||
|
||||
@@ -29,6 +29,16 @@ body.welcome-page {
|
||||
flex-direction: column;
|
||||
margin: $welcomePageHeaderContainerMargin;
|
||||
z-index: $zindex2;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
max-width: 688px;
|
||||
}
|
||||
|
||||
.header-watermark-container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-top: calc(20px - #{$welcomePageHeaderContainerMarginTop});
|
||||
}
|
||||
|
||||
.header-text-title {
|
||||
@@ -123,16 +133,11 @@ body.welcome-page {
|
||||
max-width: calc(100% - 40px);
|
||||
padding: 16px 0 39px 0;
|
||||
width: $welcomePageEnterRoomWidth;
|
||||
text-align: center;
|
||||
|
||||
p {
|
||||
color: $welcomePageDescriptionColor;
|
||||
float: left;
|
||||
text-align: $welcomePageHeaderTextAlign;
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
font-weight: 600;
|
||||
}
|
||||
a {
|
||||
color: inherit;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,8 +205,8 @@ body.welcome-page {
|
||||
color: $welcomePageDescriptionColor;
|
||||
padding: 4px;
|
||||
position: absolute;
|
||||
top: 32px;
|
||||
right: 32px;
|
||||
top: calc(35px - #{$welcomePageHeaderContainerMarginTop});
|
||||
right: 0;
|
||||
z-index: $zindex2;
|
||||
|
||||
* {
|
||||
@@ -224,6 +229,11 @@ body.welcome-page {
|
||||
width: $welcomePageWatermarkWidth;
|
||||
height: $welcomePageWatermarkHeight;
|
||||
}
|
||||
|
||||
.watermark.leftwatermarknomargin {
|
||||
width: $welcomePageWatermarkWidth;
|
||||
height: $welcomePageWatermarkHeight;
|
||||
}
|
||||
}
|
||||
|
||||
&.without-content {
|
||||
@@ -242,10 +252,17 @@ body.welcome-page {
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.welcome-card-row {
|
||||
.welcome-card-column {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 0 32px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
max-width: 688px;
|
||||
margin: auto;
|
||||
|
||||
> div {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.welcome-card-text {
|
||||
@@ -253,7 +270,7 @@ body.welcome-page {
|
||||
}
|
||||
|
||||
.welcome-card {
|
||||
width: 49%;
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
|
||||
&--dark {
|
||||
@@ -268,10 +285,6 @@ body.welcome-page {
|
||||
&--grey {
|
||||
background: #F2F3F4;
|
||||
}
|
||||
|
||||
&--shadow {
|
||||
box-shadow: 0px 4px 30px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
.welcome-footer {
|
||||
|
||||
@@ -2,7 +2,8 @@ $sidePanelWidth: 300px;
|
||||
|
||||
.prejoin-third-party {
|
||||
flex-direction: column-reverse;
|
||||
|
||||
z-index: auto;
|
||||
|
||||
.content {
|
||||
height: auto;
|
||||
margin: 0 auto;
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
* Override default InlineDialog behaviour, since it does not play nicely with relative widths
|
||||
*/
|
||||
& > div:nth-child(2) {
|
||||
background: #fff;
|
||||
background: #E0E0E0;
|
||||
padding: 0;
|
||||
position: absolute !important;
|
||||
width: 100%;
|
||||
|
||||
4
debian/jitsi-meet-web-config.postinst
vendored
@@ -176,6 +176,10 @@ case "$1" in
|
||||
fi
|
||||
|
||||
# Fixes multi-stream flags to workaround problem with mobile joining a multi-stream call with multi-stream disabled
|
||||
FIX_MSG="//Enables multi-stream, do not delete me"
|
||||
if ! grep -q "^${FIX_MSG}" $JITSI_MEET_CONFIG; then
|
||||
sed -i "s#config.flags.sourceNameSignaling#${FIX_MSG}\nconfig.flags = config.flags || {};\nconfig.flags.sourceNameSignaling#g" $JITSI_MEET_CONFIG
|
||||
fi
|
||||
if ! grep -q "^config.flags.sourceNameSignaling*" $JITSI_MEET_CONFIG; then
|
||||
echo "config.flags.sourceNameSignaling = true;" >> $JITSI_MEET_CONFIG
|
||||
fi
|
||||
|
||||
@@ -15,6 +15,17 @@ upstream jvb1 {
|
||||
server 127.0.0.1:9090;
|
||||
keepalive 2;
|
||||
}
|
||||
map $arg_vnode $prosody_node {
|
||||
default prosody;
|
||||
v1 v1;
|
||||
v2 v2;
|
||||
v3 v3;
|
||||
v4 v4;
|
||||
v5 v5;
|
||||
v6 v6;
|
||||
v7 v7;
|
||||
v8 v8;
|
||||
}
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
@@ -95,7 +106,7 @@ server {
|
||||
|
||||
# BOSH
|
||||
location = /http-bind {
|
||||
proxy_pass http://prosody/http-bind?prefix=$prefix&$args;
|
||||
proxy_pass http://$prosody_node/http-bind?prefix=$prefix&$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header Host $http_host;
|
||||
@@ -104,7 +115,7 @@ server {
|
||||
|
||||
# xmpp websockets
|
||||
location = /xmpp-websocket {
|
||||
proxy_pass http://prosody/xmpp-websocket?prefix=$prefix&$args;
|
||||
proxy_pass http://$prosody_node/xmpp-websocket?prefix=$prefix&$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
1
globals.d.ts
vendored
@@ -24,6 +24,7 @@ declare global {
|
||||
JITSI_MEET_LITE_SDK?: boolean;
|
||||
interfaceConfig?: any;
|
||||
JitsiMeetJS?: any;
|
||||
JitsiMeetElectron?: any;
|
||||
}
|
||||
|
||||
const config: IConfig;
|
||||
|
||||
@@ -76,11 +76,6 @@ var interfaceConfig = {
|
||||
|
||||
GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true,
|
||||
|
||||
/**
|
||||
* Hide the logo on the deep linking pages.
|
||||
*/
|
||||
HIDE_DEEP_LINKING_LOGO: false,
|
||||
|
||||
/**
|
||||
* Hide the invite prompt in the header when alone in the meeting.
|
||||
*/
|
||||
@@ -108,23 +103,6 @@ var interfaceConfig = {
|
||||
*/
|
||||
MOBILE_APP_PROMO: true,
|
||||
|
||||
/**
|
||||
* Specify custom URL for downloading android mobile app.
|
||||
*/
|
||||
MOBILE_DOWNLOAD_LINK_ANDROID: 'https://play.google.com/store/apps/details?id=org.jitsi.meet',
|
||||
|
||||
/**
|
||||
* Specify custom URL for downloading f droid app.
|
||||
*/
|
||||
MOBILE_DOWNLOAD_LINK_F_DROID: 'https://f-droid.org/en/packages/org.jitsi.meet/',
|
||||
|
||||
/**
|
||||
* Specify URL for downloading ios mobile app.
|
||||
*/
|
||||
MOBILE_DOWNLOAD_LINK_IOS: 'https://itunes.apple.com/us/app/jitsi-meet/id1165103905',
|
||||
|
||||
NATIVE_APP_NAME: 'Jitsi Meet',
|
||||
|
||||
// Names of browsers which should show a warning stating the current browser
|
||||
// has a suboptimal experience. Browsers which are not listed as optimal or
|
||||
// unsupported are considered suboptimal. Valid values are:
|
||||
@@ -159,7 +137,6 @@ var interfaceConfig = {
|
||||
*/
|
||||
SHOW_CHROME_EXTENSION_BANNER: false,
|
||||
|
||||
SHOW_DEEP_LINKING_IMAGE: false,
|
||||
SHOW_JITSI_WATERMARK: true,
|
||||
SHOW_POWERED_BY: false,
|
||||
SHOW_PROMOTIONAL_CLOSE_PAGE: false,
|
||||
@@ -200,6 +177,33 @@ var interfaceConfig = {
|
||||
*/
|
||||
// TILE_VIEW_MAX_COLUMNS: 5,
|
||||
|
||||
// List of undocumented settings
|
||||
/**
|
||||
INDICATOR_FONT_SIZES
|
||||
PHONE_NUMBER_REGEX
|
||||
*/
|
||||
|
||||
// -----------------DEPRECATED CONFIGS BELOW THIS LINE-----------------------------
|
||||
|
||||
/**
|
||||
* Specify URL for downloading ios mobile app.
|
||||
*/
|
||||
// MOBILE_DOWNLOAD_LINK_IOS: 'https://itunes.apple.com/us/app/jitsi-meet/id1165103905',
|
||||
|
||||
/**
|
||||
* Specify custom URL for downloading android mobile app.
|
||||
*/
|
||||
// MOBILE_DOWNLOAD_LINK_ANDROID: 'https://play.google.com/store/apps/details?id=org.jitsi.meet',
|
||||
|
||||
// SHOW_DEEP_LINKING_IMAGE: false,
|
||||
|
||||
/**
|
||||
* Specify mobile app scheme for opening the app from the mobile browser.
|
||||
*/
|
||||
// APP_SCHEME: 'org.jitsi.meet',
|
||||
|
||||
// NATIVE_APP_NAME: 'Jitsi Meet',
|
||||
|
||||
/**
|
||||
* Specify Firebase dynamic link properties for the mobile apps.
|
||||
*/
|
||||
@@ -212,22 +216,19 @@ var interfaceConfig = {
|
||||
// },
|
||||
|
||||
/**
|
||||
* Specify mobile app scheme for opening the app from the mobile browser.
|
||||
* Hide the logo on the deep linking pages.
|
||||
*/
|
||||
// APP_SCHEME: 'org.jitsi.meet',
|
||||
// HIDE_DEEP_LINKING_LOGO: false,
|
||||
|
||||
/**
|
||||
* Specify the Android app package name.
|
||||
*/
|
||||
// ANDROID_APP_PACKAGE: 'org.jitsi.meet',
|
||||
|
||||
// List of undocumented settings
|
||||
/**
|
||||
INDICATOR_FONT_SIZES
|
||||
PHONE_NUMBER_REGEX
|
||||
*/
|
||||
|
||||
// -----------------DEPRECATED CONFIGS BELOW THIS LINE-----------------------------
|
||||
* Specify custom URL for downloading f droid app.
|
||||
*/
|
||||
// MOBILE_DOWNLOAD_LINK_F_DROID: 'https://f-droid.org/en/packages/org.jitsi.meet/',
|
||||
|
||||
// Connection indicators (
|
||||
// CONNECTION_INDICATOR_AUTO_HIDE_ENABLED,
|
||||
|
||||
@@ -385,7 +385,7 @@ PODS:
|
||||
- react-native-video/Video (6.0.0-alpha.1):
|
||||
- PromisesSwift
|
||||
- React-Core
|
||||
- react-native-webrtc (1.106.1):
|
||||
- react-native-webrtc (106.0.1):
|
||||
- JitsiWebRTC (~> 106.0.0)
|
||||
- React-Core
|
||||
- react-native-webview (11.15.1):
|
||||
@@ -755,7 +755,7 @@ SPEC CHECKSUMS:
|
||||
react-native-slider: 6e9b86e76cce4b9e35b3403193a6432ed07e0c81
|
||||
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
|
||||
react-native-video: bb6f12a7198db53b261fefb5d609dc77417acc8b
|
||||
react-native-webrtc: 4a4c31be61f88d1d3356526eebce72f462a6760e
|
||||
react-native-webrtc: aa3a0fdc4c410813892b97d18947f223d3e50f0c
|
||||
react-native-webview: ea4899a1056c782afa96dd082179a66cbebf5504
|
||||
React-perflogger: 0458a87ea9a7342079e7a31b0d32b3734fb8415f
|
||||
React-RCTActionSheet: 22538001ea2926dea001111dd2846c13a0730bc9
|
||||
|
||||
@@ -1061,7 +1061,6 @@
|
||||
"chat": "اظهِر/اخفِ نافذة الدردشة",
|
||||
"clap": "تصفيق",
|
||||
"collapse": "قلّص",
|
||||
"dock": "إرساء في النافذة الرئيسية",
|
||||
"document": "اظهِر/اخفِ الملف المشارك",
|
||||
"download": "نزِّل التطبيق",
|
||||
"embedMeeting": "ضمِّن المُلتقى",
|
||||
@@ -1115,7 +1114,6 @@
|
||||
"tileView": "اظهِر/اخفِ عرض العنوان",
|
||||
"toggleCamera": "بدِّل الكاميرا",
|
||||
"toggleFilmstrip": "بدِّل وضع الشريط السينمائي (filmstrip)",
|
||||
"undock": "فك في نافذة منفصلة",
|
||||
"videoblur": "استعمل/اخرج من وضع تغبيش خلفية الفيديو",
|
||||
"videomute": "بدِّل وضع اخفاء الفيديو"
|
||||
},
|
||||
@@ -1133,7 +1131,6 @@
|
||||
"closeReactionsMenu": "إغلاق قائمة ردود الفعل",
|
||||
"disableNoiseSuppression": "قم بتعطيل خاصية منع الضوضاء",
|
||||
"disableReactionSounds": "يمكنك تعطيل أصوات ردود الفعل لهذا المُلتقى",
|
||||
"dock": "إرساء في النافذة الرئيسية",
|
||||
"documentClose": "أغلق الملف المشارك",
|
||||
"documentOpen": "افتح الملف المشارك",
|
||||
"download": "نزِّل التطبيق",
|
||||
@@ -1205,7 +1202,6 @@
|
||||
"talkWhileMutedPopup": "أتحاول التحدث؟ الميكروفون لديك مكتوم.",
|
||||
"tileViewToggle": "بدِّل عنوان العرض",
|
||||
"toggleCamera": "بدِّل الكاميرا",
|
||||
"undock": "فك في نافذة منفصلة",
|
||||
"videoSettings": "اعدادات الفيديو",
|
||||
"videomute": "استعمل / أوقف الكاميرا"
|
||||
},
|
||||
|
||||
@@ -1027,7 +1027,6 @@
|
||||
"chat": "Obre o tanca el xat",
|
||||
"clap": "Picament de mans",
|
||||
"collapse": "Col·lapsa",
|
||||
"dock": "Acobla a la finestra principal",
|
||||
"document": "Activa o desactiva el document compartit",
|
||||
"download": "Baixeu les nostres aplicacions",
|
||||
"embedMeeting": "Insereix la reunió",
|
||||
@@ -1079,7 +1078,6 @@
|
||||
"tileView": "Activa o desactiva el mode mosaic",
|
||||
"toggleCamera": "Activa o desactiva la càmera",
|
||||
"toggleFilmstrip": "Mostra o amaga la cinta",
|
||||
"undock": "Desacobla en una finestra separada",
|
||||
"videoblur": "Activa o desactiva el desenfocament del vídeo",
|
||||
"videomute": "Activa o desactiva la càmera"
|
||||
},
|
||||
@@ -1096,7 +1094,6 @@
|
||||
"closeChat": "Tanca el xat",
|
||||
"closeReactionsMenu": "Tanca el menú de reaccions",
|
||||
"disableReactionSounds": "Podeu desactivar els sons de reacció per a aquesta reunió",
|
||||
"dock": "Acobla en la finestra principal",
|
||||
"documentClose": "Tanca el document compartit",
|
||||
"documentOpen": "Obre el document compartit",
|
||||
"download": "Baixeu les nostres aplicacions",
|
||||
@@ -1166,7 +1163,6 @@
|
||||
"talkWhileMutedPopup": "Intenteu parlar? Esteu silenciat.",
|
||||
"tileViewToggle": "Activa o desactiva el mode mosaic",
|
||||
"toggleCamera": "Activa o desactiva la càmera",
|
||||
"undock": "Desacobla en una finestra principal",
|
||||
"videoSettings": "Paràmetres de vídeo",
|
||||
"videomute": "Inicia o atura la càmera"
|
||||
},
|
||||
|
||||
@@ -1060,7 +1060,6 @@
|
||||
"chat": "Přepnout okno zpráv",
|
||||
"clap": "Tleskat",
|
||||
"collapse": "Zabalit",
|
||||
"dock": "Dokovat v hlavním okně",
|
||||
"document": "Přepnout sdílený dokument",
|
||||
"download": "Stáhnout naše aplikace",
|
||||
"embedMeeting": "Vložit setkání",
|
||||
@@ -1114,7 +1113,6 @@
|
||||
"tileView": "Přepnout dlaždicové zobrazení",
|
||||
"toggleCamera": "Přepnout kameru",
|
||||
"toggleFilmstrip": "Přepnout video náhledy",
|
||||
"undock": "Oddokovat do samostatného okna",
|
||||
"videoblur": "Přepnout rozmazání videa",
|
||||
"videomute": "Přepnout ztišení videa"
|
||||
},
|
||||
@@ -1132,7 +1130,6 @@
|
||||
"closeReactionsMenu": "Zavrít menu reakcí",
|
||||
"disableNoiseSuppression": "Vypnout potlačení šumu",
|
||||
"disableReactionSounds": "Vypnout zvuky reakcí",
|
||||
"dock": "Dokovat v hlavním okně",
|
||||
"documentClose": "Zavřít sdílený dokument",
|
||||
"documentOpen": "Otevřít sdílený dokument",
|
||||
"download": "Stáhnout naše aplikace",
|
||||
@@ -1204,7 +1201,6 @@
|
||||
"talkWhileMutedPopup": "Snažíte se mluvit? Máte ztišený mikrofon.",
|
||||
"tileViewToggle": "Přepnout dlaždicové zobrazení",
|
||||
"toggleCamera": "Přepnout kameru",
|
||||
"undock": "",
|
||||
"videoSettings": "",
|
||||
"videomute": "Zapnout / Vypnout kameru"
|
||||
},
|
||||
|
||||
@@ -147,6 +147,7 @@
|
||||
"bridgeCount": "Serverzahl: ",
|
||||
"codecs": "Codecs (A/V): ",
|
||||
"connectedTo": "Verbunden mit:",
|
||||
"e2eeVerified": "E2EE verifiziert:",
|
||||
"framerate": "Bildwiederholrate:",
|
||||
"less": "Weniger anzeigen",
|
||||
"localaddress": "Lokale Adresse:",
|
||||
@@ -408,6 +409,10 @@
|
||||
"user": "Anmeldename",
|
||||
"userIdentifier": "Benutzername",
|
||||
"userPassword": "Passwort",
|
||||
"verifyParticipantConfirm": "Sie stimmen überein",
|
||||
"verifyParticipantDismiss": "Sie stimmen nicht überein",
|
||||
"verifyParticipantQuestion": "EXPERIMENTELL: Frage Person {{participantName}} ob sie den selben Inhalt in der selben Reihenfolge sieht.",
|
||||
"verifyParticipantTitle": "Personsverifikation",
|
||||
"videoLink": "Video-Link",
|
||||
"viewUpgradeOptions": "Upgradeoptionen anzeigen",
|
||||
"viewUpgradeOptionsContent": "Sie müssen Ihren Tarif erweitern, um Premium-Features wie Aufnahme, Transkription, RTMP-Streaming und mehr zu nutzen.",
|
||||
@@ -437,9 +442,6 @@
|
||||
"noResults": "Keine Ergebnisse :(",
|
||||
"search": "GIPHY durchsuchen"
|
||||
},
|
||||
"helpView": {
|
||||
"title": "Hilfecenter"
|
||||
},
|
||||
"incomingCall": {
|
||||
"answer": "Antworten",
|
||||
"audioCallTitle": "Eingehender Anruf",
|
||||
@@ -563,7 +565,6 @@
|
||||
"lobby": {
|
||||
"admit": "Zulassen",
|
||||
"admitAll": "Alle zulassen",
|
||||
"allow": "Annehmen",
|
||||
"backToKnockModeButton": "Kein Passwort, stattdessen Beitritt anfragen",
|
||||
"chat": "Chat",
|
||||
"dialogTitle": "Lobbymodus",
|
||||
@@ -649,6 +650,8 @@
|
||||
"connectedOneMember": "{{name}} nimmt am Meeting teil",
|
||||
"connectedThreePlusMembers": "{{name}} und {{count}} andere Personen nehmen am Meeting teil",
|
||||
"connectedTwoMembers": "{{first}} und {{second}} nehmen am Meeting teil",
|
||||
"dataChannelClosed": "Schlechte Videoqualität",
|
||||
"dataChannelClosedDescription": "Die Steuerungsverbindung (Bridge Channel) wurde unterbrochen, daher ist die Videoqulität auf die schlechteste Stufe limitiert.",
|
||||
"disconnected": "getrennt",
|
||||
"displayNotifications": "Benachrichtigungen anzeigen für",
|
||||
"focus": "Konferenzleitung",
|
||||
@@ -709,6 +712,8 @@
|
||||
"reactionSoundsForAll": "Interaktionstöne für alle deaktivieren",
|
||||
"screenShareNoAudio": "Die Option \"Audio freigeben\" wurde bei der Auswahl des Fensters nicht ausgewählt.",
|
||||
"screenShareNoAudioTitle": "Share audio was not checked",
|
||||
"screenSharingAudioOnlyDescription": "Durch die Bildschirmfreigabe wird der Modus \"Beste Leistung\" beeinflusst und daher mehr Datenrate benötigt.",
|
||||
"screenSharingAudioOnlyTitle": "Modus \"Beste Leistung\"",
|
||||
"selfViewTitle": "Sie können die eigene Ansicht immer in den Einstellungen reaktivieren",
|
||||
"somebody": "Jemand",
|
||||
"startSilentDescription": "Treten Sie dem Meeting noch einmal bei, um Ihr Audio zu aktivieren",
|
||||
@@ -858,9 +863,6 @@
|
||||
"rejected": "Abgelehnt",
|
||||
"ringing": "Es klingelt …"
|
||||
},
|
||||
"privacyView": {
|
||||
"title": "Datenschutz"
|
||||
},
|
||||
"profile": {
|
||||
"avatar": "Benutzerbild",
|
||||
"setDisplayNameLabel": "Anzeigename festlegen",
|
||||
@@ -1003,6 +1005,7 @@
|
||||
"displayName": "Anzeigename",
|
||||
"displayNamePlaceholderText": "z.B. Erika Musterfrau",
|
||||
"email": "E-Mail",
|
||||
"emailPlaceholderText": "email@beispiel.de",
|
||||
"goTo": "Gehe zu",
|
||||
"header": "Einstellungen",
|
||||
"help": "Hilfe",
|
||||
@@ -1011,6 +1014,7 @@
|
||||
"profileSection": "Profil",
|
||||
"serverURL": "Server-URL",
|
||||
"showAdvanced": "Erweiterte Einstellungen anzeigen",
|
||||
"startCarModeInLowBandwidthMode": "Automodus mit Datensparmodus starten",
|
||||
"startWithAudioMuted": "Stumm beitreten",
|
||||
"startWithVideoMuted": "Ohne Video beitreten",
|
||||
"terms": "Nutzungsbedingungen",
|
||||
@@ -1066,7 +1070,6 @@
|
||||
"chat": "Chatfenster öffnen / schließen",
|
||||
"clap": "Klatschen",
|
||||
"collapse": "Einklappen",
|
||||
"dock": "In Hauptfenster einbinden",
|
||||
"document": "Geteiltes Dokument schließen",
|
||||
"download": "Unsere Apps herunterladen",
|
||||
"embedMeeting": "Konferenz einbetten",
|
||||
@@ -1120,7 +1123,6 @@
|
||||
"tileView": "Kachelansicht ein-/ausschalten",
|
||||
"toggleCamera": "Kamera wechseln",
|
||||
"toggleFilmstrip": "Miniaturansichten ein-/ausschalten",
|
||||
"undock": "In eigenem Fenster anzeigen",
|
||||
"videoblur": "Unscharfer Hintergrund ein-/ausschalten",
|
||||
"videomute": "„Video stummschalten“ ein-/ausschalten",
|
||||
"whiteboard": "Whiteboard ein-/ausschalten"
|
||||
@@ -1139,7 +1141,6 @@
|
||||
"closeReactionsMenu": "Interaktionsmenü schließen",
|
||||
"disableNoiseSuppression": "Rauschunterdrückung deaktivieren",
|
||||
"disableReactionSounds": "Sie können die Interaktionstöne für diese Konferenz deaktivieren",
|
||||
"dock": "In Hauptfenster einbinden",
|
||||
"documentClose": "Geteiltes Dokument schließen",
|
||||
"documentOpen": "Geteiltes Dokument öffnen",
|
||||
"download": "Unsere Apps herunterladen",
|
||||
@@ -1213,7 +1214,6 @@
|
||||
"talkWhileMutedPopup": "Versuchen Sie zu sprechen? Ihr Mikrofon ist stummgeschaltet.",
|
||||
"tileViewToggle": "Kachelansicht ein-/ausschalten",
|
||||
"toggleCamera": "Kamera wechseln",
|
||||
"undock": "In eigenem Fenster anzeigen",
|
||||
"videoSettings": "Kameraeinstellungen",
|
||||
"videomute": "Kamera starten / stoppen"
|
||||
},
|
||||
@@ -1294,6 +1294,7 @@
|
||||
"show": "Im Vordergrund anzeigen",
|
||||
"showSelfView": "Eigene Ansicht anzeigen",
|
||||
"unpinFromStage": "Lösen",
|
||||
"verify": "Person verifizieren",
|
||||
"videoMuted": "Kamera ausgeschaltet",
|
||||
"videomute": "Person hat die Kamera angehalten"
|
||||
},
|
||||
@@ -1361,6 +1362,7 @@
|
||||
"recentList": "Verlauf",
|
||||
"recentListDelete": "Eintrag löschen",
|
||||
"recentListEmpty": "Ihr Konferenzverlauf ist derzeit leer. Reden Sie mit Ihrem Team und Ihre vergangenen Konferenzen landen hier.",
|
||||
"recentMeetings": "Ihre letzten Konferenzen",
|
||||
"reducedUIText": "Willkommen bei {{app}}!",
|
||||
"roomNameAllowedChars": "Der Konferenzname sollte keines der folgenden Zeichen enthalten: ?, &, :, ', \", %, #.",
|
||||
"roomname": "Konferenzname eingeben",
|
||||
@@ -1369,6 +1371,7 @@
|
||||
"settings": "Einstellungen",
|
||||
"startMeeting": "Meeting starten",
|
||||
"terms": "AGB",
|
||||
"title": "Sichere, voll funktionale und komplett kostenlose Videokonferenzen"
|
||||
"title": "Sichere, voll funktionale und komplett kostenlose Videokonferenzen",
|
||||
"upcomingMeetings": "Ihre zukünftigen Konferenzen"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "Otvori/Zatvori chat",
|
||||
"clap": "Plješći",
|
||||
"collapse": "Sklopi",
|
||||
"dock": "Prikvači u glavni prozor",
|
||||
"document": "Uključi/Isključi dijeljeni dokument",
|
||||
"download": "Preuzmi naše aplikacije",
|
||||
"embedMeeting": "Ugradi sastanak",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "Uključi/Isključi pločasti prikaz",
|
||||
"toggleCamera": "Uključi/Isključi kameru",
|
||||
"toggleFilmstrip": "Uključi/Isključi slike videa",
|
||||
"undock": "Odspoji u zasebni prozor",
|
||||
"videoblur": "Uključi/Isključi zamućenje videa",
|
||||
"videomute": "Pokreni/Prekini kameru",
|
||||
"whiteboard": "Pokaži/Sakrij ploču za prezentacije"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "Zatvori izbornik reakcija",
|
||||
"disableNoiseSuppression": "Isključi suzbijanje šumova",
|
||||
"disableReactionSounds": "Za ovaj sastanak možeš isključiti zvukove reakcija",
|
||||
"dock": "Prikvači u glavni prozor",
|
||||
"documentClose": "Zatvori dijeljeni dokument",
|
||||
"documentOpen": "Otvori dijeljeni dokument",
|
||||
"download": "Preuzmi naše aplikacije",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "Pokušavaš govoriti? Tvoj zvuk je isključen.",
|
||||
"tileViewToggle": "Uključi/Isključi pločasti prikaz",
|
||||
"toggleCamera": "Uključi/Isključi kameru",
|
||||
"undock": "Odspoji u zasebni prozor",
|
||||
"videoSettings": "Videopostavke",
|
||||
"videomute": "Pokreni/Prekini kameru"
|
||||
},
|
||||
|
||||
@@ -1033,7 +1033,6 @@
|
||||
"chat": "chat-woknješko pokazać/schować",
|
||||
"clap": "placać",
|
||||
"collapse": "pomjeńšić",
|
||||
"dock": "we hłownej wobrazowce fiksěrować",
|
||||
"document": "dźěleny dokument začinić",
|
||||
"download": "naše aplikacije downloadować ",
|
||||
"embedMeeting": "konferencu integrować",
|
||||
@@ -1085,7 +1084,6 @@
|
||||
"tileView": "kachlicowy napohlad zapnyć/hasnyć",
|
||||
"toggleCamera": "kameru měnić",
|
||||
"toggleFilmstrip": "miniaturowy napohlad zapnyć/hasnyć ",
|
||||
"undock": "rozwjazać",
|
||||
"videoblur": "njejasny widejo zapnyć/hasnyć ",
|
||||
"videomute": "„něme šaltowanje wideja zapnyć/hasnyć "
|
||||
},
|
||||
@@ -1102,7 +1100,6 @@
|
||||
"closeChat": "chat začinić",
|
||||
"closeReactionsMenu": "meni za interakcije začinić",
|
||||
"disableReactionSounds": "Móžeće zwuki za interakcije za tutu konferencu deaktiwěrować.",
|
||||
"dock": "fiksěrować",
|
||||
"documentClose": "dźěleny dokument začinić",
|
||||
"documentOpen": "dźěleny dokument wočinić",
|
||||
"download": "naše aplikacije downloadować",
|
||||
@@ -1172,7 +1169,6 @@
|
||||
"talkWhileMutedPopup": "Spytaće Wy rěčeć? Waš mikrofon je němy.",
|
||||
"tileViewToggle": " kachlicowy napohlad zapnyć/hasnyć ",
|
||||
"toggleCamera": "kameru měnić",
|
||||
"undock": "rozwjazać",
|
||||
"videoSettings": "nastajenja za widejo",
|
||||
"videomute": "kameru startować/hasnyć"
|
||||
},
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "Conversazione",
|
||||
"clap": "Applaudi",
|
||||
"collapse": "Riduci",
|
||||
"dock": "Aggancia alla finestra principale",
|
||||
"document": "Documenti condivisi",
|
||||
"download": "Scarica le nostre app",
|
||||
"embedMeeting": "Incorpora riunione altrove",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "Vedi tutti i partecipanti, o uno solo",
|
||||
"toggleCamera": "Cambia videocamera",
|
||||
"toggleFilmstrip": "Pellicola",
|
||||
"undock": "Sgancia in una finestra separata",
|
||||
"videoblur": "Sfoca video",
|
||||
"videomute": "Videocamera",
|
||||
"whiteboard": "Usa lavagna"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "Chiudi il menù reazioni",
|
||||
"disableNoiseSuppression": "Interrompi riduzione rumore",
|
||||
"disableReactionSounds": "Puoi disattivare i suoni delle reaction, in questa riunione",
|
||||
"dock": "Aggancia nella finestra principale",
|
||||
"documentClose": "Chiudi documento condiviso",
|
||||
"documentOpen": "Apri documento condiviso",
|
||||
"download": "Scarica le nostre app",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "Stai provando a parlare? Il microfono è disattivato.",
|
||||
"tileViewToggle": "Vedi tutti i partecipanti insieme, o uno solo",
|
||||
"toggleCamera": "Cambia videocamera",
|
||||
"undock": "Sgancia in una finestra separata",
|
||||
"videoSettings": "Impostazioni video",
|
||||
"videomute": "Videocamera"
|
||||
},
|
||||
|
||||
@@ -1057,7 +1057,6 @@
|
||||
"chat": "Przełączanie okna rozmowy",
|
||||
"clap": "Klaskanie",
|
||||
"collapse": "Zwiń",
|
||||
"dock": "Zadokuj w głównym oknie",
|
||||
"document": "Przełączanie wspólnego dokumentu",
|
||||
"download": "Pobierz nasze aplikacje",
|
||||
"embedMeeting": "Osadź spotkanie",
|
||||
@@ -1109,7 +1108,6 @@
|
||||
"tileView": "Przełącz widok kafelkowy",
|
||||
"toggleCamera": "Przełączanie kamery",
|
||||
"toggleFilmstrip": "Przełącz filmstrip",
|
||||
"undock": "Oddokuj w osobnym oknie",
|
||||
"videoblur": "Przełącz rozmazanie obrazu",
|
||||
"videomute": "Przełączanie wyciszonego filmu wideo"
|
||||
},
|
||||
@@ -1127,7 +1125,6 @@
|
||||
"closeReactionsMenu": "Zamknij reakcje",
|
||||
"disableNoiseSuppression": "Wyłącz tłumienie szumów",
|
||||
"disableReactionSounds": "Wyłącz dźwięki reakcji dla tego spotkania",
|
||||
"dock": "Zadokuj w głównym oknie",
|
||||
"documentClose": "Zamknij udostępniony dokument",
|
||||
"documentOpen": "Otwarty udostępniony dokument",
|
||||
"download": "Pobierz nasze aplikacje",
|
||||
@@ -1197,7 +1194,6 @@
|
||||
"talkWhileMutedPopup": "Próbujesz mówić? Jesteś wyciszony.",
|
||||
"tileViewToggle": "Przełączanie kafelkowego widoku",
|
||||
"toggleCamera": "Przełączanie kamery",
|
||||
"undock": "Oddokuj w osobnym oknie",
|
||||
"videoSettings": "Ustawienia video",
|
||||
"videomute": "Włącz / Wyłącz kamerę"
|
||||
},
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "Abrir / Fechar chat",
|
||||
"clap": "Aplausos",
|
||||
"collapse": "Colapsar",
|
||||
"dock": "Ancorar na janela principal",
|
||||
"document": "Mudar para documento partilhado",
|
||||
"download": "Descarregar as nossas aplicações",
|
||||
"embedMeeting": "Reunião incorporada",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "Mudar a vista em quadrícula",
|
||||
"toggleCamera": "Mudar a câmara",
|
||||
"toggleFilmstrip": "Mudar a película de filme",
|
||||
"undock": "Desancorar numa janela separada",
|
||||
"videoblur": "Mudar o desfoque de vídeo",
|
||||
"videomute": "Iniciar / Parar câmara",
|
||||
"whiteboard": "Mostrar / Esconder quadro branco"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "Fechar menu de reações",
|
||||
"disableNoiseSuppression": "Desativar a supressão de ruído",
|
||||
"disableReactionSounds": "Pode desactivar os sons de reacção para esta reunião",
|
||||
"dock": "Ancorar na janela principal",
|
||||
"documentClose": "Fechar documento partilhado",
|
||||
"documentOpen": "Abrir documento partilhado",
|
||||
"download": "Descarregar as nossas aplicações",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "Está a tentar falar? Está com o microfone desativado.",
|
||||
"tileViewToggle": "Mudar para vista em quadrícula",
|
||||
"toggleCamera": "Mudar a câmara",
|
||||
"undock": "Desancorar numa janela separada",
|
||||
"videoSettings": "Definições de vídeo",
|
||||
"videomute": "Iniciar / Parar câmara"
|
||||
},
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "Öppna eller stäng chattfönster",
|
||||
"clap": "Klappa",
|
||||
"collapse": "Kollaps",
|
||||
"dock": "Docka i huvudfönstret",
|
||||
"document": "Öppna eller stäng delat dokument",
|
||||
"download": "Ladda ner app",
|
||||
"embedMeeting": "Bädda in möte",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "Öppna eller stäng panelvyn",
|
||||
"toggleCamera": "Växla kamera",
|
||||
"toggleFilmstrip": "Växla filmremsa",
|
||||
"undock": "Lossa till ett separat fönster",
|
||||
"videoblur": "Växla videooskärpa",
|
||||
"videomute": "Sätt på eller stäng av mikrofonen",
|
||||
"whiteboard": "Visa/dölj whiteboardtavlan"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "Stäng meny för reaktioner",
|
||||
"disableNoiseSuppression": "Inaktivera brusreducering",
|
||||
"disableReactionSounds": "Du kan inaktivera reaktionsljud för det här mötet",
|
||||
"dock": "Docka i huvudfönstret",
|
||||
"documentClose": "Stäng delat dokument",
|
||||
"documentOpen": "Öppna delat dokument",
|
||||
"download": "Ladda ner vår app",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "Försöker du tala? Din mikrofon är tystad.",
|
||||
"tileViewToggle": "Öppna eller stäng panelvyn",
|
||||
"toggleCamera": "Byta kamera",
|
||||
"undock": "Lossa till ett separat fönster",
|
||||
"videoSettings": "Video inställningar",
|
||||
"videomute": "Aktivera / avaktivera kameran"
|
||||
},
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "Mesajlaşma penceresini aç/kapat",
|
||||
"clap": "Alkış",
|
||||
"collapse": "Daralt",
|
||||
"dock": "Ana pencerede sabitleyin",
|
||||
"document": "Paylaşılan dokümanı aç/kapat",
|
||||
"download": "Uygulamalarımızı indirin",
|
||||
"embedMeeting": "Toplantıyı yerleştir",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "Döşeme görünümünü aç/kapat",
|
||||
"toggleCamera": "Kamerayı değiştir",
|
||||
"toggleFilmstrip": "Film şeridini aç/kapat",
|
||||
"undock": "Ayrı pencereye çıkarın",
|
||||
"videoblur": "Video bulanıklaştırma aç/kapat",
|
||||
"videomute": "Sessiz videoyu aç/kapat",
|
||||
"whiteboard": "Beyaztahtayı Göster / Gizle"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "Reaksiyon menüsünü kapat",
|
||||
"disableNoiseSuppression": "",
|
||||
"disableReactionSounds": "Toplantı için reaksiyon seslerini devre dışı bırak",
|
||||
"dock": "Ana pencerede sabitleyin",
|
||||
"documentClose": "Paylaşılan dokümanı kapat",
|
||||
"documentOpen": "Paylaşılan dokümanı aç",
|
||||
"download": "Uygulamalarımızı indirin",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "Bir şey mi dediniz? Mikrofonunuz kapalı.",
|
||||
"tileViewToggle": "Döşeme görünümünü aç/kapat",
|
||||
"toggleCamera": "Kamerayı değiştir",
|
||||
"undock": "Ayrı pencereye çıkarın",
|
||||
"videoSettings": "Video ayarları",
|
||||
"videomute": "Kamera başlat / durdur"
|
||||
},
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "Показати/приховати чат",
|
||||
"clap": "Овації",
|
||||
"collapse": "Згорнути",
|
||||
"dock": "Закріпити в головному вікні",
|
||||
"document": "Відкрити/закрити спільний документ",
|
||||
"download": "Звантажити мобільний застосунок",
|
||||
"embedMeeting": "Вставити зустріч",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "Увімкнути/вимкнути плитки",
|
||||
"toggleCamera": "Увімкнути/вимкнути камеру",
|
||||
"toggleFilmstrip": "Показати/приховати панель видів",
|
||||
"undock": "Відкріпити в окремому вікні",
|
||||
"videoblur": "Увімкнути/вимкнути розмиття фону",
|
||||
"videomute": "Увімкнути/вимкнути камеру",
|
||||
"whiteboard": "Показати/приховати дошку"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "Закрити меню реакцій",
|
||||
"disableNoiseSuppression": "Вимкнути придушення шуму",
|
||||
"disableReactionSounds": "Ви можете вимкнути звуки реакції для цієї зустрічі",
|
||||
"dock": "Закріпити в головному вікні",
|
||||
"documentClose": "Закрити спільний документ",
|
||||
"documentOpen": "Відкрити спільний документ",
|
||||
"download": "Звантажити мобільний застосунок",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "Намагаєтесь говорити? Ваш мікрофон вимкнено.",
|
||||
"tileViewToggle": "Плитки",
|
||||
"toggleCamera": "Увімкнути/вимкнути камеру",
|
||||
"undock": "Відкріпити в окремому вікні",
|
||||
"videoSettings": "Налаштування камери",
|
||||
"videomute": "Камера"
|
||||
},
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "打开/关闭聊天窗口",
|
||||
"clap": "鼓掌",
|
||||
"collapse": "收起",
|
||||
"dock": "在主窗口停靠",
|
||||
"document": "开启/关闭文件共享",
|
||||
"download": "下载应用",
|
||||
"embedMeeting": "嵌入会议",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "开启/关闭画廊视图",
|
||||
"toggleCamera": "开启/关闭摄像头",
|
||||
"toggleFilmstrip": "开启/关闭幻灯片",
|
||||
"undock": "取消停靠到单独的窗口",
|
||||
"videoblur": "开启/关闭视频模糊",
|
||||
"videomute": "启动/停止摄像头",
|
||||
"whiteboard": "显示/隐藏白板"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "关闭反应菜单",
|
||||
"disableNoiseSuppression": "关闭噪音抑制",
|
||||
"disableReactionSounds": "你可以禁用此会议的反应声音",
|
||||
"dock": "在主窗口停靠",
|
||||
"documentClose": "关闭文件共享",
|
||||
"documentOpen": "开启文件共享",
|
||||
"download": "下载我们的APP",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "你在尝试发言吗? 当前你是静音状态。",
|
||||
"tileViewToggle": "画面模式",
|
||||
"toggleCamera": "开启/关闭摄像头",
|
||||
"undock": "取消停靠到单独的窗口",
|
||||
"videoSettings": "视频设置",
|
||||
"videomute": "开启/关闭摄像头"
|
||||
},
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "打開/關閉聊天視窗",
|
||||
"clap": "鼓掌",
|
||||
"collapse": "收回",
|
||||
"dock": "停靠在主視窗中",
|
||||
"document": "啟用/停用分享文檔",
|
||||
"download": "下載我們的應用程式",
|
||||
"embedMeeting": "嵌入會議",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "啟用/停用畫廊檢視",
|
||||
"toggleCamera": "啟用/停用網路攝影機",
|
||||
"toggleFilmstrip": "啟用/停用簡報",
|
||||
"undock": "取消停靠到單獨的视窗",
|
||||
"videoblur": "啟用/停用畫面模糊",
|
||||
"videomute": "啟用/停用網路攝影機",
|
||||
"whiteboard": "啟用/停用白板"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "關閉反應選單",
|
||||
"disableNoiseSuppression": "停用雜訊抑制",
|
||||
"disableReactionSounds": "您可以停用此會議的反應音效",
|
||||
"dock": "停靠在主視窗中",
|
||||
"documentClose": "關閉分享檔案欄",
|
||||
"documentOpen": "開啟分享檔案欄",
|
||||
"download": "下載我們的應用程式",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "您要發言嗎?目前您處於靜音。",
|
||||
"tileViewToggle": "啟動/停用畫廊檢視",
|
||||
"toggleCamera": "啟動/停用網路攝影機",
|
||||
"undock": "取消停靠到單獨的视窗",
|
||||
"videoSettings": "視訊設定",
|
||||
"videomute": "啟動/停用網路攝影機"
|
||||
},
|
||||
|
||||
@@ -442,9 +442,6 @@
|
||||
"noResults": "No results found :(",
|
||||
"search": "Search GIPHY"
|
||||
},
|
||||
"helpView": {
|
||||
"title": "Help center"
|
||||
},
|
||||
"incomingCall": {
|
||||
"answer": "Answer",
|
||||
"audioCallTitle": "Incoming call",
|
||||
@@ -715,6 +712,8 @@
|
||||
"reactionSoundsForAll": "Disable sounds for all",
|
||||
"screenShareNoAudio": "Share audio box was not checked in the window selection screen.",
|
||||
"screenShareNoAudioTitle": "Couldn't share system audio!",
|
||||
"screenSharingAudioOnlyDescription": "Please note that by sharing your screen you're affecting the \"Best performance\" mode and you will use more bandwidth.",
|
||||
"screenSharingAudioOnlyTitle": "\"Best performance\" mode",
|
||||
"selfViewTitle": "You can always un-hide the self-view from settings",
|
||||
"somebody": "Somebody",
|
||||
"startSilentDescription": "Rejoin the meeting to enable audio",
|
||||
@@ -864,9 +863,6 @@
|
||||
"rejected": "Rejected",
|
||||
"ringing": "Ringing..."
|
||||
},
|
||||
"privacyView": {
|
||||
"title": "Privacy"
|
||||
},
|
||||
"profile": {
|
||||
"avatar": "avatar",
|
||||
"setDisplayNameLabel": "Set your display name",
|
||||
@@ -1074,7 +1070,6 @@
|
||||
"chat": "Open / Close chat",
|
||||
"clap": "Clap",
|
||||
"collapse": "Collapse",
|
||||
"dock": "Dock in main window",
|
||||
"document": "Toggle shared document",
|
||||
"download": "Download our apps",
|
||||
"embedMeeting": "Embed meeting",
|
||||
@@ -1128,7 +1123,6 @@
|
||||
"tileView": "Toggle tile view",
|
||||
"toggleCamera": "Toggle camera",
|
||||
"toggleFilmstrip": "Toggle filmstrip",
|
||||
"undock": "Undock into separate window",
|
||||
"videoblur": "Toggle video blur",
|
||||
"videomute": "Start / Stop camera",
|
||||
"whiteboard": "Show / Hide whiteboard"
|
||||
@@ -1147,7 +1141,6 @@
|
||||
"closeReactionsMenu": "Close reactions menu",
|
||||
"disableNoiseSuppression": "Disable noise suppression",
|
||||
"disableReactionSounds": "You can disable reaction sounds for this meeting",
|
||||
"dock": "Dock in main window",
|
||||
"documentClose": "Close shared document",
|
||||
"documentOpen": "Open shared document",
|
||||
"download": "Download our apps",
|
||||
@@ -1221,7 +1214,6 @@
|
||||
"talkWhileMutedPopup": "Trying to speak? You are muted.",
|
||||
"tileViewToggle": "Toggle tile view",
|
||||
"toggleCamera": "Toggle camera",
|
||||
"undock": "Undock into separate window",
|
||||
"videoSettings": "Video settings",
|
||||
"videomute": "Start / Stop camera"
|
||||
},
|
||||
@@ -1370,6 +1362,7 @@
|
||||
"recentList": "Recent",
|
||||
"recentListDelete": "Delete entry",
|
||||
"recentListEmpty": "Your recent list is currently empty. Chat with your team and you will find all your recent meetings here.",
|
||||
"recentMeetings": "Your recent meetings",
|
||||
"reducedUIText": "Welcome to {{app}}!",
|
||||
"roomNameAllowedChars": "Meeting name should not contain any of these characters: ?, &, :, ', \", %, #.",
|
||||
"roomname": "Enter room name",
|
||||
@@ -1378,6 +1371,7 @@
|
||||
"settings": "Settings",
|
||||
"startMeeting": "Start meeting",
|
||||
"terms": "Terms",
|
||||
"title": "Secure, fully featured, and completely free video conferencing"
|
||||
"title": "Secure, fully featured, and completely free video conferencing",
|
||||
"upcomingMeetings": "Your upcoming meetings"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1671,22 +1671,6 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that the iframe
|
||||
* docked state has been changed. The responsibility for implementing
|
||||
* the dock / undock functionality lies with the external application.
|
||||
*
|
||||
* @param {boolean} docked - Whether or not the iframe has been set to
|
||||
* be docked or undocked.
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyIframeDockStateChanged(docked: boolean) {
|
||||
this._sendEvent({
|
||||
name: 'iframe-dock-state-changed',
|
||||
docked
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application of a participant, remote or local, being
|
||||
* removed from the conference by another participant.
|
||||
|
||||
1
modules/API/external/external_api.js
vendored
@@ -117,7 +117,6 @@ const events = {
|
||||
'feedback-submitted': 'feedbackSubmitted',
|
||||
'feedback-prompt-displayed': 'feedbackPromptDisplayed',
|
||||
'filmstrip-display-changed': 'filmstripDisplayChanged',
|
||||
'iframe-dock-state-changed': 'iframeDockStateChanged',
|
||||
'incoming-message': 'incomingMessage',
|
||||
'knocking-participant': 'knockingParticipant',
|
||||
'log': 'log',
|
||||
|
||||
@@ -23,7 +23,6 @@ import {
|
||||
getVideoTrackByParticipant,
|
||||
trackStreamingStatusChanged
|
||||
} from '../../../react/features/base/tracks';
|
||||
import { createDeferred } from '../../../react/features/base/util/helpers';
|
||||
import { CHAT_SIZE } from '../../../react/features/chat';
|
||||
import {
|
||||
isTrackStreamingStatusActive,
|
||||
@@ -39,6 +38,7 @@ import { getParticipantsPaneOpen } from '../../../react/features/participants-pa
|
||||
import { PresenceLabel } from '../../../react/features/presence-status';
|
||||
import { shouldDisplayTileView } from '../../../react/features/video-layout';
|
||||
/* eslint-enable no-unused-vars */
|
||||
import { createDeferred } from '../../util/helpers';
|
||||
import AudioLevels from '../audio_levels/AudioLevels';
|
||||
|
||||
import { VIDEO_CONTAINER_TYPE, VideoContainer } from './VideoContainer';
|
||||
|
||||
@@ -158,7 +158,6 @@ export default {
|
||||
* Determines if currently selected media devices should be changed after
|
||||
* list of available devices has been changed.
|
||||
* @param {MediaDeviceInfo[]} newDevices
|
||||
* @param {boolean} isSharingScreen
|
||||
* @param {JitsiLocalTrack} localVideo
|
||||
* @param {JitsiLocalTrack} localAudio
|
||||
* @returns {{
|
||||
@@ -169,13 +168,12 @@ export default {
|
||||
*/
|
||||
getNewMediaDevicesAfterDeviceListChanged( // eslint-disable-line max-params
|
||||
newDevices,
|
||||
isSharingScreen,
|
||||
localVideo,
|
||||
localAudio,
|
||||
newLabels) {
|
||||
return {
|
||||
audioinput: getNewAudioInputDevice(newDevices, localAudio, newLabels),
|
||||
videoinput: isSharingScreen ? undefined : getNewVideoInputDevice(newDevices, localVideo, newLabels),
|
||||
videoinput: getNewVideoInputDevice(newDevices, localVideo, newLabels),
|
||||
audiooutput: getNewAudioOutputDevice(newDevices)
|
||||
};
|
||||
},
|
||||
|
||||
71
modules/util/TaskQueue.js
Normal file
@@ -0,0 +1,71 @@
|
||||
const logger = require('@jitsi/logger').getLogger(__filename);
|
||||
|
||||
/**
|
||||
* Manages a queue of functions where the current function in progress will
|
||||
* automatically execute the next queued function.
|
||||
*/
|
||||
export class TaskQueue {
|
||||
/**
|
||||
* Creates a new instance of {@link TaskQueue} and sets initial instance
|
||||
* variable values.
|
||||
*/
|
||||
constructor() {
|
||||
this._queue = [];
|
||||
this._currentTask = null;
|
||||
|
||||
this._onTaskComplete = this._onTaskComplete.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new function to the queue. It will be immediately invoked if no
|
||||
* other functions are queued.
|
||||
*
|
||||
* @param {Function} taskFunction - The function to be queued for execution.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
enqueue(taskFunction) {
|
||||
this._queue.push(taskFunction);
|
||||
this._executeNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* If no queued task is currently executing, invokes the first task in the
|
||||
* queue if any.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_executeNext() {
|
||||
if (this._currentTask) {
|
||||
logger.warn('Task queued while a task is in progress.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this._currentTask = this._queue.shift() || null;
|
||||
|
||||
if (this._currentTask) {
|
||||
logger.debug('Executing a task.');
|
||||
|
||||
try {
|
||||
this._currentTask(this._onTaskComplete);
|
||||
} catch (error) {
|
||||
logger.error(`Task execution failed: ${error}`);
|
||||
this._onTaskComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares to invoke the next function in the queue.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onTaskComplete() {
|
||||
this._currentTask = null;
|
||||
logger.debug('Task completed.');
|
||||
this._executeNext();
|
||||
}
|
||||
}
|
||||
26
modules/util/helpers.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { TaskQueue } from './TaskQueue';
|
||||
|
||||
/**
|
||||
* Create deferred object.
|
||||
*
|
||||
* @returns {{promise, resolve, reject}}
|
||||
*/
|
||||
export function createDeferred() {
|
||||
const deferred = {};
|
||||
|
||||
deferred.promise = new Promise((resolve, reject) => {
|
||||
deferred.resolve = resolve;
|
||||
deferred.reject = reject;
|
||||
});
|
||||
|
||||
return deferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of {@link TaskQueue}.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function createTaskQueue() {
|
||||
return new TaskQueue();
|
||||
}
|
||||
215
package-lock.json
generated
@@ -28,10 +28,10 @@
|
||||
"@giphy/react-native-sdk": "1.7.0",
|
||||
"@hapi/bourne": "2.0.0",
|
||||
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.12/jitsi-excalidraw-0.0.12.tgz",
|
||||
"@jitsi/js-utils": "2.0.4",
|
||||
"@jitsi/js-utils": "2.0.5",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
"@jitsi/rnnoise-wasm": "0.1.0",
|
||||
"@jitsi/rtcstats": "9.5.0",
|
||||
"@jitsi/rtcstats": "9.5.1",
|
||||
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
|
||||
"@microsoft/microsoft-graph-client": "3.0.1",
|
||||
"@mui/material": "5.10.2",
|
||||
@@ -74,7 +74,7 @@
|
||||
"js-md5": "0.6.1",
|
||||
"js-sha512": "0.8.0",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1549.0.0+877c4546/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1564.0.0+e2aa3700/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -102,7 +102,7 @@
|
||||
"react-native-keep-awake": "4.0.0",
|
||||
"react-native-orientation-locker": "1.5.0",
|
||||
"react-native-pager-view": "5.4.9",
|
||||
"react-native-paper": "4.11.1",
|
||||
"react-native-paper": "5.1.2",
|
||||
"react-native-performance": "2.1.0",
|
||||
"react-native-safe-area-context": "3.3.2",
|
||||
"react-native-screens": "3.13.1",
|
||||
@@ -114,14 +114,14 @@
|
||||
"react-native-url-polyfill": "1.3.0",
|
||||
"react-native-video": "https://git@github.com/react-native-video/react-native-video#7c48ae7c8544b2b537fb60194e9620b9fcceae52",
|
||||
"react-native-watch-connectivity": "1.0.11",
|
||||
"react-native-webrtc": "1.106.1",
|
||||
"react-native-webrtc": "106.0.1",
|
||||
"react-native-webview": "11.15.1",
|
||||
"react-native-youtube-iframe": "2.2.1",
|
||||
"react-redux": "7.1.0",
|
||||
"react-textarea-autosize": "8.3.0",
|
||||
"react-transition-group": "2.4.0",
|
||||
"react-window": "1.8.6",
|
||||
"react-youtube": "7.13.1",
|
||||
"react-youtube": "10.1.0",
|
||||
"redux": "4.0.4",
|
||||
"redux-thunk": "2.4.1",
|
||||
"resemblejs": "4.0.0",
|
||||
@@ -2928,9 +2928,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@callstack/react-theme-provider": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@callstack/react-theme-provider/-/react-theme-provider-3.0.7.tgz",
|
||||
"integrity": "sha512-Ab6rbD2w4u9W3yf7LQQ8evx9m8fZNsoWxt+MFm3AyZnyKQNCJf4K7ip9tHHZgSs+HTdoj38lEqPehvFOVQKvAg==",
|
||||
"version": "3.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@callstack/react-theme-provider/-/react-theme-provider-3.0.8.tgz",
|
||||
"integrity": "sha512-5U231sYY2sqQOaELX0WBCn+iluV8bFaXIS7em03k4W5Xz0AhGvKlnpLIhDGFP8im/SvNW7/2XoR0BsClhn9t6Q==",
|
||||
"dependencies": {
|
||||
"deepmerge": "^3.2.0",
|
||||
"hoist-non-react-statics": "^3.3.0"
|
||||
@@ -3756,9 +3756,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jitsi/js-utils": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-2.0.4.tgz",
|
||||
"integrity": "sha512-voXa8Y8srv/q3gD9wWOGMPVqOWT4s0n4B/ApkPDAIN8EG/6mpzAfHNMi4BIOQeeo2P0srIdcD6Y/1S/ftjuhYQ==",
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-2.0.5.tgz",
|
||||
"integrity": "sha512-Aa7lt/sGsDymWnKJtM1RePmR2b2J5TwY3QLv5iOmzMDYR+5RE0NyYc/vKW51JeatDVSkj+LT7kpUDvtJua0rmQ==",
|
||||
"dependencies": {
|
||||
"bowser": "2.7.0",
|
||||
"js-md5": "0.7.3"
|
||||
@@ -3780,9 +3780,9 @@
|
||||
"integrity": "sha512-JujivPbOUvdRYa2xqByHYKfKGNGa7ZPyNLaNuh8hEp9XsiNfjaJAHdboq6M1VY9TP+765nyxC0LjpAw1VkikOQ=="
|
||||
},
|
||||
"node_modules/@jitsi/rtcstats": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.5.0.tgz",
|
||||
"integrity": "sha512-jKB+1IzKuqynA2etmWAA4uDFF0oAFUZWxRq+m+rOt8FfBp6pXojWbWA7xblcjxerj/3njGc8nEQbcK9qck1How==",
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.5.1.tgz",
|
||||
"integrity": "sha512-UDcsNwPvweQ6owV/chwabd6DsQd2aB4qjqrOB+BlJnETZ+zssGYAey3ezaiNK6nxevwBkbHj980/S9v+2y4btg==",
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "^2.0.0",
|
||||
"sdp": "^3.0.3",
|
||||
@@ -13497,13 +13497,13 @@
|
||||
},
|
||||
"node_modules/lib-jitsi-meet": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1549.0.0+877c4546/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-cxzr8vnJ6RyqWYzJ4LO09PqblJ6nIrJFFmzW8kPQgC1Nhq7sDAD896827q/shd+FE6bSoK0xVjDP+gW+JInS9A==",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1564.0.0+e2aa3700/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-yXMl8yUsac0tymhzsegYc5NQ33gLTceoWtzeK+D36UzwUYUvLSez2YRgBSQmz24vYVtJLqqhqgHW60IPvEOS2Q==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
"@jitsi/sdp-interop": "https://git@github.com/jitsi/sdp-interop#3d49eb4aa26863a3f8d32d7581cdb4321244266b",
|
||||
"@jitsi/sdp-interop": "git+https://github.com/jitsi/sdp-interop#3d49eb4aa26863a3f8d32d7581cdb4321244266b",
|
||||
"@jitsi/sdp-simulcast": "0.4.0",
|
||||
"async": "3.2.3",
|
||||
"base64-js": "1.3.1",
|
||||
@@ -13516,7 +13516,7 @@
|
||||
"sdp-transform": "2.3.0",
|
||||
"strophe.js": "1.3.4",
|
||||
"strophejs-plugin-disco": "0.0.2",
|
||||
"strophejs-plugin-stream-management": "https://git@github.com/jitsi/strophejs-plugin-stream-management#001cf02bef2357234e1ac5d163611b4d60bf2b6a",
|
||||
"strophejs-plugin-stream-management": "git+https://github.com/jitsi/strophejs-plugin-stream-management#001cf02bef2357234e1ac5d163611b4d60bf2b6a",
|
||||
"uuid": "8.1.0",
|
||||
"webrtc-adapter": "8.1.1"
|
||||
}
|
||||
@@ -13571,9 +13571,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/loader-utils": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.1.tgz",
|
||||
"integrity": "sha512-1Qo97Y2oKaU+Ro2xnDMR26g1BwMT29jNbem1EvcujW2jqt+j5COXyscjM7bLQkM9HaxI7pkWeW7gnI072yMI9Q==",
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
|
||||
"integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"big.js": "^5.2.2",
|
||||
@@ -14711,9 +14711,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/null-loader/node_modules/loader-utils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz",
|
||||
"integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
|
||||
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
|
||||
"dependencies": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
@@ -16281,14 +16281,6 @@
|
||||
"react-native": ">=0.47.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-iphone-x-helper": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz",
|
||||
"integrity": "sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg==",
|
||||
"peerDependencies": {
|
||||
"react-native": ">=0.42.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-keep-awake": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-keep-awake/-/react-native-keep-awake-4.0.0.tgz",
|
||||
@@ -16314,17 +16306,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-paper": {
|
||||
"version": "4.11.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-4.11.1.tgz",
|
||||
"integrity": "sha512-mAQ74KUrOIcMEg1crrIsA7eXDaPk/fjvKFDLcN7gBBeV/zhhQiqc+/y6t+8STKsZutRA2U5/eB+0MBisybokmQ==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-5.1.2.tgz",
|
||||
"integrity": "sha512-muf70CPtji6gTukV+9ecvzOYFOflK2hi4t4GLt9y4Ynhf/YQCvXsefPTp45n7RS6bz9+ueG4jtuGg64oOY8dxA==",
|
||||
"dependencies": {
|
||||
"@callstack/react-theme-provider": "^3.0.7",
|
||||
"@callstack/react-theme-provider": "^3.0.8",
|
||||
"color": "^3.1.2",
|
||||
"react-native-iphone-x-helper": "^1.3.1"
|
||||
"use-event-callback": "^0.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-safe-area-context": "*",
|
||||
"react-native-vector-icons": "*"
|
||||
}
|
||||
},
|
||||
@@ -16501,13 +16494,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-webrtc": {
|
||||
"version": "1.106.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.106.1.tgz",
|
||||
"integrity": "sha512-955gqWFdISARz9D4hmnPzKQwpaU+AGqUbU+vBjzLCozUseSJ69tTQg2cShyPCBH6A1rwJQE+mrdjcpkeGbx3pQ==",
|
||||
"version": "106.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-106.0.1.tgz",
|
||||
"integrity": "sha512-0l911lDIqj7jKMvxwQEF6mQt6CMnmOZjgwyifNT28w3XY4p+0Tm/mg5S0UqjbFzcUWeI5w2q/Xk7zn0mcbEhPg==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"adm-zip": "0.5.9",
|
||||
"base64-js": "1.5.1",
|
||||
"debug": "4.3.4",
|
||||
"event-target-shim": "6.0.2",
|
||||
"tar": "6.1.11"
|
||||
},
|
||||
@@ -16766,36 +16760,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-youtube": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-youtube/-/react-youtube-7.13.1.tgz",
|
||||
"integrity": "sha512-b++TLHmHDpd0ZBS1wcbYabbuchU+W4jtx5A2MUQX0BINNKKsaIQX29sn/aLvZ9v5luwAoceia3VGtyz9blaB9w==",
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-youtube/-/react-youtube-10.1.0.tgz",
|
||||
"integrity": "sha512-ZfGtcVpk0SSZtWCSTYOQKhfx5/1cfyEW1JN/mugGNfAxT3rmVJeMbGpA9+e78yG21ls5nc/5uZJETE3cm3knBg==",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "3.1.3",
|
||||
"prop-types": "15.7.2",
|
||||
"prop-types": "15.8.1",
|
||||
"youtube-player": "5.5.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.x"
|
||||
"node": ">= 14.x"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=0.14.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-youtube/node_modules/prop-types": {
|
||||
"version": "15.7.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-youtube/node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
@@ -18191,9 +18170,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/string-replace-loader/node_modules/loader-utils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz",
|
||||
"integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
|
||||
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"big.js": "^5.2.2",
|
||||
@@ -19380,6 +19359,14 @@
|
||||
"react": "^16.8.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/use-event-callback": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/use-event-callback/-/use-event-callback-0.1.0.tgz",
|
||||
"integrity": "sha512-5fTzY5UEXHMK5UR0NRkUz6TPfWmmX9fO8Tx3SnHrfMPdrQ7Rna0gDBy0r56SP68TwsP9DgwSBzeysCu3A/Z2NA==",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/use-isomorphic-layout-effect": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz",
|
||||
@@ -22506,9 +22493,9 @@
|
||||
}
|
||||
},
|
||||
"@callstack/react-theme-provider": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@callstack/react-theme-provider/-/react-theme-provider-3.0.7.tgz",
|
||||
"integrity": "sha512-Ab6rbD2w4u9W3yf7LQQ8evx9m8fZNsoWxt+MFm3AyZnyKQNCJf4K7ip9tHHZgSs+HTdoj38lEqPehvFOVQKvAg==",
|
||||
"version": "3.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@callstack/react-theme-provider/-/react-theme-provider-3.0.8.tgz",
|
||||
"integrity": "sha512-5U231sYY2sqQOaELX0WBCn+iluV8bFaXIS7em03k4W5Xz0AhGvKlnpLIhDGFP8im/SvNW7/2XoR0BsClhn9t6Q==",
|
||||
"requires": {
|
||||
"deepmerge": "^3.2.0",
|
||||
"hoist-non-react-statics": "^3.3.0"
|
||||
@@ -23182,9 +23169,9 @@
|
||||
"integrity": "sha512-WFzaH5GCZLA5DTSZ6ReqAz9g53mSgi+211zTC7AFZUYZme5tzKpPg55AKkJZA3ZIRikkbKaEfP/dC4QOH5NMmA=="
|
||||
},
|
||||
"@jitsi/js-utils": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-2.0.4.tgz",
|
||||
"integrity": "sha512-voXa8Y8srv/q3gD9wWOGMPVqOWT4s0n4B/ApkPDAIN8EG/6mpzAfHNMi4BIOQeeo2P0srIdcD6Y/1S/ftjuhYQ==",
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-2.0.5.tgz",
|
||||
"integrity": "sha512-Aa7lt/sGsDymWnKJtM1RePmR2b2J5TwY3QLv5iOmzMDYR+5RE0NyYc/vKW51JeatDVSkj+LT7kpUDvtJua0rmQ==",
|
||||
"requires": {
|
||||
"bowser": "2.7.0",
|
||||
"js-md5": "0.7.3"
|
||||
@@ -23208,9 +23195,9 @@
|
||||
"integrity": "sha512-JujivPbOUvdRYa2xqByHYKfKGNGa7ZPyNLaNuh8hEp9XsiNfjaJAHdboq6M1VY9TP+765nyxC0LjpAw1VkikOQ=="
|
||||
},
|
||||
"@jitsi/rtcstats": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.5.0.tgz",
|
||||
"integrity": "sha512-jKB+1IzKuqynA2etmWAA4uDFF0oAFUZWxRq+m+rOt8FfBp6pXojWbWA7xblcjxerj/3njGc8nEQbcK9qck1How==",
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.5.1.tgz",
|
||||
"integrity": "sha512-UDcsNwPvweQ6owV/chwabd6DsQd2aB4qjqrOB+BlJnETZ+zssGYAey3ezaiNK6nxevwBkbHj980/S9v+2y4btg==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "^2.0.0",
|
||||
"sdp": "^3.0.3",
|
||||
@@ -23220,7 +23207,7 @@
|
||||
"@jitsi/sdp-interop": {
|
||||
"version": "git+https://git@github.com/jitsi/sdp-interop.git#3d49eb4aa26863a3f8d32d7581cdb4321244266b",
|
||||
"integrity": "sha512-80u69QNTBArnCd1CGbTTrl/8AsZOOMF82dQhrgXBQAnrimdpomX1fMZ82ZkxyWyYvRMPG167u43Tp8y1g2DLNA==",
|
||||
"from": "@jitsi/sdp-interop@https://git@github.com/jitsi/sdp-interop#3d49eb4aa26863a3f8d32d7581cdb4321244266b",
|
||||
"from": "@jitsi/sdp-interop@git+https://github.com/jitsi/sdp-interop#3d49eb4aa26863a3f8d32d7581cdb4321244266b",
|
||||
"requires": {
|
||||
"lodash.clonedeep": "4.5.0",
|
||||
"sdp-transform": "2.14.1"
|
||||
@@ -30510,12 +30497,12 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1549.0.0+877c4546/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-cxzr8vnJ6RyqWYzJ4LO09PqblJ6nIrJFFmzW8kPQgC1Nhq7sDAD896827q/shd+FE6bSoK0xVjDP+gW+JInS9A==",
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1564.0.0+e2aa3700/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-yXMl8yUsac0tymhzsegYc5NQ33gLTceoWtzeK+D36UzwUYUvLSez2YRgBSQmz24vYVtJLqqhqgHW60IPvEOS2Q==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
"@jitsi/sdp-interop": "https://git@github.com/jitsi/sdp-interop#3d49eb4aa26863a3f8d32d7581cdb4321244266b",
|
||||
"@jitsi/sdp-interop": "git+https://github.com/jitsi/sdp-interop#3d49eb4aa26863a3f8d32d7581cdb4321244266b",
|
||||
"@jitsi/sdp-simulcast": "0.4.0",
|
||||
"async": "3.2.3",
|
||||
"base64-js": "1.3.1",
|
||||
@@ -30528,7 +30515,7 @@
|
||||
"sdp-transform": "2.3.0",
|
||||
"strophe.js": "1.3.4",
|
||||
"strophejs-plugin-disco": "0.0.2",
|
||||
"strophejs-plugin-stream-management": "https://git@github.com/jitsi/strophejs-plugin-stream-management#001cf02bef2357234e1ac5d163611b4d60bf2b6a",
|
||||
"strophejs-plugin-stream-management": "git+https://github.com/jitsi/strophejs-plugin-stream-management#001cf02bef2357234e1ac5d163611b4d60bf2b6a",
|
||||
"uuid": "8.1.0",
|
||||
"webrtc-adapter": "8.1.1"
|
||||
},
|
||||
@@ -30579,9 +30566,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.1.tgz",
|
||||
"integrity": "sha512-1Qo97Y2oKaU+Ro2xnDMR26g1BwMT29jNbem1EvcujW2jqt+j5COXyscjM7bLQkM9HaxI7pkWeW7gnI072yMI9Q==",
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
|
||||
"integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
@@ -31488,9 +31475,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"loader-utils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz",
|
||||
"integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
|
||||
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
@@ -32652,11 +32639,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react-native-immersive/-/react-native-immersive-2.0.0.tgz",
|
||||
"integrity": "sha512-9TL05nTHN/x9sN1wbUlBoGyzH4NCuZ/7WEEUp5CvOoKuUABvdYosov0O0SAMbm/5J913RRoy98VB6tGNi9lRSw=="
|
||||
},
|
||||
"react-native-iphone-x-helper": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz",
|
||||
"integrity": "sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg=="
|
||||
},
|
||||
"react-native-keep-awake": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-keep-awake/-/react-native-keep-awake-4.0.0.tgz",
|
||||
@@ -32673,13 +32655,13 @@
|
||||
"integrity": "sha512-D6tzxpwMGdl6CXgtskGWhKRc5cJakCazESRGt7PkqnpyiH3N35ft1KmR82pCSQetAFlytFiToeu3a/dG5CELvA=="
|
||||
},
|
||||
"react-native-paper": {
|
||||
"version": "4.11.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-4.11.1.tgz",
|
||||
"integrity": "sha512-mAQ74KUrOIcMEg1crrIsA7eXDaPk/fjvKFDLcN7gBBeV/zhhQiqc+/y6t+8STKsZutRA2U5/eB+0MBisybokmQ==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-5.1.2.tgz",
|
||||
"integrity": "sha512-muf70CPtji6gTukV+9ecvzOYFOflK2hi4t4GLt9y4Ynhf/YQCvXsefPTp45n7RS6bz9+ueG4jtuGg64oOY8dxA==",
|
||||
"requires": {
|
||||
"@callstack/react-theme-provider": "^3.0.7",
|
||||
"@callstack/react-theme-provider": "^3.0.8",
|
||||
"color": "^3.1.2",
|
||||
"react-native-iphone-x-helper": "^1.3.1"
|
||||
"use-event-callback": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"react-native-performance": {
|
||||
@@ -32804,12 +32786,13 @@
|
||||
}
|
||||
},
|
||||
"react-native-webrtc": {
|
||||
"version": "1.106.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.106.1.tgz",
|
||||
"integrity": "sha512-955gqWFdISARz9D4hmnPzKQwpaU+AGqUbU+vBjzLCozUseSJ69tTQg2cShyPCBH6A1rwJQE+mrdjcpkeGbx3pQ==",
|
||||
"version": "106.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-106.0.1.tgz",
|
||||
"integrity": "sha512-0l911lDIqj7jKMvxwQEF6mQt6CMnmOZjgwyifNT28w3XY4p+0Tm/mg5S0UqjbFzcUWeI5w2q/Xk7zn0mcbEhPg==",
|
||||
"requires": {
|
||||
"adm-zip": "0.5.9",
|
||||
"base64-js": "1.5.1",
|
||||
"debug": "4.3.4",
|
||||
"event-target-shim": "6.0.2",
|
||||
"tar": "6.1.11"
|
||||
},
|
||||
@@ -32978,30 +32961,13 @@
|
||||
}
|
||||
},
|
||||
"react-youtube": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-youtube/-/react-youtube-7.13.1.tgz",
|
||||
"integrity": "sha512-b++TLHmHDpd0ZBS1wcbYabbuchU+W4jtx5A2MUQX0BINNKKsaIQX29sn/aLvZ9v5luwAoceia3VGtyz9blaB9w==",
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-youtube/-/react-youtube-10.1.0.tgz",
|
||||
"integrity": "sha512-ZfGtcVpk0SSZtWCSTYOQKhfx5/1cfyEW1JN/mugGNfAxT3rmVJeMbGpA9+e78yG21ls5nc/5uZJETE3cm3knBg==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "3.1.3",
|
||||
"prop-types": "15.7.2",
|
||||
"prop-types": "15.8.1",
|
||||
"youtube-player": "5.5.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"prop-types": {
|
||||
"version": "15.7.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.8.1"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
@@ -34116,9 +34082,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"loader-utils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz",
|
||||
"integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
|
||||
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
@@ -34249,7 +34215,7 @@
|
||||
"strophejs-plugin-stream-management": {
|
||||
"version": "git+https://git@github.com/jitsi/strophejs-plugin-stream-management.git#001cf02bef2357234e1ac5d163611b4d60bf2b6a",
|
||||
"integrity": "sha512-ijQSXeEEmGl4dfLx8RcQDCvzg1UPtEArowaCHZr8ITdBOH/X6JxxGzy/DVeMLVSvSy73tH7pGK6iPjBqQajwdQ==",
|
||||
"from": "strophejs-plugin-stream-management@https://git@github.com/jitsi/strophejs-plugin-stream-management#001cf02bef2357234e1ac5d163611b4d60bf2b6a"
|
||||
"from": "strophejs-plugin-stream-management@git+https://github.com/jitsi/strophejs-plugin-stream-management#001cf02bef2357234e1ac5d163611b4d60bf2b6a"
|
||||
},
|
||||
"style-loader": {
|
||||
"version": "3.3.1",
|
||||
@@ -34979,6 +34945,11 @@
|
||||
"resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.2.1.tgz",
|
||||
"integrity": "sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw=="
|
||||
},
|
||||
"use-event-callback": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/use-event-callback/-/use-event-callback-0.1.0.tgz",
|
||||
"integrity": "sha512-5fTzY5UEXHMK5UR0NRkUz6TPfWmmX9fO8Tx3SnHrfMPdrQ7Rna0gDBy0r56SP68TwsP9DgwSBzeysCu3A/Z2NA=="
|
||||
},
|
||||
"use-isomorphic-layout-effect": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz",
|
||||
|
||||
15
package.json
@@ -33,10 +33,10 @@
|
||||
"@giphy/react-native-sdk": "1.7.0",
|
||||
"@hapi/bourne": "2.0.0",
|
||||
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.12/jitsi-excalidraw-0.0.12.tgz",
|
||||
"@jitsi/js-utils": "2.0.4",
|
||||
"@jitsi/js-utils": "2.0.5",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
"@jitsi/rnnoise-wasm": "0.1.0",
|
||||
"@jitsi/rtcstats": "9.5.0",
|
||||
"@jitsi/rtcstats": "9.5.1",
|
||||
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
|
||||
"@microsoft/microsoft-graph-client": "3.0.1",
|
||||
"@mui/material": "5.10.2",
|
||||
@@ -79,7 +79,7 @@
|
||||
"js-md5": "0.6.1",
|
||||
"js-sha512": "0.8.0",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1549.0.0+877c4546/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1564.0.0+e2aa3700/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -107,7 +107,7 @@
|
||||
"react-native-keep-awake": "4.0.0",
|
||||
"react-native-orientation-locker": "1.5.0",
|
||||
"react-native-pager-view": "5.4.9",
|
||||
"react-native-paper": "4.11.1",
|
||||
"react-native-paper": "5.1.2",
|
||||
"react-native-performance": "2.1.0",
|
||||
"react-native-safe-area-context": "3.3.2",
|
||||
"react-native-screens": "3.13.1",
|
||||
@@ -119,14 +119,14 @@
|
||||
"react-native-url-polyfill": "1.3.0",
|
||||
"react-native-video": "https://git@github.com/react-native-video/react-native-video#7c48ae7c8544b2b537fb60194e9620b9fcceae52",
|
||||
"react-native-watch-connectivity": "1.0.11",
|
||||
"react-native-webrtc": "1.106.1",
|
||||
"react-native-webrtc": "106.0.1",
|
||||
"react-native-webview": "11.15.1",
|
||||
"react-native-youtube-iframe": "2.2.1",
|
||||
"react-redux": "7.1.0",
|
||||
"react-textarea-autosize": "8.3.0",
|
||||
"react-transition-group": "2.4.0",
|
||||
"react-window": "1.8.6",
|
||||
"react-youtube": "7.13.1",
|
||||
"react-youtube": "10.1.0",
|
||||
"redux": "4.0.4",
|
||||
"redux-thunk": "2.4.1",
|
||||
"resemblejs": "4.0.0",
|
||||
@@ -199,7 +199,8 @@
|
||||
"tsc:web": "tsc --noEmit --project tsconfig.web.json",
|
||||
"tsc:native": "tsc --noEmit --project tsconfig.native.json",
|
||||
"tsc:ci": "npm run tsc:web && npm run tsc:native",
|
||||
"lint:ci": "eslint --ext .js,.ts,.tsx --max-warnings 0 . && npm run tsc:ci",
|
||||
"lint:ci": "eslint --ext .js,.ts,.tsx --max-warnings 0 . && npm run tsc:ci && npm run lint:lang",
|
||||
"lint:lang": "for file in lang/*.json; do npx --yes jsonlint -q $file || exit 1; done",
|
||||
"lang-sort": "./resources/lang-sort.sh",
|
||||
"lint-fix": "eslint --ext .js,.ts,.tsx --max-warnings 0 --fix .",
|
||||
"postinstall": "patch-package --error-on-fail && jetify",
|
||||
|
||||
@@ -21,6 +21,7 @@ import { isVpaasMeeting } from '../jaas/functions';
|
||||
import { clearNotifications, showNotification } from '../notifications/actions';
|
||||
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
|
||||
import { setFatalError } from '../overlay/actions';
|
||||
import { isWelcomePageEnabled } from '../welcome/functions';
|
||||
|
||||
import {
|
||||
redirectToStaticPage,
|
||||
@@ -203,7 +204,7 @@ export function maybeRedirectToWelcomePage(options: { feedbackSubmitted?: boolea
|
||||
|
||||
// if Welcome page is enabled redirect to welcome page after 3 sec, if
|
||||
// there is a thank you message to be shown, 0.5s otherwise.
|
||||
if (getState()['features/base/config'].enableWelcomePage) {
|
||||
if (isWelcomePageEnabled(getState())) {
|
||||
setTimeout(
|
||||
() => {
|
||||
dispatch(redirectWithStoredParams('/'));
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Conference } from '../conference';
|
||||
import { getDeepLinkingPage } from '../deep-linking';
|
||||
import { UnsupportedDesktopBrowser } from '../unsupported-browser';
|
||||
import { BlankPage, WelcomePage } from '../welcome';
|
||||
import { isWelcomePageEnabled } from '../welcome/functions';
|
||||
import { getCustomLandingPageURL, isWelcomePageEnabled } from '../welcome/functions';
|
||||
|
||||
/**
|
||||
* Determines which route is to be rendered in order to depict a specific Redux
|
||||
@@ -75,7 +75,13 @@ function _getWebWelcomePageRoute(state) {
|
||||
|
||||
if (isWelcomePageEnabled(state)) {
|
||||
if (isSupportedBrowser()) {
|
||||
route.component = WelcomePage;
|
||||
const customLandingPage = getCustomLandingPageURL(state);
|
||||
|
||||
if (customLandingPage) {
|
||||
route.href = customLandingPage;
|
||||
} else {
|
||||
route.component = WelcomePage;
|
||||
}
|
||||
} else {
|
||||
route.component = UnsupportedDesktopBrowser;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import '../base/media/middleware';
|
||||
import '../base/net-info/middleware';
|
||||
import '../base/participants/middleware';
|
||||
import '../base/responsive-ui/middleware';
|
||||
import '../base/redux/middleware';
|
||||
import '../base/settings/middleware';
|
||||
import '../base/sounds/middleware';
|
||||
import '../base/testing/middleware';
|
||||
@@ -2,7 +2,6 @@ import '../authentication/middleware';
|
||||
import '../base/i18n/middleware';
|
||||
import '../base/devices/middleware';
|
||||
import '../base/media/middleware';
|
||||
import '../base/redux/middleware';
|
||||
import '../dynamic-branding/middleware';
|
||||
import '../e2ee/middleware';
|
||||
import '../external-api/middleware';
|
||||
@@ -24,7 +24,7 @@ import { IResponsiveUIState } from '../base/responsive-ui/reducer';
|
||||
import { ISettingsState } from '../base/settings/reducer';
|
||||
import { ISoundsState } from '../base/sounds/reducer';
|
||||
import { ITestingState } from '../base/testing/reducer';
|
||||
import { INoSrcDataState, ITrackOperations, ITracksState } from '../base/tracks/reducer';
|
||||
import { INoSrcDataState, ITracksState } from '../base/tracks/reducer';
|
||||
import { IUserInteractionState } from '../base/user-interaction/reducer';
|
||||
import { IBreakoutRoomsState } from '../breakout-rooms/reducer';
|
||||
import { ICalendarSyncState } from '../calendar-sync/reducer';
|
||||
@@ -107,7 +107,6 @@ export interface IReduxState {
|
||||
'features/base/responsive-ui': IResponsiveUIState;
|
||||
'features/base/settings': ISettingsState;
|
||||
'features/base/sounds': ISoundsState;
|
||||
'features/base/track-operations': ITrackOperations;
|
||||
'features/base/tracks': ITracksState;
|
||||
'features/base/user-interaction': IUserInteractionState;
|
||||
'features/breakout-rooms': IBreakoutRoomsState;
|
||||
|
||||
@@ -21,13 +21,11 @@ import { getNormalizedDisplayName } from '../participants/functions';
|
||||
import { toState } from '../redux/functions';
|
||||
import {
|
||||
destroyLocalTracks,
|
||||
executeTrackOperation,
|
||||
replaceStoredTracks,
|
||||
replaceLocalTrack,
|
||||
trackAdded,
|
||||
trackRemoved
|
||||
} from '../tracks/actions';
|
||||
} from '../tracks/actions.any';
|
||||
import { getLocalTracks } from '../tracks/functions';
|
||||
import { TrackOperationType } from '../tracks/types';
|
||||
import { getBackendSafeRoomName } from '../util/uri';
|
||||
|
||||
import {
|
||||
@@ -139,43 +137,34 @@ function _addConferenceListeners(conference: IJitsiConference, dispatch: IStore[
|
||||
conference.on(
|
||||
JitsiConferenceEvents.STARTED_MUTED,
|
||||
() => {
|
||||
dispatch(executeTrackOperation(TrackOperationType.AudioVideo, () => {
|
||||
const promises = [];
|
||||
const audioMuted = Boolean(conference.isStartAudioMuted());
|
||||
const videoMuted = Boolean(conference.isStartVideoMuted());
|
||||
const localTracks = getLocalTracks(state['features/base/tracks']);
|
||||
const audioMuted = Boolean(conference.isStartAudioMuted());
|
||||
const videoMuted = Boolean(conference.isStartVideoMuted());
|
||||
const localTracks = getLocalTracks(state['features/base/tracks']);
|
||||
|
||||
sendAnalytics(createStartMutedConfigurationEvent('remote', audioMuted, videoMuted));
|
||||
logger.log(`Start muted: ${audioMuted ? 'audio, ' : ''}${videoMuted ? 'video' : ''}`);
|
||||
sendAnalytics(createStartMutedConfigurationEvent('remote', audioMuted, videoMuted));
|
||||
logger.log(`Start muted: ${audioMuted ? 'audio, ' : ''}${videoMuted ? 'video' : ''}`);
|
||||
|
||||
// XXX Jicofo tells lib-jitsi-meet to start with audio and/or video
|
||||
// muted i.e. Jicofo expresses an intent. Lib-jitsi-meet has turned
|
||||
// Jicofo's intent into reality by actually muting the respective
|
||||
// tracks. The reality is expressed in base/tracks already so what
|
||||
// is left is to express Jicofo's intent in base/media.
|
||||
// TODO Maybe the app needs to learn about Jicofo's intent and
|
||||
// transfer that intent to lib-jitsi-meet instead of lib-jitsi-meet
|
||||
// acting on Jicofo's intent without the app's knowledge.
|
||||
promises.push(
|
||||
dispatch(setAudioMuted(audioMuted)).catch(e => logger.error(`Set audio muted failed: ${e}`)));
|
||||
promises.push(
|
||||
dispatch(setVideoMuted(videoMuted)).catch(e => logger.error(`Set video muted failed: ${e}`)));
|
||||
// XXX Jicofo tells lib-jitsi-meet to start with audio and/or video
|
||||
// muted i.e. Jicofo expresses an intent. Lib-jitsi-meet has turned
|
||||
// Jicofo's intent into reality by actually muting the respective
|
||||
// tracks. The reality is expressed in base/tracks already so what
|
||||
// is left is to express Jicofo's intent in base/media.
|
||||
// TODO Maybe the app needs to learn about Jicofo's intent and
|
||||
// transfer that intent to lib-jitsi-meet instead of lib-jitsi-meet
|
||||
// acting on Jicofo's intent without the app's knowledge.
|
||||
dispatch(setAudioMuted(audioMuted));
|
||||
dispatch(setVideoMuted(videoMuted));
|
||||
|
||||
// Remove the tracks from peerconnection as well.
|
||||
for (const track of localTracks) {
|
||||
const trackType = track.jitsiTrack.getType();
|
||||
// Remove the tracks from peerconnection as well.
|
||||
for (const track of localTracks) {
|
||||
const trackType = track.jitsiTrack.getType();
|
||||
|
||||
// Do not remove the audio track on RN. Starting with iOS 15 it will fail to unmute otherwise.
|
||||
if ((audioMuted && trackType === MEDIA_TYPE.AUDIO && navigator.product !== 'ReactNative')
|
||||
|| (videoMuted && trackType === MEDIA_TYPE.VIDEO)) {
|
||||
promises.push(
|
||||
dispatch(replaceStoredTracks(track.jitsiTrack, null))
|
||||
.catch(e => logger.error(`replaceLocalTrack failed: ${e}`)));
|
||||
}
|
||||
// Do not remove the audio track on RN. Starting with iOS 15 it will fail to unmute otherwise.
|
||||
if ((audioMuted && trackType === MEDIA_TYPE.AUDIO && navigator.product !== 'ReactNative')
|
||||
|| (videoMuted && trackType === MEDIA_TYPE.VIDEO)) {
|
||||
dispatch(replaceLocalTrack(track.jitsiTrack, null, conference));
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
conference.on(
|
||||
|
||||
@@ -252,6 +252,37 @@ export function getConferenceOptions(stateful: IStateful) {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the global config (that is, window.config) with XMPP configuration required to join as a visitor.
|
||||
*
|
||||
* @param {IStateful} stateful - The redux store state.
|
||||
* @param {Array<string>} params - The received parameters.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function generateVisitorConfig(stateful: IStateful, params: Array<string>) {
|
||||
const [ vnode, focusJid ] = params;
|
||||
|
||||
const config = toState(stateful)['features/base/config'];
|
||||
|
||||
if (!config || !config.hosts) {
|
||||
logger.warn('Wrong configuration, missing hosts.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const oldDomain = config.hosts.domain;
|
||||
|
||||
config.hosts.domain = `${vnode}.meet.jitsi`;
|
||||
config.hosts.muc = config.hosts.muc.replace(oldDomain, config.hosts.domain);
|
||||
config.focusUserJid = focusJid;
|
||||
|
||||
// This flag disables sending the initial conference request
|
||||
config.disableFocus = true;
|
||||
|
||||
config.bosh += `?vnode=${vnode}`;
|
||||
config.websocket += `?vnode=${vnode}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UTC timestamp when the first participant joined the conference.
|
||||
*
|
||||
|
||||
@@ -46,6 +46,7 @@ export interface IJitsiConference {
|
||||
avModerationApprove: Function;
|
||||
avModerationReject: Function;
|
||||
createVideoSIPGWSession: Function;
|
||||
dial: Function;
|
||||
disableAVModeration: Function;
|
||||
enableAVModeration: Function;
|
||||
end: Function;
|
||||
@@ -74,6 +75,7 @@ export interface IJitsiConference {
|
||||
myUserId: Function;
|
||||
off: Function;
|
||||
on: Function;
|
||||
options: any;
|
||||
removeTrack: Function;
|
||||
replaceTrack: Function;
|
||||
room: IJitsiConferenceRoom;
|
||||
|
||||
@@ -2,7 +2,6 @@ type ToolbarButtons = 'camera' |
|
||||
'chat' |
|
||||
'closedcaptions' |
|
||||
'desktop' |
|
||||
'dock-iframe' |
|
||||
'download' |
|
||||
'embedmeeting' |
|
||||
'etherpad' |
|
||||
@@ -29,7 +28,6 @@ type ToolbarButtons = 'camera' |
|
||||
'stats' |
|
||||
'tileview' |
|
||||
'toggle-camera' |
|
||||
'undock-iframe' |
|
||||
'videoquality' |
|
||||
'__end';
|
||||
|
||||
@@ -90,6 +88,36 @@ export type Sounds = 'ASKED_TO_UNMUTE_SOUND' |
|
||||
'RECORDING_ON_SOUND' |
|
||||
'TALK_WHILE_MUTED_SOUND';
|
||||
|
||||
|
||||
export interface IMobileDynamicLink {
|
||||
apn: string;
|
||||
appCode: string;
|
||||
customDomain?: string;
|
||||
ibi: string;
|
||||
isi: string;
|
||||
}
|
||||
|
||||
export interface IDeeplinkingPlatformConfig {
|
||||
appName: string;
|
||||
}
|
||||
|
||||
export interface IDeeplinkingMobileConfig extends IDeeplinkingPlatformConfig {
|
||||
appPackage?: string;
|
||||
appScheme: string;
|
||||
downloadLink: string;
|
||||
dynamicLink?: IMobileDynamicLink;
|
||||
fDroidUrl?: string;
|
||||
}
|
||||
|
||||
export interface IDeeplinkingConfig {
|
||||
android?: IDeeplinkingMobileConfig;
|
||||
desktop?: IDeeplinkingPlatformConfig;
|
||||
disabled: boolean;
|
||||
hideLogo: boolean;
|
||||
ios?: IDeeplinkingMobileConfig;
|
||||
showImage: boolean;
|
||||
}
|
||||
|
||||
export interface IConfig {
|
||||
_desktopSharingSourceDevice?: string;
|
||||
analytics?: {
|
||||
@@ -129,6 +157,7 @@ export interface IConfig {
|
||||
preventExecution: boolean;
|
||||
}>;
|
||||
callDisplayName?: string;
|
||||
callFlowsEnabled?: boolean;
|
||||
callStatsConfigParams?: {
|
||||
additionalIDs?: {
|
||||
customerID?: string;
|
||||
@@ -177,6 +206,7 @@ export interface IConfig {
|
||||
};
|
||||
};
|
||||
corsAvatarURLs?: Array<string>;
|
||||
deeplinking?: IDeeplinkingConfig;
|
||||
defaultLanguage?: string;
|
||||
defaultLocalDisplayName?: string;
|
||||
defaultLogoUrl?: string;
|
||||
@@ -203,7 +233,7 @@ export interface IConfig {
|
||||
disableChatSmileys?: boolean;
|
||||
disableDeepLinking?: boolean;
|
||||
disableFilmstripAutohiding?: boolean;
|
||||
disableH264?: boolean;
|
||||
disableFocus?: boolean;
|
||||
disableIncomingMessageSound?: boolean;
|
||||
disableInitialGUM?: boolean;
|
||||
disableInviteFunctions?: boolean;
|
||||
@@ -341,10 +371,13 @@ export interface IConfig {
|
||||
domain: string;
|
||||
focus?: string;
|
||||
muc: string;
|
||||
visitorFocus: string;
|
||||
};
|
||||
iAmRecorder?: boolean;
|
||||
iAmSipGateway?: boolean;
|
||||
inviteAppName?: string | null;
|
||||
inviteServiceCallFlowsUrl?: string;
|
||||
inviteServiceUrl?: string;
|
||||
jaasActuatorUrl?: string;
|
||||
jaasFeedbackMetadataURL?: string;
|
||||
jaasTokenUrl?: string;
|
||||
@@ -381,12 +414,10 @@ export interface IConfig {
|
||||
opusMaxAverageBitrate?: number;
|
||||
p2p?: {
|
||||
backToP2PDelay?: number;
|
||||
disableH264?: boolean;
|
||||
disabledCodec?: string;
|
||||
enableUnifiedOnChrome?: boolean;
|
||||
enabled?: boolean;
|
||||
iceTransportPolicy?: string;
|
||||
preferH264?: boolean;
|
||||
preferredCodec?: string;
|
||||
stunServers?: Array<{ urls: string; }>;
|
||||
};
|
||||
@@ -397,7 +428,6 @@ export interface IConfig {
|
||||
};
|
||||
pcStatsInterval?: number;
|
||||
peopleSearchUrl?: string;
|
||||
preferH264?: boolean;
|
||||
preferredTranscribeLanguage?: string;
|
||||
prejoinConfig?: {
|
||||
enabled?: boolean;
|
||||
@@ -452,12 +482,10 @@ export interface IConfig {
|
||||
subject?: string;
|
||||
testing?: {
|
||||
callStatsThreshold?: number;
|
||||
capScreenshareBitrate?: number;
|
||||
disableE2EE?: boolean;
|
||||
mobileXmppWsThreshold?: number;
|
||||
noAutoPlayVideo?: boolean;
|
||||
p2pTestMode?: boolean;
|
||||
setScreenSharingResolutionConstraints?: boolean;
|
||||
testMode?: boolean;
|
||||
};
|
||||
tileView?: {
|
||||
@@ -483,7 +511,6 @@ export interface IConfig {
|
||||
useAppLanguage?: boolean;
|
||||
};
|
||||
useHostPageLocalStorage?: boolean;
|
||||
useNewBandwidthAllocationStrategy?: boolean;
|
||||
useTurnUdp?: boolean;
|
||||
videoQuality?: {
|
||||
disabledCodec?: string;
|
||||
@@ -506,6 +533,10 @@ export interface IConfig {
|
||||
webrtcIceUdpDisable?: boolean;
|
||||
websocket?: string;
|
||||
websocketKeepAliveUrl?: string;
|
||||
welcomePage?: {
|
||||
customUrl?: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
whiteboard?: {
|
||||
collabServerBaseUrl?: string;
|
||||
enabled?: boolean;
|
||||
|
||||
@@ -81,6 +81,8 @@ export default [
|
||||
'brandingRoomAlias',
|
||||
'debug',
|
||||
'debugAudioLevels',
|
||||
'deeplinking.disabled',
|
||||
'deeplinking.showImage',
|
||||
'defaultLocalDisplayName',
|
||||
'defaultRemoteDisplayName',
|
||||
'deploymentUrls',
|
||||
@@ -99,7 +101,6 @@ export default [
|
||||
'disabledSounds',
|
||||
'disableFilmstripAutohiding',
|
||||
'disableInitialGUM',
|
||||
'disableH264',
|
||||
'disableHPF',
|
||||
'disableInviteFunctions',
|
||||
'disableIncomingMessageSound',
|
||||
@@ -197,7 +198,6 @@ export default [
|
||||
'p2p',
|
||||
'participantsPane',
|
||||
'pcStatsInterval',
|
||||
'preferH264',
|
||||
'preferredCodec',
|
||||
'prejoinConfig',
|
||||
'prejoinPageEnabled',
|
||||
|
||||
@@ -60,7 +60,7 @@ export function getMeetingRegion(state: IReduxState) {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function getMultipleVideoSendingSupportFeatureFlag(state: IReduxState) {
|
||||
return navigator.product !== 'ReactNative' && isUnifiedPlanEnabled(state);
|
||||
return isUnifiedPlanEnabled(state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@ import { IReduxState } from '../../app/types';
|
||||
import { REPLACE_PARTICIPANT } from '../flags/constants';
|
||||
import { getFeatureFlag } from '../flags/functions';
|
||||
|
||||
import { IConfig } from './configType';
|
||||
import { IConfig, IDeeplinkingConfig } from './configType';
|
||||
|
||||
export * from './functions.any';
|
||||
|
||||
@@ -15,11 +15,18 @@ export * from './functions.any';
|
||||
* @returns {void}
|
||||
*/
|
||||
export function _cleanupConfig(config: IConfig) {
|
||||
config.analytics = {};
|
||||
config.analytics = config.analytics ?? {};
|
||||
config.analytics.scriptURLs = [];
|
||||
|
||||
if (NativeModules.AppInfo.LIBRE_BUILD) {
|
||||
delete config.analytics?.amplitudeAPPKey;
|
||||
delete config.analytics?.googleAnalyticsTrackingId;
|
||||
delete config.analytics?.rtcstatsEnabled;
|
||||
delete config.analytics?.rtcstatsEndpoint;
|
||||
delete config.analytics?.rtcstatsPollInterval;
|
||||
delete config.analytics?.rtcstatsSendSdp;
|
||||
delete config.analytics?.rtcstatsUseLegacy;
|
||||
delete config.analytics?.obfuscateRoomName;
|
||||
delete config.callStatsID;
|
||||
delete config.callStatsSecret;
|
||||
config.giphy = { enabled: false };
|
||||
@@ -35,3 +42,14 @@ export function _cleanupConfig(config: IConfig) {
|
||||
export function getReplaceParticipant(state: IReduxState): string {
|
||||
return getFeatureFlag(state, REPLACE_PARTICIPANT, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the defaults for deeplinking.
|
||||
*
|
||||
* @param {IDeeplinkingConfig} _deeplinking - The deeplinking config.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function _setDeeplinkingDefaults(_deeplinking: IDeeplinkingConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { IReduxState } from '../../app/types';
|
||||
|
||||
import { IConfig } from './configType';
|
||||
import { IConfig, IDeeplinkingConfig, IDeeplinkingMobileConfig, IDeeplinkingPlatformConfig } from './configType';
|
||||
import { TOOLBAR_BUTTONS } from './constants';
|
||||
|
||||
export * from './functions.any';
|
||||
@@ -8,10 +8,11 @@ export * from './functions.any';
|
||||
/**
|
||||
* Removes all analytics related options from the given configuration, in case of a libre build.
|
||||
*
|
||||
* @param {*} config - The configuration which needs to be cleaned up.
|
||||
* @param {*} _config - The configuration which needs to be cleaned up.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function _cleanupConfig(config: IConfig) { // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
export function _cleanupConfig(_config: IConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,3 +61,43 @@ export function areAudioLevelsEnabled(state: IReduxState): boolean {
|
||||
// Default to false for React Native as audio levels are of no interest to the mobile app.
|
||||
return navigator.product !== 'ReactNative' && !state['features/base/config'].disableAudioLevels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the defaults for deeplinking.
|
||||
*
|
||||
* @param {IDeeplinkingConfig} deeplinking - The deeplinking config.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function _setDeeplinkingDefaults(deeplinking: IDeeplinkingConfig) {
|
||||
const {
|
||||
desktop = {} as IDeeplinkingPlatformConfig,
|
||||
android = {} as IDeeplinkingMobileConfig,
|
||||
ios = {} as IDeeplinkingMobileConfig
|
||||
} = deeplinking;
|
||||
|
||||
desktop.appName = desktop.appName || 'Jitsi Meet';
|
||||
|
||||
ios.appName = ios.appName || 'Jitsi Meet';
|
||||
ios.appScheme = ios.appScheme || 'org.jitsi.meet';
|
||||
ios.downloadLink = ios.downloadLink
|
||||
|| 'https://itunes.apple.com/us/app/jitsi-meet/id1165103905';
|
||||
if (ios.dynamicLink) {
|
||||
ios.dynamicLink.apn = ios.dynamicLink.apn || 'org.jitsi.meet';
|
||||
ios.dynamicLink.appCode = ios.dynamicLink.appCode || 'w2atb';
|
||||
ios.dynamicLink.ibi = ios.dynamicLink.ibi || 'com.atlassian.JitsiMeet.ios';
|
||||
ios.dynamicLink.isi = ios.dynamicLink.isi || '1165103905';
|
||||
}
|
||||
|
||||
android.appName = android.appName || 'Jitsi Meet';
|
||||
android.appScheme = android.appScheme || 'org.jitsi.meet';
|
||||
android.downloadLink = android.downloadLink
|
||||
|| 'https://play.google.com/store/apps/details?id=org.jitsi.meet';
|
||||
android.appPackage = android.appPackage || 'org.jitsi.meet';
|
||||
android.fDroidUrl = android.fDroidUrl || 'https://f-droid.org/en/packages/org.jitsi.meet/';
|
||||
if (android.dynamicLink) {
|
||||
android.dynamicLink.apn = android.dynamicLink.apn || 'org.jitsi.meet';
|
||||
android.dynamicLink.appCode = android.dynamicLink.appCode || 'w2atb';
|
||||
android.dynamicLink.ibi = android.dynamicLink.ibi || 'com.atlassian.JitsiMeet.ios';
|
||||
android.dynamicLink.isi = android.dynamicLink.isi || '1165103905';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { AnyAction } from 'redux';
|
||||
|
||||
import { IStore } from '../../app/types';
|
||||
import { getFeatureFlag } from '../flags/functions';
|
||||
import Platform from '../react/Platform';
|
||||
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
import { updateSettings } from '../settings/actions';
|
||||
|
||||
@@ -53,7 +52,9 @@ function _setConfig({ dispatch, getState }: IStore, next: Function, action: AnyA
|
||||
const settings = state['features/base/settings'];
|
||||
const config: IConfig = {};
|
||||
|
||||
if (Platform.OS !== 'android' && typeof settings.disableP2P !== 'undefined') {
|
||||
// FIXME: P2P is currently temporality disabled on mobile.
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
if (false && typeof settings.disableP2P !== 'undefined') {
|
||||
config.p2p = { enabled: !settings.disableP2P };
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
import { CONFERENCE_INFO } from '../../conference/components/constants';
|
||||
import Platform from '../react/Platform';
|
||||
import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
import { equals } from '../redux/functions';
|
||||
|
||||
@@ -12,8 +11,14 @@ import {
|
||||
SET_CONFIG,
|
||||
UPDATE_CONFIG
|
||||
} from './actionTypes';
|
||||
import { IConfig } from './configType';
|
||||
import { _cleanupConfig } from './functions';
|
||||
import {
|
||||
IConfig,
|
||||
IDeeplinkingConfig,
|
||||
IDeeplinkingMobileConfig,
|
||||
IDeeplinkingPlatformConfig,
|
||||
IMobileDynamicLink
|
||||
} from './configType';
|
||||
import { _cleanupConfig, _setDeeplinkingDefaults } from './functions';
|
||||
|
||||
/**
|
||||
* The initial state of the feature base/config when executing in a
|
||||
@@ -48,16 +53,18 @@ const INITIAL_RN_STATE: IConfig = {
|
||||
// fastest to merely disable them.
|
||||
disableAudioLevels: true,
|
||||
|
||||
// FIXME: Mobile codecs should probably be configurable separately, rather
|
||||
// than requiring this override here...
|
||||
|
||||
p2p: {
|
||||
// Temporarily disable P2P on Android while we sort out some (codec?) issues.
|
||||
...(Platform.OS === 'android' ? { enabled: false } : {}), // eslint-disable-line no-extra-parens
|
||||
// Temporarily disable P2P on mobile while we sort out some (codec?) issues.
|
||||
enabled: false,
|
||||
disabledCodec: 'vp9',
|
||||
preferredCodec: 'h264'
|
||||
},
|
||||
|
||||
videoQuality: {
|
||||
// FIXME: Mobile codecs should probably be configurable separately, rather
|
||||
// than requiring this override here...
|
||||
enforcePreferredCodec: true,
|
||||
disabledCodec: 'vp9',
|
||||
preferredCodec: 'vp8'
|
||||
}
|
||||
};
|
||||
@@ -291,6 +298,52 @@ function _translateInterfaceConfig(oldValue: IConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
// if we have `deeplinking` defined, ignore deprecated values. Otherwise, compose the config.
|
||||
if (!oldValue.deeplinking) {
|
||||
const disabled = Boolean(oldValue.disableDeepLinking);
|
||||
const deeplinking: IDeeplinkingConfig = {
|
||||
desktop: {} as IDeeplinkingPlatformConfig,
|
||||
hideLogo: false,
|
||||
disabled,
|
||||
showImage: false,
|
||||
android: {} as IDeeplinkingMobileConfig,
|
||||
ios: {} as IDeeplinkingMobileConfig
|
||||
};
|
||||
|
||||
if (typeof interfaceConfig === 'object') {
|
||||
const mobileDynamicLink = interfaceConfig.MOBILE_DYNAMIC_LINK;
|
||||
const dynamicLink: IMobileDynamicLink | undefined = mobileDynamicLink ? {
|
||||
apn: mobileDynamicLink.APN,
|
||||
appCode: mobileDynamicLink.APP_CODE,
|
||||
ibi: mobileDynamicLink.IBI,
|
||||
isi: mobileDynamicLink.ISI,
|
||||
customDomain: mobileDynamicLink.CUSTOM_DOMAIN
|
||||
} : undefined;
|
||||
|
||||
if (deeplinking.desktop) {
|
||||
deeplinking.desktop.appName = interfaceConfig.NATIVE_APP_NAME;
|
||||
}
|
||||
|
||||
deeplinking.hideLogo = Boolean(interfaceConfig.HIDE_DEEP_LINKING_LOGO);
|
||||
deeplinking.showImage = interfaceConfig.SHOW_DEEP_LINKING_IMAGE;
|
||||
deeplinking.android = {
|
||||
appName: interfaceConfig.NATIVE_APP_NAME,
|
||||
appScheme: interfaceConfig.APP_SCHEME,
|
||||
downloadLink: interfaceConfig.MOBILE_DOWNLOAD_LINK_ANDROID,
|
||||
appPackage: interfaceConfig.ANDROID_APP_PACKAGE,
|
||||
fDroidUrl: interfaceConfig.MOBILE_DOWNLOAD_LINK_F_DROID,
|
||||
dynamicLink
|
||||
};
|
||||
deeplinking.ios = {
|
||||
appName: interfaceConfig.NATIVE_APP_NAME,
|
||||
appScheme: interfaceConfig.APP_SCHEME,
|
||||
downloadLink: interfaceConfig.MOBILE_DOWNLOAD_LINK_IOS,
|
||||
dynamicLink
|
||||
};
|
||||
}
|
||||
newValue.deeplinking = deeplinking;
|
||||
}
|
||||
|
||||
return newValue;
|
||||
}
|
||||
|
||||
@@ -338,6 +391,13 @@ function _translateLegacyConfig(oldValue: IConfig) {
|
||||
});
|
||||
}
|
||||
|
||||
newValue.welcomePage = oldValue.welcomePage || {};
|
||||
if (oldValue.hasOwnProperty('enableWelcomePage')
|
||||
&& !newValue.welcomePage.hasOwnProperty('disabled')
|
||||
) {
|
||||
newValue.welcomePage.disabled = !oldValue.enableWelcomePage;
|
||||
}
|
||||
|
||||
newValue.prejoinConfig = oldValue.prejoinConfig || {};
|
||||
if (oldValue.hasOwnProperty('prejoinPageEnabled')
|
||||
&& !newValue.prejoinConfig.hasOwnProperty('enabled')
|
||||
@@ -472,6 +532,8 @@ function _translateLegacyConfig(oldValue: IConfig) {
|
||||
};
|
||||
}
|
||||
|
||||
_setDeeplinkingDefaults(newValue.deeplinking as IDeeplinkingConfig);
|
||||
|
||||
return newValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.3332 3.33329C18.3332 2.41282 17.587 1.66663 16.6665 1.66663H8.33317C7.4127 1.66663 6.6665 2.41282 6.6665 3.33329V4.99996H3.33317C2.4127 4.99996 1.6665 5.74615 1.6665 6.66663V16.6666C1.6665 17.5871 2.4127 18.3333 3.33317 18.3333H13.3332C14.2536 18.3333 14.9998 17.5871 14.9998 16.6666V15H16.6665C17.587 15 18.3332 14.2538 18.3332 13.3333V3.33329ZM8.33317 3.33329H16.6665L16.6665 13.3333H14.9998V6.66663C14.9998 5.74615 14.2536 4.99996 13.3332 4.99996H8.33317V3.33329ZM3.33317 6.66663V16.6666H13.3332V6.66663H3.33317ZM6.6665 12.1024V9.99996C6.6665 9.53972 6.29341 9.16663 5.83317 9.16663C5.37293 9.16663 4.99984 9.53972 4.99984 9.99996V14.1296V14.1666C4.99984 14.5693 5.28549 14.9053 5.66523 14.983C5.71947 14.9941 5.77564 15 5.83317 15L5.83356 14.9992C5.83397 14.9992 5.83439 14.9992 5.8348 14.9992L5.83445 15H5.87022H9.99984C10.4601 15 10.8332 14.6269 10.8332 14.1666C10.8332 13.7064 10.4601 13.3333 9.99984 13.3333H7.89741L11.4116 9.81913C11.7515 9.47922 11.7515 8.92813 11.4116 8.58822C11.0717 8.24832 10.5206 8.24832 10.1807 8.58822L6.6665 12.1024Z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -22,7 +22,6 @@ export { default as IconConnectionInactive } from './ninja.svg';
|
||||
export { default as IconCopy } from './copy.svg';
|
||||
export { default as IconCrown } from './host.svg';
|
||||
export { default as IconDeviceHeadphone } from './headset.svg';
|
||||
export { default as IconDock } from './dock.svg';
|
||||
export { default as IconDotsHorizontal } from './dots-horizontal.svg';
|
||||
export { default as IconDownload } from './download.svg';
|
||||
export { default as IconE2EE } from './e2ee.svg';
|
||||
@@ -88,7 +87,6 @@ export { default as IconStopScreenshare } from './stop-screenshare.svg';
|
||||
export { default as IconSubtitles } from './subtitles.svg';
|
||||
export { default as IconTileView } from './tile-view.svg';
|
||||
export { default as IconTrash } from './trash.svg';
|
||||
export { default as IconUndock } from './undock.svg';
|
||||
export { default as IconUserDeleted } from './user-deleted.svg';
|
||||
export { default as IconUserGroups } from './user-groups.svg';
|
||||
export { default as IconUsers } from './users.svg';
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.6665 1.66663H6.6665C5.74603 1.66663 4.99984 2.41282 4.99984 3.33329V4.99996H3.33317C2.4127 4.99996 1.6665 5.74615 1.6665 6.66663V16.6666C1.6665 17.5871 2.4127 18.3333 3.33317 18.3333H13.3332C14.2536 18.3333 14.9998 17.5871 14.9998 16.6666V15H16.6665C17.587 15 18.3332 14.2538 18.3332 13.3333V3.33329C18.3332 2.41282 17.587 1.66663 16.6665 1.66663ZM13.3332 16.6666V15H6.6665C5.74603 15 4.99984 14.2538 4.99984 13.3333V6.66663H3.33317V16.6666H13.3332ZM6.6665 3.33329V13.3333H16.6665V3.33329H6.6665ZM9.99984 4.99996C9.5396 4.99996 9.1665 5.37306 9.1665 5.83329C9.1665 6.29353 9.5396 6.66663 9.99984 6.66663H12.1023L8.5881 10.1808C8.24819 10.5207 8.24819 11.0718 8.5881 11.4117C8.928 11.7516 9.4791 11.7516 9.819 11.4117L13.3332 7.89753V9.99996C13.3332 10.4602 13.7063 10.8333 14.1665 10.8333C14.6267 10.8333 14.9998 10.4602 14.9998 9.99996V5.83329C14.9998 5.37306 14.6267 4.99996 14.1665 4.99996H14.1295H9.99984Z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
@@ -5,7 +5,6 @@ import { SET_FILMSTRIP_ENABLED } from '../../filmstrip/actionTypes';
|
||||
import { SELECT_LARGE_VIDEO_PARTICIPANT } from '../../large-video/actionTypes';
|
||||
import { APP_STATE_CHANGED } from '../../mobile/background/actionTypes';
|
||||
import {
|
||||
SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
|
||||
SET_CAR_MODE,
|
||||
SET_TILE_VIEW,
|
||||
VIRTUAL_SCREENSHARE_REMOTE_PARTICIPANTS_UPDATED
|
||||
@@ -102,7 +101,6 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
case PARTICIPANT_JOINED:
|
||||
case PARTICIPANT_KICKED:
|
||||
case PARTICIPANT_LEFT:
|
||||
case SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED:
|
||||
case SELECT_LARGE_VIDEO_PARTICIPANT:
|
||||
case SET_AUDIO_ONLY:
|
||||
case SET_CAR_MODE:
|
||||
|
||||
@@ -2,11 +2,6 @@ import { IStore } from '../../app/types';
|
||||
import { showModeratedNotification } from '../../av-moderation/actions';
|
||||
import { shouldShowModeratedNotification } from '../../av-moderation/functions';
|
||||
import { isModerationNotificationDisplayed } from '../../notifications/functions';
|
||||
import { isForceMuted } from '../../participants-pane/functions';
|
||||
import { maybeStopMuteBecauseOfLocalRecording } from '../../recording/functions';
|
||||
import { getLocalParticipant } from '../participants/functions';
|
||||
import { setMuted } from '../tracks/actions.any';
|
||||
import { isUserInteractionRequiredForUnmute } from '../tracks/functions';
|
||||
|
||||
import {
|
||||
SET_AUDIO_AVAILABLE,
|
||||
@@ -22,7 +17,6 @@ import {
|
||||
} from './actionTypes';
|
||||
import {
|
||||
MEDIA_TYPE,
|
||||
type MediaType,
|
||||
SCREENSHARE_MUTISM_AUTHORITY,
|
||||
VIDEO_MUTISM_AUTHORITY
|
||||
} from './constants';
|
||||
@@ -58,32 +52,10 @@ export function setAudioAvailable(available: boolean) {
|
||||
* }}
|
||||
*/
|
||||
export function setAudioMuted(muted: boolean, ensureTrack = false) {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
const participant = getLocalParticipant(state);
|
||||
|
||||
if (!muted && isForceMuted(participant, MEDIA_TYPE.AUDIO, state)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (!muted
|
||||
&& isUserInteractionRequiredForUnmute(state)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const mutePromise = dispatch(setMuted({
|
||||
muted,
|
||||
ensureTrack,
|
||||
mediaType: MEDIA_TYPE.AUDIO
|
||||
}));
|
||||
|
||||
dispatch({
|
||||
type: SET_AUDIO_MUTED,
|
||||
ensureTrack,
|
||||
muted
|
||||
});
|
||||
|
||||
return mutePromise;
|
||||
return {
|
||||
type: SET_AUDIO_MUTED,
|
||||
ensureTrack,
|
||||
muted
|
||||
};
|
||||
}
|
||||
|
||||
@@ -122,14 +94,12 @@ export function setCameraFacingMode(cameraFacingMode: string) {
|
||||
* Action to set the muted state of the local screenshare.
|
||||
*
|
||||
* @param {boolean} muted - True if the local screenshare is to be enabled or false otherwise.
|
||||
* @param {MEDIA_TYPE} mediaType - The type of media.
|
||||
* @param {number} authority - The {@link SCREENSHARE_MUTISM_AUTHORITY} which is muting/unmuting the local screenshare.
|
||||
* @param {boolean} ensureTrack - True if we want to ensure that a new track is created if missing.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function setScreenshareMuted(
|
||||
muted: boolean,
|
||||
mediaType: MediaType = MEDIA_TYPE.SCREENSHARE,
|
||||
authority: number = SCREENSHARE_MUTISM_AUTHORITY.USER,
|
||||
ensureTrack = false) {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
@@ -141,7 +111,7 @@ export function setScreenshareMuted(
|
||||
ensureTrack && dispatch(showModeratedNotification(MEDIA_TYPE.SCREENSHARE));
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const oldValue = state['features/base/media'].screenshare.muted;
|
||||
@@ -149,28 +119,12 @@ export function setScreenshareMuted(
|
||||
// eslint-disable-next-line no-bitwise
|
||||
const newValue = muted ? oldValue | authority : oldValue & ~authority;
|
||||
|
||||
const participant = getLocalParticipant(state);
|
||||
|
||||
if (!newValue && isForceMuted(participant, MEDIA_TYPE.SCREENSHARE, state)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const mutePromise = dispatch(setMuted({
|
||||
authority,
|
||||
mediaType,
|
||||
ensureTrack,
|
||||
muted: Boolean(newValue)
|
||||
}));
|
||||
|
||||
dispatch({
|
||||
return dispatch({
|
||||
type: SET_SCREENSHARE_MUTED,
|
||||
authority,
|
||||
mediaType,
|
||||
ensureTrack,
|
||||
muted: newValue
|
||||
});
|
||||
|
||||
return mutePromise;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -196,7 +150,6 @@ export function setVideoAvailable(available: boolean) {
|
||||
*
|
||||
* @param {boolean} muted - True if the local video is to be muted or false if
|
||||
* the local video is to be unmuted.
|
||||
* @param {MEDIA_TYPE} mediaType - The type of media.
|
||||
* @param {number} authority - The {@link VIDEO_MUTISM_AUTHORITY} which is
|
||||
* muting/unmuting the local video.
|
||||
* @param {boolean} ensureTrack - True if we want to ensure that a new track is
|
||||
@@ -205,7 +158,6 @@ export function setVideoAvailable(available: boolean) {
|
||||
*/
|
||||
export function setVideoMuted(
|
||||
muted: boolean,
|
||||
mediaType: MediaType = MEDIA_TYPE.VIDEO,
|
||||
authority: number = VIDEO_MUTISM_AUTHORITY.USER,
|
||||
ensureTrack = false) {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
@@ -217,43 +169,20 @@ export function setVideoMuted(
|
||||
ensureTrack && dispatch(showModeratedNotification(MEDIA_TYPE.VIDEO));
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const oldValue = state['features/base/media'].video.muted;
|
||||
|
||||
// eslint-disable-next-line no-bitwise
|
||||
const newValue = muted ? oldValue | authority : oldValue & ~authority;
|
||||
const participant = getLocalParticipant(state);
|
||||
|
||||
if (!newValue && isForceMuted(participant, MEDIA_TYPE.VIDEO, state)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (maybeStopMuteBecauseOfLocalRecording(Boolean(newValue), dispatch)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (!newValue && isUserInteractionRequiredForUnmute(state)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const mutePromise = dispatch(setMuted({
|
||||
ensureTrack,
|
||||
authority,
|
||||
muted: Boolean(newValue),
|
||||
mediaType
|
||||
}));
|
||||
|
||||
dispatch({
|
||||
return dispatch({
|
||||
type: SET_VIDEO_MUTED,
|
||||
authority,
|
||||
mediaType,
|
||||
ensureTrack,
|
||||
muted: newValue
|
||||
});
|
||||
|
||||
return mutePromise;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { PanResponder, PixelRatio, View } from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { type Dispatch } from 'redux';
|
||||
|
||||
import { connect } from '../../../redux';
|
||||
import { ASPECT_RATIO_WIDE } from '../../../responsive-ui';
|
||||
import { IReduxState } from '../../../../app/types';
|
||||
import { connect } from '../../../redux/functions';
|
||||
import { ASPECT_RATIO_WIDE } from '../../../responsive-ui/constants';
|
||||
import { storeVideoTransform } from '../../actions';
|
||||
|
||||
// @ts-ignore
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
/**
|
||||
* The default/initial transform (= no transform).
|
||||
*/
|
||||
@@ -55,9 +57,9 @@ const TAP_TIMEOUT_MS = 400;
|
||||
* Type of a transform object this component is capable of handling.
|
||||
*/
|
||||
type Transform = {
|
||||
scale: number,
|
||||
translateX: number,
|
||||
translateY: number
|
||||
scale: number;
|
||||
translateX: number;
|
||||
translateY: number;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
@@ -65,43 +67,43 @@ type Props = {
|
||||
/**
|
||||
* The current aspect ratio of the screen.
|
||||
*/
|
||||
_aspectRatio: Symbol,
|
||||
_aspectRatio: Symbol;
|
||||
|
||||
/**
|
||||
* The children components of this view.
|
||||
* Action to dispatch when the component is unmounted.
|
||||
*/
|
||||
children: Object,
|
||||
|
||||
/**
|
||||
* Transformation is only enabled when this flag is true.
|
||||
*/
|
||||
enabled: boolean,
|
||||
|
||||
/**
|
||||
* Function to invoke when a press event is detected.
|
||||
*/
|
||||
onPress?: Function,
|
||||
|
||||
/**
|
||||
* The id of the current stream that is displayed.
|
||||
*/
|
||||
streamId: string,
|
||||
|
||||
/**
|
||||
* Style of the top level transformable view.
|
||||
*/
|
||||
style: Object,
|
||||
_onUnmount: Function;
|
||||
|
||||
/**
|
||||
* The stored transforms retrieved from Redux to be initially applied
|
||||
* to different streams.
|
||||
*/
|
||||
_transforms: Object,
|
||||
_transforms: Object;
|
||||
|
||||
/**
|
||||
* Action to dispatch when the component is unmounted.
|
||||
* The children components of this view.
|
||||
*/
|
||||
_onUnmount: Function
|
||||
children: Object;
|
||||
|
||||
/**
|
||||
* Transformation is only enabled when this flag is true.
|
||||
*/
|
||||
enabled: boolean;
|
||||
|
||||
/**
|
||||
* Function to invoke when a press event is detected.
|
||||
*/
|
||||
onPress?: Function;
|
||||
|
||||
/**
|
||||
* The id of the current stream that is displayed.
|
||||
*/
|
||||
streamId: string;
|
||||
|
||||
/**
|
||||
* Style of the top level transformable view.
|
||||
*/
|
||||
style: Object;
|
||||
};
|
||||
|
||||
type State = {
|
||||
@@ -109,12 +111,12 @@ type State = {
|
||||
/**
|
||||
* The current (non-transformed) layout of the View.
|
||||
*/
|
||||
layout: ?Object,
|
||||
layout: any;
|
||||
|
||||
/**
|
||||
* The current transform that is applied.
|
||||
*/
|
||||
transform: Transform
|
||||
transform: Transform;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -129,14 +131,14 @@ class VideoTransform extends Component<Props, State> {
|
||||
/**
|
||||
* The initial distance of the fingers on pinch start.
|
||||
*/
|
||||
initialDistance: ?number;
|
||||
initialDistance: number;
|
||||
|
||||
/**
|
||||
* The initial position of the finger on touch start.
|
||||
*/
|
||||
initialPosition: {
|
||||
x: number,
|
||||
y: number
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -233,14 +235,17 @@ class VideoTransform extends Component<Props, State> {
|
||||
videoTransformedViewContainerStyles,
|
||||
style
|
||||
] }
|
||||
|
||||
// @ts-ignore
|
||||
{ ...this.gestureHandlers.panHandlers }>
|
||||
<View
|
||||
<SafeAreaView
|
||||
edges = { [ 'bottom', 'left' ] }
|
||||
style = { [
|
||||
styles.videoTranformedView,
|
||||
this._getTransformStyle()
|
||||
] }>
|
||||
{ children }
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -281,15 +286,13 @@ class VideoTransform extends Component<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
_didMove: Object => boolean;
|
||||
|
||||
/**
|
||||
* Determines if there was large enough movement to be handled.
|
||||
*
|
||||
* @param {Object} gestureState - The gesture state.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_didMove({ dx, dy }) {
|
||||
_didMove({ dx, dy }: any) {
|
||||
return Math.abs(dx) > this.moveThreshold
|
||||
|| Math.abs(dy) > this.moveThreshold;
|
||||
}
|
||||
@@ -302,14 +305,13 @@ class VideoTransform extends Component<Props, State> {
|
||||
* @private
|
||||
* @returns {Object | null}
|
||||
*/
|
||||
_getSavedTransform(streamId) {
|
||||
_getSavedTransform(streamId: string) {
|
||||
const { enabled, _transforms } = this.props;
|
||||
|
||||
// @ts-ignore
|
||||
return (enabled && _transforms[streamId]) || null;
|
||||
}
|
||||
|
||||
_getTouchDistance: Object => number;
|
||||
|
||||
/**
|
||||
* Calculates the touch distance on a pinch event.
|
||||
*
|
||||
@@ -317,15 +319,13 @@ class VideoTransform extends Component<Props, State> {
|
||||
* @private
|
||||
* @returns {number}
|
||||
*/
|
||||
_getTouchDistance({ nativeEvent: { touches } }) {
|
||||
_getTouchDistance({ nativeEvent: { touches } }: any) {
|
||||
const dx = Math.abs(touches[0].pageX - touches[1].pageX);
|
||||
const dy = Math.abs(touches[0].pageY - touches[1].pageY);
|
||||
|
||||
return Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
|
||||
}
|
||||
|
||||
_getTouchPosition: Object => Object;
|
||||
|
||||
/**
|
||||
* Calculates the position of the touch event.
|
||||
*
|
||||
@@ -333,15 +333,13 @@ class VideoTransform extends Component<Props, State> {
|
||||
* @private
|
||||
* @returns {Object}
|
||||
*/
|
||||
_getTouchPosition({ nativeEvent: { touches } }) {
|
||||
_getTouchPosition({ nativeEvent: { touches } }: any) {
|
||||
return {
|
||||
x: touches[0].pageX,
|
||||
y: touches[0].pageY
|
||||
};
|
||||
}
|
||||
|
||||
_getTransformStyle: () => Object;
|
||||
|
||||
/**
|
||||
* Generates a transform style object to be used on the component.
|
||||
*
|
||||
@@ -473,8 +471,6 @@ class VideoTransform extends Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
_onGesture: (string, ?Object | number) => void;
|
||||
|
||||
/**
|
||||
* Handles gestures and converts them to transforms.
|
||||
*
|
||||
@@ -494,7 +490,7 @@ class VideoTransform extends Component<Props, State> {
|
||||
* @param {?Object | number} value - The value of the gesture, if any.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onGesture(type, value) {
|
||||
_onGesture(type: string, value: any) {
|
||||
let transform;
|
||||
|
||||
switch (type) {
|
||||
@@ -528,8 +524,6 @@ class VideoTransform extends Component<Props, State> {
|
||||
this.lastTap = 0;
|
||||
}
|
||||
|
||||
_onLayout: Object => void;
|
||||
|
||||
/**
|
||||
* Callback for the onLayout of the component.
|
||||
*
|
||||
@@ -537,7 +531,7 @@ class VideoTransform extends Component<Props, State> {
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onLayout({ nativeEvent: { layout: { x, y, width, height } } }) {
|
||||
_onLayout({ nativeEvent: { layout: { x, y, width, height } } }: any) {
|
||||
this.setState({
|
||||
layout: {
|
||||
x,
|
||||
@@ -548,8 +542,6 @@ class VideoTransform extends Component<Props, State> {
|
||||
});
|
||||
}
|
||||
|
||||
_onMoveShouldSetPanResponder: (Object, Object) => boolean;
|
||||
|
||||
/**
|
||||
* Function to decide whether the responder should respond to a move event.
|
||||
*
|
||||
@@ -558,14 +550,12 @@ class VideoTransform extends Component<Props, State> {
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_onMoveShouldSetPanResponder(evt, gestureState) {
|
||||
_onMoveShouldSetPanResponder(evt: Object, gestureState: any) {
|
||||
return this.props.enabled
|
||||
&& (this._didMove(gestureState)
|
||||
|| gestureState.numberActiveTouches === 2);
|
||||
}
|
||||
|
||||
_onPanResponderGrant: (Object, Object) => void;
|
||||
|
||||
/**
|
||||
* Calculates the initial touch distance.
|
||||
*
|
||||
@@ -574,7 +564,7 @@ class VideoTransform extends Component<Props, State> {
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onPanResponderGrant(evt, { numberActiveTouches }) {
|
||||
_onPanResponderGrant(evt: Object, { numberActiveTouches }: any) {
|
||||
if (numberActiveTouches === 1) {
|
||||
this.initialPosition = this._getTouchPosition(evt);
|
||||
this.lastTap = Date.now();
|
||||
@@ -584,8 +574,6 @@ class VideoTransform extends Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
_onPanResponderMove: (Object, Object) => void;
|
||||
|
||||
/**
|
||||
* Handles the PanResponder move (touch move) event.
|
||||
*
|
||||
@@ -594,7 +582,7 @@ class VideoTransform extends Component<Props, State> {
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onPanResponderMove(evt, gestureState) {
|
||||
_onPanResponderMove(evt: Object, gestureState: any) {
|
||||
if (gestureState.numberActiveTouches === 2) {
|
||||
// this is a zoom event
|
||||
if (
|
||||
@@ -628,8 +616,6 @@ class VideoTransform extends Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
_onPanResponderRelease: () => void;
|
||||
|
||||
/**
|
||||
* Handles the PanResponder gesture end event.
|
||||
*
|
||||
@@ -638,8 +624,11 @@ class VideoTransform extends Component<Props, State> {
|
||||
*/
|
||||
_onPanResponderRelease() {
|
||||
if (this.lastTap && Date.now() - this.lastTap < TAP_TIMEOUT_MS) {
|
||||
// @ts-ignore
|
||||
this._onGesture('press');
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
delete this.initialDistance;
|
||||
this.initialPosition = {
|
||||
x: 0,
|
||||
@@ -647,8 +636,6 @@ class VideoTransform extends Component<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
_onStartShouldSetPanResponder: () => boolean;
|
||||
|
||||
/**
|
||||
* Function to decide whether the responder should respond to a start
|
||||
* (touch) event.
|
||||
@@ -668,7 +655,7 @@ class VideoTransform extends Component<Props, State> {
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_restoreTransform(streamId) {
|
||||
_restoreTransform(streamId: string) {
|
||||
const savedTransform = this._getSavedTransform(streamId);
|
||||
|
||||
if (savedTransform) {
|
||||
@@ -687,7 +674,7 @@ class VideoTransform extends Component<Props, State> {
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_storeTransform(streamId, transform) {
|
||||
_storeTransform(streamId: string, transform: Transform) {
|
||||
const { _onUnmount, enabled } = this.props;
|
||||
|
||||
if (enabled) {
|
||||
@@ -715,7 +702,7 @@ function _mapDispatchToProps(dispatch: Dispatch<any>) {
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onUnmount(streamId, transform) {
|
||||
_onUnmount(streamId: string, transform: Transform) {
|
||||
dispatch(storeVideoTransform(streamId, transform));
|
||||
}
|
||||
};
|
||||
@@ -730,7 +717,7 @@ function _mapDispatchToProps(dispatch: Dispatch<any>) {
|
||||
* _transforms: Object
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
return {
|
||||
_aspectRatio: state['features/base/responsive-ui'].aspectRatio,
|
||||
|
||||
@@ -23,7 +23,7 @@ export default StyleSheet.create({
|
||||
|
||||
videoTransformedViewContainerWide: {
|
||||
overflow: 'hidden',
|
||||
paddingRight: '14%'
|
||||
paddingRight: '16%'
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,7 +43,8 @@ export const VIDEO_MUTISM_AUTHORITY = {
|
||||
AUDIO_ONLY: 1 << 0,
|
||||
BACKGROUND: 1 << 1,
|
||||
USER: 1 << 2,
|
||||
CAR_MODE: 1 << 3
|
||||
CAR_MODE: 1 << 3,
|
||||
SCREEN_SHARE: 1 << 4
|
||||
};
|
||||
|
||||
/* eslint-enable no-bitwise */
|
||||
|
||||
@@ -12,10 +12,12 @@ import {
|
||||
NOTIFICATION_TIMEOUT_TYPE,
|
||||
showWarningNotification
|
||||
} from '../../notifications';
|
||||
import { isForceMuted } from '../../participants-pane/functions';
|
||||
import { isScreenMediaShared } from '../../screen-share/functions';
|
||||
import { SET_AUDIO_ONLY, setAudioOnly } from '../audio-only';
|
||||
import { SET_ROOM, isRoomValid } from '../conference';
|
||||
import { getMultipleVideoSendingSupportFeatureFlag } from '../config';
|
||||
import { getLocalParticipant } from '../participants';
|
||||
import { MiddlewareRegistry } from '../redux';
|
||||
import { getPropertyValue } from '../settings';
|
||||
import {
|
||||
@@ -25,11 +27,12 @@ import {
|
||||
isLocalVideoTrackDesktop,
|
||||
setTrackMuted
|
||||
} from '../tracks';
|
||||
import { executeTrackOperation } from '../tracks/actions';
|
||||
import { TrackOperationType } from '../tracks/types';
|
||||
|
||||
import {
|
||||
SET_AUDIO_MUTED,
|
||||
SET_AUDIO_UNMUTE_PERMISSIONS,
|
||||
SET_SCREENSHARE_MUTED,
|
||||
SET_VIDEO_MUTED,
|
||||
SET_VIDEO_UNMUTE_PERMISSIONS
|
||||
} from './actionTypes';
|
||||
import {
|
||||
@@ -51,9 +54,6 @@ import {
|
||||
_VIDEO_INITIAL_MEDIA_STATE
|
||||
} from './reducer';
|
||||
|
||||
|
||||
import './subscriber';
|
||||
|
||||
/**
|
||||
* Implements the entry point of the middleware of the feature base/media.
|
||||
*
|
||||
@@ -83,6 +83,16 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
return result;
|
||||
}
|
||||
|
||||
case SET_AUDIO_MUTED: {
|
||||
const state = store.getState();
|
||||
const participant = getLocalParticipant(state);
|
||||
|
||||
if (!action.muted && isForceMuted(participant, MEDIA_TYPE.AUDIO, state)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SET_AUDIO_UNMUTE_PERMISSIONS: {
|
||||
const { blocked, skipNotification } = action;
|
||||
const state = store.getState();
|
||||
@@ -98,6 +108,25 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
break;
|
||||
}
|
||||
|
||||
case SET_SCREENSHARE_MUTED: {
|
||||
const state = store.getState();
|
||||
const participant = getLocalParticipant(state);
|
||||
|
||||
if (!action.muted && isForceMuted(participant, MEDIA_TYPE.SCREENSHARE, state)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SET_VIDEO_MUTED: {
|
||||
const state = store.getState();
|
||||
const participant = getLocalParticipant(state);
|
||||
|
||||
if (!action.muted && isForceMuted(participant, MEDIA_TYPE.VIDEO, state)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SET_VIDEO_UNMUTE_PERMISSIONS: {
|
||||
const { blocked, skipNotification } = action;
|
||||
const state = store.getState();
|
||||
@@ -137,7 +166,7 @@ function _appStateChanged({ dispatch, getState }, next, action) {
|
||||
|
||||
sendAnalytics(createTrackMutedEvent('video', 'background mode', mute));
|
||||
|
||||
dispatch(setVideoMuted(mute, MEDIA_TYPE.VIDEO, VIDEO_MUTISM_AUTHORITY.BACKGROUND));
|
||||
dispatch(setVideoMuted(mute, VIDEO_MUTISM_AUTHORITY.BACKGROUND));
|
||||
}
|
||||
|
||||
return next(action);
|
||||
@@ -162,12 +191,9 @@ function _setAudioOnly({ dispatch, getState }, next, action) {
|
||||
sendAnalytics(createTrackMutedEvent('video', 'audio-only mode', audioOnly));
|
||||
|
||||
// Make sure we mute both the desktop and video tracks.
|
||||
dispatch(executeTrackOperation(TrackOperationType.Video,
|
||||
() => dispatch(setVideoMuted(audioOnly, MEDIA_TYPE.VIDEO, VIDEO_MUTISM_AUTHORITY.AUDIO_ONLY))));
|
||||
dispatch(setVideoMuted(audioOnly, VIDEO_MUTISM_AUTHORITY.AUDIO_ONLY));
|
||||
if (getMultipleVideoSendingSupportFeatureFlag(state)) {
|
||||
dispatch(executeTrackOperation(TrackOperationType.Video,
|
||||
() => dispatch(setScreenshareMuted(
|
||||
audioOnly, MEDIA_TYPE.SCREENSHARE, SCREENSHARE_MUTISM_AUTHORITY.AUDIO_ONLY))));
|
||||
dispatch(setScreenshareMuted(audioOnly, SCREENSHARE_MUTISM_AUTHORITY.AUDIO_ONLY));
|
||||
}
|
||||
|
||||
return next(action);
|
||||
@@ -208,9 +234,9 @@ function _setRoom({ dispatch, getState }, next, action) {
|
||||
// Unconditionally express the desires/expectations/intents of the app and
|
||||
// the user i.e. the state of base/media. Eventually, practice/reality i.e.
|
||||
// the state of base/tracks will or will not agree with the desires.
|
||||
dispatch(executeTrackOperation(TrackOperationType.Audio, () => dispatch(setAudioMuted(audioMuted))));
|
||||
dispatch(setAudioMuted(audioMuted));
|
||||
dispatch(setCameraFacingMode(CAMERA_FACING_MODE.USER));
|
||||
dispatch(executeTrackOperation(TrackOperationType.Video, () => dispatch(setVideoMuted(videoMuted))));
|
||||
dispatch(setVideoMuted(videoMuted));
|
||||
|
||||
// startAudioOnly
|
||||
//
|
||||
@@ -270,29 +296,21 @@ function _setRoom({ dispatch, getState }, next, action) {
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
function _syncTrackMutedState({ dispatch, getState }, track) {
|
||||
function _syncTrackMutedState({ getState }, track) {
|
||||
const state = getState()['features/base/media'];
|
||||
const mediaType = track.mediaType;
|
||||
const trackOpType = mediaType === MEDIA_TYPE.AUDIO ? TrackOperationType.Audio : TrackOperationType.Video;
|
||||
const muted = Boolean(state[mediaType].muted);
|
||||
|
||||
dispatch(executeTrackOperation(trackOpType, () => {
|
||||
const state = getState()['features/base/media'];
|
||||
// XXX If muted state of track when it was added is different from our media
|
||||
// muted state, we need to mute track and explicitly modify 'muted' property
|
||||
// on track. This is because though TRACK_ADDED action was dispatched it's
|
||||
// not yet in redux state and JitsiTrackEvents.TRACK_MUTE_CHANGED may be
|
||||
// fired before track gets to state.
|
||||
if (track.muted !== muted) {
|
||||
sendAnalytics(createSyncTrackStateEvent(mediaType, muted));
|
||||
logger.log(`Sync ${mediaType} track muted state to ${muted ? 'muted' : 'unmuted'}`);
|
||||
|
||||
const muted = Boolean(state[mediaType].muted);
|
||||
|
||||
// XXX If muted state of track when it was added is different from our media
|
||||
// muted state, we need to mute track and explicitly modify 'muted' property
|
||||
// on track. This is because though TRACK_ADDED action was dispatched it's
|
||||
// not yet in redux state and JitsiTrackEvents.TRACK_MUTE_CHANGED may be
|
||||
// fired before track gets to state.
|
||||
if (track.muted !== muted) {
|
||||
sendAnalytics(createSyncTrackStateEvent(track.mediaType, muted));
|
||||
logger.log(`Sync ${track.mediaType} track muted state to ${muted ? 'muted' : 'unmuted'}`);
|
||||
|
||||
track.muted = muted;
|
||||
|
||||
return setTrackMuted(track.jitsiTrack, muted, state);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}));
|
||||
track.muted = muted;
|
||||
setTrackMuted(track.jitsiTrack, muted, state);
|
||||
}
|
||||
}
|
||||
1
react/features/base/media/middleware.native.ts
Normal file
@@ -0,0 +1 @@
|
||||
import './middleware.any.js';
|
||||
45
react/features/base/media/middleware.web.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import './middleware.any.js';
|
||||
|
||||
import { IStore } from '../../app/types';
|
||||
import { showNotification } from '../../notifications/actions';
|
||||
import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants';
|
||||
import LocalRecordingManager from '../../recording/components/Recording/LocalRecordingManager.web';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import StopRecordingDialog from '../../recording/components/Recording/web/StopRecordingDialog';
|
||||
import { openDialog } from '../dialog/actions';
|
||||
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
|
||||
import { SET_VIDEO_MUTED } from './actionTypes';
|
||||
|
||||
import './subscriber';
|
||||
|
||||
/**
|
||||
* Implements the entry point of the middleware of the feature base/media.
|
||||
*
|
||||
* @param {IStore} store - The redux store.
|
||||
* @returns {Function}
|
||||
*/
|
||||
MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: any) => {
|
||||
const { dispatch } = store;
|
||||
|
||||
switch (action.type) {
|
||||
case SET_VIDEO_MUTED: {
|
||||
if (LocalRecordingManager.isRecordingLocally() && LocalRecordingManager.selfRecording.on) {
|
||||
if (action.muted && LocalRecordingManager.selfRecording.withVideo) {
|
||||
dispatch(openDialog(StopRecordingDialog, { localRecordingVideoStop: true }));
|
||||
|
||||
return;
|
||||
} else if (!action.muted && !LocalRecordingManager.selfRecording.withVideo) {
|
||||
dispatch(showNotification({
|
||||
titleKey: 'recording.localRecordingNoVideo',
|
||||
descriptionKey: 'recording.localRecordingVideoWarning',
|
||||
uid: 'recording.localRecordingNoVideo'
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return next(action);
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import WebView from 'react-native-webview';
|
||||
|
||||
import JitsiScreen from './JitsiScreen';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The URL to display.
|
||||
*/
|
||||
source: string,
|
||||
|
||||
/**
|
||||
* The component's external style.
|
||||
*/
|
||||
style: Object
|
||||
}
|
||||
|
||||
const JitsiScreenWebView = ({ source, style }: Props) => (
|
||||
<JitsiScreen
|
||||
disableForcedKeyboardDismiss = { true }
|
||||
style = { style }>
|
||||
<WebView source = {{ uri: source }} />
|
||||
</JitsiScreen>
|
||||
);
|
||||
|
||||
export default JitsiScreenWebView;
|
||||
@@ -351,11 +351,11 @@ export function isWhiteboardParticipant(participant?: IParticipant): boolean {
|
||||
* features/base/participants.
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getRemoteParticipantCount(stateful: IStateful) {
|
||||
export function getRemoteParticipantCountWithFake(stateful: IStateful) {
|
||||
const state = toState(stateful);
|
||||
const participantsState = state['features/base/participants'];
|
||||
|
||||
return participantsState.remote.size - participantsState.sortedRemoteVirtualScreenshareParticipants.size;
|
||||
return participantsState.remote.size;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import {
|
||||
SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED
|
||||
} from '../../video-layout/actionTypes';
|
||||
import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
import { set } from '../redux/functions';
|
||||
|
||||
@@ -74,7 +71,6 @@ const DEFAULT_STATE = {
|
||||
remote: new Map(),
|
||||
sortedRemoteVirtualScreenshareParticipants: new Map(),
|
||||
sortedRemoteParticipants: new Map(),
|
||||
sortedRemoteScreenshares: new Map(),
|
||||
speakersList: new Map()
|
||||
};
|
||||
|
||||
@@ -89,7 +85,6 @@ export interface IParticipantsState {
|
||||
raisedHandsQueue: Array<{ id: string; raisedHandTimestamp: number; }>;
|
||||
remote: Map<string, IParticipant>;
|
||||
sortedRemoteParticipants: Map<string, string>;
|
||||
sortedRemoteScreenshares: Map<string, string>;
|
||||
sortedRemoteVirtualScreenshareParticipants: Map<string, string>;
|
||||
speakersList: Map<string, string>;
|
||||
}
|
||||
@@ -385,29 +380,6 @@ ReducerRegistry.register<IParticipantsState>('features/base/participants',
|
||||
raisedHandsQueue: action.queue
|
||||
};
|
||||
}
|
||||
case SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED: {
|
||||
const { participantIds } = action;
|
||||
const sortedSharesList = [];
|
||||
|
||||
for (const participant of participantIds) {
|
||||
const remoteParticipant = state.remote.get(participant);
|
||||
|
||||
if (remoteParticipant) {
|
||||
const displayName
|
||||
= _getDisplayName(state, remoteParticipant.name);
|
||||
|
||||
sortedSharesList.push([ participant, displayName ]);
|
||||
}
|
||||
}
|
||||
|
||||
// Keep the remote screen share list sorted alphabetically.
|
||||
sortedSharesList.length && sortedSharesList.sort((a, b) => a[1].localeCompare(b[1]));
|
||||
|
||||
// @ts-ignore
|
||||
state.sortedRemoteScreenshares = new Map(sortedSharesList);
|
||||
|
||||
return { ...state };
|
||||
}
|
||||
case OVERWRITE_PARTICIPANT_NAME: {
|
||||
const { id, name } = action;
|
||||
|
||||
|
||||
@@ -38,6 +38,11 @@ type Props = {
|
||||
*/
|
||||
_showJitsiWatermark: boolean,
|
||||
|
||||
/**
|
||||
* Whether the watermark should have a `top` and `left` value.
|
||||
*/
|
||||
noMargins: boolean;
|
||||
|
||||
/**
|
||||
* The default value for the Jitsi logo URL.
|
||||
*/
|
||||
@@ -160,7 +165,9 @@ class Watermarks extends Component<Props, State> {
|
||||
_logoUrl,
|
||||
_showJitsiWatermark
|
||||
} = this.props;
|
||||
const { t } = this.props;
|
||||
const { noMargins, t } = this.props;
|
||||
const className = `watermark ${noMargins ? 'leftwatermarknomargin' : 'leftwatermark'}`;
|
||||
|
||||
let reactElement = null;
|
||||
|
||||
if (_showJitsiWatermark) {
|
||||
@@ -172,14 +179,14 @@ class Watermarks extends Component<Props, State> {
|
||||
};
|
||||
|
||||
reactElement = (<div
|
||||
className = 'watermark leftwatermark'
|
||||
className = { className }
|
||||
style = { style } />);
|
||||
|
||||
if (_logoLink) {
|
||||
reactElement = (
|
||||
<a
|
||||
aria-label = { t('jitsiHome', { logo: interfaceConfig.APP_NAME }) }
|
||||
className = 'watermark leftwatermark'
|
||||
className = { className }
|
||||
href = { _logoLink }
|
||||
target = '_new'>
|
||||
{ reactElement }
|
||||
|
||||
@@ -9,17 +9,6 @@
|
||||
*/
|
||||
export const SET_NO_SRC_DATA_NOTIFICATION_UID = 'SET_NO_SRC_DATA_NOTIFICATION_UID';
|
||||
|
||||
/**
|
||||
* Sets the track operation promise.
|
||||
*
|
||||
* {
|
||||
* type: SET_TRACK_OPERATIONS_PROMISE,
|
||||
* audioTrackOperationsPromise: Promise<void>,
|
||||
* videoTrackOperationsPromise: Promise<void>
|
||||
* }
|
||||
*/
|
||||
export const SET_TRACK_OPERATIONS_PROMISE = 'SET_TRACK_OPERATIONS_PROMISE';
|
||||
|
||||
/**
|
||||
* The type of redux action dispatched when a track has been (locally or
|
||||
* remotely) added to the conference.
|
||||
|
||||
@@ -3,22 +3,22 @@ import { sendAnalytics } from '../../analytics/functions';
|
||||
import { IStore } from '../../app/types';
|
||||
import { showErrorNotification, showNotification } from '../../notifications/actions';
|
||||
import { NOTIFICATION_TIMEOUT, NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants';
|
||||
import { isPrejoinPageVisible } from '../../prejoin/functions';
|
||||
import { getCurrentConference } from '../conference/functions';
|
||||
import { IJitsiConference } from '../conference/reducer';
|
||||
import { getMultipleVideoSendingSupportFeatureFlag } from '../config/functions.any';
|
||||
import { JitsiTrackErrors, JitsiTrackEvents } from '../lib-jitsi-meet';
|
||||
import { createLocalTrack } from '../lib-jitsi-meet/functions.any';
|
||||
import { setAudioMuted, setScreenshareMuted, setVideoMuted } from '../media/actions';
|
||||
import {
|
||||
CAMERA_FACING_MODE,
|
||||
MEDIA_TYPE,
|
||||
MediaType,
|
||||
SCREENSHARE_MUTISM_AUTHORITY,
|
||||
VIDEO_MUTISM_AUTHORITY,
|
||||
VIDEO_TYPE,
|
||||
VideoType
|
||||
} from '../media/constants';
|
||||
import { getLocalParticipant } from '../participants/functions';
|
||||
import { updateSettings } from '../settings/actions';
|
||||
|
||||
import {
|
||||
SET_NO_SRC_DATA_NOTIFICATION_UID,
|
||||
@@ -38,8 +38,7 @@ import {
|
||||
getLocalTrack,
|
||||
getLocalTracks,
|
||||
getLocalVideoTrack,
|
||||
getTrackByJitsiTrack,
|
||||
setTrackMuted
|
||||
getTrackByJitsiTrack
|
||||
} from './functions';
|
||||
import logger from './logger';
|
||||
import { ITrackOptions } from './types';
|
||||
@@ -58,7 +57,7 @@ export function addLocalTrack(newTrack: any) {
|
||||
await conference.addTrack(newTrack);
|
||||
}
|
||||
|
||||
const setMutedA = newTrack.isVideoTrack()
|
||||
const setMuted = newTrack.isVideoTrack()
|
||||
? getMultipleVideoSendingSupportFeatureFlag(getState())
|
||||
&& newTrack.getVideoType() === VIDEO_TYPE.DESKTOP
|
||||
? setScreenshareMuted
|
||||
@@ -67,7 +66,7 @@ export function addLocalTrack(newTrack: any) {
|
||||
const isMuted = newTrack.isMuted();
|
||||
|
||||
logger.log(`Adding ${newTrack.getType()} track - ${isMuted ? 'muted' : 'unmuted'}`);
|
||||
await dispatch(setMutedA(isMuted));
|
||||
await dispatch(setMuted(isMuted));
|
||||
|
||||
return dispatch(_addTracks([ newTrack ]));
|
||||
};
|
||||
@@ -140,7 +139,6 @@ export function createLocalTracksA(options: ITrackOptions = {}) {
|
||||
dispatch,
|
||||
getState
|
||||
};
|
||||
const promises: Promise<any>[] = [];
|
||||
|
||||
// The following executes on React Native only at the time of this
|
||||
// writing. The effort to port Web's createInitialLocalTracksAndConnect
|
||||
@@ -218,14 +216,7 @@ export function createLocalTracksA(options: ITrackOptions = {}) {
|
||||
mediaType: device
|
||||
}
|
||||
});
|
||||
|
||||
promises.push(gumProcess.catch(() => {
|
||||
// ignore the error in the result promises so that the Promise.all resolves after all promises are
|
||||
// settled.
|
||||
}));
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -338,7 +329,7 @@ export function replaceLocalTrack(oldTrack: any, newTrack: any, conference?: IJi
|
||||
* @param {JitsiLocalTrack|null} newTrack - The track to use instead.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function replaceStoredTracks(oldTrack: any, newTrack: any) {
|
||||
function replaceStoredTracks(oldTrack: any, newTrack: any) {
|
||||
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
// We call dispose after doing the replace because dispose will
|
||||
// try and do a new o/a after the track removes itself. Doing it
|
||||
@@ -354,7 +345,7 @@ export function replaceStoredTracks(oldTrack: any, newTrack: any) {
|
||||
// should be falsey. As such, emit a mute event here to set up the app to reflect the track's mute
|
||||
// state. If this is not done, the current mute state of the app will be reflected on the track,
|
||||
// not vice-versa.
|
||||
const setMutedA = newTrack.isVideoTrack()
|
||||
const setMuted = newTrack.isVideoTrack()
|
||||
? getMultipleVideoSendingSupportFeatureFlag(getState())
|
||||
&& newTrack.getVideoType() === VIDEO_TYPE.DESKTOP
|
||||
? setScreenshareMuted
|
||||
@@ -365,7 +356,7 @@ export function replaceStoredTracks(oldTrack: any, newTrack: any) {
|
||||
sendAnalytics(createTrackMutedEvent(newTrack.getType(), 'track.replaced', isMuted));
|
||||
logger.log(`Replace ${newTrack.getType()} track - ${isMuted ? 'muted' : 'unmuted'}`);
|
||||
|
||||
await dispatch(setMutedA(isMuted));
|
||||
await dispatch(setMuted(isMuted));
|
||||
await dispatch(_addTracks([ newTrack ]));
|
||||
}
|
||||
};
|
||||
@@ -826,48 +817,37 @@ export function updateLastTrackVideoMediaEvent(track: any, name: string): {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mutes or unmutes a local track with a specific media type.
|
||||
* Toggles the facingMode constraint on the video stream.
|
||||
*
|
||||
* @param {Object} options - Parameters of the function.
|
||||
* @private
|
||||
* @returns {Promise}
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function setMuted({ ensureTrack, authority, mediaType, muted }: {
|
||||
authority?: number; ensureTrack: boolean; mediaType: MediaType; muted: boolean; }) {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']): Promise<any> => {
|
||||
export function toggleCamera() {
|
||||
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
const localTrack = getLocalTrack(state['features/base/tracks'], mediaType, true);
|
||||
const tracks = state['features/base/tracks'];
|
||||
const localVideoTrack = getLocalVideoTrack(tracks)?.jitsiTrack;
|
||||
const currentFacingMode = localVideoTrack.getCameraFacingMode();
|
||||
|
||||
if (mediaType === MEDIA_TYPE.SCREENSHARE
|
||||
&& getMultipleVideoSendingSupportFeatureFlag(state)
|
||||
&& !muted) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
/**
|
||||
* FIXME: Ideally, we should be dispatching {@code replaceLocalTrack} here,
|
||||
* but it seems to not trigger the re-rendering of the local video on Chrome;
|
||||
* could be due to a plan B vs unified plan issue. Therefore, we use the legacy
|
||||
* method defined in conference.js that manually takes care of updating the local
|
||||
* video as well.
|
||||
*/
|
||||
await APP.conference.useVideoStream(null);
|
||||
|
||||
if (localTrack) {
|
||||
// The `jitsiTrack` property will have a value only for a localTrack for which `getUserMedia` has
|
||||
// already completed. If there's no `jitsiTrack`, then the `muted` state will be applied once the
|
||||
// `jitsiTrack` is created.
|
||||
const { jitsiTrack } = localTrack;
|
||||
const isAudioOnly = (mediaType === MEDIA_TYPE.VIDEO && authority === VIDEO_MUTISM_AUTHORITY.AUDIO_ONLY)
|
||||
|| (mediaType === MEDIA_TYPE.SCREENSHARE && authority === SCREENSHARE_MUTISM_AUTHORITY.AUDIO_ONLY);
|
||||
const targetFacingMode = currentFacingMode === CAMERA_FACING_MODE.USER
|
||||
? CAMERA_FACING_MODE.ENVIRONMENT
|
||||
: CAMERA_FACING_MODE.USER;
|
||||
|
||||
// Screenshare cannot be unmuted using the video mute button unless it is muted by audioOnly in
|
||||
// the legacy screensharing mode.
|
||||
if (jitsiTrack && (
|
||||
jitsiTrack.videoType !== 'desktop' || isAudioOnly || getMultipleVideoSendingSupportFeatureFlag(state))
|
||||
) {
|
||||
return setTrackMuted(jitsiTrack, muted, state).catch(
|
||||
() => dispatch(trackMuteUnmuteFailed(localTrack, muted)));
|
||||
}
|
||||
} else if (!muted && ensureTrack && (typeof APP === 'undefined' || isPrejoinPageVisible(state))) {
|
||||
// FIXME: This only runs on mobile now because web has its own way of
|
||||
// creating local tracks. Adjust the check once they are unified.
|
||||
return dispatch(createLocalTracksA({ devices: [ mediaType ] }));
|
||||
}
|
||||
// Update the flipX value so the environment facing camera is not flipped, before the new track is created.
|
||||
dispatch(updateSettings({ localFlipX: targetFacingMode === CAMERA_FACING_MODE.USER }));
|
||||
|
||||
return Promise.resolve();
|
||||
const newVideoTrack = await createLocalTrack('video', null, null, { facingMode: targetFacingMode });
|
||||
|
||||
// FIXME: See above.
|
||||
await APP.conference.useVideoStream(newVideoTrack);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,13 +2,17 @@ import { IReduxState, IStore } from '../../app/types';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { setPictureInPictureEnabled } from '../../mobile/picture-in-picture/functions';
|
||||
import { setAudioOnly } from '../audio-only/actions';
|
||||
import { showNotification } from '../../notifications/actions';
|
||||
import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants';
|
||||
import JitsiMeetJS from '../lib-jitsi-meet';
|
||||
import {
|
||||
setScreenshareMuted,
|
||||
setVideoMuted
|
||||
} from '../media/actions';
|
||||
import { VIDEO_MUTISM_AUTHORITY } from '../media/constants';
|
||||
|
||||
import { destroyLocalDesktopTrackIfExists, replaceLocalTrack } from './actions.any';
|
||||
import { getLocalVideoTrack, isLocalVideoTrackDesktop } from './functions.native';
|
||||
import { TrackOperationType } from './types';
|
||||
/* eslint-enable lines-around-comment */
|
||||
import { addLocalTrack, replaceLocalTrack } from './actions.any';
|
||||
import { getLocalDesktopTrack, getTrackState, isLocalVideoTrackDesktop } from './functions.native';
|
||||
|
||||
export * from './actions.any';
|
||||
|
||||
@@ -33,7 +37,8 @@ export function toggleScreensharing(enabled: boolean, _ignore1?: boolean, _ignor
|
||||
_startScreenSharing(dispatch, state);
|
||||
}
|
||||
} else {
|
||||
dispatch(destroyLocalDesktopTrackIfExists());
|
||||
dispatch(setScreenshareMuted(true));
|
||||
dispatch(setVideoMuted(false, VIDEO_MUTISM_AUTHORITY.SCREEN_SHARE));
|
||||
setPictureInPictureEnabled(true);
|
||||
}
|
||||
};
|
||||
@@ -49,45 +54,37 @@ export function toggleScreensharing(enabled: boolean, _ignore1?: boolean, _ignor
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _startScreenSharing(dispatch: Function, state: IReduxState) {
|
||||
async function _startScreenSharing(dispatch: Function, state: IReduxState) {
|
||||
setPictureInPictureEnabled(false);
|
||||
|
||||
JitsiMeetJS.createLocalTracks({ devices: [ 'desktop' ] })
|
||||
.then((tracks: any[]) => {
|
||||
try {
|
||||
const tracks: any[] = await JitsiMeetJS.createLocalTracks({ devices: [ 'desktop' ] });
|
||||
const track = tracks[0];
|
||||
const currentLocalTrack = getLocalVideoTrack(state['features/base/tracks']);
|
||||
const currentJitsiTrack = currentLocalTrack?.jitsiTrack;
|
||||
const currentLocalDesktopTrack = getLocalDesktopTrack(getTrackState(state));
|
||||
const currentJitsiTrack = currentLocalDesktopTrack?.jitsiTrack;
|
||||
|
||||
dispatch(replaceLocalTrack(currentJitsiTrack, track));
|
||||
// The first time the user shares the screen we add the track and create the transceiver.
|
||||
// Afterwards, we just replace the old track, so the transceiver will be reused.
|
||||
if (currentJitsiTrack) {
|
||||
dispatch(replaceLocalTrack(currentJitsiTrack, track));
|
||||
} else {
|
||||
dispatch(addLocalTrack(track));
|
||||
}
|
||||
|
||||
dispatch(setVideoMuted(true, VIDEO_MUTISM_AUTHORITY.SCREEN_SHARE));
|
||||
|
||||
const { enabled: audioOnly } = state['features/base/audio-only'];
|
||||
|
||||
if (audioOnly) {
|
||||
dispatch(setAudioOnly(false));
|
||||
dispatch(showNotification({
|
||||
titleKey: 'notify.screenSharingAudioOnlyTitle',
|
||||
descriptionKey: 'notify.screenSharingAudioOnlyDescription',
|
||||
maxLines: 3
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
} catch (error: any) {
|
||||
console.log('ERROR creating ScreeSharing stream ', error);
|
||||
|
||||
setPictureInPictureEnabled(true);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes a track operation.
|
||||
*
|
||||
* NOTE: This is dummy implementation for mobile. Currently we are not sure if we need to chain the track operations.
|
||||
* For now we are just executing the passed operation without chaining it.
|
||||
*
|
||||
* @param {TrackOperationType} type - The type of the operation ('audio', 'video' or 'audio-video').
|
||||
* @param {Function} operation - The operation.
|
||||
* @returns {{
|
||||
* type: SET_TRACK_OPERATIONS_PROMISE,
|
||||
* audioTrackOperationsPromise: Promise<void>,
|
||||
* videoTrackOperationsPromise: Promise<void>
|
||||
* }}
|
||||
*/
|
||||
export function executeTrackOperation(type: TrackOperationType, operation: () => Promise<any>) {
|
||||
return () => operation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,16 +14,12 @@ import { isAudioOnlySharing, isScreenVideoShared } from '../../screen-share/func
|
||||
import { isScreenshotCaptureEnabled, toggleScreenshotCaptureSummary } from '../../screenshot-capture';
|
||||
// @ts-ignore
|
||||
import { AudioMixerEffect } from '../../stream-effects/audio-mixer/AudioMixerEffect';
|
||||
import { setAudioOnly } from '../audio-only/actions';
|
||||
import { getCurrentConference } from '../conference/functions';
|
||||
import { JitsiTrackErrors, JitsiTrackEvents } from '../lib-jitsi-meet';
|
||||
import { createLocalTrack } from '../lib-jitsi-meet/functions.any';
|
||||
import { setScreenshareMuted } from '../media/actions';
|
||||
import { CAMERA_FACING_MODE, MEDIA_TYPE, VIDEO_TYPE } from '../media/constants';
|
||||
import { updateSettings } from '../settings/actions';
|
||||
import { MEDIA_TYPE, VIDEO_TYPE } from '../media/constants';
|
||||
/* eslint-enable lines-around-comment */
|
||||
|
||||
import { SET_TRACK_OPERATIONS_PROMISE } from './actionTypes';
|
||||
import {
|
||||
addLocalTrack,
|
||||
replaceLocalTrack
|
||||
@@ -31,10 +27,9 @@ import {
|
||||
import {
|
||||
createLocalTracksF,
|
||||
getLocalDesktopTrack,
|
||||
getLocalJitsiAudioTrack,
|
||||
getLocalVideoTrack
|
||||
getLocalJitsiAudioTrack
|
||||
} from './functions';
|
||||
import { IShareOptions, IToggleScreenSharingOptions, TrackOperationType } from './types';
|
||||
import { IShareOptions, IToggleScreenSharingOptions } from './types';
|
||||
|
||||
export * from './actions.any';
|
||||
|
||||
@@ -152,6 +147,8 @@ async function _toggleScreenSharing(
|
||||
const audioOnlySharing = isAudioOnlySharing(state);
|
||||
const screenSharing = isScreenVideoShared(state);
|
||||
const conference = getCurrentConference(state);
|
||||
const localAudio = getLocalJitsiAudioTrack(state);
|
||||
const localScreenshare = getLocalDesktopTrack(state['features/base/tracks']);
|
||||
|
||||
// Toggle screenshare or audio-only share if the new state is not passed. Happens in the following two cases.
|
||||
// 1. ShareAudioDialog passes undefined when the user hits continue in the share audio demo modal.
|
||||
@@ -201,16 +198,11 @@ async function _toggleScreenSharing(
|
||||
throw new Error(AUDIO_ONLY_SCREEN_SHARE_NO_TRACK);
|
||||
}
|
||||
} else if (desktopVideoTrack) {
|
||||
await dispatch(executeTrackOperation(TrackOperationType.Video, async () => {
|
||||
const localScreenshare = getLocalDesktopTrack(getState()['features/base/tracks']);
|
||||
|
||||
if (localScreenshare) {
|
||||
await dispatch(replaceLocalTrack(localScreenshare.jitsiTrack, desktopVideoTrack, conference));
|
||||
} else {
|
||||
await dispatch(addLocalTrack(desktopVideoTrack));
|
||||
}
|
||||
}));
|
||||
|
||||
if (localScreenshare) {
|
||||
await dispatch(replaceLocalTrack(localScreenshare.jitsiTrack, desktopVideoTrack, conference));
|
||||
} else {
|
||||
await dispatch(addLocalTrack(desktopVideoTrack));
|
||||
}
|
||||
if (isScreenshotCaptureEnabled(state, false, true)) {
|
||||
dispatch(toggleScreenshotCaptureSummary(true));
|
||||
}
|
||||
@@ -223,31 +215,26 @@ async function _toggleScreenSharing(
|
||||
// Noise suppression doesn't work with desktop audio because we can't chain track effects yet, disable it
|
||||
// first. We need to to wait for the effect to clear first or it might interfere with the audio mixer.
|
||||
await dispatch(setNoiseSuppressionEnabled(false));
|
||||
_maybeApplyAudioMixerEffect(desktopAudioTrack, state);
|
||||
dispatch(setScreenshareAudioTrack(desktopAudioTrack));
|
||||
|
||||
dispatch(executeTrackOperation(TrackOperationType.Audio,
|
||||
() => {
|
||||
const result = _maybeApplyAudioMixerEffect(desktopAudioTrack, state);
|
||||
|
||||
dispatch(setScreenshareAudioTrack(desktopAudioTrack));
|
||||
|
||||
// Handle the case where screen share was stopped from the browsers 'screen share in progress'
|
||||
// window.
|
||||
if (audioOnly) {
|
||||
desktopAudioTrack?.on(
|
||||
JitsiTrackEvents.LOCAL_TRACK_STOPPED,
|
||||
() => dispatch(toggleScreensharing(undefined, true)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}));
|
||||
// Handle the case where screen share was stopped from the browsers 'screen share in progress' window.
|
||||
if (audioOnly) {
|
||||
desktopAudioTrack?.on(
|
||||
JitsiTrackEvents.LOCAL_TRACK_STOPPED,
|
||||
() => dispatch(toggleScreensharing(undefined, true)));
|
||||
}
|
||||
}
|
||||
|
||||
// Disable audio-only or best performance mode if the user starts screensharing. This doesn't apply to
|
||||
// audio-only screensharing.
|
||||
// Show notification about more bandwidth usage in audio-only mode if the user starts screensharing. This
|
||||
// doesn't apply to audio-only screensharing.
|
||||
const { enabled: bestPerformanceMode } = state['features/base/audio-only'];
|
||||
|
||||
if (bestPerformanceMode && !audioOnly) {
|
||||
dispatch(setAudioOnly(false));
|
||||
dispatch(showNotification({
|
||||
titleKey: 'notify.screenSharingAudioOnlyTitle',
|
||||
descriptionKey: 'notify.screenSharingAudioOnlyDescription'
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
|
||||
}
|
||||
} else {
|
||||
const { desktopAudioTrack } = state['features/screen-share'];
|
||||
@@ -256,25 +243,16 @@ async function _toggleScreenSharing(
|
||||
|
||||
dispatch(toggleScreenshotCaptureSummary(false));
|
||||
|
||||
await dispatch(executeTrackOperation(TrackOperationType.Video, () => {
|
||||
// Mute the desktop track instead of removing it from the conference since we don't want the client to
|
||||
// signal a source-remove to the remote peer for the screenshare track. Later when screenshare is enabled
|
||||
// again, the same sender will be re-used without the need for signaling a new ssrc through source-add.
|
||||
dispatch(setScreenshareMuted(true));
|
||||
|
||||
return Promise.resolve();
|
||||
}));
|
||||
|
||||
// Mute the desktop track instead of removing it from the conference since we don't want the client to signal
|
||||
// a source-remove to the remote peer for the screenshare track. Later when screenshare is enabled again, the
|
||||
// same sender will be re-used without the need for signaling a new ssrc through source-add.
|
||||
dispatch(setScreenshareMuted(true));
|
||||
if (desktopAudioTrack) {
|
||||
await dispatch(executeTrackOperation(TrackOperationType.Audio, async () => {
|
||||
const localAudio = getLocalJitsiAudioTrack(state);
|
||||
|
||||
if (localAudio) {
|
||||
await localAudio.setEffect(undefined);
|
||||
} else {
|
||||
await conference.replaceTrack(desktopAudioTrack, null);
|
||||
}
|
||||
}));
|
||||
if (localAudio) {
|
||||
localAudio.setEffect(undefined);
|
||||
} else {
|
||||
await conference.replaceTrack(desktopAudioTrack, null);
|
||||
}
|
||||
desktopAudioTrack.dispose();
|
||||
dispatch(setScreenshareAudioTrack(null));
|
||||
}
|
||||
@@ -287,101 +265,3 @@ async function _toggleScreenSharing(
|
||||
APP.API.notifyScreenSharingStatusChanged(enable, screensharingDetails);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes a track operation.
|
||||
*
|
||||
* @param {TrackOperationType} type - The type of the operation ('audio', 'video' or 'audio-video').
|
||||
* @param {Function} operation - The operation.
|
||||
* @returns {{
|
||||
* type: SET_TRACK_OPERATIONS_PROMISE,
|
||||
* audioTrackOperationsPromise: Promise<void>,
|
||||
* videoTrackOperationsPromise: Promise<void>
|
||||
* }}
|
||||
*/
|
||||
export function executeTrackOperation(type: TrackOperationType, operation: () => Promise<any>) {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const {
|
||||
audioTrackOperationsPromise,
|
||||
videoTrackOperationsPromise
|
||||
} = getState()['features/base/track-operations'];
|
||||
|
||||
switch (type) {
|
||||
case TrackOperationType.Audio: {
|
||||
const promise = audioTrackOperationsPromise.then(operation, operation);
|
||||
|
||||
dispatch({
|
||||
type: SET_TRACK_OPERATIONS_PROMISE,
|
||||
audioTrackOperationsPromise: promise
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
case TrackOperationType.Video: {
|
||||
const promise = videoTrackOperationsPromise.then(operation, operation);
|
||||
|
||||
dispatch({
|
||||
type: SET_TRACK_OPERATIONS_PROMISE,
|
||||
videoTrackOperationsPromise: promise
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
case TrackOperationType.AudioVideo: {
|
||||
const promise = Promise.allSettled([
|
||||
audioTrackOperationsPromise,
|
||||
videoTrackOperationsPromise
|
||||
]).then(operation);
|
||||
|
||||
dispatch({
|
||||
type: SET_TRACK_OPERATIONS_PROMISE,
|
||||
audioTrackOperationsPromise: promise,
|
||||
videoTrackOperationsPromise: promise
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
default: {
|
||||
const unexpectedType: never = type;
|
||||
|
||||
return Promise.reject(new Error(`Unexpected track operation type: ${unexpectedType}`));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the facingMode constraint on the video stream.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function toggleCamera() {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) =>
|
||||
dispatch(executeTrackOperation(TrackOperationType.Video, () =>
|
||||
|
||||
/**
|
||||
* FIXME: Ideally, we should be dispatching {@code replaceLocalTrack} here,
|
||||
* but it seems to not trigger the re-rendering of the local video on Chrome;
|
||||
* could be due to a plan B vs unified plan issue. Therefore, we use the legacy
|
||||
* method defined in conference.js that manually takes care of updating the local
|
||||
* video as well.
|
||||
*/
|
||||
APP.conference.useVideoStream(null).then(() => {
|
||||
const state = getState();
|
||||
const tracks = state['features/base/tracks'];
|
||||
const localVideoTrack = getLocalVideoTrack(tracks)?.jitsiTrack;
|
||||
const currentFacingMode = localVideoTrack.getCameraFacingMode();
|
||||
|
||||
const targetFacingMode = currentFacingMode === CAMERA_FACING_MODE.USER
|
||||
? CAMERA_FACING_MODE.ENVIRONMENT
|
||||
: CAMERA_FACING_MODE.USER;
|
||||
|
||||
// Update the flipX value so the environment facing camera is not flipped, before the new track is
|
||||
// created.
|
||||
dispatch(updateSettings({ localFlipX: targetFacingMode === CAMERA_FACING_MODE.USER }));
|
||||
|
||||
return createLocalTrack('video', null, null, { facingMode: targetFacingMode });
|
||||
})
|
||||
.then((newVideoTrack: any) => APP.conference.useVideoStream(newVideoTrack))));
|
||||
}
|
||||
|
||||
@@ -313,9 +313,9 @@ export function isLocalTrackMuted(tracks: ITrack[], mediaType: MediaType) {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isLocalVideoTrackDesktop(state: IReduxState) {
|
||||
const videoTrack = getLocalVideoTrack(getTrackState(state));
|
||||
const desktopTrack = getLocalDesktopTrack(getTrackState(state));
|
||||
|
||||
return videoTrack && videoTrack.videoType === VIDEO_TYPE.DESKTOP;
|
||||
return desktopTrack !== undefined && !desktopTrack.muted;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,12 +9,10 @@ import {
|
||||
getUserSelectedMicDeviceId
|
||||
} from '../settings/functions.web';
|
||||
|
||||
import { executeTrackOperation } from './actions.web';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import loadEffects from './loadEffects';
|
||||
import logger from './logger';
|
||||
import { ITrackOptions, TrackOperationType } from './types';
|
||||
import { ITrackOptions } from './types';
|
||||
|
||||
export * from './functions.any';
|
||||
|
||||
@@ -109,15 +107,14 @@ export function createPrejoinTracks() {
|
||||
const initialDevices = [ 'audio' ];
|
||||
const requestedAudio = true;
|
||||
let requestedVideo = false;
|
||||
const { dispatch, getState } = APP.store;
|
||||
const { startAudioOnly, startWithAudioMuted, startWithVideoMuted } = getState()['features/base/settings'];
|
||||
const { startAudioOnly, startWithAudioMuted, startWithVideoMuted } = APP.store.getState()['features/base/settings'];
|
||||
|
||||
// Always get a handle on the audio input device so that we have statistics even if the user joins the
|
||||
// conference muted. Previous implementation would only acquire the handle when the user first unmuted,
|
||||
// which would results in statistics ( such as "No audio input" or "Are you trying to speak?") being available
|
||||
// only after that point.
|
||||
if (startWithAudioMuted) {
|
||||
dispatch(executeTrackOperation(TrackOperationType.Audio, () => dispatch(setAudioMuted(true))));
|
||||
APP.store.dispatch(setAudioMuted(true));
|
||||
}
|
||||
|
||||
if (!startWithVideoMuted && !startAudioOnly) {
|
||||
@@ -131,11 +128,10 @@ export function createPrejoinTracks() {
|
||||
// Resolve with no tracks
|
||||
tryCreateLocalTracks = Promise.resolve([]);
|
||||
} else {
|
||||
tryCreateLocalTracks = dispatch(executeTrackOperation(TrackOperationType.AudioVideo, () =>
|
||||
createLocalTracksF({
|
||||
devices: initialDevices,
|
||||
firePermissionPromptIsShownEvent: true
|
||||
}, APP.store)
|
||||
tryCreateLocalTracks = createLocalTracksF({
|
||||
devices: initialDevices,
|
||||
firePermissionPromptIsShownEvent: true
|
||||
}, APP.store)
|
||||
.catch((err: Error) => {
|
||||
if (requestedAudio && requestedVideo) {
|
||||
|
||||
@@ -181,7 +177,7 @@ export function createPrejoinTracks() {
|
||||
errors.videoOnlyError = err;
|
||||
|
||||
return [];
|
||||
})));
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,17 +1,42 @@
|
||||
import { batch } from 'react-redux';
|
||||
|
||||
import { IStore } from '../../app/types';
|
||||
import { _RESET_BREAKOUT_ROOMS } from '../../breakout-rooms/actionTypes';
|
||||
import { isPrejoinPageVisible } from '../../prejoin/functions';
|
||||
import { getCurrentConference } from '../conference/functions';
|
||||
import { getMultipleVideoSendingSupportFeatureFlag } from '../config/functions.any';
|
||||
import {
|
||||
SET_AUDIO_MUTED,
|
||||
SET_CAMERA_FACING_MODE,
|
||||
SET_SCREENSHARE_MUTED,
|
||||
SET_VIDEO_MUTED,
|
||||
TOGGLE_CAMERA_FACING_MODE
|
||||
} from '../media/actionTypes';
|
||||
import { toggleCameraFacingMode } from '../media/actions';
|
||||
import {
|
||||
CAMERA_FACING_MODE,
|
||||
MEDIA_TYPE,
|
||||
MediaType
|
||||
MediaType,
|
||||
SCREENSHARE_MUTISM_AUTHORITY,
|
||||
VIDEO_MUTISM_AUTHORITY
|
||||
} from '../media/constants';
|
||||
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
import StateListenerRegistry from '../redux/StateListenerRegistry';
|
||||
|
||||
import { TRACK_UPDATED } from './actionTypes';
|
||||
import { getLocalTrack } from './functions';
|
||||
import {
|
||||
TRACK_UPDATED
|
||||
} from './actionTypes';
|
||||
import {
|
||||
createLocalTracksA,
|
||||
destroyLocalTracks,
|
||||
trackMuteUnmuteFailed,
|
||||
trackRemoved
|
||||
} from './actions';
|
||||
import {
|
||||
getLocalTrack,
|
||||
isUserInteractionRequiredForUnmute,
|
||||
setTrackMuted
|
||||
} from './functions';
|
||||
import './subscriber';
|
||||
|
||||
/**
|
||||
@@ -24,6 +49,15 @@ import './subscriber';
|
||||
*/
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
switch (action.type) {
|
||||
case SET_AUDIO_MUTED:
|
||||
if (!action.muted
|
||||
&& isUserInteractionRequiredForUnmute(store.getState())) {
|
||||
return;
|
||||
}
|
||||
|
||||
_setMuted(store, action, MEDIA_TYPE.AUDIO);
|
||||
break;
|
||||
|
||||
case SET_CAMERA_FACING_MODE: {
|
||||
// XXX The camera facing mode of a MediaStreamTrack can be specified
|
||||
// only at initialization time and then it can only be toggled. So in
|
||||
@@ -44,6 +78,19 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
break;
|
||||
}
|
||||
|
||||
case SET_SCREENSHARE_MUTED:
|
||||
_setMuted(store, action, MEDIA_TYPE.SCREENSHARE);
|
||||
break;
|
||||
|
||||
case SET_VIDEO_MUTED:
|
||||
if (!action.muted
|
||||
&& isUserInteractionRequiredForUnmute(store.getState())) {
|
||||
return;
|
||||
}
|
||||
|
||||
_setMuted(store, action, MEDIA_TYPE.VIDEO);
|
||||
break;
|
||||
|
||||
case TOGGLE_CAMERA_FACING_MODE: {
|
||||
const localTrack = _getLocalTrack(store, MEDIA_TYPE.VIDEO);
|
||||
let jitsiTrack;
|
||||
@@ -74,6 +121,31 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
return next(action);
|
||||
});
|
||||
|
||||
/**
|
||||
* Set up state change listener to perform maintenance tasks when the conference
|
||||
* is left or failed, remove all tracks from the store.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
state => getCurrentConference(state),
|
||||
(conference, { dispatch, getState }, prevConference) => {
|
||||
const { authRequired, error } = getState()['features/base/conference'];
|
||||
|
||||
// conference keep flipping while we are authenticating, skip clearing while we are in that process
|
||||
if (prevConference && !conference && !authRequired && !error) {
|
||||
|
||||
// Clear all tracks.
|
||||
const remoteTracks = getState()['features/base/tracks'].filter(t => !t.local);
|
||||
|
||||
batch(() => {
|
||||
dispatch(destroyLocalTracks());
|
||||
for (const track of remoteTracks) {
|
||||
dispatch(trackRemoved(track.jitsiTrack));
|
||||
}
|
||||
dispatch({ type: _RESET_BREAKOUT_ROOMS });
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets the local track associated with a specific {@code MEDIA_TYPE} in a
|
||||
* specific redux store.
|
||||
@@ -101,3 +173,48 @@ function _getLocalTrack(
|
||||
mediaType,
|
||||
includePending));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutes or unmutes a local track with a specific media type.
|
||||
*
|
||||
* @param {Store} store - The redux store in which the specified action is
|
||||
* dispatched.
|
||||
* @param {Action} action - The redux action dispatched in the specified store.
|
||||
* @param {MEDIA_TYPE} mediaType - The {@link MEDIA_TYPE} of the local track
|
||||
* which is being muted or unmuted.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
async function _setMuted(store: IStore, { ensureTrack, authority, muted }: {
|
||||
authority: number; ensureTrack: boolean; muted: boolean; }, mediaType: MediaType) {
|
||||
const { dispatch, getState } = store;
|
||||
const localTrack = _getLocalTrack(store, mediaType, /* includePending */ true);
|
||||
const state = getState();
|
||||
|
||||
if (mediaType === MEDIA_TYPE.SCREENSHARE
|
||||
&& getMultipleVideoSendingSupportFeatureFlag(state)
|
||||
&& !muted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (localTrack) {
|
||||
// The `jitsiTrack` property will have a value only for a localTrack for which `getUserMedia` has already
|
||||
// completed. If there's no `jitsiTrack`, then the `muted` state will be applied once the `jitsiTrack` is
|
||||
// created.
|
||||
const { jitsiTrack } = localTrack;
|
||||
const isAudioOnly = (mediaType === MEDIA_TYPE.VIDEO && authority === VIDEO_MUTISM_AUTHORITY.AUDIO_ONLY)
|
||||
|| (mediaType === MEDIA_TYPE.SCREENSHARE && authority === SCREENSHARE_MUTISM_AUTHORITY.AUDIO_ONLY);
|
||||
|
||||
// Screenshare cannot be unmuted using the video mute button unless it is muted by audioOnly in the legacy
|
||||
// screensharing mode.
|
||||
if (jitsiTrack && (
|
||||
jitsiTrack.videoType !== 'desktop' || isAudioOnly || getMultipleVideoSendingSupportFeatureFlag(state))
|
||||
) {
|
||||
setTrackMuted(jitsiTrack, muted, state).catch(() => dispatch(trackMuteUnmuteFailed(localTrack, muted)));
|
||||
}
|
||||
} else if (!muted && ensureTrack && (typeof APP === 'undefined' || isPrejoinPageVisible(state))) {
|
||||
// FIXME: This only runs on mobile now because web has its own way of
|
||||
// creating local tracks. Adjust the check once they are unified.
|
||||
dispatch(createLocalTracksA({ devices: [ mediaType ] }));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import {
|
||||
TRACK_UPDATED
|
||||
} from './actionTypes';
|
||||
import {
|
||||
executeTrackOperation,
|
||||
showNoDataFromSourceVideoError,
|
||||
toggleScreensharing,
|
||||
trackNoDataFromSourceNotificationInfoChanged
|
||||
@@ -26,7 +25,7 @@ import {
|
||||
import {
|
||||
getTrackByJitsiTrack
|
||||
} from './functions.web';
|
||||
import { ITrack, TrackOperationType } from './types';
|
||||
import { ITrack } from './types';
|
||||
|
||||
import './middleware.any';
|
||||
|
||||
@@ -68,10 +67,9 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
const { jitsiTrack } = action.track;
|
||||
const muted = action.wasMuted;
|
||||
const isVideoTrack = jitsiTrack.getType() !== MEDIA_TYPE.AUDIO;
|
||||
const { dispatch } = store;
|
||||
|
||||
if (isVideoTrack && jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP) {
|
||||
dispatch(executeTrackOperation(TrackOperationType.Video, () => dispatch(setScreenshareMuted(!muted))));
|
||||
store.dispatch(setScreenshareMuted(!muted));
|
||||
} else if (isVideoTrack) {
|
||||
APP.conference.setVideoMuteStatus();
|
||||
} else {
|
||||
|
||||
@@ -4,7 +4,6 @@ import { set } from '../redux/functions';
|
||||
|
||||
import {
|
||||
SET_NO_SRC_DATA_NOTIFICATION_UID,
|
||||
SET_TRACK_OPERATIONS_PROMISE,
|
||||
TRACK_ADDED,
|
||||
TRACK_CREATE_CANCELED,
|
||||
TRACK_CREATE_ERROR,
|
||||
@@ -153,31 +152,3 @@ ReducerRegistry.register<INoSrcDataState>('features/base/no-src-data', (state =
|
||||
}
|
||||
});
|
||||
|
||||
export interface ITrackOperations {
|
||||
audioTrackOperationsPromise: Promise<void>;
|
||||
videoTrackOperationsPromise: Promise<void>;
|
||||
}
|
||||
|
||||
const DEFAULT_TRACK_OPERATIONS_STATE = {
|
||||
audioTrackOperationsPromise: Promise.resolve(),
|
||||
videoTrackOperationsPromise: Promise.resolve()
|
||||
};
|
||||
|
||||
/**
|
||||
* Listen for actions that mutate the no-src-data state, like the current notification id.
|
||||
*/
|
||||
ReducerRegistry.register<ITrackOperations>(
|
||||
'features/base/track-operations',
|
||||
(state = DEFAULT_TRACK_OPERATIONS_STATE, action): ITrackOperations => {
|
||||
switch (action.type) {
|
||||
case SET_TRACK_OPERATIONS_PROMISE:
|
||||
return {
|
||||
...state,
|
||||
audioTrackOperationsPromise: action.audioTrackOperationsPromise || state.audioTrackOperationsPromise,
|
||||
videoTrackOperationsPromise: action.videoTrackOperationsPromise || state.videoTrackOperationsPromise
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import _ from 'lodash';
|
||||
import { batch } from 'react-redux';
|
||||
|
||||
import { _RESET_BREAKOUT_ROOMS } from '../../breakout-rooms/actionTypes';
|
||||
import { getCurrentConference } from '../conference/functions';
|
||||
import { MEDIA_TYPE } from '../media/constants';
|
||||
import { getScreenshareParticipantIds } from '../participants/functions';
|
||||
import StateListenerRegistry from '../redux/StateListenerRegistry';
|
||||
|
||||
import { destroyLocalTracks, trackRemoved } from './actions.any';
|
||||
import { isLocalTrackMuted } from './functions';
|
||||
|
||||
/**
|
||||
@@ -42,28 +38,3 @@ StateListenerRegistry.register(
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Set up state change listener to perform maintenance tasks when the conference
|
||||
* is left or failed, remove all tracks from the store.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
state => getCurrentConference(state),
|
||||
(conference, { dispatch, getState }, prevConference) => {
|
||||
const { authRequired, error } = getState()['features/base/conference'];
|
||||
|
||||
// conference keep flipping while we are authenticating, skip clearing while we are in that process
|
||||
if (prevConference && !conference && !authRequired && !error) {
|
||||
|
||||
// Clear all tracks.
|
||||
const remoteTracks = getState()['features/base/tracks'].filter(t => !t.local);
|
||||
|
||||
batch(() => {
|
||||
dispatch(destroyLocalTracks());
|
||||
for (const track of remoteTracks) {
|
||||
dispatch(trackRemoved(track.jitsiTrack));
|
||||
}
|
||||
dispatch({ type: _RESET_BREAKOUT_ROOMS });
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -72,9 +72,3 @@ export interface IShareOptions {
|
||||
desktopSharingSources?: string[];
|
||||
desktopStream?: any;
|
||||
}
|
||||
|
||||
export enum TrackOperationType {
|
||||
Audio = 'audio',
|
||||
AudioVideo = 'audio-video',
|
||||
Video = 'video'
|
||||
}
|
||||
|
||||
@@ -90,8 +90,8 @@ const Button: React.FC<IProps> = ({
|
||||
return (
|
||||
<NativePaperButton
|
||||
accessibilityLabel = { t(accessibilityLabel ?? '') }
|
||||
buttonColor = { color }
|
||||
children = { t(labelKey ?? '') }
|
||||
color = { color }
|
||||
contentStyle = { [
|
||||
styles.buttonContent,
|
||||
contentStyle
|
||||
|
||||
@@ -34,6 +34,11 @@ export interface IButtonProps {
|
||||
*/
|
||||
onClick?: (e?: React.MouseEvent<HTMLButtonElement> | GestureResponderEvent) => void;
|
||||
|
||||
/**
|
||||
* Key press callback.
|
||||
*/
|
||||
onKeyPress?: (e?: React.KeyboardEvent<HTMLButtonElement>) => void;
|
||||
|
||||
/**
|
||||
* The type of button to be displayed.
|
||||
*/
|
||||
|
||||
@@ -187,6 +187,7 @@ const Button = React.forwardRef<any, any>(({
|
||||
label,
|
||||
labelKey,
|
||||
onClick = () => null,
|
||||
onKeyPress = () => null,
|
||||
size = 'medium',
|
||||
testId,
|
||||
type = BUTTON_TYPES.PRIMARY
|
||||
@@ -206,6 +207,7 @@ const Button = React.forwardRef<any, any>(({
|
||||
disabled = { disabled }
|
||||
{ ...(id ? { id } : {}) }
|
||||
onClick = { onClick }
|
||||
onKeyPress = { onKeyPress }
|
||||
ref = { ref }
|
||||
title = { accessibilityLabel }
|
||||
type = { isSubmit ? 'submit' : 'button' }>
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { parseURLParams } from './parseURLParams';
|
||||
import { normalizeNFKC } from './strings';
|
||||
|
||||
/**
|
||||
* Http status codes.
|
||||
*/
|
||||
export enum StatusCode {
|
||||
PaymentRequired = 402
|
||||
}
|
||||
|
||||
/**
|
||||
* The app linking scheme.
|
||||
* TODO: This should be read from the manifest files later.
|
||||
|
||||
@@ -6,7 +6,8 @@ import type { Dispatch } from 'redux';
|
||||
import { v4 as uuidV4 } from 'uuid';
|
||||
import { findWindows } from 'windows-iana';
|
||||
|
||||
import { createDeferred, parseStandardURIString, parseURLParams } from '../../base/util';
|
||||
import { createDeferred } from '../../../../modules/util/helpers';
|
||||
import { parseStandardURIString, parseURLParams } from '../../base/util';
|
||||
import { getShareInfoText } from '../../invite';
|
||||
import { setCalendarAPIAuthState } from '../actions';
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import { getLogger } from '../base/logging/functions';
|
||||
|
||||
export default getLogger('features/chrome-banner');
|
||||