Compare commits

..

45 Commits

Author SHA1 Message Date
Alex Bumbu
95ccc2cbe1 fix methods naming for swift 2022-09-14 16:17:42 +03:00
Alex Bumbu
468d77c3d6 feat(iOS): callkit objc implementation 2022-09-14 16:17:42 +03:00
Gabriel Borlea
d6f3c2a0f4 ref(face-landmarks): convert to typescript and add detector class (#12144)
* fix(face-landmarks): stop recognition when imageCapture error

* ref(face-landmarks): convert files in typescript

fix: lint issues

* code review

* ref(face-landmarks): move detection part to a class

* ref(face-landmarks): make FaceLandmarksDetector singleton

* fix typo and ts-ignore problematic types

* fix linting issues
2022-09-14 15:42:46 +03:00
tmoldovan8x8
b83c55e9c4 fix(rn) fixes typo in functions.native 2022-09-14 14:49:13 +03:00
Robert Pintilii
a1d20dc188 ref(TS) Convert some features to TS (#12149)
Convert AV Moderation and Breakout Rooms to TS
2022-09-14 14:32:58 +03:00
Robert Pintilii
95084e1004 ref(TS) Convert some base features to TS (#12138) 2022-09-14 10:54:56 +03:00
Saúl Ibarra Corretgé
5502601fb3 fix(subtitles) web components must not be used in generic action files 2022-09-13 16:17:10 +02:00
Saúl Ibarra Corretgé
3fa72c99bc fix(rn,conference) fix mobile build
Looks like Metro is confused by these imports.
2022-09-13 16:17:10 +02:00
Дамян Минков
079a2a505d feat: Adds LE choice when installing debian package. (#12154)
* feat: Adds LE choice when installing debian package.

* Update debian/jitsi-meet-web-config.templates

Co-authored-by: raluca8x8 <raluca.tocmag@8x8.com>

* squash: Print in the console the JaaS link everytime.

* squash: Note that JaaS does not support self-signed certs.

* squash: Fix message.

* squash: Moves acme.sh stuff into a script, so it is easy to re-run.

Co-authored-by: raluca8x8 <raluca.tocmag@8x8.com>
2022-09-13 07:55:00 -05:00
Robert Pintilii
139884fbe7 ref(dep) Upgrade MUI (#12089) 2022-09-13 10:36:00 +03:00
Misha
3ef3233242 ref(conn-indicator): remove E2E RTT (#12139)
There was a fundamental change in how e2e pings work in lib-jitsi-meet where it does few pings at the beginning, pushes metrics and shuts the whole thing down, so there are no more e2ertt updates after that. Plus it's disabled by default. @paweldomas have decided with @bgrozev to remove that instead of trying to adjust. Even if e2e pings are enabled the data is not feed correctly to the indicators, what's wrong there is as soon as the pings stop going the new data does not arrive and then all you get is N/A if the UI component is recreated.
2022-09-12 15:57:15 -05:00
JohnProv
443f4e4feb fix(lang) update Dutch translation 2022-09-12 19:28:25 +02:00
Alexandru Petrus
21a1d52753 fix(large-video) disable screen-sharing placeholder on Spot
Temporary hack, this should likely be configurable.
2022-09-12 18:00:02 +02:00
Bogdan Duduman
0f63e560b0 feat(external_api) add adbility to resize the filmstrip 2022-09-12 14:08:55 +02:00
Horatiu Muresan
43bea201e6 fix(prejoin) Hide conference name based on config 2022-09-12 10:35:37 +03:00
Horatiu Muresan
6e1e6df952 fix(prejoin) Fix roomname showing for 3rd party prejoin app (#12155)
* fix(prejoin) Fix roomname showing for 3rd party prejoin app

* fix: Do not convert roomName to string when undefined.

Co-authored-by: damencho <damencho@jitsi.org>
2022-09-09 12:10:50 -05:00
Saúl Ibarra Corretgé
8ce1423373 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1496.0.0+e1ca2f5a...v1498.0.0+bc3aae02
2022-09-09 16:57:08 +02:00
Saúl Ibarra Corretgé
ede97584f2 fix(ios) fix lite SDK release process 2022-09-09 13:37:08 +02:00
Robert Pintilii
247c54b6c6 ref(TS) Convert constants tiles to TS (#12148)
Remove unnecessary ts-ignores
2022-09-09 12:22:30 +03:00
Robert Pintilii
10bb186c13 ref(eslint) Use new TypeScript ESlint config (#12143)
Use new TS config from @jitsi/eslint
Fix all lint errors
2022-09-08 12:52:36 +03:00
Artur Shepilko
e296008d95 lang: update Ukrainian translation 2022-09-07 18:33:00 -05:00
Jaya Allamsetty
01001d6438 fix(large-video) Update large-video when the streamingStatus of the attached track changes.
This fixes an issue where screenshare appears on the thumbnail but not on the large-video.
2022-09-07 18:31:23 -04:00
damencho
fce15b491d feat: Adds jaas choice when installing. 2022-09-07 08:21:12 -05:00
damencho
cf37ba8771 feat: Drops prosody 0.10 checks. 2022-09-07 08:21:12 -05:00
damencho
0350f18e68 feat: Drops migration from jetty deployments. 2022-09-07 08:21:12 -05:00
Robert Pintilii
c9bbc6c762 ref(TS) Remove unnecessary ts-ignores (#12136) 2022-09-07 11:20:05 +03:00
Christoph Settgast
fa942e9f3b fix(lang) update German translation (#12122)
Signed-off-by: Christoph Settgast <csett86@web.de>
2022-09-07 09:13:19 +02:00
Robert Pintilii
fd67fb652b fix(analytics) Fix lint error (#12135) 2022-09-07 09:54:31 +03:00
Ali Alhaidary
a87d4f4a1d fix(lang) updated Arabic translation 2022-09-06 19:32:47 +02:00
Robert Pintilii
efb69d5382 ref: Improve TS files (#12130)
Remove unnecessary ts-ignores
Change any to actual types
Fix eslint rule
2022-09-06 20:32:20 +03:00
Flying-Light
db988f6e62 fix(lang) improve Arabic translation
Modify some translations for their difficulty for the user.
Add some missing translations like "ask to unmute"
2022-09-06 19:27:44 +02:00
Robert Pintilii
f4b46128bc ref(analytics) Convert to TS (#12099) 2022-09-06 15:51:50 +03:00
Gabriel Borlea
9323b86e3c feat(rtc-stats): support for react native and breakout rooms (#11835)
* feat(rtc-stats): mobile flow

* fix(rtc-stats): create websocket connection event

* feat(rtc-stats): separate middlewares and filter callstats pcs

* fix: linting problems

* fix: linting problems 2

* fix(rtc-stats): middlewares

* ref(rtc-stats): rewrite in typescript

* remove blank line and flow tag

* fix: linting problems

* remove redundant comment

* remove index file

* fix: sort interface keys

* feat(rtc-stats): support for breakout rooms

* ref(rtc-stats): send isBreakoutRoom flag when connecting to rtc stats

* code review

* fix(rtc-stats): rebase issues

* remove empty lines

* chore(rtc-stats): update rtc-stats to latest version

* fix: linting issues
2022-09-06 10:42:59 +03:00
Saúl Ibarra Corretgé
06842c724a fix(rn,video-layout) fix mobile
In adcd9a501b a call to getCurrentLayout
was introduced, which is not mobile-friendly :-(
2022-09-06 09:27:47 +02:00
Duduman Bogdan Vlad
5f62acc67c fix(external_api): Fix number of participants in meeting (#12052) 2022-09-06 09:51:38 +03:00
Robert Pintilii
17008237dc ref: Improve TS state (#12125)
Create IStateful interface
Use IState interface everywhere
Remove unnecessary @ts-ignore
2022-09-05 14:24:13 +03:00
Robert Pintilii
271ea8315b ref: Improve reducers TS (#12123) 2022-09-05 12:05:07 +03:00
Alexey Matveev
f18f8c1061 fix(lang) update Russian translation 2022-09-05 10:22:13 +02:00
Saúl Ibarra Corretgé
b535b8c583 fix(lobby) fix opening lobby chat after API change 2022-09-01 14:21:32 -05:00
Hristo Terezov
adcd9a501b ref(receiver-constraints): Refactor and fixes. 2022-09-01 13:22:09 -05:00
Saúl Ibarra Corretgé
cfb1fef162 fix(breakout-rooms) fix broadcast timer 2022-09-01 18:19:29 +02:00
Saúl Ibarra Corretgé
8b4f2495dc fixup! 2022-09-01 17:13:33 +02:00
Saúl Ibarra Corretgé
7e7107d45a feat(build,ljm) don't expose jquery
lib-jitsi-meet no longer requires it.
2022-09-01 17:13:33 +02:00
Saúl Ibarra Corretgé
45c0597aff chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1494.0.0+c9be46e2...v1496.0.0+e1ca2f5a
2022-09-01 17:12:50 +02:00
Calinteodor
c77e2c8301 feat(settings/native): fixes and updates (#12094)
feat(settings/native): fixes and updates
2022-09-01 15:05:14 +03:00
518 changed files with 7786 additions and 6219 deletions

View File

@@ -21,5 +21,5 @@ jobs:
- run: npm run lint
- run: for file in lang/*.json; do npx --yes jsonlint -q $file || exit 1; done
- env:
NODE_OPTIONS: '--max-old-space-size=4096'
NODE_OPTIONS: '--max-old-space-size=8192'
run: make

6
app.js
View File

@@ -1,6 +1,10 @@
/* application specific logic */
import 'jquery';
// Re-export jQuery
// FIXME: Remove this requirement from torture tests.
import $ from 'jquery';
window.$ = window.jQuery = $;
import '@matrix-org/olm';

View File

@@ -22,6 +22,8 @@ if (subdomain.startsWith('<!--')) {
subdomain = '';
}
var enableJaaS = false;
var config = {
// Connection
//
@@ -1287,11 +1289,6 @@ var config = {
// {"countryCode":"US","tollFree":false,"formattedNumber":"+1 123-456-7890"}
// dialInConfCodeUrl is the conference mapper converting a meeting id to a PIN used for dial-in
// or the other way around (more info in resources/cloud-api.swagger)
//
// For JaaS customers the default values are:
// dialInNumbersUrl: 'https://conference-mapper.jitsi.net/v1/access/dids',
// dialInConfCodeUrl: 'https://conference-mapper.jitsi.net/v1/access',
//
// List of undocumented settings used in jitsi-meet
/**
@@ -1494,3 +1491,10 @@ var config = {
// Application logo url
// defaultLogoUrl: 'images/watermark.svg',
};
// Set the default values for JaaS customers
if (enableJaaS) {
config.dialInNumbersUrl = 'https://conference-mapper.jitsi.net/v1/access/dids';
config.dialInConfCodeUrl = 'https://conference-mapper.jitsi.net/v1/access';
config.roomPasswordNumberOfDigits = 10; // skip re-adding it (do not remove comment)
}

2
debian/control vendored
View File

@@ -20,7 +20,7 @@ Description: WebRTC JavaScript video conferences
Package: jitsi-meet-web-config
Architecture: all
Depends: openssl, nginx | nginx-full | nginx-extras | apache2
Depends: openssl, nginx | nginx-full | nginx-extras | apache2, curl
Description: Configuration for web serving of Jitsi Meet
Jitsi Meet is a WebRTC JavaScript application that uses Jitsi
Videobridge to provide high quality, scalable video conferences.

View File

@@ -1,2 +1,3 @@
doc/debian/jitsi-meet-prosody/prosody.cfg.lua-jvb.example /usr/share/jitsi-meet-prosody/
doc/debian/jitsi-meet-prosody/jaas.cfg.lua /usr/share/jitsi-meet-prosody/
resources/prosody-plugins/ /usr/share/jitsi-meet/

View File

@@ -83,6 +83,18 @@ case "$1" in
TURN_SECRET="$RET"
fi
db_get jitsi-meet/jaas-choice
JAAS_INPUT="$RET"
# In the case of updating from an older version the configure of -prosody package may happen before the -config
# one, so if JAAS_INPUT is empty (the question is not asked), let's ask it now.
if [ -z "$JAAS_INPUT" ] ; then
db_subst jitsi-meet/jaas-choice domain "${JVB_HOSTNAME}"
db_input critical jitsi-meet/jaas-choice || true
db_go
db_get jitsi-meet/jaas-choice
JAAS_INPUT="$RET"
fi
# and we're done with debconf
db_stop
@@ -141,7 +153,7 @@ case "$1" in
# New:
# Component "focus.jitmeet.example.com" "client_proxy"
# target_address = "focus@auth.jitmeet.example.com"
if grep -q "Component \"focus.$JVB_HOSTNAME\"" $PROSODY_HOST_CONFIG && ! grep "Component \"focus.$JVB_HOSTNAME\" \"client_proxy\"" $PROSODY_HOST_CONFIG ;then
if grep -q "Component \"focus.$JVB_HOSTNAME\"" $PROSODY_HOST_CONFIG && ! grep -q "Component \"focus.$JVB_HOSTNAME\" \"client_proxy\"" $PROSODY_HOST_CONFIG ;then
sed -i "s/Component \"focus.$JVB_HOSTNAME\"/Component \"focus.$JVB_HOSTNAME\" \"client_proxy\"\n target_address = \"$JICOFO_AUTH_USER@$JICOFO_AUTH_DOMAIN\"/g" $PROSODY_HOST_CONFIG
PROSODY_CONFIG_PRESENT="false"
fi
@@ -166,6 +178,29 @@ case "$1" in
PROSODY_CONFIG_PRESENT="false"
fi
JAAS_HOST_CONFIG="/etc/prosody/conf.avail/jaas.cfg.lua"
if [ "${JAAS_INPUT}" = "true" ] && [ ! -f $JAAS_HOST_CONFIG ]; then
sed -i "s/enabled = false -- Jitsi meet components/enabled = true -- Jitsi meet components/g" $PROSODY_HOST_CONFIG
PROSODY_CONFIG_PRESENT="false"
fi
# For those deployments that don't have the config in the jitsi-meet prosody config add the new jaas file
if [ ! -f $JAAS_HOST_CONFIG ] && ! grep -q "VirtualHost \"jigasi.meet.jitsi\"" $PROSODY_HOST_CONFIG; then
PROSODY_CONFIG_PRESENT="false"
cp /usr/share/jitsi-meet-prosody/jaas.cfg.lua $JAAS_HOST_CONFIG
sed -i "s/jitmeet.example.com/$JVB_HOSTNAME/g" $JAAS_HOST_CONFIG
fi
if [ "${JAAS_INPUT}" = "true" ]; then
JAAS_HOST_CONFIG_ENABLED="/etc/prosody/conf.d/jaas.cfg.lua "
if [ ! -f $JAAS_HOST_CONFIG_ENABLED ] && ! grep -q "VirtualHost \"jigasi.meet.jitsi\"" $PROSODY_HOST_CONFIG; then
if [ -f $JAAS_HOST_CONFIG ]; then
ln -s $JAAS_HOST_CONFIG $JAAS_HOST_CONFIG_ENABLED
PROSODY_CONFIG_PRESENT="false"
fi
fi
fi
# Make sure the focus@auth user's roster includes the proxy component (this is idempotent)
prosodyctl mod_roster_command subscribe focus.$JVB_HOSTNAME $JICOFO_AUTH_USER@$JICOFO_AUTH_DOMAIN
@@ -178,32 +213,6 @@ case "$1" in
ln -sf /var/lib/prosody/$JVB_HOSTNAME.crt /etc/prosody/certs/$JVB_HOSTNAME.crt
fi
PRTRUNK_INSTALL_CHECK="$(dpkg-query -f '${Status}' -W 'prosody-trunk' 2>/dev/null | awk '{print $3}' || true)"
PR10_INSTALL_CHECK="$(dpkg-query -f '${Status}' -W 'prosody-0.10' 2>/dev/null | awk '{print $3}' || true)"
PR_VER_INSTALLED=$(dpkg-query -f='${Version}\n' --show prosody 2>/dev/null || true)
if [ "$PRTRUNK_INSTALL_CHECK" = "installed" ] \
|| [ "$PRTRUNK_INSTALL_CHECK" = "unpacked" ] ; then
if [ -f $PROSODY_HOST_CONFIG ]; then
sed -i 's/storage = \"memory\"/storage = \"null\"/g' $PROSODY_HOST_CONFIG
# trigger a restart
PROSODY_CONFIG_PRESENT="false"
fi
fi
if [ "$PR10_INSTALL_CHECK" = "installed" ] \
|| [ "$PR10_INSTALL_CHECK" = "unpacked" ] \
|| dpkg --compare-versions "$PR_VER_INSTALLED" gt "0.10" ; then
# if the version is 0.10.X (>0.10 and <0.11)
if [ -f $PROSODY_HOST_CONFIG ] \
&& dpkg --compare-versions "$PR_VER_INSTALLED" lt "0.11" ; then
sed -i 's/storage = \"memory\"/storage = \"none\"/g' $PROSODY_HOST_CONFIG
# trigger a restart
PROSODY_CONFIG_PRESENT="false"
fi
fi
CERT_ADDED_TO_TRUST="false"
if [ ! -f /var/lib/prosody/$JICOFO_AUTH_DOMAIN.crt ]; then

View File

@@ -35,6 +35,8 @@ case "$1" in
if [ -n "$RET" ]; then
rm -f /etc/prosody/conf.avail/$JVB_HOSTNAME.cfg.lua
rm -f /etc/prosody/conf.d/$JVB_HOSTNAME.cfg.lua
rm -f /etc/prosody/conf.avail/jaas.cfg.lua
rm -f /etc/prosody/conf.d/jaas.cfg.lua
JICOFO_AUTH_DOMAIN="auth.$JVB_HOSTNAME"
# clean up generated certificates

View File

@@ -1,3 +1,2 @@
doc/debian/jitsi-meet-turn/turnserver.conf /usr/share/jitsi-meet-turnserver/
doc/debian/jitsi-meet/jitsi-meet.conf /usr/share/jitsi-meet-turnserver/
doc/debian/jitsi-meet-turn/coturn-certbot-deploy.sh /usr/share/jitsi-meet-turnserver/

View File

@@ -107,7 +107,9 @@ denied-peer-ip=240.0.0.0-255.255.255.255" >> $TURN_CONFIG
db_get jitsi-meet/cert-choice
CERT_CHOICE="$RET"
if [ "$CERT_CHOICE" = "I want to use my own certificate" ] ; then
UPLOADED_CERT_CHOICE="I want to use my own certificate"
LE_CERT_CHOICE="Let's Encrypt certificates"
if [ "$CERT_CHOICE" = "$UPLOADED_CERT_CHOICE" ]; then
db_get jitsi-meet/cert-path-key
CERT_KEY="$RET"
db_get jitsi-meet/cert-path-crt
@@ -120,22 +122,13 @@ denied-peer-ip=240.0.0.0-255.255.255.255" >> $TURN_CONFIG
CERT_CRT_ESC=$(echo $CERT_CRT | sed 's/\./\\\./g')
CERT_CRT_ESC=$(echo $CERT_CRT_ESC | sed 's/\//\\\//g')
sed -i "s/cert=\/etc\/jitsi\/meet\/.*crt/cert=$CERT_CRT_ESC/g" $TURN_CONFIG
elif [ "$CERT_CHOICE" = "$LE_CERT_CHOICE" ]; then
/usr/share/jitsi-meet/scripts/coturn-le-update.sh ${JVB_HOSTNAME}
fi
sed -i "s/#TURNSERVER_ENABLED/TURNSERVER_ENABLED/g" /etc/default/coturn
invoke-rc.d coturn restart || true
NGINX_STREAM_CONFIG="/etc/nginx/modules-enabled/60-jitsi-meet.conf"
if [ -f $NGINX_STREAM_CONFIG ] ; then
echo "------------------------------------------------"
echo ""
echo "You have multiplexing enabled, it is recommended to disable it and migrate to using websockets for the bridge channel."
echo "The support for sctp data channels is deprecated and will be dropped at some point."
echo "How to do it at: https://jitsi.org/multiplexing-to-bridge-ws-howto"
echo ""
echo "------------------------------------------------"
fi
# and we're done with debconf
db_stop
;;

View File

@@ -1,8 +0,0 @@
#!/bin/sh -e
# Source debconf library.
. /usr/share/debconf/confmodule
# certificate type choice
db_input critical jitsi-meet/cert-choice || true
db_go

View File

@@ -43,14 +43,6 @@ case "$1" in
rm -f /etc/jitsi/meet/$JVB_HOSTNAME_OLD-config.js
fi
JVB_SERVE="false"
# this detect only old installations
RET=""
db_get jitsi-meet/jvb-serve || true
if [ "$RET" = "true" ] ; then
JVB_SERVE="true"
fi
# stores the hostname so we will reuse it later, like in purge
db_set jitsi-meet/jvb-hostname $JVB_HOSTNAME
@@ -76,14 +68,23 @@ case "$1" in
FORCE_NGINX="false"
fi
db_subst jitsi-meet/jaas-choice domain "${JVB_HOSTNAME}"
db_input critical jitsi-meet/jaas-choice || true
db_go
db_get jitsi-meet/jaas-choice
JAAS_INPUT="$RET"
UPLOADED_CERT_CHOICE="I want to use my own certificate"
LE_CERT_CHOICE="Let's Encrypt certificates"
# if first time config ask for certs, or if we are reconfiguring
if [ -z "$JVB_HOSTNAME_OLD" ] || [ "$RECONFIGURING" = "true" ] ; then
RET=""
db_input critical jitsi-meet/cert-choice || true
db_go
db_get jitsi-meet/cert-choice
CERT_CHOICE="$RET"
if [ "$CERT_CHOICE" = "$UPLOADED_CERT_CHOICE" ] ; then
if [ "$CERT_CHOICE" = "$UPLOADED_CERT_CHOICE" ]; then
RET=""
db_get jitsi-meet/cert-path-key
if [ -z "$RET" ] ; then
@@ -103,7 +104,7 @@ case "$1" in
fi
CERT_CRT="$RET"
else
# create self-signed certs
# create self-signed certs (we also need them for the case of LE so we can start nginx)
CERT_KEY="/etc/jitsi/meet/$JVB_HOSTNAME.key"
CERT_CRT="/etc/jitsi/meet/$JVB_HOSTNAME.crt"
HOST="$( (hostname -s; echo localhost) | head -n 1)"
@@ -116,6 +117,17 @@ case "$1" in
-extensions SAN \
-config <(cat /etc/ssl/openssl.cnf \
<(printf "[SAN]\nsubjectAltName=DNS:localhost,DNS:$JVB_HOSTNAME"))
if [ "$CERT_CHOICE" = "$LE_CERT_CHOICE" ]; then
db_subst jitsi-meet/email domain "${JVB_HOSTNAME}"
db_input critical jitsi-meet/email || true
db_go
db_get jitsi-meet/email
EMAIL="$RET"
if [ ! -z "$EMAIL" ] ; then
ISSUE_LE_CERT="true"
fi
fi
fi
fi
@@ -130,51 +142,20 @@ case "$1" in
sed -i "s/jitsi-meet.example.com/$JVB_HOSTNAME/g" $JITSI_MEET_CONFIG
fi
# getting rid of jetty serving web
if [[ "$JVB_SERVE" = "true" ]] ; then
JVB_CONFIG="/etc/jitsi/videobridge/sip-communicator.properties"
if [ "${JAAS_INPUT}" = "true" ] && ! grep -q "^var enableJaaS = true;$" $JITSI_MEET_CONFIG; then
if grep -q "^var enableJaaS = false;$" $JITSI_MEET_CONFIG; then
sed -i "s/^var enableJaaS = false;$/var enableJaaS = true;/g" $JITSI_MEET_CONFIG
else
# old config, let's add the lines at the end. Adding var enableJaaS to avoid adding it on update again
echo "var enableJaaS = true;" >> $JITSI_MEET_CONFIG
echo "config.dialInNumbersUrl = 'https://conference-mapper.jitsi.net/v1/access/dids';" >> $JITSI_MEET_CONFIG
echo "config.dialInConfCodeUrl = 'https://conference-mapper.jitsi.net/v1/access';" >> $JITSI_MEET_CONFIG
# we will write to the file if missing create it
if [ -f $JVB_CONFIG ] ; then
echo ""
echo "------------------------------------------------"
echo ""
echo "You are using jetty to serve jitsi-meet, we are now upgrading you to use nginx!"
echo ""
echo "If you are using Lets Encrypt certificates please re-run the script."
echo ""
echo "------------------------------------------------"
echo ""
sed -i "s/org.jitsi.videobridge.rest.jetty/#org.jitsi.videobridge.rest.jetty/g" $JVB_CONFIG
sed -i "s/org.jitsi.videobridge.TCP_HARVESTER_PORT/#org.jitsi.videobridge.TCP_HARVESTER_PORT/g" $JVB_CONFIG
if [ -d /run/systemd/system ]; then
systemctl restart jitsi-videobridge2.service >/dev/null || true
fi
# Removing this value will force nginx or apache to be locally configured
JVB_HOSTNAME_OLD=""
RET=""
db_get jitsi-meet/cert-choice
CERT_CHOICE="$RET"
# Fix certs on upgrade from jetty
if [ "$CERT_CHOICE" = "$UPLOADED_CERT_CHOICE" ] ; then
RET=""
db_get jitsi-meet/cert-path-key
CERT_KEY="$RET"
RET=""
db_get jitsi-meet/cert-path-crt
CERT_CRT="$RET"
else
# create self-signed certs
CERT_KEY="/etc/jitsi/meet/$JVB_HOSTNAME.key"
CERT_CRT="/etc/jitsi/meet/$JVB_HOSTNAME.crt"
# Sets roomPasswordNumberOfDigits only if there was not already set
if ! cat $JITSI_MEET_CONFIG | grep roomPasswordNumberOfDigits | grep -qv //; then
echo "config.roomPasswordNumberOfDigits = 10; // skip re-adding it (do not remove comment)" >> $JITSI_MEET_CONFIG
fi
fi
db_set jitsi-meet/jvb-serve "false"
fi
if [[ "$FORCE_NGINX" = "true" && ( -z "$JVB_HOSTNAME_OLD" || "$RECONFIGURING" = "true" ) ]] ; then
@@ -239,12 +220,9 @@ case "$1" in
invoke-rc.d apache2 reload || true
fi
echo "----------------"
echo ""
echo "You can now switch to a Lets Encrypt certificate. To do so, execute:"
echo "/usr/share/jitsi-meet/scripts/install-letsencrypt-cert.sh"
echo ""
echo "----------------"
if [ "$ISSUE_LE_CERT" = "true" ] ; then
/usr/share/jitsi-meet/scripts/install-letsencrypt-cert.sh $EMAIL $JVB_HOSTNAME
fi
echo ""
echo ""
@@ -254,10 +232,17 @@ case "$1" in
echo " .xMMMMNxkNc"
echo " dMMMMMkxXc"
echo " cNMMMNl.."
echo " .kMMMX; Interested in adding telephony to your Jitsi meetings?"
echo " ;XMMMO'"
echo " lNMMWO' Sign up on https://jaas.8x8.vc/#/components"
echo " lNMMM0, and follow the guide in the dev console."
if [ "${JAAS_INPUT}" != "true" ]; then
echo " .kMMMX; Interested in adding telephony to your Jitsi meetings?"
echo " ;XMMMO'"
echo " lNMMWO' Sign up on https://jaas.8x8.vc/components?host=${JVB_HOSTNAME}"
echo " lNMMM0, and follow the guide in the dev console."
else
echo " .kMMMX;"
echo " ;XMMMO' Don't forget to sign up on"
echo " lNMMWO' https://jaas.8x8.vc/components?host=${JVB_HOSTNAME}"
echo " lNMMM0, in order to add telephony to your Jitsi meetings!"
fi
echo " lXMMMK:."
echo " ;KMMMNKd. 'oo,"
echo " 'xNMMMMXkkkkOKOl'"

View File

@@ -1,13 +1,16 @@
Template: jitsi-meet/cert-choice
Type: select
__Choices: Generate a new self-signed certificate (You will later get a chance to obtain a Let's encrypt certificate), I want to use my own certificate
__Choices: Generate a new self-signed certificate, Let's Encrypt certificates, I want to use my own certificate
_Description: SSL certificate for the Jitsi Meet instance
.
Jitsi Meet is best to be set up with an SSL certificate.
.
Having no certificate, a self-signed one will be generated.
By choosing self-signed you will later have a chance to install Lets Encrypt certificates.
Having a certificate signed by a recognised CA, it can be uploaded on the server
and point its location. The default filenames will be /etc/ssl/--domain.name--.key
for the key and /etc/ssl/--domain.name--.crt for the certificate.
In the case of using a self-signed certificate, only the web app will be available with some warnings, the mobile app will not connect.
Self-signed certificates are not supported by JaaS (Jitsi as a Service).
.
Having a certificate signed by a recognised CA, it can be uploaded on the server and point its location.
The default filenames will be /etc/ssl/--domain.name--.key for the key and /etc/ssl/--domain.name--.crt for the certificate.
Template: jitsi-meet/cert-path-key
Type: string
@@ -30,3 +33,21 @@ Template: jitsi-videobridge/jvb-hostname
Type: string
_Description: Hostname:
The Jitsi Meet web config package needs the DNS hostname of your instance.
Template: jitsi-meet/jaas-choice
Type: boolean
_Description: Interested in adding telephony to your Jitsi meetings?
You can easily add dialing in support to your meetings using JaaS (Jitsi as a Service).
You need to:
- have a certificate signed by a recognised CA or Lets Encrypt on your deployment
- sign in for JaaS at https://jaas.8x8.vc/components?host=${domain}
Template: jitsi-meet/email
Type: string
_Description: Enter your email:
To successfully issue Let's Encrypt certificates:
.
You need a working DNS record pointing to this machine(for hostname ${domain})"
.
You need to agree to the ACME server's Subscriber Agreement (https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf)
by providing an email address for important account notifications

View File

@@ -20,7 +20,7 @@ msgstr ""
#. Type: select
#. Choices
#: ../jitsi-meet-web-config.templates:1001
msgid "Generate a new self-signed certificate (You will later get a chance to obtain a Let's encrypt certificate)"
msgid "Generate a new self-signed certificate"
msgstr ""
#. Type: select

View File

@@ -0,0 +1,12 @@
-- Enables dial-in for Jitsi meet components customers
VirtualHost "jigasi.meet.jitsi"
modules_enabled = {
"ping";
"bosh";
"muc_password_check";
}
authentication = "token"
app_id = "jitsi";
asap_key_server = "https://jaas-public-keys.jitsi.net/jitsi-components/prod-8x8"
asap_accepted_issuers = { "jaas-components" }
asap_accepted_audiences = { "jigasi.jitmeet.example.com" }

View File

@@ -140,19 +140,3 @@ Component "lobby.jitmeet.example.com" "muc"
"muc_rate_limit";
"polls";
}
-- Enables dial-in for Jitsi meet components customers
-- Note: make sure you have the following packages installed: lua-basexx, liblua5.3-dev, libssl-dev, luarocks
-- and execute $ sudo luarocks install luajwtjitsi 3.0-0
VirtualHost "jigasi.meet.jitsi"
enabled = false -- Jitsi meet components customers remove this line
modules_enabled = {
"ping";
"bosh";
"muc_password_check";
}
authentication = "token"
app_id = "jitsi";
asap_key_server = "https://jaas-public-keys.jitsi.net/jitsi-components/prod-8x8"
asap_accepted_issuers = { "jaas-components" }
asap_accepted_audiences = { "jigasi.jitmeet.example.com" }

View File

@@ -1,45 +0,0 @@
#!/bin/sh
set -e
COTURN_CERT_DIR="/etc/coturn/certs"
TURN_CONFIG="/etc/turnserver.conf"
# create a directory to store certs if it does not exists
if [ ! -d "$COTURN_CERT_DIR" ]; then
mkdir -p $COTURN_CERT_DIR
chown -R turnserver:turnserver /etc/coturn/
chmod -R 700 /etc/coturn/
fi
# This is a template and when copied to /etc/letsencrypt/renewal-hooks/deploy/
# during creating the Let's encrypt certs script
# jitsi-meet.example.com will be replaced with the real domain of deployment
for domain in $RENEWED_DOMAINS; do
case $domain in
jitsi-meet.example.com)
# Make sure the certificate and private key files are
# never world readable, even just for an instant while
# we're copying them into daemon_cert_root.
umask 077
cp "$RENEWED_LINEAGE/fullchain.pem" "$COTURN_CERT_DIR/$domain.fullchain.pem"
cp "$RENEWED_LINEAGE/privkey.pem" "$COTURN_CERT_DIR/$domain.privkey.pem"
# Apply the proper file ownership and permissions for
# the daemon to read its certificate and key.
chown turnserver "$COTURN_CERT_DIR/$domain.fullchain.pem" \
"$COTURN_CERT_DIR/$domain.privkey.pem"
chmod 400 "$COTURN_CERT_DIR/$domain.fullchain.pem" \
"$COTURN_CERT_DIR/$domain.privkey.pem"
if [ -f $TURN_CONFIG ] && grep -q "jitsi-meet coturn config" "$TURN_CONFIG" ; then
echo "Configuring turnserver"
sed -i "/^cert/c\cert=\/etc\/coturn\/certs\/${domain}.fullchain.pem" $TURN_CONFIG
sed -i "/^pkey/c\pkey=\/etc\/coturn\/certs\/${domain}.privkey.pem" $TURN_CONFIG
fi
service coturn restart
;;
esac
done

View File

@@ -16,6 +16,8 @@ no-tlsv1
no-tlsv1_1
# https://ssl-config.mozilla.org/#server=haproxy&version=2.1&config=intermediate&openssl=1.1.0g&guideline=5.4
cipher-list=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
# without it there are errors when running on Ubuntu 20.04
dh2066
# jitsi-meet coturn relay disable config. Do not modify this line
denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=10.0.0.0-10.255.255.255

View File

@@ -15,7 +15,7 @@ echo "Releasing Jitsi Meet SDK Lite ${SDK_VERSION}"
pushd ${RELEASE_REPO}
# Generate podspec file
cat JitsiMeetSDKLite.podspec.tpl | sed -e s/VERSION/${SDK_VERSION}/g > JitsiMeetSDKLite.podspec
cat JitsiMeetSDKLite.podspec.tpl | sed -e s/VERSION/${SDK_VERSION}-lite/g > JitsiMeetSDKLite.podspec
# Cleanup
rm -rf lite/Frameworks/*
@@ -66,7 +66,7 @@ cp -a ${PROJECT_REPO}/ios/sdk/out/JitsiMeetSDK.xcframework lite/Frameworks/
if [[ $DO_GIT_TAG == 1 ]]; then
git add -A .
git commit -m "${SDK_VERSION} lite"
git tag "lite-${SDK_VERSION}"
git tag "${SDK_VERSION}-lite"
fi
popd

View File

@@ -23,6 +23,16 @@
0BCA49611EC4B6C600B793EE /* Proximity.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BCA495E1EC4B6C600B793EE /* Proximity.m */; };
0BD906EA1EC0C00300C8C18E /* JitsiMeet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BD906E81EC0C00300C8C18E /* JitsiMeet.h */; settings = {ATTRIBUTES = (Public, ); }; };
3453F4A32680898C4A40E821 /* libPods-JitsiMeetSDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 927ED7DF018DE5E12C4C3404 /* libPods-JitsiMeetSDK.a */; };
4E0EF63028CA2FB3005D1B03 /* JMCallKitEmitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E0EF62E28CA2FB3005D1B03 /* JMCallKitEmitter.h */; };
4E0EF63128CA2FB3005D1B03 /* JMCallKitEmitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E0EF62E28CA2FB3005D1B03 /* JMCallKitEmitter.h */; };
4E0EF63228CA2FB3005D1B03 /* JMCallKitEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E0EF62F28CA2FB3005D1B03 /* JMCallKitEmitter.m */; };
4E0EF63328CA2FB3005D1B03 /* JMCallKitEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E0EF62F28CA2FB3005D1B03 /* JMCallKitEmitter.m */; };
4E0EF63528CA317E005D1B03 /* JMCallKitListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E0EF63428CA317E005D1B03 /* JMCallKitListener.h */; settings = {ATTRIBUTES = (Public, ); }; };
4E0EF63628CA317E005D1B03 /* JMCallKitListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E0EF63428CA317E005D1B03 /* JMCallKitListener.h */; settings = {ATTRIBUTES = (Public, ); }; };
4E0EF63928CA4069005D1B03 /* JMCallKitProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E0EF63728CA4069005D1B03 /* JMCallKitProxy.h */; settings = {ATTRIBUTES = (Public, ); }; };
4E0EF63A28CA4069005D1B03 /* JMCallKitProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E0EF63728CA4069005D1B03 /* JMCallKitProxy.h */; settings = {ATTRIBUTES = (Public, ); }; };
4E0EF63B28CA4069005D1B03 /* JMCallKitProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E0EF63828CA4069005D1B03 /* JMCallKitProxy.m */; };
4E0EF63C28CA4069005D1B03 /* JMCallKitProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E0EF63828CA4069005D1B03 /* JMCallKitProxy.m */; };
4E51B76425E5345E0038575A /* ScheenshareEventEmiter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E51B76225E5345E0038575A /* ScheenshareEventEmiter.h */; };
4E51B76525E5345E0038575A /* ScheenshareEventEmiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E51B76325E5345E0038575A /* ScheenshareEventEmiter.m */; };
4EBA6E61286072E300B31882 /* JitsiMeetViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4EBA6E5F286072E300B31882 /* JitsiMeetViewController.h */; };
@@ -33,14 +43,11 @@
4ED4FFF42721B9B90074E620 /* JitsiAudioSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ED4FFF22721B9B90074E620 /* JitsiAudioSession.m */; };
4EEC9630286C73A2008705FA /* JitsiMeetView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4EEC962E286C73A2008705FA /* JitsiMeetView+Private.h */; };
4EEC9631286C73A2008705FA /* JitsiMeetView+Private.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EEC962F286C73A2008705FA /* JitsiMeetView+Private.m */; };
6F08DF7D4458EE3CF3F36F6D /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
6F08DF7D4458EE3CF3F36F6D /* (null) in Frameworks */ = {isa = PBXBuildFile; };
9A8EE79C77C17743BB66E8BD /* libPods-JitsiMeetSDKLite.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B46497DE9A95BDF5E312AF48 /* libPods-JitsiMeetSDKLite.a */; };
A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */ = {isa = PBXBuildFile; fileRef = A4A934E8212F3ADB001E9388 /* Dropbox.m */; };
C6245F5D2053091D0040BE68 /* image-resize@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6245F5B2053091D0040BE68 /* image-resize@2x.png */; };
C6245F5E2053091D0040BE68 /* image-resize@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6245F5C2053091D0040BE68 /* image-resize@3x.png */; };
C69EFA0C209A0F660027712B /* JMCallKitEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA09209A0F650027712B /* JMCallKitEmitter.swift */; };
C69EFA0D209A0F660027712B /* JMCallKitProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA0A209A0F660027712B /* JMCallKitProxy.swift */; };
C69EFA0E209A0F660027712B /* JMCallKitListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA0B209A0F660027712B /* JMCallKitListener.swift */; };
C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3425E204EF76800E062DD /* DragGestureController.swift */; };
C6CC49AF207412CF000DFA42 /* PiPViewCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */; };
C81E9AB925AC5AD800B134D9 /* ExternalAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = C81E9AB825AC5AD800B134D9 /* ExternalAPI.h */; };
@@ -49,8 +56,6 @@
DE438CDA2350934700DD541D /* JavaScriptSandbox.m in Sources */ = {isa = PBXBuildFile; fileRef = DE438CD82350934700DD541D /* JavaScriptSandbox.m */; };
DE65AACA2317FFCD00290BEC /* LogUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DE65AAC92317FFCD00290BEC /* LogUtils.h */; };
DE65AACC2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */; };
DE66914428BCC1C7007C4533 /* JitsiMeetSDK-Swift.h in Headers */ = {isa = PBXBuildFile; fileRef = DE66914328BCC1C7007C4533 /* JitsiMeetSDK-Swift.h */; };
DE66914528BCC1C7007C4533 /* JitsiMeetSDK-Swift.h in Headers */ = {isa = PBXBuildFile; fileRef = DE66914328BCC1C7007C4533 /* JitsiMeetSDK-Swift.h */; };
DE762DB422AFDE76000DEBD6 /* JitsiMeetUserInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DE762DB322AFDE76000DEBD6 /* JitsiMeetUserInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
DE762DB622AFDE8D000DEBD6 /* JitsiMeetUserInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DE762DB522AFDE8D000DEBD6 /* JitsiMeetUserInfo.m */; };
DE81A2D42316AC4D00AE1940 /* JitsiMeetLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = DE81A2D22316AC4D00AE1940 /* JitsiMeetLogger.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -93,15 +98,12 @@
DE9A0151289A9A9A00E41CBB /* LocaleDetector.m in Sources */ = {isa = PBXBuildFile; fileRef = DEFC743D21B178FA00E4DD96 /* LocaleDetector.m */; };
DE9A0152289A9A9A00E41CBB /* AudioMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BCA495C1EC4B6C600B793EE /* AudioMode.m */; };
DE9A0153289A9A9A00E41CBB /* Proximity.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BCA495E1EC4B6C600B793EE /* Proximity.m */; };
DE9A0154289A9A9A00E41CBB /* JMCallKitEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA09209A0F650027712B /* JMCallKitEmitter.swift */; };
DE9A0155289A9A9A00E41CBB /* ReactUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DEFE535521FB2E8300011A3A /* ReactUtils.m */; };
DE9A0156289A9A9A00E41CBB /* JitsiMeetView+Private.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EEC962F286C73A2008705FA /* JitsiMeetView+Private.m */; };
DE9A0157289A9A9A00E41CBB /* DragGestureController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3425E204EF76800E062DD /* DragGestureController.swift */; };
DE9A0158289A9A9A00E41CBB /* ScheenshareEventEmiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E51B76325E5345E0038575A /* ScheenshareEventEmiter.m */; };
DE9A015A289A9A9A00E41CBB /* JitsiMeetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EBA6E60286072E300B31882 /* JitsiMeetViewController.m */; };
DE9A015B289A9A9A00E41CBB /* JMCallKitProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA0A209A0F660027712B /* JMCallKitProxy.swift */; };
DE9A015C289A9A9A00E41CBB /* JitsiMeetLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = DE81A2D32316AC4D00AE1940 /* JitsiMeetLogger.m */; };
DE9A015D289A9A9A00E41CBB /* JMCallKitListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA0B209A0F660027712B /* JMCallKitListener.swift */; };
DE9A015E289A9A9A00E41CBB /* JitsiMeetView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B412F171EDEC65D00B1A0A6 /* JitsiMeetView.m */; };
DE9A015F289A9A9A00E41CBB /* JitsiMeet.m in Sources */ = {isa = PBXBuildFile; fileRef = DEFE535321FB1BF800011A3A /* JitsiMeet.m */; };
DE9A0160289A9A9A00E41CBB /* JavaScriptSandbox.m in Sources */ = {isa = PBXBuildFile; fileRef = DE438CD82350934700DD541D /* JavaScriptSandbox.m */; };
@@ -139,6 +141,11 @@
0BD906E51EC0C00300C8C18E /* JitsiMeetSDK.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JitsiMeetSDK.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0BD906E81EC0C00300C8C18E /* JitsiMeet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeet.h; sourceTree = "<group>"; };
0BD906E91EC0C00300C8C18E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4E0EF62E28CA2FB3005D1B03 /* JMCallKitEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMCallKitEmitter.h; sourceTree = "<group>"; };
4E0EF62F28CA2FB3005D1B03 /* JMCallKitEmitter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMCallKitEmitter.m; sourceTree = "<group>"; };
4E0EF63428CA317E005D1B03 /* JMCallKitListener.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMCallKitListener.h; sourceTree = "<group>"; };
4E0EF63728CA4069005D1B03 /* JMCallKitProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMCallKitProxy.h; sourceTree = "<group>"; };
4E0EF63828CA4069005D1B03 /* JMCallKitProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMCallKitProxy.m; sourceTree = "<group>"; };
4E51B76225E5345E0038575A /* ScheenshareEventEmiter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScheenshareEventEmiter.h; sourceTree = "<group>"; };
4E51B76325E5345E0038575A /* ScheenshareEventEmiter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ScheenshareEventEmiter.m; sourceTree = "<group>"; };
4EBA6E5F286072E300B31882 /* JitsiMeetViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeetViewController.h; sourceTree = "<group>"; };
@@ -161,9 +168,6 @@
B46497DE9A95BDF5E312AF48 /* libPods-JitsiMeetSDKLite.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-JitsiMeetSDKLite.a"; sourceTree = BUILT_PRODUCTS_DIR; };
C6245F5B2053091D0040BE68 /* image-resize@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "image-resize@2x.png"; path = "src/picture-in-picture/image-resize@2x.png"; sourceTree = "<group>"; };
C6245F5C2053091D0040BE68 /* image-resize@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "image-resize@3x.png"; path = "src/picture-in-picture/image-resize@3x.png"; sourceTree = "<group>"; };
C69EFA09209A0F650027712B /* JMCallKitEmitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JMCallKitEmitter.swift; sourceTree = "<group>"; };
C69EFA0A209A0F660027712B /* JMCallKitProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JMCallKitProxy.swift; sourceTree = "<group>"; };
C69EFA0B209A0F660027712B /* JMCallKitListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JMCallKitListener.swift; sourceTree = "<group>"; };
C6A3425E204EF76800E062DD /* DragGestureController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragGestureController.swift; sourceTree = "<group>"; };
C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiPViewCoordinator.swift; sourceTree = "<group>"; };
C81E9AB825AC5AD800B134D9 /* ExternalAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExternalAPI.h; sourceTree = "<group>"; };
@@ -172,7 +176,6 @@
DE438CD82350934700DD541D /* JavaScriptSandbox.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JavaScriptSandbox.m; sourceTree = "<group>"; };
DE65AAC92317FFCD00290BEC /* LogUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogUtils.h; sourceTree = "<group>"; };
DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetBaseLogHandler+Private.h"; sourceTree = "<group>"; };
DE66914328BCC1C7007C4533 /* JitsiMeetSDK-Swift.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetSDK-Swift.h"; sourceTree = "<group>"; };
DE762DB322AFDE76000DEBD6 /* JitsiMeetUserInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeetUserInfo.h; sourceTree = "<group>"; };
DE762DB522AFDE8D000DEBD6 /* JitsiMeetUserInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JitsiMeetUserInfo.m; sourceTree = "<group>"; };
DE762DB722AFE166000DEBD6 /* JitsiMeetUserInfo+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetUserInfo+Private.h"; sourceTree = "<group>"; };
@@ -203,7 +206,7 @@
files = (
0BB9AD791F5EC6D7001C08DB /* Intents.framework in Frameworks */,
0BB9AD771F5EC6CE001C08DB /* CallKit.framework in Frameworks */,
6F08DF7D4458EE3CF3F36F6D /* BuildFile in Frameworks */,
6F08DF7D4458EE3CF3F36F6D /* (null) in Frameworks */,
3453F4A32680898C4A40E821 /* libPods-JitsiMeetSDK.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -306,7 +309,6 @@
4E51B76225E5345E0038575A /* ScheenshareEventEmiter.h */,
4E51B76325E5345E0038575A /* ScheenshareEventEmiter.m */,
DE9A0170289A9A9A00E41CBB /* Lite-Info.plist */,
DE66914328BCC1C7007C4533 /* JitsiMeetSDK-Swift.h */,
);
path = src;
sourceTree = "<group>";
@@ -349,9 +351,11 @@
isa = PBXGroup;
children = (
0BB9AD7A1F5EC8F4001C08DB /* CallKit.m */,
C69EFA09209A0F650027712B /* JMCallKitEmitter.swift */,
C69EFA0B209A0F660027712B /* JMCallKitListener.swift */,
C69EFA0A209A0F660027712B /* JMCallKitProxy.swift */,
4E0EF62E28CA2FB3005D1B03 /* JMCallKitEmitter.h */,
4E0EF62F28CA2FB3005D1B03 /* JMCallKitEmitter.m */,
4E0EF63428CA317E005D1B03 /* JMCallKitListener.h */,
4E0EF63728CA4069005D1B03 /* JMCallKitProxy.h */,
4E0EF63828CA4069005D1B03 /* JMCallKitProxy.m */,
);
path = callkit;
sourceTree = "<group>";
@@ -379,10 +383,12 @@
DEA9F284258A5D9900D4CD74 /* JitsiMeetSDK.h in Headers */,
4E51B76425E5345E0038575A /* ScheenshareEventEmiter.h in Headers */,
DE65AACC2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h in Headers */,
DE66914428BCC1C7007C4533 /* JitsiMeetSDK-Swift.h in Headers */,
4EBA6E652860B1E800B31882 /* JitsiMeetRenderingView.h in Headers */,
0B412F221EDEF6EA00B1A0A6 /* JitsiMeetViewDelegate.h in Headers */,
4E0EF63528CA317E005D1B03 /* JMCallKitListener.h in Headers */,
4E0EF63028CA2FB3005D1B03 /* JMCallKitEmitter.h in Headers */,
4ED4FFF32721B9B90074E620 /* JitsiAudioSession.h in Headers */,
4E0EF63928CA4069005D1B03 /* JMCallKitProxy.h in Headers */,
4EEC9630286C73A2008705FA /* JitsiMeetView+Private.h in Headers */,
0BD906EA1EC0C00300C8C18E /* JitsiMeet.h in Headers */,
DE81A2D42316AC4D00AE1940 /* JitsiMeetLogger.h in Headers */,
@@ -405,10 +411,12 @@
DE9A0134289A9A9A00E41CBB /* JitsiMeetSDK.h in Headers */,
DE9A0135289A9A9A00E41CBB /* ScheenshareEventEmiter.h in Headers */,
DE9A0136289A9A9A00E41CBB /* JitsiMeetBaseLogHandler+Private.h in Headers */,
DE66914528BCC1C7007C4533 /* JitsiMeetSDK-Swift.h in Headers */,
DE9A0137289A9A9A00E41CBB /* JitsiMeetRenderingView.h in Headers */,
DE9A0138289A9A9A00E41CBB /* JitsiMeetViewDelegate.h in Headers */,
4E0EF63628CA317E005D1B03 /* JMCallKitListener.h in Headers */,
4E0EF63128CA2FB3005D1B03 /* JMCallKitEmitter.h in Headers */,
DE9A0139289A9A9A00E41CBB /* JitsiAudioSession.h in Headers */,
4E0EF63A28CA4069005D1B03 /* JMCallKitProxy.h in Headers */,
DE9A013A289A9A9A00E41CBB /* JitsiMeetView+Private.h in Headers */,
DE9A013B289A9A9A00E41CBB /* JitsiMeet.h in Headers */,
DE9A013C289A9A9A00E41CBB /* JitsiMeetLogger.h in Headers */,
@@ -677,6 +685,7 @@
files = (
0BB9AD7B1F5EC8F4001C08DB /* CallKit.m in Sources */,
DE81A2DF2317ED5400AE1940 /* JitsiMeetBaseLogHandler.m in Sources */,
4E0EF63B28CA4069005D1B03 /* JMCallKitProxy.m in Sources */,
4EBA6E662860B1E800B31882 /* JitsiMeetRenderingView.m in Sources */,
4ED4FFF42721B9B90074E620 /* JitsiAudioSession.m in Sources */,
0BB9AD7D1F60356D001C08DB /* AppInfo.m in Sources */,
@@ -692,16 +701,14 @@
DEFC743F21B178FA00E4DD96 /* LocaleDetector.m in Sources */,
0BCA495F1EC4B6C600B793EE /* AudioMode.m in Sources */,
0BCA49611EC4B6C600B793EE /* Proximity.m in Sources */,
C69EFA0C209A0F660027712B /* JMCallKitEmitter.swift in Sources */,
4E0EF63228CA2FB3005D1B03 /* JMCallKitEmitter.m in Sources */,
DEFE535621FB2E8300011A3A /* ReactUtils.m in Sources */,
4EEC9631286C73A2008705FA /* JitsiMeetView+Private.m in Sources */,
C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */,
4E51B76525E5345E0038575A /* ScheenshareEventEmiter.m in Sources */,
A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */,
4EBA6E62286072E300B31882 /* JitsiMeetViewController.m in Sources */,
C69EFA0D209A0F660027712B /* JMCallKitProxy.swift in Sources */,
DE81A2D52316AC4D00AE1940 /* JitsiMeetLogger.m in Sources */,
C69EFA0E209A0F660027712B /* JMCallKitListener.swift in Sources */,
0B412F191EDEC65D00B1A0A6 /* JitsiMeetView.m in Sources */,
DEFE535421FB1BF800011A3A /* JitsiMeet.m in Sources */,
DE438CDA2350934700DD541D /* JavaScriptSandbox.m in Sources */,
@@ -716,6 +723,7 @@
DE9A0144289A9A9A00E41CBB /* JitsiMeetBaseLogHandler.m in Sources */,
DE9A0145289A9A9A00E41CBB /* JitsiMeetRenderingView.m in Sources */,
DE9A0146289A9A9A00E41CBB /* JitsiAudioSession.m in Sources */,
4E0EF63C28CA4069005D1B03 /* JMCallKitProxy.m in Sources */,
DE9A0147289A9A9A00E41CBB /* AppInfo.m in Sources */,
DE9A0148289A9A9A00E41CBB /* LogBridge.m in Sources */,
DE9A0149289A9A9A00E41CBB /* RNRootView.m in Sources */,
@@ -729,15 +737,13 @@
DE9A0151289A9A9A00E41CBB /* LocaleDetector.m in Sources */,
DE9A0152289A9A9A00E41CBB /* AudioMode.m in Sources */,
DE9A0153289A9A9A00E41CBB /* Proximity.m in Sources */,
DE9A0154289A9A9A00E41CBB /* JMCallKitEmitter.swift in Sources */,
DE9A0155289A9A9A00E41CBB /* ReactUtils.m in Sources */,
DE9A0156289A9A9A00E41CBB /* JitsiMeetView+Private.m in Sources */,
DE9A0157289A9A9A00E41CBB /* DragGestureController.swift in Sources */,
DE9A0158289A9A9A00E41CBB /* ScheenshareEventEmiter.m in Sources */,
DE9A015A289A9A9A00E41CBB /* JitsiMeetViewController.m in Sources */,
DE9A015B289A9A9A00E41CBB /* JMCallKitProxy.swift in Sources */,
DE9A015C289A9A9A00E41CBB /* JitsiMeetLogger.m in Sources */,
DE9A015D289A9A9A00E41CBB /* JMCallKitListener.swift in Sources */,
4E0EF63328CA2FB3005D1B03 /* JMCallKitEmitter.m in Sources */,
DE9A015E289A9A9A00E41CBB /* JitsiMeetView.m in Sources */,
DE9A015F289A9A9A00E41CBB /* JitsiMeet.m in Sources */,
DE9A0160289A9A9A00E41CBB /* JavaScriptSandbox.m in Sources */,

View File

@@ -1,271 +0,0 @@
// IMPORTANT!
// This file was once auto-generated by Xcode, and this is a copy of it. If any of the following
// classes is modified this file needs to be regenerated.
// - JMCallKitListener
// - JMCallKitProxy
#ifndef JITSIMEETSDK_SWIFT_H
#define JITSIMEETSDK_SWIFT_H
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgcc-compat"
#if !defined(__has_include)
# define __has_include(x) 0
#endif
#if !defined(__has_attribute)
# define __has_attribute(x) 0
#endif
#if !defined(__has_feature)
# define __has_feature(x) 0
#endif
#if !defined(__has_warning)
# define __has_warning(x) 0
#endif
#if __has_include(<swift/objc-prologue.h>)
# include <swift/objc-prologue.h>
#endif
#pragma clang diagnostic ignored "-Wauto-import"
#include <Foundation/Foundation.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#if !defined(SWIFT_TYPEDEFS)
# define SWIFT_TYPEDEFS 1
# if __has_include(<uchar.h>)
# include <uchar.h>
# elif !defined(__cplusplus)
typedef uint_least16_t char16_t;
typedef uint_least32_t char32_t;
# endif
typedef float swift_float2 __attribute__((__ext_vector_type__(2)));
typedef float swift_float3 __attribute__((__ext_vector_type__(3)));
typedef float swift_float4 __attribute__((__ext_vector_type__(4)));
typedef double swift_double2 __attribute__((__ext_vector_type__(2)));
typedef double swift_double3 __attribute__((__ext_vector_type__(3)));
typedef double swift_double4 __attribute__((__ext_vector_type__(4)));
typedef int swift_int2 __attribute__((__ext_vector_type__(2)));
typedef int swift_int3 __attribute__((__ext_vector_type__(3)));
typedef int swift_int4 __attribute__((__ext_vector_type__(4)));
typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2)));
typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3)));
typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4)));
#endif
#if !defined(SWIFT_PASTE)
# define SWIFT_PASTE_HELPER(x, y) x##y
# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y)
#endif
#if !defined(SWIFT_METATYPE)
# define SWIFT_METATYPE(X) Class
#endif
#if !defined(SWIFT_CLASS_PROPERTY)
# if __has_feature(objc_class_property)
# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__
# else
# define SWIFT_CLASS_PROPERTY(...)
# endif
#endif
#if __has_attribute(objc_runtime_name)
# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X)))
#else
# define SWIFT_RUNTIME_NAME(X)
#endif
#if __has_attribute(swift_name)
# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
#else
# define SWIFT_COMPILE_NAME(X)
#endif
#if __has_attribute(objc_method_family)
# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X)))
#else
# define SWIFT_METHOD_FAMILY(X)
#endif
#if __has_attribute(noescape)
# define SWIFT_NOESCAPE __attribute__((noescape))
#else
# define SWIFT_NOESCAPE
#endif
#if __has_attribute(ns_consumed)
# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed))
#else
# define SWIFT_RELEASES_ARGUMENT
#endif
#if __has_attribute(warn_unused_result)
# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
# define SWIFT_WARN_UNUSED_RESULT
#endif
#if __has_attribute(noreturn)
# define SWIFT_NORETURN __attribute__((noreturn))
#else
# define SWIFT_NORETURN
#endif
#if !defined(SWIFT_CLASS_EXTRA)
# define SWIFT_CLASS_EXTRA
#endif
#if !defined(SWIFT_PROTOCOL_EXTRA)
# define SWIFT_PROTOCOL_EXTRA
#endif
#if !defined(SWIFT_ENUM_EXTRA)
# define SWIFT_ENUM_EXTRA
#endif
#if !defined(SWIFT_CLASS)
# if __has_attribute(objc_subclassing_restricted)
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA
# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
# else
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
# endif
#endif
#if !defined(SWIFT_RESILIENT_CLASS)
# if __has_attribute(objc_class_stub)
# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub))
# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME)
# else
# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME)
# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME)
# endif
#endif
#if !defined(SWIFT_PROTOCOL)
# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
#endif
#if !defined(SWIFT_EXTENSION)
# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__)
#endif
#if !defined(OBJC_DESIGNATED_INITIALIZER)
# if __has_attribute(objc_designated_initializer)
# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
# else
# define OBJC_DESIGNATED_INITIALIZER
# endif
#endif
#if !defined(SWIFT_ENUM_ATTR)
# if defined(__has_attribute) && __has_attribute(enum_extensibility)
# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility)))
# else
# define SWIFT_ENUM_ATTR(_extensibility)
# endif
#endif
#if !defined(SWIFT_ENUM)
# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
# if __has_feature(generalized_swift_name)
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
# else
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility)
# endif
#endif
#if !defined(SWIFT_UNAVAILABLE)
# define SWIFT_UNAVAILABLE __attribute__((unavailable))
#endif
#if !defined(SWIFT_UNAVAILABLE_MSG)
# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg)))
#endif
#if !defined(SWIFT_AVAILABILITY)
# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__)))
#endif
#if !defined(SWIFT_WEAK_IMPORT)
# define SWIFT_WEAK_IMPORT __attribute__((weak_import))
#endif
#if !defined(SWIFT_DEPRECATED)
# define SWIFT_DEPRECATED __attribute__((deprecated))
#endif
#if !defined(SWIFT_DEPRECATED_MSG)
# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__)))
#endif
#if __has_feature(attribute_diagnose_if_objc)
# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning")))
#else
# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg)
#endif
#if !defined(IBSegueAction)
# define IBSegueAction
#endif
#if !defined(SWIFT_EXTERN)
# if defined(__cplusplus)
# define SWIFT_EXTERN extern "C"
# else
# define SWIFT_EXTERN extern
# endif
#endif
#if __has_feature(modules)
#if __has_warning("-Watimport-in-framework-header")
#pragma clang diagnostic ignored "-Watimport-in-framework-header"
#endif
@import CallKit;
@import ObjectiveC;
#endif
#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch"
#pragma clang diagnostic ignored "-Wduplicate-method-arg"
#if __has_warning("-Wpragma-clang-attribute")
# pragma clang diagnostic ignored "-Wpragma-clang-attribute"
#endif
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wnullability"
#if __has_attribute(external_source_symbol)
# pragma push_macro("any")
# undef any
# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="JitsiMeetSDK",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol))
# pragma pop_macro("any")
#endif
@class NSUUID;
@class AVAudioSession;
@class CXAction;
SWIFT_PROTOCOL("_TtP12JitsiMeetSDK17JMCallKitListener_")
@protocol JMCallKitListener <NSObject>
@optional
- (void)providerDidReset;
- (void)performAnswerCallWithUUID:(NSUUID * _Nonnull)UUID;
- (void)performEndCallWithUUID:(NSUUID * _Nonnull)UUID;
- (void)performSetMutedCallWithUUID:(NSUUID * _Nonnull)UUID isMuted:(BOOL)isMuted;
- (void)performStartCallWithUUID:(NSUUID * _Nonnull)UUID isVideo:(BOOL)isVideo;
- (void)providerDidActivateAudioSessionWithSession:(AVAudioSession * _Nonnull)session;
- (void)providerDidDeactivateAudioSessionWithSession:(AVAudioSession * _Nonnull)session;
- (void)providerTimedOutPerformingActionWithAction:(CXAction * _Nonnull)action;
@end
@class NSString;
@class NSData;
@class NSDate;
@class CXTransaction;
SWIFT_CLASS("_TtC12JitsiMeetSDK14JMCallKitProxy")
@interface JMCallKitProxy : NSObject
- (nonnull instancetype)init SWIFT_UNAVAILABLE;
+ (nonnull instancetype)new SWIFT_UNAVAILABLE_MSG("-init is unavailable");
/// Enables the proxy in between CallKit and the consumers of the SDK.
/// Defaults to disabled. Set to true when you want to use CallKit.
SWIFT_CLASS_PROPERTY(@property (nonatomic, class) BOOL enabled;)
+ (BOOL)enabled SWIFT_WARN_UNUSED_RESULT;
+ (void)setEnabled:(BOOL)value;
+ (void)configureProviderWithLocalizedName:(NSString * _Nonnull)localizedName ringtoneSound:(NSString * _Nullable)ringtoneSound iconTemplateImageData:(NSData * _Nullable)iconTemplateImageData;
+ (BOOL)isProviderConfigured SWIFT_WARN_UNUSED_RESULT;
+ (void)addListener:(id <JMCallKitListener> _Nonnull)listener;
+ (void)removeListener:(id <JMCallKitListener> _Nonnull)listener;
+ (BOOL)hasActiveCallForUUID:(NSString * _Nonnull)callUUID SWIFT_WARN_UNUSED_RESULT;
+ (void)reportNewIncomingCallWithUUID:(NSUUID * _Nonnull)UUID handle:(NSString * _Nullable)handle displayName:(NSString * _Nullable)displayName hasVideo:(BOOL)hasVideo completion:(void (^ _Nonnull)(NSError * _Nullable))completion;
+ (void)reportCallUpdateWith:(NSUUID * _Nonnull)UUID handle:(NSString * _Nullable)handle displayName:(NSString * _Nullable)displayName hasVideo:(BOOL)hasVideo;
+ (void)reportCallWith:(NSUUID * _Nonnull)UUID endedAt:(NSDate * _Nullable)dateEnded reason:(CXCallEndedReason)endedReason;
+ (void)reportOutgoingCallWith:(NSUUID * _Nonnull)UUID startedConnectingAt:(NSDate * _Nullable)dateStartedConnecting;
+ (void)reportOutgoingCallWith:(NSUUID * _Nonnull)UUID connectedAt:(NSDate * _Nullable)dateConnected;
+ (void)request:(CXTransaction * _Nonnull)transaction completion:(void (^ _Nonnull)(NSError * _Nullable))completion;
@end
#if __has_attribute(external_source_symbol)
# pragma clang attribute pop
#endif
#pragma clang diagnostic pop
#endif

View File

@@ -22,3 +22,5 @@
#import <JitsiMeetSDK/JitsiMeetBaseLogHandler.h>
#import <JitsiMeetSDK/JitsiAudioSession.h>
#import <JitsiMeetSDK/InfoPlistUtil.h>
#import <JitsiMeetSDK/JMCallKitListener.h>
#import <JitsiMeetSDK/JMCallKitProxy.h>

View File

@@ -30,7 +30,7 @@
#import <WebRTC/WebRTC.h>
#import "../JitsiAudioSession.h"
#import "../JitsiMeetSDK-Swift.h"
#import "JMCallKitProxy.h"
// The events emitted/supported by RNCallKit:

View File

@@ -0,0 +1,35 @@
/*
* Copyright @ 2022-present 8x8, Inc.
* Copyright @ 2018-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <CallKit/CallKit.h>
#import <Foundation/Foundation.h>
#import "JMCallKitListener.h"
NS_ASSUME_NONNULL_BEGIN
@interface JMCallKitEmitter : NSObject <CXProviderDelegate>
#pragma mark Add/Remove listeners
- (void)addListener:(id<JMCallKitListener>)listener;
- (void)removeListener:(id<JMCallKitListener>)listener;
#pragma mark Add mute action
- (void)addMuteAction:(NSUUID *)actionUUID;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,116 @@
/*
* Copyright @ 2022-present 8x8, Inc.
* Copyright @ 2018-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "JMCallKitEmitter.h"
@interface JMCallKitEmitter()
@property(nonatomic, strong) NSMutableArray<id<JMCallKitListener>> *listeners;
@property(nonatomic, strong) NSMutableSet<NSUUID *> *pendingMuteActions;
@end
@implementation JMCallKitEmitter
- (instancetype)init {
self = [super init];
if (self) {
self.listeners = [[NSMutableArray alloc] init];
self.pendingMuteActions = [[NSMutableSet alloc] init];
}
return self;
}
#pragma mark Add/Remove listeners
- (void)addListener:(id<JMCallKitListener>)listener {
if (![self.listeners containsObject:listener]) {
[self.listeners addObject:listener];
}
}
- (void)removeListener:(id<JMCallKitListener>)listener {
[self.listeners removeObject:listener];
}
#pragma mark Add mute action
- (void)addMuteAction:(NSUUID *)actionUUID {
[self.pendingMuteActions addObject:actionUUID];
}
#pragma mark CXProviderDelegate
- (void)providerDidReset:(CXProvider *)provider {
for (id listener in self.listeners) {
[listener providerDidReset];
}
[self.pendingMuteActions removeAllObjects];
}
- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action {
for (id listener in self.listeners) {
[listener performAnswerCallWithUUID:action.callUUID];
}
[action fulfill];
}
- (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action {
for (id listener in self.listeners) {
[listener performEndCallWithUUID:action.callUUID];
}
[action fulfill];
}
- (void)provider:(CXProvider *)provider performSetMutedCallAction:(CXSetMutedCallAction *)action {
NSUUID *uuid = ([self.pendingMuteActions containsObject:action.UUID]) ? action.UUID : nil;
[self.pendingMuteActions removeObject:action.UUID];
// Avoid mute actions ping-pong: if the mute action was caused by
// the JS side (we requested a transaction) don't call the delegate
// method. If it was called by the provider itself (when the user presses
// the mute button in the CallKit view) then call the delegate method.
//
// NOTE: don't try to be clever and remove this. Been there, done that.
// Won't work.
if (uuid == nil) {
for (id listener in self.listeners) {
[listener performSetMutedCallWithUUID:action.callUUID isMuted:action.isMuted];
}
}
[action fulfill];
}
- (void)provider:(CXProvider *)provider performStartCallAction:(CXStartCallAction *)action {
for (id listener in self.listeners) {
[listener performStartCallWithUUID:action.callUUID isVideo:action.isVideo];
}
}
- (void)provider:(CXProvider *)provider didActivateAudioSession:(AVAudioSession *)audioSession {
for (id listener in self.listeners) {
[listener providerDidActivateAudioSessionWithSession:audioSession];
}
}
- (void)provider:(CXProvider *)provider didDeactivateAudioSession:(AVAudioSession *)audioSession {
for (id listener in self.listeners) {
[listener providerDidDeactivateAudioSessionWithSession:audioSession];
}
}
@end

View File

@@ -1,118 +0,0 @@
/*
* Copyright @ 2018-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import AVKit
import CallKit
import Foundation
internal final class JMCallKitEmitter: NSObject, CXProviderDelegate {
private let listeners = NSMutableArray()
private var pendingMuteActions = Set<UUID>()
internal override init() {}
// MARK: - Add/remove listeners
func addListener(_ listener: JMCallKitListener) {
if (!listeners.contains(listener)) {
listeners.add(listener)
}
}
func removeListener(_ listener: JMCallKitListener) {
listeners.remove(listener)
}
// MARK: - Add mute action
func addMuteAction(_ actionUUID: UUID) {
pendingMuteActions.insert(actionUUID)
}
// MARK: - CXProviderDelegate
func providerDidReset(_ provider: CXProvider) {
listeners.forEach {
let listener = $0 as! JMCallKitListener
listener.providerDidReset?()
}
pendingMuteActions.removeAll()
}
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
listeners.forEach {
let listener = $0 as! JMCallKitListener
listener.performAnswerCall?(UUID: action.callUUID)
}
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
listeners.forEach {
let listener = $0 as! JMCallKitListener
listener.performEndCall?(UUID: action.callUUID)
}
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {
let uuid = pendingMuteActions.remove(action.uuid)
// Avoid mute actions ping-pong: if the mute action was caused by
// the JS side (we requested a transaction) don't call the delegate
// method. If it was called by the provider itself (when the user presses
// the mute button in the CallKit view) then call the delegate method.
//
// NOTE: don't try to be clever and remove this. Been there, done that.
// Won't work.
if (uuid == nil) {
listeners.forEach {
let listener = $0 as! JMCallKitListener
listener.performSetMutedCall?(UUID: action.callUUID, isMuted: action.isMuted)
}
}
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
listeners.forEach {
let listener = $0 as! JMCallKitListener
listener.performStartCall?(UUID: action.callUUID, isVideo: action.isVideo)
}
action.fulfill()
}
func provider(_ provider: CXProvider,
didActivate audioSession: AVAudioSession) {
listeners.forEach {
let listener = $0 as! JMCallKitListener
listener.providerDidActivateAudioSession?(session: audioSession)
}
}
func provider(_ provider: CXProvider,
didDeactivate audioSession: AVAudioSession) {
listeners.forEach {
let listener = $0 as! JMCallKitListener
listener.providerDidDeactivateAudioSession?(session: audioSession)
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright @ 2022-present 8x8, Inc.
* Copyright @ 2018-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <AVKit/AVKit.h>
#import <CallKit/CallKit.h>
#import <Foundation/Foundation.h>
@protocol JMCallKitListener <NSObject>
@optional
- (void)providerDidReset;
- (void)performAnswerCallWithUUID:(nonnull NSUUID *)UUID;
- (void)performEndCallWithUUID:(nonnull NSUUID *)UUID;
- (void)performSetMutedCallWithUUID:(nonnull NSUUID *)UUID isMuted:(BOOL)isMuted;
- (void)performStartCallWithUUID:(nonnull NSUUID *)UUID isVideo:(BOOL)isVideo;
- (void)providerDidActivateAudioSessionWithSession:(nonnull AVAudioSession *)session;
- (void)providerDidDeactivateAudioSessionWithSession:(nonnull AVAudioSession *)session;
- (void)providerTimedOutPerformingActionWithAction:(nonnull CXAction *)action;
@end

View File

@@ -1,38 +0,0 @@
/*
* Copyright @ 2018-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import AVKit
import CallKit
import Foundation
@objc public protocol JMCallKitListener: NSObjectProtocol {
@objc optional func providerDidReset()
@objc optional func performAnswerCall(UUID: UUID)
@objc optional func performEndCall(UUID: UUID)
@objc optional func performSetMutedCall(UUID: UUID, isMuted: Bool)
@objc optional func performStartCall(UUID: UUID, isVideo: Bool)
@objc optional func providerDidActivateAudioSession(session: AVAudioSession)
@objc optional func providerDidDeactivateAudioSession(session: AVAudioSession)
@objc optional func providerTimedOutPerformingAction(action: CXAction)
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright @ 2022-present 8x8, Inc.
* Copyright @ 2018-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <CallKit/CallKit.h>
#import <Foundation/Foundation.h>
#import "JMCallKitListener.h"
NS_ASSUME_NONNULL_BEGIN
@protocol CXProviderProtocol <NSObject>
@property (nonatomic, readwrite, copy) CXProviderConfiguration* configuration;
- (void)setDelegate:(nullable id<CXProviderDelegate>)delegate queue:(nullable dispatch_queue_t)queue;
- (void)reportNewIncomingCallWithUUID:(NSUUID *)uuid update:(CXCallUpdate *)update completion:(void (^)(NSError *))completion;
- (void)reportCallWithUUID:(NSUUID *)uuid updated:(CXCallUpdate *)update;
- (void)reportCallWithUUID:(NSUUID *)uuid endedAtDate:(NSDate *)dateEnded reason:(CXCallEndedReason)endedReason;
- (void)reportOutgoingCallWithUUID:(NSUUID *)uuid startedConnectingAtDate:(NSDate *)dateStartedConnecting;
- (void)reportOutgoingCallWithUUID:(NSUUID *)uuid connectedAtDate:(NSDate *)dateConnected;
- (void)invalidate;
@end
#pragma mark -
@protocol CXCallControllerProtocol <NSObject>
@property (nonatomic, readonly) NSArray<CXCall*> *calls;
- (void)requestTransaction:(CXTransaction *)transaction completion:(void (^)(NSError *_Nullable))completion;
@end
#pragma mark -
/// JitsiMeet CallKit proxy
// NOTE: The methods this class exposes are meant to be called in the UI thread.
// All delegate methods called by JMCallKitEmitter will be called in the UI thread.
@interface JMCallKitProxy : NSObject
/// Enables the proxy in between CallKit and the consumers of the SDK.
/// Defaults to disabled. Set to true when you want to use CallKit.
@property (class) BOOL enabled;
@property (class) id<CXProviderProtocol> callKitProvider;
@property (class) id<CXCallControllerProtocol> callKitCallController;
+ (void)configureProviderWithLocalizedName:(nonnull NSString *)localizedName
ringtoneSound:(nullable NSString *)ringtoneSound
iconTemplateImageData:(nullable NSData*)imageData
NS_SWIFT_NAME(configureProvider(localizedName:ringtoneSound:iconTemplateImageData:));
+ (BOOL)isProviderConfigured;
+ (void)addListener:(nonnull id<JMCallKitListener>)listener NS_SWIFT_NAME(addListener(_:));
+ (void)removeListener:(nonnull id<JMCallKitListener>)listener NS_SWIFT_NAME(removeListener(_:));
+ (BOOL)hasActiveCallForUUID:(nonnull NSString *)callUUID NS_SWIFT_NAME(hasActiveCallForUUID(_:));
+ (void)reportNewIncomingCallWithUUID:(nonnull NSUUID *)uuid
handle:(nullable NSString*)handle
displayName:(nullable NSString*)displayName
hasVideo:(BOOL)hasVideo
completion:(nonnull void (^)(NSError *_Nullable))completion
NS_SWIFT_NAME(reportNewIncomingCall(UUID:handle:displayName:hasVideo:completion:));
+ (void)reportCallUpdateWith:(nonnull NSUUID *)uuid
handle:(nullable NSString *)handle
displayName:(nullable NSString *)displayName
hasVideo:(BOOL)hasVideo;
+ (void)reportCallWith:(nonnull NSUUID *)uuid
endedAt:(nullable NSDate *)dateEnded
reason:(CXCallEndedReason)endedReason;
+ (void)reportOutgoingCallWith:(nonnull NSUUID *)uuid startedConnectingAt:(nullable NSDate *)dateStartedConnecting;
+ (void)reportOutgoingCallWith:(nonnull NSUUID *)uuid connectedAt:(nullable NSDate *)dateConnected;
+ (void)request:(nonnull CXTransaction *)transaction completion:(nonnull void (^)(NSError *_Nullable))completion;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,284 @@
/*
* Copyright @ 2022-present 8x8, Inc.
* Copyright @ 2018-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "JMCallKitProxy.h"
#import "JMCallKitEmitter.h"
#pragma mark -
@interface CXProvider(CXProviderProtocol) <CXProviderProtocol>
@end
@implementation CXProvider(CXProviderProtocol)
@end
#pragma mark -
@interface CXCallController(CXCallControllerProtocol) <CXCallControllerProtocol>
@property (nonatomic, readonly) NSArray<CXCall*> *calls;
@end
@implementation CXCallController(CXCallControllerProtocol)
@dynamic calls;
- (NSArray<CXCall*> *)calls {
return self.callObserver.calls;
}
@end
#pragma mark -
@interface JMCallKitProxy ()
@property (class) CXProvider *defaultProvider;
@property (class) CXProviderConfiguration *providerConfiguration;
@end
@interface JMCallKitProxy (Helpers)
+ (CXCallUpdate *)makeCXUpdateWithHandle:(nullable NSString *)handle displayName:(nullable NSString *)displayName hasVideo:(BOOL)hasVideo;
@end
@implementation JMCallKitProxy
@dynamic callKitProvider, callKitCallController, enabled;
@dynamic defaultProvider, providerConfiguration;
static id<CXProviderProtocol> _callKitProvider = nil;
static id<CXCallControllerProtocol> _callKitCallController = nil;
static BOOL _enabled = false;
static CXProvider *_defaultProvider = nil;
static CXProviderConfiguration *_providerConfiguration = nil;
#pragma mark CallJit proxy
+ (id<CXProviderProtocol>)callKitProvider {
return _callKitProvider;
}
+ (void)setCallKitProvider:(id<CXProviderProtocol>)callKitProvider {
if (_callKitProvider != callKitProvider) {
_callKitProvider = callKitProvider;
}
}
+ (id<CXCallControllerProtocol>)callKitCallController {
return _callKitCallController;
}
+ (void)setCallKitCallController:(id<CXCallControllerProtocol>)callKitCallController {
if (_callKitCallController != callKitCallController) {
_callKitCallController = callKitCallController;
}
}
+ (BOOL)enabled {
return _enabled;
}
+ (void)setEnabled:(BOOL)enabled {
_enabled = enabled ;
if (!self.callKitProvider) {
[self.provider invalidate];
}
if (enabled) {
CXProviderConfiguration *configuration = self.providerConfiguration? self.providerConfiguration : [[CXProviderConfiguration alloc] initWithLocalizedName:@""];
if (!self.callKitProvider) {
self.defaultProvider = [[CXProvider alloc] initWithConfiguration: configuration];
}
[self.provider setDelegate:self.emitter queue:nil];
} else {
[self.provider setDelegate:nil queue:nil];
}
}
+ (CXProvider *)defaultProvider {
return _defaultProvider;
}
+ (void)setDefaultProvider:(CXProvider *)defaultProvider {
if (_defaultProvider != defaultProvider) {
_defaultProvider = defaultProvider;
}
}
+ (id<CXProviderProtocol>)provider {
return self.callKitProvider != nil ? self.callKitProvider : self.defaultProvider;
}
+ (id<CXCallControllerProtocol>)callController {
return self.callKitCallController != nil ? self.callKitCallController : self.defaultCallController;
}
+ (CXProviderConfiguration *)providerConfiguration {
return _providerConfiguration;
}
+ (void)setProviderConfiguration:(CXProviderConfiguration *)providerConfiguration {
if (_providerConfiguration != providerConfiguration) {
_providerConfiguration = providerConfiguration;
if (providerConfiguration) {
self.provider.configuration = providerConfiguration;
[self.provider setDelegate:self.emitter queue:nil];
}
}
}
+ (CXCallController *)defaultCallController {
static dispatch_once_t once;
static CXCallController *defaultCallController;
dispatch_once(&once, ^{
defaultCallController = [[CXCallController alloc] init];
});
return defaultCallController;
}
+ (JMCallKitEmitter *)emitter {
static dispatch_once_t once;
static JMCallKitEmitter *emitter;
dispatch_once(&once, ^{
emitter = [[JMCallKitEmitter alloc] init];
});
return emitter;
}
+ (void)configureProviderWithLocalizedName:(nonnull NSString *)localizedName
ringtoneSound:(nullable NSString *)ringtoneSound
iconTemplateImageData:(nullable NSData*)imageData {
if (!self.enabled) {
return;
}
CXProviderConfiguration *configuration = [[CXProviderConfiguration alloc] initWithLocalizedName:localizedName];
configuration.iconTemplateImageData = imageData;
configuration.maximumCallGroups = 1;
configuration.maximumCallsPerCallGroup = 1;
configuration.ringtoneSound = ringtoneSound;
configuration.supportedHandleTypes = [NSSet setWithArray:@[@(CXHandleTypeGeneric)]];
configuration.supportsVideo = true;
self.providerConfiguration = configuration;
}
+ (BOOL)isProviderConfigured {
return self.providerConfiguration != nil;
}
+ (void)addListener:(nonnull id<JMCallKitListener>)listener {
[self.emitter addListener:listener];
}
+ (void)removeListener:(nonnull id<JMCallKitListener>)listener {
[self.emitter removeListener:listener];
}
+ (BOOL)hasActiveCallForUUID:(nonnull NSString *)callUUID {
CXCall *activeCallForUUID = [[self.callController calls] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(CXCall *evaluatedObject, NSDictionary<NSString *,id> *bindings) {
return evaluatedObject.UUID.UUIDString == callUUID;
}]].firstObject;
if (!activeCallForUUID) {
return false;
}
return true;
}
+ (void)reportNewIncomingCallWithUUID:(nonnull NSUUID *)uuid
handle:(nullable NSString*)handle
displayName:(nullable NSString*)displayName
hasVideo:(BOOL)hasVideo
completion:(nonnull void (^)(NSError *_Nullable))completion {
if (!self.enabled) {
return;
}
CXCallUpdate *callUpdate = [self makeCXUpdateWithHandle:handle displayName:displayName hasVideo:hasVideo];
[self.provider reportNewIncomingCallWithUUID:uuid update:callUpdate completion:completion];
}
+ (void)reportCallUpdateWith:(nonnull NSUUID *)uuid
handle:(nullable NSString *)handle
displayName:(nullable NSString *)displayName
hasVideo:(BOOL)hasVideo {
if (!self.enabled) {
return;
}
CXCallUpdate *callUpdate = [self makeCXUpdateWithHandle:handle displayName:displayName hasVideo:hasVideo];
[self.provider reportCallWithUUID:uuid updated:callUpdate];
}
+ (void)reportCallWith:(nonnull NSUUID *)uuid
endedAt:(nullable NSDate *)dateEnded
reason:(CXCallEndedReason)endedReason {
[self.provider reportCallWithUUID:uuid endedAtDate:dateEnded reason:endedReason];
}
+ (void)reportOutgoingCallWith:(nonnull NSUUID *)uuid startedConnectingAt:(nullable NSDate *)dateStartedConnecting {
[self.provider reportOutgoingCallWithUUID:uuid startedConnectingAtDate:dateStartedConnecting];
}
+ (void)reportOutgoingCallWith:(nonnull NSUUID *)uuid connectedAt:(nullable NSDate *)dateConnected {
[self.provider reportOutgoingCallWithUUID:uuid connectedAtDate:dateConnected];
}
+ (void)request:(nonnull CXTransaction *)transaction completion:(nonnull void (^)(NSError *_Nullable))completion {
if (!self.enabled) {
return;
}
// XXX keep track of muted actions to avoid "ping-pong"ing. See
// JMCallKitEmitter for details on the CXSetMutedCallAction handling.
for (CXAction *action in transaction.actions) {
if ([CXAction isKindOfClass:[CXSetMutedCallAction class]]) {
[self.emitter addMuteAction:action.UUID];
}
}
[self.callController requestTransaction:transaction completion:completion];
}
@end
@implementation JMCallKitProxy (Helpers)
+ (CXCallUpdate *)makeCXUpdateWithHandle:(nullable NSString *)handle displayName:(nullable NSString *)displayName hasVideo:(BOOL)hasVideo {
CXCallUpdate *update = [[CXCallUpdate alloc] init];
update.supportsDTMF = false;
update.supportsHolding = false;
update.supportsGrouping = false;
update.supportsUngrouping = false;
update.hasVideo = hasVideo;
update.localizedCallerName = displayName;
if (handle) {
update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:handle];
}
return update;
}
@end

View File

@@ -1,231 +0,0 @@
/*
* Copyright @ 2018-present 8x8, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import CallKit
import Foundation
public protocol CXProviderProtocol: AnyObject {
var configuration: CXProviderConfiguration { get set }
func setDelegate(_ delegate: CXProviderDelegate?, queue: DispatchQueue?)
func reportNewIncomingCall(with UUID: UUID, update: CXCallUpdate, completion: @escaping (Error?) -> Void)
func reportCall(with UUID: UUID, updated update: CXCallUpdate)
func reportCall(with UUID: UUID, endedAt dateEnded: Date?, reason endedReason: CXCallEndedReason)
func reportOutgoingCall(with UUID: UUID, startedConnectingAt dateStartedConnecting: Date?)
func reportOutgoingCall(with UUID: UUID, connectedAt dateConnected: Date?)
func invalidate()
}
public protocol CXCallControllerProtocol: AnyObject {
var calls: [CXCall] { get }
func request(_ transaction: CXTransaction, completion: @escaping (Error?) -> Swift.Void)
}
extension CXProvider: CXProviderProtocol {}
extension CXCallController: CXCallControllerProtocol {
public var calls: [CXCall] {
return callObserver.calls
}
}
/// JitsiMeet CallKit proxy
// NOTE: The methods this class exposes are meant to be called in the UI thread.
// All delegate methods called by JMCallKitEmitter will be called in the UI thread.
@objc public final class JMCallKitProxy: NSObject {
private override init() {}
// MARK: - CallKit proxy
public static var callKitProvider: CXProviderProtocol?
public static var callKitCallController: CXCallControllerProtocol?
private static var defaultProvider: CXProvider?
private static var provider: CXProviderProtocol? {
callKitProvider ?? defaultProvider
}
private static var callController: CXCallControllerProtocol {
callKitCallController ?? defaultCallController
}
private static var providerConfiguration: CXProviderConfiguration? {
didSet {
guard let configuration = providerConfiguration else { return }
provider?.configuration = configuration
provider?.setDelegate(emitter, queue: nil)
}
}
private static let defaultCallController: CXCallController = {
return CXCallController()
}()
private static let emitter: JMCallKitEmitter = {
return JMCallKitEmitter()
}()
/// Enables the proxy in between CallKit and the consumers of the SDK.
/// Defaults to disabled. Set to true when you want to use CallKit.
@objc public static var enabled: Bool = false {
didSet {
if callKitProvider == nil {
provider?.invalidate()
}
if enabled {
let configuration = providerConfiguration ?? CXProviderConfiguration(localizedName: "")
if callKitProvider == nil {
defaultProvider = CXProvider(configuration: configuration)
}
provider?.setDelegate(emitter, queue: nil)
} else {
provider?.setDelegate(nil, queue: nil)
}
}
}
@objc public static func configureProvider(localizedName: String,
ringtoneSound: String?,
iconTemplateImageData: Data?) {
guard enabled else { return }
let configuration = CXProviderConfiguration(localizedName: localizedName)
configuration.iconTemplateImageData = iconTemplateImageData
configuration.maximumCallGroups = 1
configuration.maximumCallsPerCallGroup = 1
configuration.ringtoneSound = ringtoneSound
configuration.supportedHandleTypes = [CXHandle.HandleType.generic]
configuration.supportsVideo = true
providerConfiguration = configuration
}
@objc public static func isProviderConfigured() -> Bool {
return providerConfiguration != nil
}
@objc public static func addListener(_ listener: JMCallKitListener) {
emitter.addListener(listener)
}
@objc public static func removeListener(_ listener: JMCallKitListener) {
emitter.removeListener(listener)
}
@objc public static func hasActiveCallForUUID(_ callUUID: String) -> Bool {
let activeCallForUUID = callController.calls.first {
$0.uuid == UUID(uuidString: callUUID)
}
guard activeCallForUUID != nil else { return false }
return true
}
@objc public static func reportNewIncomingCall(UUID: UUID,
handle: String?,
displayName: String?,
hasVideo: Bool,
completion: @escaping (Error?) -> Void) {
guard enabled else { return }
let callUpdate = makeCXUpdate(handle: handle,
displayName: displayName,
hasVideo: hasVideo)
provider?.reportNewIncomingCall(with: UUID,
update: callUpdate,
completion: completion)
}
@objc public static func reportCallUpdate(with UUID: UUID,
handle: String?,
displayName: String?,
hasVideo: Bool) {
guard enabled else { return }
let callUpdate = makeCXUpdate(handle: handle,
displayName: displayName,
hasVideo: hasVideo)
provider?.reportCall(with: UUID, updated: callUpdate)
}
@objc public static func reportCall(
with UUID: UUID,
endedAt dateEnded: Date?,
reason endedReason: CXCallEndedReason) {
guard enabled else { return }
provider?.reportCall(with: UUID,
endedAt: dateEnded,
reason: endedReason)
}
@objc public static func reportOutgoingCall(
with UUID: UUID,
startedConnectingAt dateStartedConnecting: Date?) {
guard enabled else { return }
provider?.reportOutgoingCall(with: UUID,
startedConnectingAt: dateStartedConnecting)
}
@objc public static func reportOutgoingCall(
with UUID: UUID,
connectedAt dateConnected: Date?) {
guard enabled else { return }
provider?.reportOutgoingCall(with: UUID, connectedAt: dateConnected)
}
@objc public static func request(
_ transaction: CXTransaction,
completion: @escaping (Error?) -> Swift.Void) {
guard enabled else { return }
// XXX keep track of muted actions to avoid "ping-pong"ing. See
// JMCallKitEmitter for details on the CXSetMutedCallAction handling.
for action in transaction.actions {
if (action as? CXSetMutedCallAction) != nil {
emitter.addMuteAction(action.uuid)
}
}
callController.request(transaction, completion: completion)
}
// MARK: - Callkit Proxy helpers
private static func makeCXUpdate(handle: String?,
displayName: String?,
hasVideo: Bool) -> CXCallUpdate {
let update = CXCallUpdate()
update.supportsDTMF = false
update.supportsHolding = false
update.supportsGrouping = false
update.supportsUngrouping = false
update.hasVideo = hasVideo
if let handle = handle {
update.remoteHandle = CXHandle(type: .generic,
value: handle)
}
if let displayName = displayName {
update.localizedCallerName = displayName
}
return update
}
}

View File

@@ -11,7 +11,6 @@
"defaultEmail": "بريدك الافتراضي",
"disabled": "لا يمكنك دعوة أحد.",
"failedToAdd": "فشل إضافة مشاركين",
"footerText": "الاتصال لدعوة الغير مُعطَّل.",
"googleEmail": "بريد غوغل",
"inviteMoreHeader": "أنت بمفردك في هذا المُلتقى",
"inviteMoreMailSubject": "ضم {{appName}} للمُلتقى",
@@ -97,6 +96,7 @@
"messageAccessibleTitleMe": "أنا أقول:",
"messageTo": "أرسل رسالة خاصة إلى {{recipient}}",
"messagebox": "اكتب رسالة",
"newMessages": "رسائل جديدة",
"nickname": {
"popover": "اختر لقبًا",
"title": "اكتب لقبًا لاعتماده في المحادثة",
@@ -146,7 +146,6 @@
"bridgeCount": "عدد المخدِّمات: ",
"codecs": "المرماز (A/V): ",
"connectedTo": "وصل إلى:",
"e2e_rtt": "E2E RTT:",
"framerate": "مُعدَّل الإطارات:",
"less": "اخف",
"localaddress": "العنوان المحلي:",
@@ -198,8 +197,8 @@
"deviceError": {
"cameraError": "فشل الوصول إلى كاميرتك",
"cameraPermission": "خطأ في تحصيل إذن استخدام كاميرتك",
"microphoneError": "فشل الوصول إلى مجهارك (المايكروفون)",
"microphonePermission": "خطأ في تحصيل إذن استخدام المجهار (المايكروفون)"
"microphoneError": "فشل الوصول إلى المايكروفون",
"microphonePermission": "خطأ في تحصيل إذن استخدام المايكروفون"
},
"deviceSelection": {
"noPermission": "لم يُمنَح الإذن",
@@ -285,7 +284,6 @@
"linkMeetingTitle": "ربط المُلتقى بـ Salesforce",
"liveStreaming": "البث المباشر الحي",
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "غير ممكن أثناء التسجيل",
"liveStreamingDisabledTooltip": "بدء بثٍ حيٍّ مُعطَّل",
"localUserControls": "ضوابط المستخدم المحلي",
"lockMessage": "فشل جعل المؤتمر مغلقًا.",
"lockRoom": "أضف المُلتقى $t(lockRoomPasswordUppercase)",
@@ -295,11 +293,11 @@
"logoutTitle": "الخروج",
"maxUsersLimitReached": "وصل عدد المشاركين إلى الحد الأقصى. المؤتمر مكتمل الحضور. اتصل رجاءً براعي المؤتمر أو جرب مرة أخرى لاحقًا.",
"maxUsersLimitReachedTitle": "وصل عدد المشاركين إلى الحد الأقصى",
"micConstraintFailedError": "لا يوافق المجهار (المايكروفون) لديك بعض القيود المطلوبة.",
"micNotFoundError": "لم يُعثَر على أي مجهار (مايكروفون)",
"micNotSendingData": "اذهب إلى إعدادات حاسوبك لإلغاء كتم المجهار (المايكروفون) وضبط مستواه",
"micNotSendingDataTitle": "كتم ضبط الإعدادات لديك المجهار (المايكروفون)",
"micPermissionDeniedError": "لم تعط إذن استعمال المجهار (المايكروفون) الخاص بك. ما يزال بإمكانك الإنضمام إلى المؤتمر ولكن دون أن يسمعك الآخرون. جرب استعمال زر الكاميرا في شريط العنوان لإصلاح هذه المشكلة.",
"micConstraintFailedError": "لا يوافق المايكروفون لديك بعض القيود المطلوبة.",
"micNotFoundError": "لم يُعثَر على أي مايكروفون",
"micNotSendingData": "اذهب إلى إعدادات حاسوبك لإلغاء كتم المايكروفون وضبط مستواه",
"micNotSendingDataTitle": "كتم ضبط الإعدادات لديك المايكروفون",
"micPermissionDeniedError": "لم تعط إذن استعمال المايكروفون الخاص بك. ما يزال بإمكانك الإنضمام إلى المؤتمر ولكن دون أن يسمعك الآخرون. جرب استعمال زر الكاميرا في شريط العنوان لإصلاح هذه المشكلة.",
"micTimeoutError": "تعذر بدء مصدر الصوت. انقضت المهلة!",
"micUnknownError": "لا يمكن استخدام الميكروفون لسبب غير معروف.",
"moderationAudioLabel": "السماح للحاضرين بإعادة الصوت بأنفسهم",
@@ -340,7 +338,6 @@
"recentlyUsedObjects": "الأشياء المستخدمة مؤخرًا",
"recording": "قيد التسجيل",
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "ليس بالإمكان ما دمت قيد البث المباشر",
"recordingDisabledTooltip": "عملية التسجيل معطلة.",
"rejoinNow": "انضم مجدَّدًا الآن",
"remoteControlAllowedMessage": "قبل {{user}} طلب إمكانية التحكم البعيد!",
"remoteControlDeniedMessage": "رفض {{user}} طلب إمكانية التحكم البعيد!",
@@ -506,7 +503,7 @@
"giphyMenu": "تبديل قائمة GIPHY",
"keyboardShortcuts": "اختصارات لوحة المفاتيح",
"localRecording": "اظهِر أو اخفِ التحكم بالتسجيل المحلي",
"mute": "اكتم أو ألغ كتم المجهار (المايكروفون) الخاص بك",
"mute": "اكتم أو ألغ كتم المايكروفون الخاص بك",
"pushToTalk": "اضغط للتحدث",
"raiseHand": "ارفع/اخفض يدك",
"showSpeakerStats": "اظهر حالة مكبر الصوت",
@@ -517,6 +514,10 @@
"toggleShortcuts": "أظهِر/اخفِ اختصارات لوحة المفاتيح",
"videoMute": "ابدأ/أوقف كاميرتك"
},
"largeVideo": {
"screenIsShared": "أنت تشارك شاشتك",
"showMeWhatImSharing": "أرني ما أشاركه"
},
"liveStreaming": {
"busy": "نعمل على تحرير موارد البث. حاول مرة أخرى رجاءً بعض بضعة دقائق.",
"busyTitle": "جميع من يبث الفيديو مشغولون حاليًا",
@@ -646,7 +647,7 @@
"focusFail": "إنَّ {{component}} غير متاح. ستعاد المحاولة مرة أخرى خلال {{ms}} ثانية.",
"gifsMenu": "GIPHY",
"groupTitle": "إشعارات",
"hostAskedUnmute": "The moderator would like you to speak",
"hostAskedUnmute": "يريدك مدير اللقاء أن تتحدث.",
"invitedOneMember": "دُعِي {{name}}",
"invitedThreePlusMembers": "دُعِي {{name}} وعدد {{count}} آخرين",
"invitedTwoMembers": "دُعِي {{first}} و {{second}}",
@@ -707,8 +708,8 @@
"suboptimalBrowserWarning": "نخشى أن لا تكون تجربة المُلتقى جيدة. نعمل على تحسين الكثير من الأمور، لكن ننصحك حتى ذلك الحين باستعمال باستعمال أحد <a href='static/recommendedBrowsers.html' target='_blank'>المتصفحات المدعومة</a>.",
"suboptimalExperienceTitle": "تحذير من المتصفح",
"unmute": "إلغاء الكتم",
"videoMutedRemotelyDescription": "You can always turn it on again.",
"videoMutedRemotelyTitle": "Your video has been turned off by {{participantDisplayName}}",
"videoMutedRemotelyDescription": "يمكنك دائمًا تشغيله مرة أخرى.",
"videoMutedRemotelyTitle": "تم إيقاف الفيديو الخاص بك بواسطة {{participantDisplayName}}",
"videoUnmuteBlockedDescription": "تم حظر عملية إلغاء كتم الكاميرا مؤقتًا بسبب قيود النظام.",
"videoUnmuteBlockedTitle": "تم حظر إعادة الكاميرا!",
"viewLobby": "مشاهدة اللوبي",
@@ -797,7 +798,7 @@
"goodQuality": "رائع! الجودة في تحسن للأفضل!",
"noMediaConnectivity": "لم نتمكن من إيجاد وسيلة لإنشاء اتصال لهذه التجربة، وسبب هذا عائد إلى الجدار الناري أو مترجم عناوين الشبكة NAT في أغلب الأحيان.",
"noVideo": "نتوقع أن تكون جودة الفيديو تعيسة.",
"undetectable": "إن مازلت غير قادر على إجراء اتصالات من المتصفح، ننصح بالتأكد من حالة مكبرات الصوت والمجهار (المايكروفون) والكاميرا، وأنَّك منحت المتصفح إذن الوصول إليها وأن المتصفح محدَّث إلى أحدث إصدار. إن ما زلت تواجه مشاكل في الاتصال بعد ذلك، حاول التواصل مع مطوري تطبيق الويب.",
"undetectable": "إن مازلت غير قادر على إجراء اتصالات من المتصفح، ننصح بالتأكد من حالة مكبرات الصوت والمايكروفون والكاميرا، وأنَّك منحت المتصفح إذن الوصول إليها وأن المتصفح محدَّث إلى أحدث إصدار. إن ما زلت تواجه مشاكل في الاتصال بعد ذلك، حاول التواصل مع مطوري تطبيق الويب.",
"veryPoorConnection": "نتوقع أن تكون جودة الاتصال تعيسة.",
"videoFreezing": "نتوقع حصول جمود في الفيديو أو تحول الصورة للسواد",
"videoHighQuality": "نتوقع أن تكون جودة الفيديو جيدة",
@@ -825,7 +826,7 @@
"joinWithoutAudio": "انضم دون صوت",
"keyboardShortcuts": "تفعيل اختصارات لوحة المفاتيح",
"linkCopied": "نُسِخ الرابط",
"lookGood": "يبدو أن المجهار لديك تعيس",
"lookGood": "يبدو أن الميكروفون لديك سيء",
"or": "أو",
"premeeting": "ما قبل المُلتقى",
"screenSharingError": "خطأ في مشاركة الشاشة:",
@@ -955,7 +956,7 @@
"language": "اللغة",
"loggedIn": "الدخول باسم {{name}}",
"maxStageParticipants": "الحد الأقصى لعدد المشاركين الذين يمكن تثبيتهم في المرحلة الرئيسية",
"microphones": "المجهار (المايكروفون)",
"microphones": "المايكروفون",
"moderator": "رئيس الجلسة",
"more": "المزيد",
"name": "الاسم",
@@ -969,7 +970,7 @@
"screenTitle": "إعدادات",
"selectAudioOutput": "خرج الصوت",
"selectCamera": "الكاميرا",
"selectMic": "المجهار (المايكروفون)",
"selectMic": "المايكروفون",
"selfView": "عرض ذاتي",
"sounds": "اصوات",
"speakers": "المذياع (مكبر الصوت)",
@@ -1032,7 +1033,7 @@
"startupoverlay": {
"genericTitle": "يحتاج المُلتقى إلى استخدام الميكروفون والكاميرا.",
"policyText": " ",
"title": "يريد {{app}} استعمال المجهار والكاميرا خاصَّتك."
"title": "يريد {{app}} استعمال الميكروفون والكاميرا خاصَّتك."
},
"suspendedoverlay": {
"rejoinKeyTitle": "المنطقة",
@@ -1061,6 +1062,7 @@
"document": "اظهِر/اخفِ الملف المشارك",
"download": "نزِّل التطبيق",
"embedMeeting": "ضمِّن المُلتقى",
"endConference": "End meeting for all",
"expand": "وسّع",
"feedback": "أبدِ رأيك",
"fullScreen": "استعمل/اخرج من وضع الشاشة الكاملة",
@@ -1134,6 +1136,7 @@
"download": "نزِّل التطبيق",
"e2ee": "تعمية طرف-لطرف",
"embedMeeting": "ضمِّن المُلتقى",
"endConference": "إنهاء الاجتماع للجميع",
"enterFullScreen": "تعمية طرف-لطرف",
"enterTileView": "عرض بشاشة كاملة",
"exitFullScreen": "أدخل عنوان العرض",
@@ -1163,10 +1166,10 @@
"noAudioSignalDescSuggestion": "إن لم تكتمه عمدًا من إعدادات النظام لديك أو من الجهاز نفسه، بدِّله إلى الجهاز الموصى به.",
"noAudioSignalDialInDesc": "يمكن أيضًا الاتصال باستعمال:",
"noAudioSignalDialInLinkDesc": "أرقام الاتصال",
"noAudioSignalTitle": "لا يصلنا شيئًا من المجهار (المايكروفون) الخاص بك",
"noAudioSignalTitle": "لا يصلنا شيئًا من المايكروفون الخاص بك",
"noiseSuppression": "قمع الضوضاء",
"noisyAudioInputDesc": "يبدو أنَّ المجهار (المايكروفون) لديك يصدر الكثير من الضجة، اكتمه رجاءً أو استعمل مجهارًا آخر.",
"noisyAudioInputTitle": "يبدو أنَّ المجهار (المايكروفون) لديك يصدر الكثير من الضجة!",
"noisyAudioInputDesc": "يبدو أنَّ المايكروفون لديك يلتقط الكثير من الضجة، اكتمه رجاءً أو استعمل ميكروفونًا آخر.",
"noisyAudioInputTitle": "يبدو أنَّ المايكروفون لديك يلتقط الكثير من الضجة!",
"openChat": "فتح الدرشة",
"openReactionsMenu": "افتح قائمة التفاعلات",
"participants": "مشاركون",
@@ -1196,7 +1199,7 @@
"stopSharedVideo": "أوقف فيديو يوتيوب المشارك",
"stopSubtitles": "أخفِ الترجمة",
"surprised": "مندهش",
"talkWhileMutedPopup": "أتحاول التحدث؟ المجهار مكتوم لديك.",
"talkWhileMutedPopup": "أتحاول التحدث؟ الميكروفون لديك مكتوم.",
"tileViewToggle": "بدِّل عنوان العرض",
"toggleCamera": "بدِّل الكاميرا",
"undock": "فك في نافذة منفصلة",
@@ -1213,16 +1216,18 @@
"pending": "التحضير لإذاعة المُلتقى...",
"start": "بدء إظهار الترجمة",
"stop": "إيقاف عرض الترجمة",
"subtitles": "ترجمات",
"subtitlesOff": "إيقاف",
"tr": "يذاع"
},
"userMedia": {
"androidGrantPermissions": "اختر <b><i>السماح</i></b> عندما يطلب المتصفح الأذونات.",
"chromeGrantPermissions": "اختر <b><i>السماح</i></b> عندما يطلب المتصفح الأذونات.",
"edgeGrantPermissions": "اختر <b><i>نعم</i></b> عندما يطلب المتصفح الأذونات.",
"electronGrantPermissions": "امنح إذنًا باستعمال الكاميرا والمجهار (المايكروفون).",
"electronGrantPermissions": "امنح إذنًا باستعمال الكاميرا والمايكروفون.",
"firefoxGrantPermissions": "اختر <b><i>مشاركة الجهاز المحدَّد</i></b> عندما يطل بالمتصفح الأذونات.",
"iexplorerGrantPermissions": "اختر <b><i>تمام</i></b> عندما يطلب المتصفح الأذونات.",
"nwjsGrantPermissions": "امنح إذنًا باستعمال الكاميرا والمجهار (المايكروفون).",
"nwjsGrantPermissions": "امنح إذنًا باستعمال الكاميرا والمايكروفون.",
"operaGrantPermissions": "اختر <b><i>السماح</i></b> عندما يطلب المتصفح الأذونات.",
"react-nativeGrantPermissions": "اختر <b><i>السماح</i></b> عندما يطلب المتصفح الأذونات.",
"safariGrantPermissions": "اختر <b><i>تمام</i></b> عندما يطلب المتصفح الأذونات."

View File

@@ -90,7 +90,6 @@
"bitrate": "Бітрэйт:",
"bridgeCount": "Колькасць сервераў: ",
"connectedTo": "Падключаны да:",
"e2e_rtt": "E2E RTT:",
"framerate": "Частата кадраў:",
"less": "Кароткая інфармацыя",
"localaddress_0": "Мясцовы адрас:",

View File

@@ -145,7 +145,6 @@
"bridgeCount": "Nombre de servidors: ",
"codecs": "Còdecs (A/V):",
"connectedTo": "Connectat a:",
"e2e_rtt": "E2E RTT:",
"framerate": "Taxa de fotogrames:",
"less": "Menys informació",
"localaddress": "Adreça local:",

View File

@@ -108,7 +108,6 @@
"bridgeCount": "Počet serverů: ",
"codecs": "Kodeky (A/V): ",
"connectedTo": "Připojeno k:",
"e2e_rtt": "E2E RTT:",
"framerate": "Rychlost snímkování:",
"less": "Zobrazit méně",
"localaddress_0": "Místní adresa:",

View File

@@ -90,7 +90,6 @@
"bitrate": "Bitrate:",
"bridgeCount": "Server antal: ",
"connectedTo": "Forbundet til:",
"e2e_rtt": "E2E RTT:",
"framerate": "Frame rate:",
"less": "Vis mindre",
"localaddress": "Lokal adresse:",

View File

@@ -11,7 +11,6 @@
"defaultEmail": "Ihre Standard-E-Mail",
"disabled": "Sie können keine Personen einladen.",
"failedToAdd": "Fehler beim Hinzufügen von Personen",
"footerText": "Abgehender Ruf ist deaktiviert.",
"googleEmail": "Google-E-Mail",
"inviteMoreHeader": "Sie sind alleine in der Sitzung",
"inviteMoreMailSubject": "An {{appName}} Meeting teilnehmen",
@@ -97,6 +96,7 @@
"messageAccessibleTitleMe": "Ich sage:",
"messageTo": "Private Nachricht an {{recipient}}",
"messagebox": "Nachricht eingeben",
"newMessages": "Neue Nachrichten",
"nickname": {
"popover": "Wähle einen Alias",
"title": "Geben Sie einen Alias zum Chatten ein",
@@ -146,7 +146,6 @@
"bridgeCount": "Serverzahl: ",
"codecs": "Codecs (A/V): ",
"connectedTo": "Verbunden mit:",
"e2e_rtt": "Ende-zu-Ende-Paketumlaufzeit:",
"framerate": "Bildwiederholrate:",
"less": "Weniger anzeigen",
"localaddress": "Lokale Adresse:",
@@ -285,7 +284,6 @@
"linkMeetingTitle": "Konferenz mit Salesforce verlinken",
"liveStreaming": "Livestreaming",
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "Während einer Aufnahme nicht möglich",
"liveStreamingDisabledTooltip": "Starten des Livestreams deaktiviert.",
"localUserControls": "Lokale Benutzersteuerung",
"lockMessage": "Die Konferenz konnte nicht gesperrt werden.",
"lockRoom": "Konferenz$t(lockRoomPassword) hinzufügen",
@@ -340,7 +338,6 @@
"recentlyUsedObjects": "Ihre zuletzt verwendeten Objekte",
"recording": "Aufnahme",
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Während eines Livestreams nicht möglich",
"recordingDisabledTooltip": "Start der Aufzeichnung deaktiviert.",
"rejoinNow": "Jetzt erneut beitreten",
"remoteControlAllowedMessage": "{{user}} hat die Anfrage zur Fernsteuerung angenommen!",
"remoteControlDeniedMessage": "{{user}} hat die Anfrage zur Fernsteuerung verweigert!",
@@ -517,6 +514,10 @@
"toggleShortcuts": "Tastenkombinationen ein- oder ausblenden",
"videoMute": "Kamera starten oder stoppen"
},
"largeVideo": {
"screenIsShared": "Ihr Bildschirm wird freigegeben",
"showMeWhatImSharing": "Anzeigen, was freigegeben wird"
},
"liveStreaming": {
"busy": "Es werden Ressourcen zum Streamen bereitgestellt. Bitte in ein paar Minuten erneut versuchen.",
"busyTitle": "Alle Streaming-Instanzen sind in Gebrauch",
@@ -993,12 +994,17 @@
"displayName": "Anzeigename",
"displayNamePlaceholderText": "z.B. Erika Musterfrau",
"email": "E-Mail",
"goTo": "Gehe zu",
"header": "Einstellungen",
"help": "Hilfe",
"links": "Links",
"privacy": "Datenschutz",
"profileSection": "Profil",
"serverURL": "Server-URL",
"showAdvanced": "Erweiterte Einstellungen anzeigen",
"startWithAudioMuted": "Stumm beitreten",
"startWithVideoMuted": "Ohne Video beitreten",
"terms": "Nutzungsbedingungen",
"version": "Version"
},
"share": {
@@ -1055,6 +1061,7 @@
"document": "Geteiltes Dokument schließen",
"download": "Unsere Apps herunterladen",
"embedMeeting": "Konferenz einbetten",
"endConference": "Konferenz für alle beenden",
"expand": "Ausklappen",
"feedback": "Feedback hinterlassen",
"fullScreen": "Vollbildmodus ein-/ausschalten",
@@ -1128,6 +1135,7 @@
"download": "Unsere Apps herunterladen",
"e2ee": "Ende-zu-Ende-Verschlüsselung",
"embedMeeting": "Konferenz einbetten",
"endConference": "Konferenz für alle beenden",
"enterFullScreen": "Vollbildmodus",
"enterTileView": "Kachelansicht einschalten",
"exitFullScreen": "Vollbildmodus verlassen",
@@ -1207,6 +1215,8 @@
"pending": "Transkribieren des Meetings wird vorbereitet…",
"start": "Anzeige der Untertitel starten",
"stop": "Anzeige der Untertitel stoppen",
"subtitles": "Untertitel",
"subtitlesOff": "Ausschalten",
"tr": "TR"
},
"userMedia": {

View File

@@ -105,7 +105,6 @@
"bitrate": "Ρυθμός μετάδοσης:",
"bridgeCount": "Αριθμός server: ",
"connectedTo": "Συνδεδεμένος με:",
"e2e_rtt": "E2E RTT:",
"framerate": "Ρυθμός ανανέωσης:",
"less": "Δείξε λιγότερα",
"localaddress": "Τοπική διεύθυνση:",

View File

@@ -92,7 +92,6 @@
"bridgeCount": "Server count: ",
"codecs": "Codecs (A/V): ",
"connectedTo": "Connected to:",
"e2e_rtt": "",
"framerate": "Frame rate:",
"less": "Show less",
"localaddress": "Local address:",

View File

@@ -90,7 +90,6 @@
"bitrate": "Bitrate:",
"bridgeCount": "Server count: ",
"connectedTo": "Connected to:",
"e2e_rtt": "E2E RTT:",
"framerate": "Frame rate:",
"less": "Show less",
"localaddress": "Local address:",

View File

@@ -114,7 +114,6 @@
"bridgeCount": "Contador del servidor: ",
"codecs": "Codecs (A/V):",
"connectedTo": "Conectado a:",
"e2e_rtt": "E2E RTT:",
"framerate": "Fotogramas por segundo:",
"less": "Mostrar menos",
"localaddress": "Dirección local:",

View File

@@ -122,7 +122,6 @@
"bridgeCount": "Contador del servidor: ",
"codecs": "Codecs (A/V):",
"connectedTo": "Conectado a:",
"e2e_rtt": "E2E RTT:",
"framerate": "Fotogramas por segundo:",
"less": "Mostrar menos",
"localaddress": "Dirección local:",

View File

@@ -90,7 +90,6 @@
"bitrate": "Andmeedastuskiirus:",
"bridgeCount": "Serverite arv: ",
"connectedTo": "Ühendatud:",
"e2e_rtt": "E2E RTT:",
"framerate": "Ekraani eraldusvõime:",
"less": "Näita vähem",
"localaddress": "Lokaalne aadress:",

View File

@@ -110,7 +110,6 @@
"bridgeCount": "Zerbitzari kopurua: ",
"codecs": "Kodekak (A/B): ",
"connectedTo": "Konektatua hona:",
"e2e_rtt": "E2E RTT:",
"framerate": "Marko-abiadura:",
"less": "Erakutsi gutxiago",
"localaddress": "Helbide lokala:",

View File

@@ -134,7 +134,6 @@
"bridgeCount": "تعداد سرور: ",
"codecs": "کدک‌ها (A/V): ",
"connectedTo": "متصل به:",
"e2e_rtt": "E2E RTT:",
"framerate": "نرخ فریم:",
"less": "خلاصه",
"localaddress": "نشانی داخلی:",

View File

@@ -134,7 +134,6 @@
"bridgeCount": "Nombre de serveurs :",
"codecs": "Codecs (A/V) :",
"connectedTo": "Connecté à :",
"e2e_rtt": "E2E RTT :",
"framerate": "Images par seconde :",
"less": "Cacher les détails",
"localaddress": "Adresse locale :",

View File

@@ -90,7 +90,6 @@
"bitrate": "קצב סיביות:",
"bridgeCount": "מספר שרתים: ",
"connectedTo": "מחובר אל:",
"e2e_rtt": "E2E RTT:",
"framerate": "קצב מסגרת:",
"less": "הצג פחות",
"localaddress": "כתובת מקומית:",

View File

@@ -109,7 +109,6 @@
"bridgeCount": "सर्वर गणना: ",
"codecs": "कोडेक (ए/वी): ",
"connectedTo": "से जुड़ा हुआ है :",
"e2e_rtt": "ई.2ई. आर.टी.टी.:",
"framerate": "फ्रेम दर:",
"less": "कम दिखाएं",
"localaddress": "स्थानीय पता:",

View File

@@ -147,7 +147,6 @@
"bridgeCount": "Broj poslužitelja: ",
"codecs": "Kodeki (A/V): ",
"connectedTo": "Povezan na:",
"e2e_rtt": "E2E RTT:",
"framerate": "Broj sličica u sekundi:",
"less": "Pokaži manje",
"localaddress": "Adresa lokalnog uređaja:",

View File

@@ -145,7 +145,6 @@
"bridgeCount": "ličba serwera: ",
"codecs": "kody (A/V): ",
"connectedTo": "zwjazane z:",
"e2e_rtt": "E2E RTT:",
"framerate": " wobrazowospjetna frekwenca:",
"less": "mjenje pokazać",
"localaddress": "lokalna adresa:",

View File

@@ -91,7 +91,6 @@
"bitrate": "Bitsebesség:",
"bridgeCount": "Kiszolgáló száma: ",
"connectedTo": "Kapcsolódva ehhez:",
"e2e_rtt": "E2E RTT:",
"framerate": "Képkockasebesség:",
"less": "Kevesebb megjelenítése",
"localaddress": "Helyi cím:",

View File

@@ -90,7 +90,6 @@
"bitrate": "Bitrate:",
"bridgeCount": "Server count: ",
"connectedTo": "Connected to:",
"e2e_rtt": "E2E RTT:",
"framerate": "Frame rate:",
"less": "Show less",
"localaddress": "Local address:",

View File

@@ -90,7 +90,6 @@
"bitrate": "Bitahraði:",
"bridgeCount": "Fjöldi netþjóna: ",
"connectedTo": "Tengt við:",
"e2e_rtt": "E2E RTT:",
"framerate": "Rammatíðni:",
"less": "Sýna minna",
"localaddress": "Staðvært vistfang:",

View File

@@ -145,7 +145,6 @@
"bridgeCount": "Conteggio server:",
"codecs": "Codec (A/V): ",
"connectedTo": "Connesso a:",
"e2e_rtt": "E2E RTT:",
"framerate": "Fotogrammi al secondo:",
"less": "Mostra meno",
"localaddress": "Indirizzo locale:",

View File

@@ -136,7 +136,6 @@
"bridgeCount": "サーバー数:",
"codecs": "コーデック (A/V): ",
"connectedTo": "接続先:",
"e2e_rtt": "E2E RTT:",
"framerate": "フレームレート:",
"less": "表示を減らす",
"localaddress": "ローカルアドレス:",

View File

@@ -114,7 +114,6 @@
"bridgeCount": "Amḍan n uqeddac: ",
"codecs": "Codecs (A/V) : ",
"connectedTo": "Yeqqen ɣer:",
"e2e_rtt": "E2E RTT:",
"framerate": "Afmiḍi n ukatar:",
"less": "Sken-d drus",
"localaddress": "Tansa tadigant:",

View File

@@ -90,7 +90,6 @@
"bitrate": "Bitrate:",
"bridgeCount": "Serverių skaičius: ",
"connectedTo": "Prijungta prie:",
"e2e_rtt": "E2E RTT:",
"framerate": "Kadrų dažnis:",
"less": "Rodyti mažiau",
"localaddress": "Vietinis adresas:",

View File

@@ -90,7 +90,6 @@
"bitrate": "Bitreits:",
"bridgeCount": "Serveru skaits:",
"connectedTo": "Pieslēdzies pie:",
"e2e_rtt": "E2E RTT:",
"framerate": "Kadru ātrums/skaits:",
"less": "Tikai kodolīga informācija",
"localaddress": "Lokālā adrese:",

View File

@@ -106,7 +106,6 @@
"bridgeCount": "Server count: ",
"codecs": "Codecs (A/V): ",
"connectedTo": "Connected to:",
"e2e_rtt": "E2E RTT:",
"framerate": "Frame rate:",
"less": "Show less",
"localaddress": "Local address:",

View File

@@ -90,7 +90,6 @@
"bitrate": "Битрат:",
"bridgeCount": "Серверийн тоо: ",
"connectedTo": "Холбогдсон:",
"e2e_rtt": "E2E RTT:",
"framerate": "Нягтаршил:",
"less": "Хураах",
"localaddress": "Дотоод хаяг:",

View File

@@ -90,7 +90,6 @@
"bitrate": "बिटरेट:",
"bridgeCount": "सर्व्हर संख्या:",
"connectedTo": "यांना जोडलेले:",
"e2e_rtt": "E2E आरटीटी:",
"framerate": "फ्रेम दर:",
"less": "कमी दाखवा",
"localaddress": "स्थानिक पत्ता:",

View File

@@ -134,7 +134,6 @@
"bridgeCount": "Aantal servers: ",
"codecs": "Codecs (A/V): ",
"connectedTo": "Verbonden met:",
"e2e_rtt": "E2E RTT:",
"framerate": "Framesnelheid:",
"less": "Minder weergeven",
"localaddress": "Lokaal adres:",
@@ -960,6 +959,7 @@
"noAudioSignalDialInDesc": "U kunt ook inbellen met:",
"noAudioSignalDialInLinkDesc": "Inbelnummers",
"noAudioSignalTitle": "Er komt geen invoer van uw microfoon!",
"noiseSuppression": "Ruisonderdrukking",
"noisyAudioInputDesc": "Het klinkt alsof uw microfoon ruis veroorzaakt. Overweeg te dempen of van apparaat te wisselen.",
"noisyAudioInputTitle": "Uw microfoon lijkt ruis te veroorzaken!",
"openChat": "Chat openen",

View File

@@ -136,7 +136,6 @@
"bridgeCount": "Nombre de servidor: ",
"codecs": "Codecs (A/V): ",
"connectedTo": "Connectat a:",
"e2e_rtt": "E2E RTT:",
"framerate": "Frequéncia imatge:",
"less": "Amagar lo detalh",
"localaddress": "Adreça locala:",

View File

@@ -146,7 +146,6 @@
"bridgeCount": "Liczba serwerów: ",
"codecs": "Kodeki (A/V): ",
"connectedTo": "Podłączone do:",
"e2e_rtt": "E2E RTT:",
"framerate": "Klatek na sekundę:",
"less": "Pokaż mniej",
"localaddress": "Adres lokalny:",

View File

@@ -146,7 +146,6 @@
"bridgeCount": "Servidores: ",
"codecs": "Codecs (A/V): ",
"connectedTo": "Ligado a:",
"e2e_rtt": "E2E RTT:",
"framerate": "Taxa de frames:",
"less": "Mostrar menos",
"localaddress": "Endereço local:",

View File

@@ -114,7 +114,6 @@
"bridgeCount": "Servidores: ",
"codecs": "Codecs (A/V): ",
"connectedTo": "Conectado a:",
"e2e_rtt": "E2E RTT:",
"framerate": "Taxa de quadros:",
"less": "Mostrar menos",
"localaddress": "Endereço local:",

View File

@@ -91,7 +91,6 @@
"bitrate": "Bitrate:",
"bridgeCount": "Numărul de servere: ",
"connectedTo": "Conectat la:",
"e2e_rtt": "",
"framerate": "Rată cadre:",
"less": "Arătați mai puțin",
"localaddress": "Adresă locala:",

View File

@@ -41,11 +41,11 @@
},
"breakoutRooms": {
"actions": {
"add": "Добавить комнату отдыха",
"autoAssign": "Auto assign to breakout roomsAuto assign to breakout rooms",
"add": "Добавить переговорную",
"autoAssign": "Привязать к переговорной автоматически",
"close": "Закрыть",
"join": "Присоединиться",
"leaveBreakoutRoom": "Покинуть комнату отдыха",
"leaveBreakoutRoom": "Покинуть переговорную",
"more": "Больше",
"remove": "Удалить",
"sendToBreakoutRoom": "Отправить участника к:"
@@ -76,6 +76,16 @@
"refresh": "Обновить календарь",
"today": "Сегодня"
},
"carmode": {
"actions": {
"selectSoundDevice": "Выбор аудиоустройства"
},
"labels": {
"buttonLabel": "Упрощенный режим",
"title": "Упрощенный режим",
"videoStopped": "Видео остановлено"
}
},
"chat": {
"enter": "Войди в комнату",
"error": "Ошибка: Ваше сообщение не было отправлено. Причина: {{error}}",
@@ -134,7 +144,6 @@
"bridgeCount": "Количество серверов: ",
"codecs": "Кодеки (A/V): ",
"connectedTo": "Подключен к:",
"e2e_rtt": "E2E RTT:",
"framerate": "Частота кадров:",
"less": "Краткая информация",
"localaddress": "Локальный адрес:",
@@ -640,11 +649,11 @@
"leftThreePlusMembers": "{{name}} и многие другие покинули встречу",
"leftTwoMembers": "{{first}} и {{second}} покинули встречу",
"linkToSalesforce": "Ссылка на Salesforce",
"linkToSalesforceDescription": "Вы можете отправить ссылку на сводку митинга Salesforce объекту.",
"linkToSalesforceError": "Ошибка отправки ссылки на митинг для Salesforce",
"linkToSalesforceKey": "Отправить сслку а эот митинг",
"linkToSalesforceProgress": "Отправка ссылки на митинг для Salesforce...",
"linkToSalesforceSuccess": "Ссылка на этот митинг была отправлена Salesforce",
"linkToSalesforceDescription": "Вы можете отправить ссылку на сводку встречи Salesforce объекту.",
"linkToSalesforceError": "Ошибка отправки ссылки на встречу для Salesforce",
"linkToSalesforceKey": "Отправить ссылку на встречу для Salesforce",
"linkToSalesforceProgress": "Отправка ссылки на встречу для Salesforce...",
"linkToSalesforceSuccess": "Ссылка на эту встречу для Salesforce была отправлена",
"me": "Я",
"moderationInEffectCSDescription": "Пожалуйста, поднимите руку, если вы хотите поделиться своим экраном.",
"moderationInEffectCSTitle": "Демонстрация экрана заблокирована модератором",
@@ -668,8 +677,8 @@
"oldElectronClientDescription1": "Похоже, вы используете старую версию клиента {{app}}, которая имеет известные уязвимости в системе безопасности. Убедитесь, что вы обновили до нашей ",
"oldElectronClientDescription2": "последней версии",
"oldElectronClientDescription3": " сейчас!",
"participantWantsToJoin": "Хочет присоединиться к митингу",
"participantsWantToJoin": "Хотят присоединиться к митингу",
"participantWantsToJoin": "Хочет присоединиться к встрече",
"participantsWantToJoin": "Хотят присоединиться к встрече",
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) удален другим участником.",
"passwordSetRemotely": "Другой участник установил $t(lockRoomPasswordUppercase)",
"raiseHandAction": "Поднять руку",
@@ -799,7 +808,8 @@
"iWantToDialIn": "Я хочу дозвониться",
"initiated": "Вызов инициирован",
"joinAudioByPhone": "Подключиться с телефонной связью",
"joinMeeting": "Присоединиться ко встрече",
"joinMeeting": "Присоединиться к встрече",
"joinMeetingInLowBandwidthMode": "Присоединиться без видео",
"joinWithoutAudio": "Присоединиться без звука",
"keyboardShortcuts": "Включить сочетания клавиш",
"linkCopied": "Ссылка скопирована в буфер обмена",
@@ -841,7 +851,7 @@
"raisedHandsLabel": "Количество поднятых рук",
"record": {
"already": {
"linked": "Ссылка на митинг уже оправлена Salesforce объекту."
"linked": "Ссылка на встречу уже оправлена Salesforce объекту."
},
"type": {
"account": "Аккаунт",
@@ -869,7 +879,7 @@
"highlightMoment": "Основной момент",
"highlightMomentDisabled": "Вы можее обозначить важные моменты когда начнётся запись",
"highlightMomentSuccess": "Моменты выделены",
"highlightMomentSucessDescription": "Ваши выделенные моменты будут добавлены в итоги митинга.",
"highlightMomentSucessDescription": "Ваши выделенные моменты будут добавлены в итоги встречи.",
"inProgress": "Идет запись или прямая трансляция",
"limitNotificationDescriptionNative": "Из-за высокой нагрузки ваша запись будет ограничена {{limit}} мин. Для неограниченного количества записей попробуйте <3> {{app}} </3>.",
"limitNotificationDescriptionWeb": "Из-за высокой нагрузки ваша запись будет ограничена {{limit}} мин. Для неограниченного количества записей попробуйте <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
@@ -899,7 +909,7 @@
"security": {
"about": "Вы можете добавить к собранию $t(lockRoomPassword). Участникам необходимо будет предоставить $t(lockRoomPassword), прежде чем им будет разрешено присоединиться к собранию.",
"aboutReadOnly": "Участники-модераторы могут добавить к собранию $t(lockRoomPassword). Участникам необходимо будет предоставить $t(lockRoomPassword), прежде чем им будет разрешено присоединиться к собранию.",
"header": "",
"header": "Настройки безопасности",
"insecureRoomNameWarning": "Имя комнаты небезопасно. Нежелательные участники могут присоединиться к вашей конференции. Подумайте о том, чтобы защитить вашу встречу используя настройки безопасности."
},
"settings": {
@@ -1005,8 +1015,9 @@
"audioOnly": "Вкл/Выкл только звук",
"audioRoute": "Выбрать аудиоустройство",
"boo": "Бу",
"breakoutRoom": "Присоединиться/выйти из комнаты обсуждения",
"breakoutRoom": "Присоединиться/выйти из переговорной",
"callQuality": "Качество связи",
"carmode": "Упрощенный режим",
"cc": "Вкл/Выкл субтитры",
"chat": "Показать/скрыть окно чата",
"clap": "Хлопок",
@@ -1024,7 +1035,8 @@
"invite": "Пригласить",
"kick": "Отключить участника",
"laugh": "Смех",
"like": "Пальцы вверх",
"leaveConference": "Покинуть встречу",
"like": "Палец вверх",
"linkToSalesforce": "Ссылка на Salesforce",
"lobbyButton": "Вкл/Выкл режим лобби",
"localRecording": "Вкл/Выкл кнопки записи",
@@ -1065,8 +1077,8 @@
"videomute": "Вкл/Выкл видео"
},
"addPeople": "Добавить людей к вашему сеансу связи",
"audioOnlyOff": "Отключить режим экономии пропускной способности",
"audioOnlyOn": "Включить режим экономии пропускной способности",
"audioOnlyOff": "Включить видео (стандартный режим)",
"audioOnlyOn": "Выключить видео (экономичный режим)",
"audioRoute": "Выбрать аудиоустройство",
"audioSettings": "Настройка звука",
"authenticate": "Аутентифицировать",
@@ -1091,9 +1103,10 @@
"hangup": "Выход",
"help": "Справка",
"invite": "Пригласить",
"joinBreakoutRoom": "Присоединяйтесь к комнате обсуждения",
"joinBreakoutRoom": "Войти в переговорную",
"laugh": "Смеяться",
"leaveBreakoutRoom": "Выйти из комнаты отдыха",
"leaveBreakoutRoom": "Покинуть переговорную",
"leaveConference": "Покинуть встречу",
"like": "Мне нравится",
"linkToSalesforce": "Ссылка на Salesforce",
"lobbyButtonDisable": "Отключить режим лобби",

View File

@@ -90,7 +90,6 @@
"bitrate": "Velotzidade de bits:",
"bridgeCount": "Nùmeru de servidores: ",
"connectedTo": "Connessione cun:",
"e2e_rtt": "E2E RTT:",
"framerate": "Velotzidade de fotogrammas:",
"less": "Prus pagu informatziones",
"localaddress": "Indiritzu locale:",

View File

@@ -105,7 +105,6 @@
"bitrate": "Prenos. rýchlosť:",
"bridgeCount": "Počet serverov: ",
"connectedTo": "Spojenie s:",
"e2e_rtt": "E2E RTT:",
"framerate": "Rýchlosť snímkovania:",
"less": "Zobraziť menej",
"localaddress": "Lokálna adresa:",

View File

@@ -114,7 +114,6 @@
"bridgeCount": "Število strežnikov: ",
"codecs": "Kodeki (A/V): ",
"connectedTo": "Povezan v:",
"e2e_rtt": "E2E RTT:",
"framerate": "Frekvenca slik:",
"less": "Prikaži manj",
"localaddress": "Lokalni naslov:",

View File

@@ -136,7 +136,6 @@
"bridgeCount": "Numër shërbyesish: ",
"codecs": "Kodekë (A/V): ",
"connectedTo": "Lidhur te:",
"e2e_rtt": "E2E RTT:",
"framerate": "Shpejtësi kuadrosh:",
"less": "Shfaq më pak",
"localaddress": "Adresë vendore:",

View File

@@ -122,7 +122,6 @@
"bridgeCount": "Serverantal: ",
"codecs": "Codecs (A/V):",
"connectedTo": "Ansluten till:",
"e2e_rtt": "E2E RTT:",
"framerate": "Bildfrekvens:",
"less": "Visa mindre",
"localaddress": "Lokal adress:",

View File

@@ -109,7 +109,6 @@
"bridgeCount": "సేవికల సంఖ్య: ",
"codecs": "కోడెక్స్ (A/V): ",
"connectedTo": "దీనికి అనుసంధానమైంది:",
"e2e_rtt": "E2E RTT:",
"framerate": "ఫ్రేమ్ రేటు:",
"less": "తక్కువ చూపించు",
"localaddress": "స్థానిక చిరునామా:",

View File

@@ -123,7 +123,6 @@
"bridgeCount": "Sunucu sayısı: ",
"codecs": "Kodekler (A/V): ",
"connectedTo": "Bağlandı şuna:",
"e2e_rtt": "E2E RTT:",
"framerate": "Çerçeve hızı:",
"less": "Daha az göster",
"localaddress": "Yerel adres:",

View File

@@ -7,11 +7,10 @@
"copyLink": "Скопіювати посилання на зустріч",
"copyStream": "Скопіювати посилання на трансляцію наживо",
"countryNotSupported": "Дзвінки в цю країну поки що не підтримуються.",
"countryReminder": "Дзвінок за межі США? Перевірте наявність коду країни у зазначеному номері!",
"countryReminder": "Дзвінок за межі США? Перевірте наявність коду країни в зазначеному номері!",
"defaultEmail": "Ваша електронна пошта",
"disabled": "Ви не можете запрошувати учасників.",
"failedToAdd": "Не вдалося запросити учасника",
"footerText": "Вихідні дзвінки вимкнені.",
"googleEmail": "Електронна пошта Google",
"inviteMoreHeader": "Ви одні на цій зустрічі",
"inviteMoreMailSubject": "Приєднатися до зустрічі {{appName}}",
@@ -79,7 +78,6 @@
},
"carmode": {
"actions": {
"leaveMeeting": " Покинути зустріч",
"selectSoundDevice": "Вибрати звуковий пристрій"
},
"labels": {
@@ -98,6 +96,7 @@
"messageAccessibleTitleMe": "я пишу:",
"messageTo": "Приватне повідомлення для {{recipient}}",
"messagebox": "Напишіть повідомлення",
"newMessages": "нові повідомлення",
"nickname": {
"popover": "Виберіть ім'я",
"title": "Зазначте ім'я, щоб використовувати чат",
@@ -147,7 +146,6 @@
"bridgeCount": "Кількість серверів: ",
"codecs": "Кодеки (A/V): ",
"connectedTo": "З'єднано з:",
"e2e_rtt": "E2E RTT:",
"framerate": "Частота кадрів:",
"less": "Показати менше",
"localaddress": "Локальна адреса:",
@@ -286,7 +284,6 @@
"linkMeetingTitle": "Пов'язати зустріч із Salesforce",
"liveStreaming": "Трансляція наживо",
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "Послуга недоступна під час запису",
"liveStreamingDisabledTooltip": "Трансляцію наживо вимкнено.",
"localUserControls": "Команди керування видом на себе",
"lockMessage": "Не вдалося обмежити сторонній доступ",
"lockRoom": "Додати $t(lockRoomPassword)",
@@ -341,7 +338,6 @@
"recentlyUsedObjects": "Нещодавно використані об'єкти",
"recording": "Запис",
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Послуга недоступна під час трансляції наживо",
"recordingDisabledTooltip": "Запис вимкнено.",
"rejoinNow": "Приєднатися знову",
"remoteControlAllowedMessage": "{{user}} погодився на дистанційне керування!",
"remoteControlDeniedMessage": "{{user}} відхилив ваш запит на дистанційне керування!",
@@ -390,7 +386,7 @@
"shareYourScreen": "Спільний перегляд екрана",
"shareYourScreenDisabled": "Спільний перегляд екрана вимкнено.",
"sharedVideoDialogError": "Помилка: недійсна URL-адреса",
"sharedVideoLinkPlaceholder": "Посилання на YouTube або посилання на файл відео",
"sharedVideoLinkPlaceholder": "Посилання на YouTube або на файл відео",
"start": "Почати ",
"startLiveStreaming": "Почати трансляцію наживо",
"startRecording": "Почати запис",
@@ -646,7 +642,7 @@
"connectedThreePlusMembers": "{{name}} та {{count}} інших учасників приєдналися до зустрічі",
"connectedTwoMembers": "{{first}} та {{second}} приєдналися до зустрічі",
"disconnected": "з'єднання розірване",
"displayNotifications": "Показувати сповіщення для",
"displayNotifications": "Показувати сповіщення:",
"focus": "Фокус зустрічі",
"focusFail": "{{component}} недоступний - повторіть спробу через {{ms}} мс",
"gifsMenu": "GIPHY",
@@ -763,7 +759,7 @@
"create": "Створити опитування",
"pollOption": "Варіант відповіді {{index}}",
"pollQuestion": "Питання",
"questionPlaceholder": "Задайте питання",
"questionPlaceholder": "Поставте запитання",
"removeOption": "Вилучити",
"send": "Надіслати"
},
@@ -939,7 +935,7 @@
"about": "Ви можете додати $t(lockRoomPassword) для захисту вашої зустрічі. Учасникам потрібно буде ввести $t(lockRoomPassword), перш ніж їм буде дозволено приєднатися до зустрічі.",
"aboutReadOnly": "Модератори можуть додати $t(lockRoomPassword) для захисту зустрічі. Учасникам потрібно буде ввести $t(lockRoomPassword), перш ніж їм буде дозволено приєднатися до зустрічі.",
"header": "Параметри безпеки",
"insecureRoomNameWarning": "Назва кімнати не є безпечною. Сторонні можуть приєднатися до вашої зустрічі. Подбайте про захист вашої зустрічі за допомогою налаштувань параметрів безпеки."
"insecureRoomNameWarning": "Назва кімнати не є безпечною. Сторонні люди можуть приєднатися до вашої зустрічі. Подбайте про додатковий захист вашої зустрічі за допомогою налаштувань параметрів безпеки."
},
"settings": {
"buttonLabel": "Налаштування",
@@ -969,7 +965,7 @@
"participantKnocking": "Учасник зайшов у приймальну",
"participantLeft": "Учасник покинув зустріч",
"playSounds": "Увімкнути звукові сповіщення:",
"reactions": "Реакції під час зустрічі",
"reactions": "Емоційна реакція",
"sameAsSystem": "Системний пристрій ({{label}})",
"screenTitle": "Налаштування",
"selectAudioOutput": "Вивід звуку",
@@ -1066,6 +1062,7 @@
"document": "Відкрити/закрити спільний документ",
"download": "Звантажити мобільний застосунок",
"embedMeeting": "Вставити зустріч",
"endConference": "Завершити зустріч для всіх",
"expand": "Розгорнути",
"feedback": "Залишити відгук",
"fullScreen": "На весь екран",
@@ -1076,6 +1073,7 @@
"invite": "Запросити на зустріч",
"kick": "Від'єднати учасника",
"laugh": "Сміюся",
"leaveConference": "Покинути зустріч",
"like": "Подобається",
"linkToSalesforce": "Пов'язати з Salesforce",
"lobbyButton": "Увімкнути/вимкнути приймальну",
@@ -1138,6 +1136,7 @@
"download": "Звантажити мобільний застосунок",
"e2ee": "Наскрізне шифрування",
"embedMeeting": "Вставити зустріч",
"endConference": "Завершити зустріч для всіх",
"enterFullScreen": "На весь екран",
"enterTileView": "Режим плиток",
"exitFullScreen": "Вийти з повноекранного режиму",
@@ -1150,6 +1149,7 @@
"joinBreakoutRoom": "Приєднатися до кімнати підгрупи",
"laugh": "сміюся",
"leaveBreakoutRoom": "Вийти з кімнати підгрупи",
"leaveConference": "Покинути зустріч",
"like": "подобається",
"linkToSalesforce": "Пов'язати з Salesforce",
"lobbyButtonDisable": "Вимкнути приймальну",
@@ -1181,7 +1181,7 @@
"reactionBoo": "Надіслати реакцію «невдоволення»",
"reactionClap": "Надіслати реакцію «овації»",
"reactionLaugh": "Надіслати реакцію «сміюся»",
"reactionLike": "Надіслати реакцію \"подобається\"",
"reactionLike": "Надіслати реакцію «подобається»",
"reactionSilence": "Надіслати реакцію «тиша»",
"reactionSurprised": "Надіслати реакцію «подив»",
"security": "Параметри безпеки",
@@ -1193,7 +1193,7 @@
"silence": "тиша",
"speakerStats": "Статистика спілкування",
"startScreenSharing": "Увімкнути спільний перегляд екрана",
"startSubtitles": "Показувати субтитри",
"startSubtitles": "Субтитри • {{language}}",
"stopAudioSharing": "Зупинити спільне аудіо",
"stopScreenSharing": "Вимкнути спільний перегляд екрана",
"stopSharedVideo": "Зупинити спільне відео",
@@ -1216,6 +1216,8 @@
"pending": "Підготовка до транскрибування зустрічі...",
"start": "Показувати субтитри",
"stop": "Припинити показ субтитрів",
"subtitles": "Субтитри",
"subtitlesOff": "Вимкнені",
"tr": "TR"
},
"userMedia": {
@@ -1341,7 +1343,7 @@
"mobileDownLoadLinkAndroid": "Завантажте мобільний застосунок для Android",
"mobileDownLoadLinkFDroid": "Завантажте мобільний застосунок для F-Droid",
"mobileDownLoadLinkIos": "Завантажте мобільний застосунок для iOS",
"moderatedMessage": "Або <a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">організуйте модеровану зустріч</a>, і розпочніть її як модератор.",
"moderatedMessage": "Або <a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">організуйте модеровану зустріч</a> і розпочніть її як модератор.",
"privacy": "Конфіденційність",
"recentList": "Нещодавні",
"recentListDelete": "Вилучити",

View File

@@ -106,7 +106,6 @@
"bridgeCount": "服务器数量:",
"codecs": "编解码器A / V",
"connectedTo": "连接到:",
"e2e_rtt": "端到端时延 RTT:",
"framerate": "帧率:",
"less": "显示更少",
"localaddress": "本地地址:",

View File

@@ -135,7 +135,6 @@
"bridgeCount": "伺服器數量:",
"codecs": "編碼 (A/V)",
"connectedTo": "已連接至:",
"e2e_rtt": "E2E RTT",
"framerate": "影格率:",
"less": "顯示較少",
"localaddress": "本機位址:",

View File

@@ -146,7 +146,6 @@
"bridgeCount": "Server count: ",
"codecs": "Codecs (A/V): ",
"connectedTo": "Connected to:",
"e2e_rtt": "E2E RTT:",
"framerate": "Frame rate:",
"less": "Show less",
"localaddress": "Local address:",

View File

@@ -55,7 +55,7 @@ import {
removeBreakoutRoom,
sendParticipantToRoom
} from '../../react/features/breakout-rooms/actions';
import { getBreakoutRooms } from '../../react/features/breakout-rooms/functions';
import { getBreakoutRooms, getRoomsInfo } from '../../react/features/breakout-rooms/functions';
import {
sendMessage,
setPrivateMessageRecipient,
@@ -68,7 +68,7 @@ import {
import { appendSuffix } from '../../react/features/display-name';
import { isEnabled as isDropboxEnabled } from '../../react/features/dropbox';
import { setMediaEncryptionKey, toggleE2EE } from '../../react/features/e2ee/actions';
import { setVolume } from '../../react/features/filmstrip';
import { resizeFilmStrip, setVolume } from '../../react/features/filmstrip/actions.web';
import { invite } from '../../react/features/invite';
import {
selectParticipantInLargeVideo
@@ -308,6 +308,16 @@ function initCommands() {
sendAnalytics(createApiEvent('film.strip.toggled'));
APP.UI.toggleFilmstrip();
},
/*
* @param {Object} options - Additional details of how to perform
* the action.
* @param {number} options.width - width value for film strip.
*/
'resize-film-strip': (options = {}) => {
sendAnalytics(createApiEvent('film.strip.resize'));
APP.store.dispatch(resizeFilmStrip(options.width));
},
'toggle-camera': () => {
if (!isToggleCameraEnabled(APP.store.getState())) {
return;
@@ -846,6 +856,10 @@ function initCommands() {
callback(getBreakoutRooms(APP.store.getState()));
break;
}
case 'rooms-info': {
callback(getRoomsInfo(APP.store.getState()));
break;
}
default:
return false;
}
@@ -1783,7 +1797,7 @@ class API {
/**
* Notify external application that the breakout rooms changed.
*
* @param {Array} rooms - Array of breakout rooms.
* @param {Array} rooms - Array containing the breakout rooms and main room.
* @returns {void}
*/
notifyBreakoutRoomsUpdated(rooms) {

View File

@@ -52,6 +52,7 @@ const commands = {
pinParticipant: 'pin-participant',
rejectParticipant: 'reject-participant',
removeBreakoutRoom: 'remove-breakout-room',
resizeFilmStrip: 'resize-film-strip',
resizeLargeVideo: 'resize-large-video',
sendChatMessage: 'send-chat-message',
sendEndpointTextMessage: 'send-endpoint-text-message',
@@ -619,6 +620,9 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
case 'video-quality-changed':
this._videoQuality = data.videoQuality;
break;
case 'breakout-rooms-updated':
this.updateNumberOfParticipants(data.rooms);
break;
case 'local-storage-changed':
jitsiLocalStorage.setItem('jitsiLocalStorage', data.localStorageContent);
@@ -638,6 +642,40 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
});
}
/**
* Update number of participants based on all rooms.
*
* @param {Object} rooms - Rooms available rooms in the conference.
* @returns {void}
*/
updateNumberOfParticipants(rooms) {
if (!rooms || !Object.keys(rooms).length) {
return;
}
const allParticipants = Object.keys(rooms).reduce((prev, roomItemKey) => {
if (rooms[roomItemKey]?.participants) {
return Object.keys(rooms[roomItemKey].participants).length + prev;
}
return prev;
}, 0);
this._numberOfParticipants = allParticipants;
}
/**
* Returns the rooms info in the conference.
*
* @returns {Object} Rooms info.
*/
async getRoomsInfo() {
return this._transport.sendRequest({
name: 'rooms-info'
});
}
/**
* Adds event listener to Meet Jitsi.
*
@@ -1101,7 +1139,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
}
/**
* Returns the number of participants in the conference. The local
* Returns the number of participants in the conference from all rooms. The local
* participant is included.
*
* @returns {int} The number of participants in the conference.

View File

@@ -1,10 +1,11 @@
/* global APP, $, config */
/* global APP, config */
const UI = {};
import Logger from '@jitsi/logger';
import EventEmitter from 'events';
import $ from 'jquery';
import { isMobileBrowser } from '../../react/features/base/environment/utils';
import { setColorAlpha } from '../../react/features/base/util';

View File

@@ -1,4 +1,6 @@
/* global $, APP, interfaceConfig */
/* global APP, interfaceConfig */
import $ from 'jquery';
import { getSharedDocumentUrl, setDocumentEditingState } from '../../../react/features/etherpad';
import { getToolboxHeight } from '../../../react/features/toolbox/functions.web';

View File

@@ -1,4 +1,4 @@
/* global $ */
import $ from 'jquery';
/**
* Created by hristo on 12/22/14.

View File

@@ -1,4 +1,6 @@
/* global $, APP, interfaceConfig */
/* global APP, interfaceConfig */
import $ from 'jquery';
import { getVerticalFilmstripVisibleAreaWidth, isFilmstripVisible } from '../../../react/features/filmstrip';

View File

@@ -1,6 +1,7 @@
/* global $, APP */
/* global APP */
/* eslint-disable no-unused-vars */
import Logger from '@jitsi/logger';
import $ from 'jquery';
import React from 'react';
import ReactDOM from 'react-dom';
import { I18nextProvider } from 'react-i18next';

View File

@@ -1,6 +1,7 @@
/* global $, APP, interfaceConfig */
/* global APP, interfaceConfig */
/* eslint-disable no-unused-vars */
import $ from 'jquery';
import React from 'react';
import ReactDOM from 'react-dom';
@@ -8,6 +9,7 @@ import { browser } from '../../../react/features/base/lib-jitsi-meet';
import { isTestModeEnabled } from '../../../react/features/base/testing';
import { FILMSTRIP_BREAKPOINT } from '../../../react/features/filmstrip';
import { ORIENTATION, LargeVideoBackground, updateLastLargeVideoMediaEvent } from '../../../react/features/large-video';
import { setLargeVideoDimensions } from '../../../react/features/large-video/actions.any';
import { LAYOUTS, getCurrentLayout } from '../../../react/features/video-layout';
/* eslint-enable no-unused-vars */
import UIUtil from '../util/UIUtil';
@@ -445,6 +447,8 @@ export class VideoContainer extends LargeContainer {
const { horizontalIndent, verticalIndent }
= this.getVideoPosition(width, height, containerWidth, containerHeight, verticalFilmstripWidth);
APP.store.dispatch(setLargeVideoDimensions(height, width));
this.$wrapper.animate({
width,
height,

View File

@@ -2,7 +2,7 @@
import Logger from '@jitsi/logger';
import { getSourceNameSignalingFeatureFlag } from '../../../react/features/base/config';
import { getMultipleVideoSupportFeatureFlag } from '../../../react/features/base/config';
import { MEDIA_TYPE, VIDEO_TYPE } from '../../../react/features/base/media';
import {
getPinnedParticipant,
@@ -95,7 +95,7 @@ const VideoLayout = {
return VIDEO_TYPE.CAMERA;
}
if (getSourceNameSignalingFeatureFlag(state) && participant?.isVirtualScreenshareParticipant) {
if (getMultipleVideoSupportFeatureFlag(state) && participant?.isVirtualScreenshareParticipant) {
return VIDEO_TYPE.DESKTOP;
}
@@ -190,7 +190,7 @@ const VideoLayout = {
let videoTrack;
if (getSourceNameSignalingFeatureFlag(state) && participant?.isVirtualScreenshareParticipant) {
if (getMultipleVideoSupportFeatureFlag(state) && participant?.isVirtualScreenshareParticipant) {
videoTrack = getVirtualScreenshareParticipantTrack(tracks, id);
} else {
videoTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, id);
@@ -218,7 +218,6 @@ const VideoLayout = {
if (!isOnLarge || forceUpdate) {
const videoType = this.getRemoteVideoType(id);
largeVideo.updateLargeVideo(
id,
videoStream,

View File

@@ -1,10 +1,10 @@
/* @flow */
import $ from 'jquery';
import jqueryI18next from 'jquery-i18next';
import { i18next } from '../../react/features/base/i18n';
declare var $: Function;
type DocumentElement = {
lang: string

1937
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,8 @@
"@atlaskit/tabs": "12.1.2",
"@atlaskit/theme": "11.0.2",
"@atlaskit/tooltip": "17.1.2",
"@emotion/react": "11.10.0",
"@emotion/styled": "11.10.0",
"@giphy/js-fetch-api": "4.1.2",
"@giphy/react-components": "5.6.0",
"@giphy/react-native-sdk": "1.7.0",
@@ -35,10 +37,11 @@
"@jitsi/js-utils": "2.0.3",
"@jitsi/logger": "2.0.0",
"@jitsi/rnnoise-wasm": "0.1.0",
"@jitsi/rtcstats": "9.2.0",
"@material-ui/core": "4.11.3",
"@jitsi/rtcstats": "9.3.0",
"@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",
"@mui/styles": "5.10.2",
"@react-native-async-storage/async-storage": "1.15.14",
"@react-native-community/clipboard": "1.5.1",
"@react-native-community/netinfo": "7.1.7",
@@ -54,6 +57,7 @@
"@tensorflow/tfjs-backend-wasm": "3.13.0",
"@tensorflow/tfjs-core": "3.13.0",
"@types/audioworklet": "0.0.29",
"@types/w3c-image-capture": "1.0.6",
"@vladmandic/human": "2.6.5",
"@vladmandic/human-models": "2.5.9",
"@xmldom/xmldom": "0.7.5",
@@ -70,12 +74,12 @@
"i18next-browser-languagedetector": "3.0.1",
"i18next-xhr-backend": "3.0.0",
"image-capture": "0.4.0",
"jquery": "3.5.1",
"jquery": "3.6.1",
"jquery-i18next": "1.2.1",
"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/v1494.0.0+c9be46e2/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1498.0.0+bc3aae02/lib-jitsi-meet.tgz",
"lodash": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",
@@ -123,10 +127,11 @@
"react-window": "1.8.6",
"react-youtube": "7.13.1",
"redux": "4.0.4",
"redux-thunk": "2.2.0",
"redux-thunk": "2.4.1",
"resemblejs": "4.0.0",
"seamless-scroll-polyfill": "2.1.8",
"styled-components": "3.4.9",
"tss-react": "4.0.0",
"util": "0.12.1",
"uuid": "8.3.2",
"wasm-check": "2.0.1",
@@ -142,7 +147,7 @@
"@babel/preset-flow": "7.16.0",
"@babel/preset-react": "7.16.0",
"@babel/runtime": "7.16.0",
"@jitsi/eslint-config": "4.0.0",
"@jitsi/eslint-config": "4.1.2",
"@types/js-md5": "0.4.3",
"@types/lodash": "4.14.182",
"@types/react": "17.0.14",
@@ -166,7 +171,6 @@
"eslint-plugin-react": "7.26.1",
"eslint-plugin-react-native": "3.11.0",
"eslint-plugin-typescript-sort-keys": "2.1.0",
"expose-loader": "3.0.0",
"imports-loader": "0.7.1",
"jetifier": "1.6.4",
"metro-react-native-babel-preset": "0.67.0",

View File

@@ -9,25 +9,7 @@ module.exports = {
'overrides': [
{
'files': [ '*.ts', '*.tsx' ],
parser: '@typescript-eslint/parser',
rules: {
'no-undef': 'off',
'no-use-before-define': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'no-prototype-builtins': 'off',
'no-shadow': 'off',
'@typescript-eslint/no-shadow': [ 'error' ],
'typescript-sort-keys/interface': 'error',
'typescript-sort-keys/string-enum': 'error'
},
'plugins': [ '@typescript-eslint', 'typescript-sort-keys' ],
'extends': [
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended'
]
extends: [ '@jitsi/eslint-config/typescript' ]
}
],
'rules': {

View File

@@ -72,13 +72,13 @@ export const VIDEO_MUTE = 'video.mute';
* Creates an event which indicates that a certain action was requested through
* the jitsi-meet API.
*
* @param {Object} action - The action which was requested through the
* @param {string} action - The action which was requested through the
* jitsi-meet API.
* @param {Object} attributes - Attributes to attach to the event.
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createApiEvent(action, attributes = {}) {
export function createApiEvent(action: string, attributes = {}) {
return {
action,
attributes,
@@ -93,7 +93,7 @@ export function createApiEvent(action, attributes = {}) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createAudioOnlyChangedEvent(enabled) {
export function createAudioOnlyChangedEvent(enabled: boolean) {
return {
action: `audio.only.${enabled ? 'enabled' : 'disabled'}`
};
@@ -107,7 +107,7 @@ export function createAudioOnlyChangedEvent(enabled) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createConnectionEvent(action, attributes = {}) {
export function createConnectionEvent(action: string, attributes = {}) {
return {
action,
actionSubject: 'connection',
@@ -124,7 +124,7 @@ export function createConnectionEvent(action, attributes = {}) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createCalendarClickedEvent(eventName, attributes = {}) {
export function createCalendarClickedEvent(eventName: string, attributes = {}) {
return {
action: 'clicked',
actionSubject: eventName,
@@ -175,7 +175,7 @@ export function createCalendarConnectedEvent(attributes = {}) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createRecentClickedEvent(eventName, attributes = {}) {
export function createRecentClickedEvent(eventName: string, attributes = {}) {
return {
action: 'clicked',
actionSubject: eventName,
@@ -193,7 +193,7 @@ export function createRecentClickedEvent(eventName, attributes = {}) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createChromeExtensionBannerEvent(installPressed, attributes = {}) {
export function createChromeExtensionBannerEvent(installPressed: boolean, attributes = {}) {
return {
action: installPressed ? 'install' : 'cancel',
attributes,
@@ -229,7 +229,7 @@ export function createRecentSelectedEvent(attributes = {}) {
* sendAnalytics.
*/
export function createDeepLinkingPageEvent(
action, actionSubject, attributes = {}) {
action: string, actionSubject: string, attributes = {}) {
return {
action,
actionSubject,
@@ -247,7 +247,7 @@ export function createDeepLinkingPageEvent(
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createDeviceChangedEvent(mediaType, deviceType) {
export function createDeviceChangedEvent(mediaType: string, deviceType: string) {
return {
action: 'device.changed',
attributes: {
@@ -264,7 +264,7 @@ export function createDeviceChangedEvent(mediaType, deviceType) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createE2EEEvent(action) {
export function createE2EEEvent(action: string) {
return {
action,
actionSubject: 'e2ee'
@@ -293,7 +293,7 @@ export function createFeedbackOpenEvent() {
* sendAnalytics.
*/
export function createInviteDialogEvent(
action, actionSubject, attributes = {}) {
action: string, actionSubject: string, attributes = {}) {
return {
action,
actionSubject,
@@ -310,8 +310,13 @@ export function createInviteDialogEvent(
* @param {Object} [details] - Extra info, see {@code NetworkInfo} type defined by the 'base/net-info' feature.
* @returns {Object}
*/
export function createNetworkInfoEvent({ isOnline, networkType, details }) {
const attributes = { isOnline };
export function createNetworkInfoEvent({ isOnline, networkType, details }:
{ details?: Object; isOnline: boolean; networkType?: string; }) {
const attributes: {
details?: Object;
isOnline: boolean;
networkType?: string;
} = { isOnline };
// Do no include optional stuff or Amplitude handler will log warnings.
networkType && (attributes.networkType = networkType);
@@ -345,7 +350,7 @@ export function createOfferAnswerFailedEvent() {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createPageReloadScheduledEvent(reason, timeout, details) {
export function createPageReloadScheduledEvent(reason: string, timeout: number, details: Object) {
return {
action: 'page.reload.scheduled',
attributes: {
@@ -365,7 +370,7 @@ export function createPageReloadScheduledEvent(reason, timeout, details) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createPinnedEvent(action, participantId, attributes) {
export function createPinnedEvent(action: string, participantId: string, attributes = {}) {
return {
type: TYPE_TRACK,
action,
@@ -392,7 +397,7 @@ export function createPinnedEvent(action, participantId, attributes) {
* @param {string} action - The action.
* @returns {Object}
*/
export function createPollEvent(action) {
export function createPollEvent(action: string) {
return {
action: `poll.${action}`
};
@@ -407,7 +412,7 @@ export function createPollEvent(action) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createProfilePanelButtonEvent(buttonName, attributes = {}) {
export function createProfilePanelButtonEvent(buttonName: string, attributes = {}) {
return {
action: 'clicked',
actionSubject: buttonName,
@@ -429,7 +434,7 @@ export function createProfilePanelButtonEvent(buttonName, attributes = {}) {
* sendAnalytics.
*/
export function createRecordingDialogEvent(
dialogName, buttonName, attributes = {}) {
dialogName: string, buttonName: string, attributes = {}) {
return {
action: 'clicked',
actionSubject: buttonName,
@@ -449,7 +454,7 @@ export function createRecordingDialogEvent(
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createLiveStreamingDialogEvent(dialogName, buttonName) {
export function createLiveStreamingDialogEvent(dialogName: string, buttonName: string) {
return {
action: 'clicked',
actionSubject: buttonName,
@@ -465,7 +470,14 @@ export function createLiveStreamingDialogEvent(dialogName, buttonName) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createLocalTracksDurationEvent(duration) {
export function createLocalTracksDurationEvent(duration: {
audio: { value: number; };
conference: { value: number; };
video: {
camera: { value: number; };
desktop: { value: number; };
};
}) {
const { audio, video, conference } = duration;
const { camera, desktop } = video;
@@ -491,7 +503,7 @@ export function createLocalTracksDurationEvent(duration) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createRecordingEvent(action, type, value) {
export function createRecordingEvent(action: string, type: string, value: number) {
return {
action,
actionSubject: `recording.${type}`,
@@ -509,7 +521,11 @@ export function createRecordingEvent(action, type, value) {
* @param {number} timeSinceLeft - How many seconds since the last conference was left.
* @returns {Object} The event in a format suitable for sending via sendAnalytics.
*/
export function createRejoinedEvent({ url, lastConferenceDuration, timeSinceLeft }) {
export function createRejoinedEvent({ url, lastConferenceDuration, timeSinceLeft }: {
lastConferenceDuration: number;
timeSinceLeft: number;
url: string;
}) {
return {
action: 'rejoined',
attributes: {
@@ -530,7 +546,7 @@ export function createRejoinedEvent({ url, lastConferenceDuration, timeSinceLeft
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createRemoteMuteConfirmedEvent(participantId, mediaType) {
export function createRemoteMuteConfirmedEvent(participantId: string, mediaType: string) {
return {
action: 'clicked',
attributes: {
@@ -551,7 +567,7 @@ export function createRemoteMuteConfirmedEvent(participantId, mediaType) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createRemoteVideoMenuButtonEvent(buttonName, attributes) {
export function createRemoteVideoMenuButtonEvent(buttonName: string, attributes = {}) {
return {
action: 'clicked',
actionSubject: buttonName,
@@ -569,8 +585,13 @@ export function createRemoteVideoMenuButtonEvent(buttonName, attributes) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createRTCStatsTraceCloseEvent(closeEvent) {
const event = {
export function createRTCStatsTraceCloseEvent(closeEvent: { code: string; reason: string; }) {
const event: {
action: string;
code?: string;
reason?: string;
source: string;
} = {
action: 'trace.onclose',
source: 'rtcstats'
};
@@ -590,7 +611,7 @@ export function createRTCStatsTraceCloseEvent(closeEvent) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createScreenSharingEvent(action, value = null) {
export function createScreenSharingEvent(action: string, value = null) {
return {
action,
actionSubject: 'screen.sharing',
@@ -606,7 +627,7 @@ export function createScreenSharingEvent(action, value = null) {
* @param {Object} attributes - Additional information that describes the issue.
* @returns {Object} The event in a format suitable for sending via sendAnalytics.
*/
export function createScreenSharingIssueEvent(attributes) {
export function createScreenSharingIssueEvent(attributes = {}) {
return {
action: 'screen.sharing.issue',
attributes
@@ -621,7 +642,7 @@ export function createScreenSharingIssueEvent(attributes) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createSharedVideoEvent(action, attributes = {}) {
export function createSharedVideoEvent(action: string, attributes = {}) {
return {
action,
attributes,
@@ -646,7 +667,7 @@ export function createSharedVideoEvent(action, attributes = {}) {
* sendAnalytics.
*/
export function createShortcutEvent(
shortcut,
shortcut: string,
action = ACTION_SHORTCUT_TRIGGERED,
attributes = {},
source = 'keyboard.shortcut') {
@@ -666,7 +687,7 @@ export function createShortcutEvent(
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createStartAudioOnlyEvent(audioOnly) {
export function createStartAudioOnlyEvent(audioOnly: boolean) {
return {
action: 'start.audio.only',
attributes: {
@@ -693,7 +714,7 @@ export function createStartSilentEvent() {
* @param {string} elementID - The ID of the HTMLAudioElement.
* @returns {Object} The event in a format suitable for sending via sendAnalytics.
*/
export function createAudioPlayErrorEvent(elementID) {
export function createAudioPlayErrorEvent(elementID: string) {
return {
action: 'audio.play.error',
attributes: {
@@ -708,7 +729,7 @@ export function createAudioPlayErrorEvent(elementID) {
* @param {string} elementID - The ID of the HTMLAudioElement.
* @returns {Object} The event in a format suitable for sending via sendAnalytics.
*/
export function createAudioPlaySuccessEvent(elementID) {
export function createAudioPlaySuccessEvent(elementID: string) {
return {
action: 'audio.play.success',
attributes: {
@@ -731,9 +752,9 @@ export function createAudioPlaySuccessEvent(elementID) {
* sendAnalytics.
*/
export function createStartMutedConfigurationEvent(
source,
audioMute,
videoMute) {
source: string,
audioMute: boolean,
videoMute: boolean) {
return {
action: 'start.muted.configuration',
attributes: {
@@ -754,7 +775,7 @@ export function createStartMutedConfigurationEvent(
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createSyncTrackStateEvent(mediaType, muted) {
export function createSyncTrackStateEvent(mediaType: string, muted: boolean) {
return {
action: 'sync.track.state',
attributes: {
@@ -776,7 +797,7 @@ export function createSyncTrackStateEvent(mediaType, muted) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createToolbarEvent(buttonName, attributes = {}) {
export function createToolbarEvent(buttonName: string, attributes = {}) {
return {
action: 'clicked',
actionSubject: buttonName,
@@ -794,7 +815,7 @@ export function createToolbarEvent(buttonName, attributes = {}) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createReactionMenuEvent(buttonName) {
export function createReactionMenuEvent(buttonName: string) {
return {
action: 'clicked',
actionSubject: 'button',
@@ -830,7 +851,7 @@ export function createReactionSoundsDisabledEvent() {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createTrackMutedEvent(mediaType, reason, muted = true) {
export function createTrackMutedEvent(mediaType: string, reason: string, muted = true) {
return {
action: 'track.muted',
attributes: {
@@ -848,7 +869,7 @@ export function createTrackMutedEvent(mediaType, reason, muted = true) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createVpaasConferenceJoinedEvent(tenant) {
export function createVpaasConferenceJoinedEvent(tenant: string) {
return {
action: 'vpaas.conference.joined',
attributes: {
@@ -866,7 +887,7 @@ export function createVpaasConferenceJoinedEvent(tenant) {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createWelcomePageEvent(action, actionSubject, attributes = {}) {
export function createWelcomePageEvent(action: string, actionSubject: string, attributes = {}) {
return {
action,
actionSubject,
@@ -894,7 +915,7 @@ export function createScreensharingCaptureTakenEvent() {
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createBreakoutRoomsEvent(actionSubject) {
export function createBreakoutRoomsEvent(actionSubject: string) {
return {
action: 'clicked',
actionSubject: `${actionSubject}.button`,

View File

@@ -1,7 +1,10 @@
// @flow
/* eslint-disable lines-around-comment */
// @ts-ignore
import { API_ID } from '../../../modules/API/constants';
// @ts-ignore
import { getName as getAppName } from '../app/functions';
import { IStore } from '../app/types';
// @ts-ignore
import { getAnalyticsRoomName } from '../base/conference';
import {
checkChromeExtensionsInstalled,
@@ -11,11 +14,16 @@ import JitsiMeetJS, {
analytics,
browser
} from '../base/lib-jitsi-meet';
// @ts-ignore
import { isAnalyticsEnabled } from '../base/lib-jitsi-meet/functions';
import { getJitsiMeetGlobalNS, loadScript, parseURIString } from '../base/util';
// @ts-ignore
import { loadScript } from '../base/util';
import { getJitsiMeetGlobalNS } from '../base/util/helpers';
import { inIframe } from '../base/util/iframeUtils';
import { parseURIString } from '../base/util/uri';
import { AmplitudeHandler, MatomoHandler } from './handlers';
import AmplitudeHandler from './handlers/AmplitudeHandler';
import MatomoHandler from './handlers/MatomoHandler';
import logger from './logger';
/**
@@ -59,7 +67,7 @@ export function resetAnalytics() {
* @param {Store} store - The redux store in which the specified {@code action} is being dispatched.
* @returns {Promise} Resolves with the handlers that have been successfully loaded.
*/
export async function createHandlers({ getState }: { getState: Function }) {
export async function createHandlers({ getState }: { getState: Function; }) {
getJitsiMeetGlobalNS().analyticsHandlers = [];
if (!isAnalyticsEnabled(getState)) {
@@ -90,15 +98,15 @@ export async function createHandlers({ getState }: { getState: Function }) {
const handlerConstructorOptions = {
amplitudeAPPKey,
blackListedEvents,
envType: (deploymentInfo && deploymentInfo.envType) || 'dev',
envType: deploymentInfo?.envType || 'dev',
googleAnalyticsTrackingId,
matomoEndpoint,
matomoSiteID,
group,
host,
product: deploymentInfo && deploymentInfo.product,
subproduct: deploymentInfo && deploymentInfo.environment,
user: user && user.id,
product: deploymentInfo?.product,
subproduct: deploymentInfo?.environment,
user: user?.id,
version: JitsiMeetJS.version,
whiteListedEvents
};
@@ -155,7 +163,7 @@ export async function createHandlers({ getState }: { getState: Function }) {
* @param {Array<Object>} handlers - The analytics handlers.
* @returns {void}
*/
export function initAnalytics(store: Store, handlers: Array<Object>) {
export function initAnalytics(store: IStore, handlers: Array<Object>) {
const { getState, dispatch } = store;
if (!isAnalyticsEnabled(getState) || handlers.length === 0) {
@@ -168,9 +176,9 @@ export function initAnalytics(store: Store, handlers: Array<Object>) {
deploymentInfo
} = config;
const { group, server } = state['features/base/jwt'];
const { locationURL = {} } = state['features/base/connection'];
const { locationURL = { href: '' } } = state['features/base/connection'];
const { tenant } = parseURIString(locationURL.href) || {};
const permanentProperties = {};
const permanentProperties: any = {};
if (server) {
permanentProperties.server = server;
@@ -199,7 +207,7 @@ export function initAnalytics(store: Store, handlers: Array<Object>) {
if (deploymentInfo) {
for (const key in deploymentInfo) {
if (deploymentInfo.hasOwnProperty(key)) {
permanentProperties[key] = deploymentInfo[key];
permanentProperties[key] = deploymentInfo[key as keyof typeof deploymentInfo];
}
}
}
@@ -232,7 +240,7 @@ export function initAnalytics(store: Store, handlers: Array<Object>) {
* @returns {Promise} Resolves with the handlers that have been successfully loaded and rejects if there are no handlers
* loaded or the analytics is disabled.
*/
function _loadHandlers(scriptURLs = [], handlerConstructorOptions) {
function _loadHandlers(scriptURLs: any[] = [], handlerConstructorOptions: Object) {
const promises = [];
for (const url of scriptURLs) {
@@ -241,7 +249,7 @@ function _loadHandlers(scriptURLs = [], handlerConstructorOptions) {
() => {
return { type: 'success' };
},
error => {
(error: Error) => {
return {
type: 'error',
error,

View File

@@ -1,13 +1,44 @@
export interface IEvent {
action?: string;
actionSubject?: string;
attributes?: {
[key: string]: string | undefined;
};
name?: string;
source?: string;
type?: string;
}
interface Options {
amplitudeAPPKey?: string;
blackListedEvents?: string[];
envType?: string;
googleAnalyticsTrackingId?: string;
group?: string;
host?: string;
matomoEndpoint?: string;
matomoSiteID?: string;
product?: string;
subproduct?: string;
user?: string;
version?: string;
whiteListedEvents?: string[];
}
/**
* Abstract implementation of analytics handler.
*/
export default class AbstractHandler {
_enabled: boolean;
_whiteListedEvents: Array<string> | undefined;
_blackListedEvents: Array<string> | undefined;
/**
* Creates new instance.
*
* @param {Object} options - Optional parameters.
*/
constructor(options = {}) {
constructor(options: Options = {}) {
this._enabled = false;
this._whiteListedEvents = options.whiteListedEvents;
@@ -28,7 +59,7 @@ export default class AbstractHandler {
* @param {Object} event - The analytics event.
* @returns {string} - The extracted name.
*/
_extractName(event) {
_extractName(event: IEvent) {
// Page events have a single 'name' field.
if (event.type === 'page') {
return event.name;
@@ -65,12 +96,12 @@ export default class AbstractHandler {
* @param {Object} event - The event.
* @returns {boolean}
*/
_shouldIgnore(event) {
_shouldIgnore(event: IEvent) {
if (!event || !this._enabled) {
return true;
}
const name = this._extractName(event);
const name = this._extractName(event) ?? '';
if (Array.isArray(this._whiteListedEvents)) {
return this._whiteListedEvents.indexOf(name) === -1;

View File

@@ -1,13 +1,18 @@
/* eslint-disable lines-around-comment */
import logger from '../logger';
import AbstractHandler from './AbstractHandler';
import AbstractHandler, { IEvent } from './AbstractHandler';
// @ts-ignore
import { fixDeviceID } from './amplitude/fixDeviceID';
// @ts-ignore
import amplitude from './amplitude/lib';
/**
* Analytics handler for Amplitude.
*/
export default class AmplitudeHandler extends AbstractHandler {
_deviceId: string;
_userId: Object;
/**
* Creates new instance of the Amplitude analytics handler.
*
@@ -15,14 +20,14 @@ export default class AmplitudeHandler extends AbstractHandler {
* @param {string} options.amplitudeAPPKey - The Amplitude app key required
* by the Amplitude API.
*/
constructor(options) {
constructor(options: any) {
super(options);
const { amplitudeAPPKey, user } = options;
this._enabled = true;
const onError = e => {
const onError = (e: Error) => {
logger.error('Error initializing Amplitude', e);
this._enabled = false;
};
@@ -31,7 +36,7 @@ export default class AmplitudeHandler extends AbstractHandler {
amplitude.getInstance().init(amplitudeAPPKey);
fixDeviceID(amplitude.getInstance()).then(() => {
amplitude.getInstance().getDeviceId()
.then(deviceId => {
.then((deviceId: string) => {
this._deviceId = deviceId;
});
});
@@ -57,7 +62,7 @@ export default class AmplitudeHandler extends AbstractHandler {
* @param {Object} userProps - The user portperties.
* @returns {void}
*/
setUserProperties(userProps) {
setUserProperties(userProps: Object) {
if (this._enabled) {
amplitude.getInstance().setUserProperties(userProps);
}
@@ -71,7 +76,7 @@ export default class AmplitudeHandler extends AbstractHandler {
* lib-jitsi-meet.
* @returns {void}
*/
sendEvent(event) {
sendEvent(event: IEvent) {
if (this._shouldIgnore(event)) {
return;
}

View File

@@ -1,13 +1,15 @@
/* global ga */
import { getJitsiMeetGlobalNS } from '../../base/util';
import { getJitsiMeetGlobalNS } from '../../base/util/helpers';
import AbstractHandler from './AbstractHandler';
import AbstractHandler, { IEvent } from './AbstractHandler';
/**
* Analytics handler for Google Analytics.
*/
class GoogleAnalyticsHandler extends AbstractHandler {
_userProperties: Object;
_userPropertiesString: string;
/**
* Creates new instance of the GA analytics handler.
@@ -16,7 +18,7 @@ class GoogleAnalyticsHandler extends AbstractHandler {
* @param {string} options.googleAnalyticsTrackingId - The GA track id
* required by the GA API.
*/
constructor(options) {
constructor(options: any) {
super(options);
this._userProperties = {};
@@ -37,16 +39,20 @@ class GoogleAnalyticsHandler extends AbstractHandler {
* required by the GA API.
* @returns {void}
*/
_initGoogleAnalytics(options) {
_initGoogleAnalytics(options: any) {
/**
* TODO: Keep this local, there's no need to add it to window.
*/
/* eslint-disable */
/* eslint-disable */ // @ts-ignore
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
// @ts-ignore
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
/* eslint-enable */
// @ts-ignore
ga('create', options.googleAnalyticsTrackingId, 'auto');
// @ts-ignore
ga('send', 'pageview');
}
@@ -60,11 +66,11 @@ class GoogleAnalyticsHandler extends AbstractHandler {
* suitable value.
* @private
*/
_extractValue(event) {
let value = event && event.attributes && event.attributes.value;
_extractValue(event: IEvent) {
let value: string | number | undefined = event?.attributes?.value;
// Try to extract an integer from the "value" attribute.
value = Math.round(parseFloat(value));
value = Math.round(parseFloat(value ?? ''));
return value;
}
@@ -78,7 +84,7 @@ class GoogleAnalyticsHandler extends AbstractHandler {
* analytics event.
* @private
*/
_extractLabel(event) {
_extractLabel(event: IEvent) {
const { attributes = {} } = event;
const labelsArray
= Object.keys(attributes).map(key => `${key}=${attributes[key]}`);
@@ -94,7 +100,7 @@ class GoogleAnalyticsHandler extends AbstractHandler {
* @param {Object} userProps - The permanent portperties.
* @returns {void}
*/
setUserProperties(userProps = {}) {
setUserProperties(userProps: any = {}) {
if (!this._enabled) {
return;
}
@@ -120,12 +126,17 @@ class GoogleAnalyticsHandler extends AbstractHandler {
* lib-jitsi-meet.
* @returns {void}
*/
sendEvent(event) {
sendEvent(event: IEvent) {
if (this._shouldIgnore(event)) {
return;
}
const gaEvent = {
const gaEvent: {
eventAction?: string;
eventCategory: string;
eventLabel: string;
eventValue?: number;
} = {
'eventCategory': 'jitsi-meet',
'eventAction': this._extractName(event),
'eventLabel': this._extractLabel(event)
@@ -136,6 +147,7 @@ class GoogleAnalyticsHandler extends AbstractHandler {
gaEvent.eventValue = value;
}
// @ts-ignore
ga('send', 'event', gaEvent);
}

View File

@@ -1,13 +1,14 @@
/* global _paq */
import { getJitsiMeetGlobalNS } from '../../base/util';
import { getJitsiMeetGlobalNS } from '../../base/util/helpers';
import AbstractHandler from './AbstractHandler';
import AbstractHandler, { IEvent } from './AbstractHandler';
/**
* Analytics handler for Matomo.
*/
export default class MatomoHandler extends AbstractHandler {
_userProperties: Object;
/**
* Creates new instance of the Matomo handler.
@@ -16,7 +17,7 @@ export default class MatomoHandler extends AbstractHandler {
* @param {string} options.matomoEndpoint - The Matomo endpoint.
* @param {string} options.matomoSiteID - The site ID.
*/
constructor(options) {
constructor(options: any) {
super(options);
this._userProperties = {};
@@ -43,9 +44,11 @@ export default class MatomoHandler extends AbstractHandler {
* @param {string} options.matomoSiteID - The site ID.
* @returns {void}
*/
_initMatomo(options) {
_initMatomo(options: any) {
// @ts-ignore
const _paq = window._paq || [];
// @ts-ignore
window._paq = _paq;
_paq.push([ 'trackPageView' ]);
@@ -70,7 +73,7 @@ export default class MatomoHandler extends AbstractHandler {
g.async = true;
g.defer = true;
g.src = `${u}matomo.js`;
s.parentNode.insertBefore(g, s);
s.parentNode?.insertBefore(g, s);
})();
}
@@ -84,11 +87,11 @@ export default class MatomoHandler extends AbstractHandler {
* suitable value.
* @private
*/
_extractValue(event) {
const value = event && event.attributes && event.attributes.value;
_extractValue(event: IEvent) {
const value = event?.attributes?.value;
// Try to extract an integer from the 'value' attribute.
return Math.round(parseFloat(value));
return Math.round(parseFloat(value ?? ''));
}
/**
@@ -97,7 +100,7 @@ export default class MatomoHandler extends AbstractHandler {
* @param {Object} userProps - The permanent properties.
* @returns {void}
*/
setUserProperties(userProps = {}) {
setUserProperties(userProps: any = {}) {
if (!this._enabled) {
return;
}
@@ -108,6 +111,7 @@ export default class MatomoHandler extends AbstractHandler {
Object.keys(userProps)
.filter(key => visitScope.indexOf(key) === -1)
.forEach((key, index) => {
// @ts-ignore
_paq.push([
'setCustomVariable',
1 + index,
@@ -122,6 +126,7 @@ export default class MatomoHandler extends AbstractHandler {
Object.keys(userProps)
.filter(key => visitScope.indexOf(key) !== -1)
.forEach((key, index) => {
// @ts-ignore
_paq.push([
'setCustomVariable',
1 + index,
@@ -141,18 +146,20 @@ export default class MatomoHandler extends AbstractHandler {
* lib-jitsi-meet.
* @returns {void}
*/
sendEvent(event) {
sendEvent(event: IEvent) {
if (this._shouldIgnore(event)) {
return;
}
const value = this._extractValue(event);
const matomoEvent = [ 'trackEvent', 'jitsi-meet', this._extractName(event) ];
const matomoEvent: Array<string | number | undefined> = [
'trackEvent', 'jitsi-meet', this._extractName(event) ];
if (!isNaN(value)) {
matomoEvent.push(value);
}
// @ts-ignore
_paq.push(matomoEvent);
}
}

View File

@@ -7,7 +7,7 @@ import DeviceInfo from 'react-native-device-info';
* @param {AmplitudeClient} amplitude - The amplitude instance.
* @returns {void}
*/
export async function fixDeviceID(amplitude) {
export async function fixDeviceID(amplitude: any) {
await DefaultPreference.setName('jitsi-preferences');
const current = await DefaultPreference.get('amplitudeDeviceId');

View File

@@ -4,6 +4,6 @@
* @param {AmplitudeClient} amplitude - The amplitude instance.
* @returns {void}
*/
export function fixDeviceID(amplitude) { // eslint-disable-line no-unused-vars
export function fixDeviceID(amplitude: any) { // eslint-disable-line @typescript-eslint/no-unused-vars
}

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