all
3
Video/FreeTube/LICENSE
Normal file
@ -0,0 +1,3 @@
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or combining it with [name of library] (or a modified version of that library), containing parts covered by the terms of [name of library's license], the licensors of this Program grant you additional permission to convey the resulting work. Corresponding Source for a non-source form of such a combination shall include the source code for the parts of [name of library] used as well as that of the covered work.
|
66
Video/FreeTube/README.md
Normal file
@ -0,0 +1,66 @@
|
||||

|
||||
URL :
|
||||
|
||||
# FreeTube
|
||||
|
||||
|
||||
|
||||
# Téléchargement, Configuration et Lancement
|
||||
|
||||
## Téléchargement de FreeTube
|
||||
|
||||
Saisir la commande pour télécharger la source
|
||||
```bash
|
||||
git clone https://git.tips-of-mine.fr/Tips-Of-Mine/Docker.git
|
||||
```
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd Video\FreeTube
|
||||
```
|
||||
|
||||
## Modifier la configuration de FreeTube
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd Video\FreeTube
|
||||
```
|
||||
|
||||
Nous éditons le fichier de configuration
|
||||
```bash
|
||||
nano .env
|
||||
```
|
||||
|
||||
Nous modifions les variables dont nous avons besoin.
|
||||
|
||||
## Lancement de FreeTube
|
||||
|
||||
Pour utiliser FreeTube tout seul
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Pour utiliser FreeTube avec Traefik
|
||||
```bash
|
||||
docker compose -f docker-compose-traefik.yml up -d
|
||||
```
|
||||
|
||||
# Utilisation
|
||||
|
||||
## Accueil
|
||||
|
||||
Ouvrir une page web avec l'url :
|
||||
Pour une utilisation tout seul
|
||||
|
||||
http://10.0.4.29:3000
|
||||
|
||||
Pour une utilisation avec Traefik
|
||||
|
||||
https://FreeTube.10.0.4.29.traefik.me`)"
|
||||
|
||||
|
||||
# More info
|
||||
- more information on the website [Tips-Of-Mine](https://www.tips-of-mine.fr/)
|
||||
|
||||
# Buy me a coffe
|
||||
<a href='https://ko-fi.com/R5R2KNI3N' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi4.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
66
Video/FreeTube/docker-compose-traefik.yml
Normal file
@ -0,0 +1,66 @@
|
||||

|
||||
URL : HHHHH
|
||||
|
||||
# Fichier-Stockage
|
||||
|
||||
GGGGG
|
||||
|
||||
# Téléchargement, Configuration et Lancement
|
||||
|
||||
## Téléchargement de Fichier-Stockage
|
||||
|
||||
Saisir la commande pour télécharger la source
|
||||
```bash
|
||||
git clone https://git.tips-of-mine.fr/Tips-Of-Mine/Docker.git
|
||||
```
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd AAAAA\Fichier-Stockage
|
||||
```
|
||||
|
||||
## Modifier la configuration de Fichier-Stockage
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd AAAAA\Fichier-Stockage
|
||||
```
|
||||
|
||||
Nous éditons le fichier de configuration
|
||||
```bash
|
||||
nano .env
|
||||
```
|
||||
|
||||
Nous modifions les variables dont nous avons besoin.
|
||||
|
||||
## Lancement de Fichier-Stockage
|
||||
|
||||
Pour utiliser Fichier-Stockage tout seul
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Pour utiliser Fichier-Stockage avec Traefik
|
||||
```bash
|
||||
docker compose -f docker-compose-traefik.yml up -d
|
||||
```
|
||||
|
||||
# Utilisation
|
||||
|
||||
## Accueil
|
||||
|
||||
Ouvrir une page web avec l'url :
|
||||
Pour une utilisation tout seul
|
||||
|
||||
http://10.0.4.29:3000
|
||||
|
||||
Pour une utilisation avec Traefik
|
||||
|
||||
https://Fichier-Stockage.10.0.4.29.traefik.me`)"
|
||||
|
||||
|
||||
# More info
|
||||
- more information on the website [Tips-Of-Mine](https://www.tips-of-mine.fr/)
|
||||
|
||||
# Buy me a coffe
|
||||
<a href='https://ko-fi.com/R5R2KNI3N' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi4.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
8
Video/FreeTube/docker-compose.yml
Normal file
@ -0,0 +1,8 @@
|
||||
#### NETWORKS
|
||||
networks:
|
||||
back_network:
|
||||
driver: bridge
|
||||
attachable: true
|
||||
|
||||
#### SERVICES
|
||||
services:
|
3
Video/Frigate/LICENSE
Normal file
@ -0,0 +1,3 @@
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or combining it with [name of library] (or a modified version of that library), containing parts covered by the terms of [name of library's license], the licensors of this Program grant you additional permission to convey the resulting work. Corresponding Source for a non-source form of such a combination shall include the source code for the parts of [name of library] used as well as that of the covered work.
|
66
Video/Frigate/README.md
Normal file
@ -0,0 +1,66 @@
|
||||

|
||||
URL :
|
||||
|
||||
# Frigate
|
||||
|
||||
|
||||
|
||||
# Téléchargement, Configuration et Lancement
|
||||
|
||||
## Téléchargement de Frigate
|
||||
|
||||
Saisir la commande pour télécharger la source
|
||||
```bash
|
||||
git clone https://git.tips-of-mine.fr/Tips-Of-Mine/Docker.git
|
||||
```
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd Video\Frigate
|
||||
```
|
||||
|
||||
## Modifier la configuration de Frigate
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd Video\Frigate
|
||||
```
|
||||
|
||||
Nous éditons le fichier de configuration
|
||||
```bash
|
||||
nano .env
|
||||
```
|
||||
|
||||
Nous modifions les variables dont nous avons besoin.
|
||||
|
||||
## Lancement de Frigate
|
||||
|
||||
Pour utiliser Frigate tout seul
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Pour utiliser Frigate avec Traefik
|
||||
```bash
|
||||
docker compose -f docker-compose-traefik.yml up -d
|
||||
```
|
||||
|
||||
# Utilisation
|
||||
|
||||
## Accueil
|
||||
|
||||
Ouvrir une page web avec l'url :
|
||||
Pour une utilisation tout seul
|
||||
|
||||
http://10.0.4.29:3000
|
||||
|
||||
Pour une utilisation avec Traefik
|
||||
|
||||
https://Frigate.10.0.4.29.traefik.me`)"
|
||||
|
||||
|
||||
# More info
|
||||
- more information on the website [Tips-Of-Mine](https://www.tips-of-mine.fr/)
|
||||
|
||||
# Buy me a coffe
|
||||
<a href='https://ko-fi.com/R5R2KNI3N' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi4.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
96
Video/Frigate/config.yml
Normal file
@ -0,0 +1,96 @@
|
||||
cameras:
|
||||
garden:
|
||||
ffmpeg:
|
||||
inputs:
|
||||
- path: rtsp://cameraIP:554/s0
|
||||
roles:
|
||||
- detect
|
||||
- rtmp
|
||||
detect:
|
||||
width: 1920 # <---- update for your camera's resolution
|
||||
height: 1080 # <---- update for your camera's resolution
|
||||
fps: 25
|
||||
garage:
|
||||
ffmpeg:
|
||||
inputs:
|
||||
- path: rtsp://cameraIP:554/s0
|
||||
roles:
|
||||
- detect
|
||||
- rtmp
|
||||
detect:
|
||||
width: 1920 # <---- update for your camera's resolution
|
||||
height: 1080 # <---- update for your camera's resolution
|
||||
fps: 25
|
||||
motion:
|
||||
mask:
|
||||
- 0,0,1920,0,1920,393,297,241,314,464,0,541
|
||||
|
||||
# Optional: Database configuration
|
||||
database:
|
||||
# The path to store the SQLite DB (default: shown below)
|
||||
path: /media/frigate/frigate.db
|
||||
|
||||
detectors:
|
||||
coral1:
|
||||
type: edgetpu
|
||||
device: pci:0
|
||||
coral2:
|
||||
type: edgetpu
|
||||
device: pci:1
|
||||
|
||||
objects:
|
||||
track:
|
||||
- person
|
||||
- dog
|
||||
- cat
|
||||
- bird
|
||||
|
||||
snapshots:
|
||||
enabled: True
|
||||
timestamp: true
|
||||
bounding_box: true
|
||||
retain:
|
||||
default: 30
|
||||
mqtt:
|
||||
host: 192.168.200.14
|
||||
|
||||
ffmpeg:
|
||||
#hwaccel_args:
|
||||
# - -hwaccel
|
||||
# - vaapi
|
||||
# - -hwaccel_device
|
||||
# - /dev/dri/renderD128
|
||||
# - -hwaccel_output_format
|
||||
# - yuv420p
|
||||
output_args:
|
||||
record: -f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c:v copy -c:a aac
|
||||
|
||||
record:
|
||||
enabled: True
|
||||
events:
|
||||
pre_capture: 5
|
||||
post_capture: 5
|
||||
retain:
|
||||
default: 30
|
||||
mode: active_objects
|
||||
objects:
|
||||
- person
|
||||
- bird
|
||||
- cat
|
||||
- dog
|
||||
|
||||
birdseye:
|
||||
# Optional: Enable birdseye view (default: shown below)
|
||||
enabled: True
|
||||
# Optional: Width of the output resolution (default: shown below)
|
||||
width: 1280
|
||||
# Optional: Height of the output resolution (default: shown below)
|
||||
height: 720
|
||||
# Optional: Encoding quality of the mpeg1 feed (default: shown below)
|
||||
# 1 is the highest quality, and 31 is the lowest. Lower quality feeds utilize less CPU resources.
|
||||
quality: 8
|
||||
# Optional: Mode of the view. Available options are: objects, motion, and continuous
|
||||
# objects - cameras are included if they have had a tracked object within the last 30 seconds
|
||||
# motion - cameras are included if motion was detected in the last 30 seconds
|
||||
# continuous - all cameras are included always
|
||||
mode: continuous
|
66
Video/Frigate/docker-compose-traefik.yml
Normal file
@ -0,0 +1,66 @@
|
||||

|
||||
URL : HHHHH
|
||||
|
||||
# Fichier-Stockage
|
||||
|
||||
GGGGG
|
||||
|
||||
# Téléchargement, Configuration et Lancement
|
||||
|
||||
## Téléchargement de Fichier-Stockage
|
||||
|
||||
Saisir la commande pour télécharger la source
|
||||
```bash
|
||||
git clone https://git.tips-of-mine.fr/Tips-Of-Mine/Docker.git
|
||||
```
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd AAAAA\Fichier-Stockage
|
||||
```
|
||||
|
||||
## Modifier la configuration de Fichier-Stockage
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd AAAAA\Fichier-Stockage
|
||||
```
|
||||
|
||||
Nous éditons le fichier de configuration
|
||||
```bash
|
||||
nano .env
|
||||
```
|
||||
|
||||
Nous modifions les variables dont nous avons besoin.
|
||||
|
||||
## Lancement de Fichier-Stockage
|
||||
|
||||
Pour utiliser Fichier-Stockage tout seul
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Pour utiliser Fichier-Stockage avec Traefik
|
||||
```bash
|
||||
docker compose -f docker-compose-traefik.yml up -d
|
||||
```
|
||||
|
||||
# Utilisation
|
||||
|
||||
## Accueil
|
||||
|
||||
Ouvrir une page web avec l'url :
|
||||
Pour une utilisation tout seul
|
||||
|
||||
http://10.0.4.29:3000
|
||||
|
||||
Pour une utilisation avec Traefik
|
||||
|
||||
https://Fichier-Stockage.10.0.4.29.traefik.me`)"
|
||||
|
||||
|
||||
# More info
|
||||
- more information on the website [Tips-Of-Mine](https://www.tips-of-mine.fr/)
|
||||
|
||||
# Buy me a coffe
|
||||
<a href='https://ko-fi.com/R5R2KNI3N' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi4.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
46
Video/Frigate/docker-compose.yaml
Normal file
@ -0,0 +1,46 @@
|
||||
version: "3.9"
|
||||
services:
|
||||
frigate:
|
||||
container_name: frigate
|
||||
# privileged: true # this may not be necessary for all setups
|
||||
restart: unless-stopped
|
||||
image: ghcr.io/blakeblackshear/frigate:stable
|
||||
devices:
|
||||
#- /dev/bus/usb:/dev/bus/usb
|
||||
- /dev/apex_0:/dev/apex_0
|
||||
- /dev/apex_1:/dev/apex_1
|
||||
#- /dev/dri/renderD128:/dev/dri/renderD128 # for intel hwaccel, needs to be updated for your hardware
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /home/ubuntu/docker/frigate/config.yml:/config/config.yml:ro
|
||||
- /home/ubuntu/freenas/Frigate/media/clips:/media/frigate/clips
|
||||
- /home/ubuntu/freenas/Frigate/media/recordings:/media/frigate/recordings
|
||||
- /home/ubuntu/docker/frigate/database:/media/frigate
|
||||
- type: tmpfs # Optional: 1GB of memory, reduces SSD/SD Card wear
|
||||
target: /tmp/cache
|
||||
tmpfs:
|
||||
size: 2000000000
|
||||
ports:
|
||||
- "5000:5000"
|
||||
- "1935:1935" # RTMP feeds (deprecated)
|
||||
- "8554:8554" # RTSP feeds
|
||||
environment:
|
||||
FRIGATE_RTSP_PASSWORD: "password"
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.frigate.entrypoints=http"
|
||||
- "traefik.http.routers.frigate.rule=Host(`frigate.jimsgarage.co.uk`)"
|
||||
- "traefik.http.middlewares.frigate-https-redirect.redirectscheme.scheme=https"
|
||||
- "traefik.http.routers.frigate.middlewares=frigate-https-redirect"
|
||||
- "traefik.http.routers.frigate-secure.entrypoints=https"
|
||||
- "traefik.http.routers.frigate-secure.rule=Host(`frigate.jimsgarage.co.uk`)"
|
||||
- "traefik.http.routers.frigate-secure.tls=true"
|
||||
- "traefik.http.routers.frigate-secure.service=frigate"
|
||||
- "traefik.http.services.frigate.loadbalancer.server.port=5000"
|
||||
- "traefik.docker.network=proxy"
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
8
Video/Frigate/docker-compose.yml
Normal file
@ -0,0 +1,8 @@
|
||||
#### NETWORKS
|
||||
networks:
|
||||
back_network:
|
||||
driver: bridge
|
||||
attachable: true
|
||||
|
||||
#### SERVICES
|
||||
services:
|
BIN
Video/Frigate/img/banniere-Frigate.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
Video/Frigate/img/logo-Frigate.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
218
Video/Jitsi Meet/.env
Normal file
@ -0,0 +1,218 @@
|
||||
# shellcheck disable=SC2034
|
||||
|
||||
################################################################################
|
||||
################################################################################
|
||||
# Welcome to the Jitsi Meet Docker setup!
|
||||
#
|
||||
# This sample .env file contains some basic options to get you started.
|
||||
# The full options reference can be found here:
|
||||
# https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker
|
||||
################################################################################
|
||||
################################################################################
|
||||
|
||||
|
||||
#
|
||||
# Basic configuration options
|
||||
#
|
||||
|
||||
# Directory where all configuration will be stored
|
||||
CONFIG=~/.jitsi-meet-cfg
|
||||
|
||||
# Exposed HTTP port
|
||||
HTTP_PORT=8000
|
||||
|
||||
# Exposed HTTPS port
|
||||
HTTPS_PORT=8443
|
||||
|
||||
# System time zone
|
||||
TZ=UTC
|
||||
|
||||
# Public URL for the web service (required)
|
||||
PUBLIC_URL=https://meet.yourdomain.com
|
||||
|
||||
# Media IP addresses to advertise by the JVB
|
||||
# This setting deprecates DOCKER_HOST_ADDRESS, and supports a comma separated list of IPs
|
||||
# See the "Running behind NAT or on a LAN environment" section in the Handbook:
|
||||
# https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker#running-behind-nat-or-on-a-lan-environment
|
||||
JVB_ADVERTISE_IPS=192.168.x.x # Add your Docker Host IP here
|
||||
|
||||
|
||||
#
|
||||
# JaaS Components (beta)
|
||||
# https://jaas.8x8.vc
|
||||
#
|
||||
|
||||
# Enable JaaS Components (hosted Jigasi)
|
||||
# NOTE: if Let's Encrypt is enabled a JaaS account will be automatically created, using the provided email in LETSENCRYPT_EMAIL
|
||||
#ENABLE_JAAS_COMPONENTS=0
|
||||
|
||||
#
|
||||
# Let's Encrypt configuration
|
||||
#
|
||||
|
||||
# Enable Let's Encrypt certificate generation
|
||||
#ENABLE_LETSENCRYPT=1
|
||||
|
||||
# Domain for which to generate the certificate
|
||||
#LETSENCRYPT_DOMAIN=meet.example.com
|
||||
|
||||
# E-Mail for receiving important account notifications (mandatory)
|
||||
#LETSENCRYPT_EMAIL=alice@atlanta.net
|
||||
|
||||
# Use the staging server (for avoiding rate limits while testing)
|
||||
#LETSENCRYPT_USE_STAGING=1
|
||||
|
||||
|
||||
#
|
||||
# Etherpad integration (for document sharing)
|
||||
#
|
||||
|
||||
# Set etherpad-lite URL in docker local network (uncomment to enable)
|
||||
#ETHERPAD_URL_BASE=http://etherpad.meet.jitsi:9001
|
||||
|
||||
# Set etherpad-lite public URL, including /p/ pad path fragment (uncomment to enable)
|
||||
#ETHERPAD_PUBLIC_URL=https://etherpad.my.domain/p/
|
||||
|
||||
# Name your etherpad instance!
|
||||
ETHERPAD_TITLE=Video Chat
|
||||
|
||||
# The default text of a pad
|
||||
ETHERPAD_DEFAULT_PAD_TEXT="Welcome to Web Chat!\n\n"
|
||||
|
||||
# Name of the skin for etherpad
|
||||
ETHERPAD_SKIN_NAME=colibris
|
||||
|
||||
# Skin variants for etherpad
|
||||
ETHERPAD_SKIN_VARIANTS="super-light-toolbar super-light-editor light-background full-width-editor"
|
||||
|
||||
|
||||
#
|
||||
# Basic Jigasi configuration options (needed for SIP gateway support)
|
||||
#
|
||||
|
||||
# SIP URI for incoming / outgoing calls
|
||||
#JIGASI_SIP_URI=test@sip2sip.info
|
||||
|
||||
# Password for the specified SIP account as a clear text
|
||||
#JIGASI_SIP_PASSWORD=passw0rd
|
||||
|
||||
# SIP server (use the SIP account domain if in doubt)
|
||||
#JIGASI_SIP_SERVER=sip2sip.info
|
||||
|
||||
# SIP server port
|
||||
#JIGASI_SIP_PORT=5060
|
||||
|
||||
# SIP server transport
|
||||
#JIGASI_SIP_TRANSPORT=UDP
|
||||
|
||||
|
||||
#
|
||||
# Authentication configuration (see handbook for details)
|
||||
#
|
||||
|
||||
# Enable authentication
|
||||
ENABLE_AUTH=1
|
||||
|
||||
# Enable guest access
|
||||
ENABLE_GUESTS=1
|
||||
|
||||
# Select authentication type: internal, jwt, ldap or matrix
|
||||
AUTH_TYPE=internal
|
||||
|
||||
# JWT authentication
|
||||
#
|
||||
|
||||
# Application identifier
|
||||
#JWT_APP_ID=my_jitsi_app_id
|
||||
|
||||
# Application secret known only to your token generator
|
||||
#JWT_APP_SECRET=my_jitsi_app_secret
|
||||
|
||||
# (Optional) Set asap_accepted_issuers as a comma separated list
|
||||
#JWT_ACCEPTED_ISSUERS=my_web_client,my_app_client
|
||||
|
||||
# (Optional) Set asap_accepted_audiences as a comma separated list
|
||||
#JWT_ACCEPTED_AUDIENCES=my_server1,my_server2
|
||||
|
||||
# LDAP authentication (for more information see the Cyrus SASL saslauthd.conf man page)
|
||||
#
|
||||
|
||||
# LDAP url for connection
|
||||
#LDAP_URL=ldaps://ldap.domain.com/
|
||||
|
||||
# LDAP base DN. Can be empty
|
||||
#LDAP_BASE=DC=example,DC=domain,DC=com
|
||||
|
||||
# LDAP user DN. Do not specify this parameter for the anonymous bind
|
||||
#LDAP_BINDDN=CN=binduser,OU=users,DC=example,DC=domain,DC=com
|
||||
|
||||
# LDAP user password. Do not specify this parameter for the anonymous bind
|
||||
#LDAP_BINDPW=LdapUserPassw0rd
|
||||
|
||||
# LDAP filter. Tokens example:
|
||||
# %1-9 - if the input key is user@mail.domain.com, then %1 is com, %2 is domain and %3 is mail
|
||||
# %s - %s is replaced by the complete service string
|
||||
# %r - %r is replaced by the complete realm string
|
||||
#LDAP_FILTER=(sAMAccountName=%u)
|
||||
|
||||
# LDAP authentication method
|
||||
#LDAP_AUTH_METHOD=bind
|
||||
|
||||
# LDAP version
|
||||
#LDAP_VERSION=3
|
||||
|
||||
# LDAP TLS using
|
||||
#LDAP_USE_TLS=1
|
||||
|
||||
# List of SSL/TLS ciphers to allow
|
||||
#LDAP_TLS_CIPHERS=SECURE256:SECURE128:!AES-128-CBC:!ARCFOUR-128:!CAMELLIA-128-CBC:!3DES-CBC:!CAMELLIA-128-CBC
|
||||
|
||||
# Require and verify server certificate
|
||||
#LDAP_TLS_CHECK_PEER=1
|
||||
|
||||
# Path to CA cert file. Used when server certificate verify is enabled
|
||||
#LDAP_TLS_CACERT_FILE=/etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
# Path to CA certs directory. Used when server certificate verify is enabled
|
||||
#LDAP_TLS_CACERT_DIR=/etc/ssl/certs
|
||||
|
||||
# Wether to use starttls, implies LDAPv3 and requires ldap:// instead of ldaps://
|
||||
# LDAP_START_TLS=1
|
||||
|
||||
|
||||
#
|
||||
# Security
|
||||
#
|
||||
# Set these to strong passwords to avoid intruders from impersonating a service account
|
||||
# The service(s) won't start unless these are specified
|
||||
# Running ./gen-passwords.sh will update .env with strong passwords
|
||||
# You may skip the Jigasi and Jibri passwords if you are not using those
|
||||
# DO NOT reuse passwords
|
||||
#
|
||||
|
||||
# ENSURE YOU CHANGE THE BELOW!!!!!!!!
|
||||
|
||||
# XMPP password for Jicofo client connections
|
||||
JICOFO_AUTH_PASSWORD=8fbfebe1142fac3efee956d7d65d0146
|
||||
|
||||
# XMPP password for JVB client connections
|
||||
JVB_AUTH_PASSWORD=0a192f85b439288b54f520faacdf209d
|
||||
|
||||
# XMPP password for Jigasi MUC client connections
|
||||
JIGASI_XMPP_PASSWORD=141b73ad8050cee2fe72c74ab1a86282
|
||||
|
||||
# XMPP recorder password for Jibri client connections
|
||||
JIBRI_RECORDER_PASSWORD=45f6506538b556d3bfa4c04291fddad3
|
||||
|
||||
# XMPP password for Jibri client connections
|
||||
JIBRI_XMPP_PASSWORD=7798d3b72dbffca6eb0e0ea384e816b7
|
||||
|
||||
#
|
||||
# Docker Compose options
|
||||
#
|
||||
|
||||
# Container restart policy
|
||||
#RESTART_POLICY=unless-stopped
|
||||
|
||||
# Jitsi image version (useful for local development)
|
||||
#JITSI_IMAGE_VERSION=latest
|
3
Video/Jitsi Meet/LICENSE
Normal file
@ -0,0 +1,3 @@
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or combining it with [name of library] (or a modified version of that library), containing parts covered by the terms of [name of library's license], the licensors of this Program grant you additional permission to convey the resulting work. Corresponding Source for a non-source form of such a combination shall include the source code for the parts of [name of library] used as well as that of the covered work.
|
31
Video/Jitsi Meet/README.md
Normal file
@ -0,0 +1,31 @@
|
||||

|
||||
|
||||
# Jitsi
|
||||
|
||||
|
||||
# Installation
|
||||
|
||||
Pour utiliser Jitsi tout seul
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Pour utiliser Jitsi avec Traefik
|
||||
```bash
|
||||
docker compose -f docker-compose-traefik.yml up -d
|
||||
```
|
||||
|
||||
Pour utiliser Jitsi avec Nginx
|
||||
```bash
|
||||
docker compose -f docker-compose-nginx.yml up -d
|
||||
```
|
||||
# Utilisation
|
||||
|
||||
## Accueil
|
||||
|
||||
|
||||
# More info
|
||||
- more information on the website [Tips-Of-Mine](https://www.tips-of-mine.fr/)
|
||||
|
||||
# Buy me a coffe
|
||||
<a href='https://ko-fi.com/R5R2KNI3N' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi4.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
66
Video/Jitsi Meet/docker-compose-traefik.yml
Normal file
@ -0,0 +1,66 @@
|
||||

|
||||
URL : HHHHH
|
||||
|
||||
# Fichier-Stockage
|
||||
|
||||
GGGGG
|
||||
|
||||
# Téléchargement, Configuration et Lancement
|
||||
|
||||
## Téléchargement de Fichier-Stockage
|
||||
|
||||
Saisir la commande pour télécharger la source
|
||||
```bash
|
||||
git clone https://git.tips-of-mine.fr/Tips-Of-Mine/Docker.git
|
||||
```
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd AAAAA\Fichier-Stockage
|
||||
```
|
||||
|
||||
## Modifier la configuration de Fichier-Stockage
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd AAAAA\Fichier-Stockage
|
||||
```
|
||||
|
||||
Nous éditons le fichier de configuration
|
||||
```bash
|
||||
nano .env
|
||||
```
|
||||
|
||||
Nous modifions les variables dont nous avons besoin.
|
||||
|
||||
## Lancement de Fichier-Stockage
|
||||
|
||||
Pour utiliser Fichier-Stockage tout seul
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Pour utiliser Fichier-Stockage avec Traefik
|
||||
```bash
|
||||
docker compose -f docker-compose-traefik.yml up -d
|
||||
```
|
||||
|
||||
# Utilisation
|
||||
|
||||
## Accueil
|
||||
|
||||
Ouvrir une page web avec l'url :
|
||||
Pour une utilisation tout seul
|
||||
|
||||
http://10.0.4.29:3000
|
||||
|
||||
Pour une utilisation avec Traefik
|
||||
|
||||
https://Fichier-Stockage.10.0.4.29.traefik.me`)"
|
||||
|
||||
|
||||
# More info
|
||||
- more information on the website [Tips-Of-Mine](https://www.tips-of-mine.fr/)
|
||||
|
||||
# Buy me a coffe
|
||||
<a href='https://ko-fi.com/R5R2KNI3N' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi4.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
400
Video/Jitsi Meet/docker-compose.yml
Normal file
@ -0,0 +1,400 @@
|
||||
version: '3.5'
|
||||
|
||||
services:
|
||||
# Frontend
|
||||
web:
|
||||
image: jitsi/web:${JITSI_IMAGE_VERSION:-stable-8922}
|
||||
restart: ${RESTART_POLICY:-unless-stopped}
|
||||
# remember to uncomment below if you do not plan on using a reverse proxy
|
||||
# ports:
|
||||
# - '${HTTP_PORT}:80'
|
||||
# - '${HTTPS_PORT}:443'
|
||||
volumes:
|
||||
- ${CONFIG}/web:/config:Z
|
||||
- ${CONFIG}/web/crontabs:/var/spool/cron/crontabs:Z
|
||||
- ${CONFIG}/transcripts:/usr/share/jitsi-meet/transcripts:Z
|
||||
environment:
|
||||
- AMPLITUDE_ID
|
||||
- ANALYTICS_SCRIPT_URLS
|
||||
- ANALYTICS_WHITELISTED_EVENTS
|
||||
- AUDIO_QUALITY_OPUS_BITRATE
|
||||
- AUTO_CAPTION_ON_RECORD
|
||||
- BRANDING_DATA_URL
|
||||
- CALLSTATS_CUSTOM_SCRIPT_URL
|
||||
- CALLSTATS_ID
|
||||
- CALLSTATS_SECRET
|
||||
- CHROME_EXTENSION_BANNER_JSON
|
||||
- COLIBRI_WEBSOCKET_PORT
|
||||
- CONFCODE_URL
|
||||
- CONFIG_EXTERNAL_CONNECT
|
||||
- DEFAULT_LANGUAGE
|
||||
- DEPLOYMENTINFO_ENVIRONMENT
|
||||
- DEPLOYMENTINFO_ENVIRONMENT_TYPE
|
||||
- DEPLOYMENTINFO_REGION
|
||||
- DEPLOYMENTINFO_SHARD
|
||||
- DEPLOYMENTINFO_USERREGION
|
||||
- DESKTOP_SHARING_FRAMERATE_MIN
|
||||
- DESKTOP_SHARING_FRAMERATE_MAX
|
||||
- DIALIN_NUMBERS_URL
|
||||
- DIALOUT_AUTH_URL
|
||||
- DIALOUT_CODES_URL
|
||||
- DISABLE_AUDIO_LEVELS
|
||||
- DISABLE_DEEP_LINKING
|
||||
- DISABLE_GRANT_MODERATOR
|
||||
- DISABLE_HTTPS
|
||||
- DISABLE_KICKOUT
|
||||
- DISABLE_LOCAL_RECORDING
|
||||
- DISABLE_POLLS
|
||||
- DISABLE_PRIVATE_CHAT
|
||||
- DISABLE_PROFILE
|
||||
- DISABLE_REACTIONS
|
||||
- DISABLE_REMOTE_VIDEO_MENU
|
||||
- DISABLE_START_FOR_ALL
|
||||
- DROPBOX_APPKEY
|
||||
- DROPBOX_REDIRECT_URI
|
||||
- DYNAMIC_BRANDING_URL
|
||||
- ENABLE_AUDIO_PROCESSING
|
||||
- ENABLE_AUTH
|
||||
- ENABLE_BREAKOUT_ROOMS
|
||||
- ENABLE_CALENDAR
|
||||
- ENABLE_COLIBRI_WEBSOCKET
|
||||
- ENABLE_E2EPING
|
||||
- ENABLE_FILE_RECORDING_SHARING
|
||||
- ENABLE_GUESTS
|
||||
- ENABLE_HSTS
|
||||
- ENABLE_HTTP_REDIRECT
|
||||
- ENABLE_IPV6
|
||||
- ENABLE_LETSENCRYPT
|
||||
- ENABLE_LIPSYNC
|
||||
- ENABLE_NO_AUDIO_DETECTION
|
||||
- ENABLE_NOISY_MIC_DETECTION
|
||||
- ENABLE_OCTO
|
||||
- ENABLE_OPUS_RED
|
||||
- ENABLE_PREJOIN_PAGE
|
||||
- ENABLE_P2P
|
||||
- ENABLE_WELCOME_PAGE
|
||||
- ENABLE_CLOSE_PAGE
|
||||
- ENABLE_LIVESTREAMING
|
||||
- ENABLE_LIVESTREAMING_DATA_PRIVACY_LINK
|
||||
- ENABLE_LIVESTREAMING_HELP_LINK
|
||||
- ENABLE_LIVESTREAMING_TERMS_LINK
|
||||
- ENABLE_LIVESTREAMING_VALIDATOR_REGEXP_STRING
|
||||
- ENABLE_LOCAL_RECORDING_NOTIFY_ALL_PARTICIPANT
|
||||
- ENABLE_LOCAL_RECORDING_SELF_START
|
||||
- ENABLE_RECORDING
|
||||
- ENABLE_REMB
|
||||
- ENABLE_REQUIRE_DISPLAY_NAME
|
||||
- ENABLE_SERVICE_RECORDING
|
||||
- ENABLE_SIMULCAST
|
||||
- ENABLE_STATS_ID
|
||||
- ENABLE_STEREO
|
||||
- ENABLE_SUBDOMAINS
|
||||
- ENABLE_TALK_WHILE_MUTED
|
||||
- ENABLE_TCC
|
||||
- ENABLE_TRANSCRIPTIONS
|
||||
- ENABLE_XMPP_WEBSOCKET
|
||||
- ENABLE_JAAS_COMPONENTS
|
||||
- ETHERPAD_PUBLIC_URL
|
||||
- ETHERPAD_URL_BASE
|
||||
- E2EPING_NUM_REQUESTS
|
||||
- E2EPING_MAX_CONFERENCE_SIZE
|
||||
- E2EPING_MAX_MESSAGE_PER_SECOND
|
||||
- GOOGLE_ANALYTICS_ID
|
||||
- GOOGLE_API_APP_CLIENT_ID
|
||||
- HIDE_PREMEETING_BUTTONS
|
||||
- HIDE_PREJOIN_DISPLAY_NAME
|
||||
- HIDE_PREJOIN_EXTRA_BUTTONS
|
||||
- INVITE_SERVICE_URL
|
||||
- LETSENCRYPT_DOMAIN
|
||||
- LETSENCRYPT_EMAIL
|
||||
- LETSENCRYPT_USE_STAGING
|
||||
- MATOMO_ENDPOINT
|
||||
- MATOMO_SITE_ID
|
||||
- MICROSOFT_API_APP_CLIENT_ID
|
||||
- NGINX_RESOLVER
|
||||
- NGINX_WORKER_PROCESSES
|
||||
- NGINX_WORKER_CONNECTIONS
|
||||
- PEOPLE_SEARCH_URL
|
||||
- PREFERRED_LANGUAGE
|
||||
- PUBLIC_URL
|
||||
- P2P_PREFERRED_CODEC
|
||||
- RESOLUTION
|
||||
- RESOLUTION_MIN
|
||||
- RESOLUTION_WIDTH
|
||||
- RESOLUTION_WIDTH_MIN
|
||||
- START_AUDIO_MUTED
|
||||
- START_AUDIO_ONLY
|
||||
- START_BITRATE
|
||||
- START_SILENT
|
||||
- START_WITH_AUDIO_MUTED
|
||||
- START_VIDEO_MUTED
|
||||
- START_WITH_VIDEO_MUTED
|
||||
- TESTING_CAP_SCREENSHARE_BITRATE
|
||||
- TESTING_OCTO_PROBABILITY
|
||||
- TOKEN_AUTH_URL
|
||||
- TOOLBAR_BUTTONS
|
||||
- TRANSLATION_LANGUAGES
|
||||
- TRANSLATION_LANGUAGES_HEAD
|
||||
- TZ
|
||||
- USE_APP_LANGUAGE
|
||||
- VIDEOQUALITY_BITRATE_H264_LOW
|
||||
- VIDEOQUALITY_BITRATE_H264_STANDARD
|
||||
- VIDEOQUALITY_BITRATE_H264_HIGH
|
||||
- VIDEOQUALITY_BITRATE_VP8_LOW
|
||||
- VIDEOQUALITY_BITRATE_VP8_STANDARD
|
||||
- VIDEOQUALITY_BITRATE_VP8_HIGH
|
||||
- VIDEOQUALITY_BITRATE_VP9_LOW
|
||||
- VIDEOQUALITY_BITRATE_VP9_STANDARD
|
||||
- VIDEOQUALITY_BITRATE_VP9_HIGH
|
||||
- VIDEOQUALITY_ENFORCE_PREFERRED_CODEC
|
||||
- VIDEOQUALITY_PREFERRED_CODEC
|
||||
- XMPP_AUTH_DOMAIN
|
||||
- XMPP_BOSH_URL_BASE
|
||||
- XMPP_DOMAIN
|
||||
- XMPP_GUEST_DOMAIN
|
||||
- XMPP_MUC_DOMAIN
|
||||
- XMPP_RECORDER_DOMAIN
|
||||
- XMPP_PORT
|
||||
- WHITEBOARD_ENABLED
|
||||
- WHITEBOARD_COLLAB_SERVER_PUBLIC_URL
|
||||
networks:
|
||||
meet.jitsi:
|
||||
proxy: # remove if you're not using a reverse proxy (including labels below)
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.jitsi.entrypoints=http"
|
||||
- "traefik.http.routers.jitsi.rule=Host(`meet2.jimsgarage.co.uk`)"
|
||||
- "traefik.http.middlewares.jitsi-https-redirect.redirectscheme.scheme=https"
|
||||
- "traefik.http.routers.jitsi.middlewares=jitsi-https-redirect"
|
||||
- "traefik.http.routers.jitsi-secure.entrypoints=https"
|
||||
- "traefik.http.routers.jitsi-secure.rule=Host(`meet2.jimsgarage.co.uk`)"
|
||||
- "traefik.http.routers.jitsi-secure.tls=true"
|
||||
- "traefik.http.routers.jitsi-secure.service=jitsi"
|
||||
- "traefik.http.services.jitsi.loadbalancer.server.port=80"
|
||||
- "traefik.docker.network=proxy"
|
||||
|
||||
# XMPP server
|
||||
prosody:
|
||||
image: jitsi/prosody:${JITSI_IMAGE_VERSION:-stable-8922}
|
||||
restart: ${RESTART_POLICY:-unless-stopped}
|
||||
expose:
|
||||
- '${XMPP_PORT:-5222}'
|
||||
- '5347'
|
||||
- '5280'
|
||||
volumes:
|
||||
- ${CONFIG}/prosody/config:/config:Z
|
||||
- ${CONFIG}/prosody/prosody-plugins-custom:/prosody-plugins-custom:Z
|
||||
environment:
|
||||
- AUTH_TYPE
|
||||
- DISABLE_POLLS
|
||||
- ENABLE_AUTH
|
||||
- ENABLE_AV_MODERATION
|
||||
- ENABLE_BREAKOUT_ROOMS
|
||||
- ENABLE_END_CONFERENCE
|
||||
- ENABLE_GUESTS
|
||||
- ENABLE_IPV6
|
||||
- ENABLE_LOBBY
|
||||
- ENABLE_RECORDING
|
||||
- ENABLE_XMPP_WEBSOCKET
|
||||
- ENABLE_JAAS_COMPONENTS
|
||||
- GC_TYPE
|
||||
- GC_INC_TH
|
||||
- GC_INC_SPEED
|
||||
- GC_INC_STEP_SIZE
|
||||
- GC_GEN_MIN_TH
|
||||
- GC_GEN_MAX_TH
|
||||
- GLOBAL_CONFIG
|
||||
- GLOBAL_MODULES
|
||||
- JIBRI_RECORDER_USER
|
||||
- JIBRI_RECORDER_PASSWORD
|
||||
- JIBRI_XMPP_USER
|
||||
- JIBRI_XMPP_PASSWORD
|
||||
- JICOFO_AUTH_PASSWORD
|
||||
- JICOFO_COMPONENT_SECRET
|
||||
- JIGASI_XMPP_USER
|
||||
- JIGASI_XMPP_PASSWORD
|
||||
- JVB_AUTH_USER
|
||||
- JVB_AUTH_PASSWORD
|
||||
- JWT_APP_ID
|
||||
- JWT_APP_SECRET
|
||||
- JWT_ACCEPTED_ISSUERS
|
||||
- JWT_ACCEPTED_AUDIENCES
|
||||
- JWT_ASAP_KEYSERVER
|
||||
- JWT_ALLOW_EMPTY
|
||||
- JWT_AUTH_TYPE
|
||||
- JWT_ENABLE_DOMAIN_VERIFICATION
|
||||
- JWT_TOKEN_AUTH_MODULE
|
||||
- MATRIX_UVS_URL
|
||||
- MATRIX_UVS_ISSUER
|
||||
- MATRIX_UVS_AUTH_TOKEN
|
||||
- MATRIX_UVS_SYNC_POWER_LEVELS
|
||||
- LOG_LEVEL
|
||||
- LDAP_AUTH_METHOD
|
||||
- LDAP_BASE
|
||||
- LDAP_BINDDN
|
||||
- LDAP_BINDPW
|
||||
- LDAP_FILTER
|
||||
- LDAP_VERSION
|
||||
- LDAP_TLS_CIPHERS
|
||||
- LDAP_TLS_CHECK_PEER
|
||||
- LDAP_TLS_CACERT_FILE
|
||||
- LDAP_TLS_CACERT_DIR
|
||||
- LDAP_START_TLS
|
||||
- LDAP_URL
|
||||
- LDAP_USE_TLS
|
||||
- MAX_PARTICIPANTS
|
||||
- PROSODY_AUTH_TYPE
|
||||
- PROSODY_RESERVATION_ENABLED
|
||||
- PROSODY_RESERVATION_REST_BASE_URL
|
||||
- PROSODY_ENABLE_RATE_LIMITS
|
||||
- PROSODY_RATE_LIMIT_LOGIN_RATE
|
||||
- PROSODY_RATE_LIMIT_SESSION_RATE
|
||||
- PROSODY_RATE_LIMIT_TIMEOUT
|
||||
- PROSODY_RATE_LIMIT_ALLOW_RANGES
|
||||
- PROSODY_RATE_LIMIT_CACHE_SIZE
|
||||
- PUBLIC_URL
|
||||
- TURN_CREDENTIALS
|
||||
- TURN_HOST
|
||||
- TURNS_HOST
|
||||
- TURN_PORT
|
||||
- TURNS_PORT
|
||||
- TURN_TRANSPORT
|
||||
- TZ
|
||||
- XMPP_DOMAIN
|
||||
- XMPP_AUTH_DOMAIN
|
||||
- XMPP_GUEST_DOMAIN
|
||||
- XMPP_MUC_DOMAIN
|
||||
- XMPP_INTERNAL_MUC_DOMAIN
|
||||
- XMPP_MODULES
|
||||
- XMPP_MUC_MODULES
|
||||
- XMPP_MUC_CONFIGURATION
|
||||
- XMPP_INTERNAL_MUC_MODULES
|
||||
- XMPP_RECORDER_DOMAIN
|
||||
- XMPP_PORT
|
||||
networks:
|
||||
meet.jitsi:
|
||||
aliases:
|
||||
- ${XMPP_SERVER:-xmpp.meet.jitsi}
|
||||
|
||||
# Focus component
|
||||
jicofo:
|
||||
image: jitsi/jicofo:${JITSI_IMAGE_VERSION:-stable-8922}
|
||||
restart: ${RESTART_POLICY:-unless-stopped}
|
||||
ports:
|
||||
- '127.0.0.1:${JICOFO_REST_PORT:-8888}:8888'
|
||||
volumes:
|
||||
- ${CONFIG}/jicofo:/config:Z
|
||||
environment:
|
||||
- AUTH_TYPE
|
||||
- BRIDGE_AVG_PARTICIPANT_STRESS
|
||||
- BRIDGE_STRESS_THRESHOLD
|
||||
- ENABLE_AUTH
|
||||
- ENABLE_AUTO_OWNER
|
||||
- ENABLE_CODEC_VP8
|
||||
- ENABLE_CODEC_VP9
|
||||
- ENABLE_CODEC_H264
|
||||
- ENABLE_CODEC_OPUS_RED
|
||||
- ENABLE_JVB_XMPP_SERVER
|
||||
- ENABLE_OCTO
|
||||
- ENABLE_RECORDING
|
||||
- ENABLE_SCTP
|
||||
- ENABLE_AUTO_LOGIN
|
||||
- JICOFO_AUTH_LIFETIME
|
||||
- JICOFO_AUTH_PASSWORD
|
||||
- JICOFO_AUTH_TYPE
|
||||
- JICOFO_BRIDGE_REGION_GROUPS
|
||||
- JICOFO_ENABLE_AUTH
|
||||
- JICOFO_ENABLE_BRIDGE_HEALTH_CHECKS
|
||||
- JICOFO_CONF_INITIAL_PARTICIPANT_WAIT_TIMEOUT
|
||||
- JICOFO_CONF_SINGLE_PARTICIPANT_TIMEOUT
|
||||
- JICOFO_CONF_SOURCE_SIGNALING_DELAYS
|
||||
- JICOFO_CONF_MAX_AUDIO_SENDERS
|
||||
- JICOFO_CONF_MAX_VIDEO_SENDERS
|
||||
- JICOFO_CONF_STRIP_SIMULCAST
|
||||
- JICOFO_CONF_SSRC_REWRITING
|
||||
- JICOFO_ENABLE_HEALTH_CHECKS
|
||||
- JICOFO_ENABLE_REST
|
||||
- JICOFO_HEALTH_CHECKS_USE_PRESENCE
|
||||
- JICOFO_MULTI_STREAM_BACKWARD_COMPAT
|
||||
- JICOFO_OCTO_REGION
|
||||
- JIBRI_BREWERY_MUC
|
||||
- JIBRI_REQUEST_RETRIES
|
||||
- JIBRI_PENDING_TIMEOUT
|
||||
- JIGASI_BREWERY_MUC
|
||||
- JIGASI_SIP_URI
|
||||
- JVB_BREWERY_MUC
|
||||
- JVB_XMPP_AUTH_DOMAIN
|
||||
- JVB_XMPP_INTERNAL_MUC_DOMAIN
|
||||
- JVB_XMPP_PORT
|
||||
- JVB_XMPP_SERVER
|
||||
- MAX_BRIDGE_PARTICIPANTS
|
||||
- OCTO_BRIDGE_SELECTION_STRATEGY
|
||||
- SENTRY_DSN="${JICOFO_SENTRY_DSN:-0}"
|
||||
- SENTRY_ENVIRONMENT
|
||||
- SENTRY_RELEASE
|
||||
- TZ
|
||||
- XMPP_DOMAIN
|
||||
- XMPP_AUTH_DOMAIN
|
||||
- XMPP_INTERNAL_MUC_DOMAIN
|
||||
- XMPP_MUC_DOMAIN
|
||||
- XMPP_RECORDER_DOMAIN
|
||||
- XMPP_SERVER
|
||||
- XMPP_PORT
|
||||
depends_on:
|
||||
- prosody
|
||||
networks:
|
||||
meet.jitsi:
|
||||
|
||||
# Video bridge
|
||||
jvb:
|
||||
image: jitsi/jvb:${JITSI_IMAGE_VERSION:-stable-8922}
|
||||
restart: ${RESTART_POLICY:-unless-stopped}
|
||||
ports:
|
||||
- '${JVB_PORT:-10000}:${JVB_PORT:-10000}/udp'
|
||||
- '127.0.0.1:${JVB_COLIBRI_PORT:-8080}:8080'
|
||||
volumes:
|
||||
- ${CONFIG}/jvb:/config:Z
|
||||
environment:
|
||||
- DOCKER_HOST_ADDRESS
|
||||
- ENABLE_COLIBRI_WEBSOCKET
|
||||
- ENABLE_JVB_XMPP_SERVER
|
||||
- ENABLE_OCTO
|
||||
- JVB_ADVERTISE_IPS
|
||||
- JVB_ADVERTISE_PRIVATE_CANDIDATES
|
||||
- JVB_AUTH_USER
|
||||
- JVB_AUTH_PASSWORD
|
||||
- JVB_BREWERY_MUC
|
||||
- JVB_DISABLE_STUN
|
||||
- JVB_PORT
|
||||
- JVB_MUC_NICKNAME
|
||||
- JVB_STUN_SERVERS
|
||||
- JVB_OCTO_BIND_ADDRESS
|
||||
- JVB_OCTO_REGION
|
||||
- JVB_OCTO_RELAY_ID
|
||||
- JVB_WS_DOMAIN
|
||||
- JVB_WS_SERVER_ID
|
||||
- JVB_XMPP_AUTH_DOMAIN
|
||||
- JVB_XMPP_INTERNAL_MUC_DOMAIN
|
||||
- JVB_XMPP_PORT
|
||||
- JVB_XMPP_SERVER
|
||||
- PUBLIC_URL
|
||||
- SENTRY_DSN="${JVB_SENTRY_DSN:-0}"
|
||||
- SENTRY_ENVIRONMENT
|
||||
- SENTRY_RELEASE
|
||||
- COLIBRI_REST_ENABLED
|
||||
- SHUTDOWN_REST_ENABLED
|
||||
- TZ
|
||||
- XMPP_AUTH_DOMAIN
|
||||
- XMPP_INTERNAL_MUC_DOMAIN
|
||||
- XMPP_SERVER
|
||||
- XMPP_PORT
|
||||
depends_on:
|
||||
- prosody
|
||||
networks:
|
||||
meet.jitsi:
|
||||
|
||||
# Custom network so all services can communicate using a FQDN
|
||||
networks:
|
||||
meet.jitsi:
|
||||
proxy: # remove if you're not using a proxy
|
||||
external: true
|
19
Video/Jitsi Meet/gen-passwords.sh
Normal file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
function generatePassword() {
|
||||
openssl rand -hex 16
|
||||
}
|
||||
|
||||
JICOFO_AUTH_PASSWORD=$(generatePassword)
|
||||
JVB_AUTH_PASSWORD=$(generatePassword)
|
||||
JIGASI_XMPP_PASSWORD=$(generatePassword)
|
||||
JIBRI_RECORDER_PASSWORD=$(generatePassword)
|
||||
JIBRI_XMPP_PASSWORD=$(generatePassword)
|
||||
|
||||
sed -i.bak \
|
||||
-e "s#JICOFO_AUTH_PASSWORD=.*#JICOFO_AUTH_PASSWORD=${JICOFO_AUTH_PASSWORD}#g" \
|
||||
-e "s#JVB_AUTH_PASSWORD=.*#JVB_AUTH_PASSWORD=${JVB_AUTH_PASSWORD}#g" \
|
||||
-e "s#JIGASI_XMPP_PASSWORD=.*#JIGASI_XMPP_PASSWORD=${JIGASI_XMPP_PASSWORD}#g" \
|
||||
-e "s#JIBRI_RECORDER_PASSWORD=.*#JIBRI_RECORDER_PASSWORD=${JIBRI_RECORDER_PASSWORD}#g" \
|
||||
-e "s#JIBRI_XMPP_PASSWORD=.*#JIBRI_XMPP_PASSWORD=${JIBRI_XMPP_PASSWORD}#g" \
|
||||
"$(dirname "$0")/.env"
|
3
Video/MeTube/LICENSE
Normal file
@ -0,0 +1,3 @@
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or combining it with [name of library] (or a modified version of that library), containing parts covered by the terms of [name of library's license], the licensors of this Program grant you additional permission to convey the resulting work. Corresponding Source for a non-source form of such a combination shall include the source code for the parts of [name of library] used as well as that of the covered work.
|
66
Video/MeTube/README.md
Normal file
@ -0,0 +1,66 @@
|
||||

|
||||
URL :
|
||||
|
||||
# MeTube
|
||||
|
||||
|
||||
|
||||
# Téléchargement, Configuration et Lancement
|
||||
|
||||
## Téléchargement de MeTube
|
||||
|
||||
Saisir la commande pour télécharger la source
|
||||
```bash
|
||||
git clone https://git.tips-of-mine.fr/Tips-Of-Mine/Docker.git
|
||||
```
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd Video\MeTube
|
||||
```
|
||||
|
||||
## Modifier la configuration de MeTube
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd Video\MeTube
|
||||
```
|
||||
|
||||
Nous éditons le fichier de configuration
|
||||
```bash
|
||||
nano .env
|
||||
```
|
||||
|
||||
Nous modifions les variables dont nous avons besoin.
|
||||
|
||||
## Lancement de MeTube
|
||||
|
||||
Pour utiliser MeTube tout seul
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Pour utiliser MeTube avec Traefik
|
||||
```bash
|
||||
docker compose -f docker-compose-traefik.yml up -d
|
||||
```
|
||||
|
||||
# Utilisation
|
||||
|
||||
## Accueil
|
||||
|
||||
Ouvrir une page web avec l'url :
|
||||
Pour une utilisation tout seul
|
||||
|
||||
http://10.0.4.29:3000
|
||||
|
||||
Pour une utilisation avec Traefik
|
||||
|
||||
https://MeTube.10.0.4.29.traefik.me`)"
|
||||
|
||||
|
||||
# More info
|
||||
- more information on the website [Tips-Of-Mine](https://www.tips-of-mine.fr/)
|
||||
|
||||
# Buy me a coffe
|
||||
<a href='https://ko-fi.com/R5R2KNI3N' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi4.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
66
Video/MeTube/docker-compose-traefik.yml
Normal file
@ -0,0 +1,66 @@
|
||||

|
||||
URL : HHHHH
|
||||
|
||||
# Fichier-Stockage
|
||||
|
||||
GGGGG
|
||||
|
||||
# Téléchargement, Configuration et Lancement
|
||||
|
||||
## Téléchargement de Fichier-Stockage
|
||||
|
||||
Saisir la commande pour télécharger la source
|
||||
```bash
|
||||
git clone https://git.tips-of-mine.fr/Tips-Of-Mine/Docker.git
|
||||
```
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd AAAAA\Fichier-Stockage
|
||||
```
|
||||
|
||||
## Modifier la configuration de Fichier-Stockage
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd AAAAA\Fichier-Stockage
|
||||
```
|
||||
|
||||
Nous éditons le fichier de configuration
|
||||
```bash
|
||||
nano .env
|
||||
```
|
||||
|
||||
Nous modifions les variables dont nous avons besoin.
|
||||
|
||||
## Lancement de Fichier-Stockage
|
||||
|
||||
Pour utiliser Fichier-Stockage tout seul
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Pour utiliser Fichier-Stockage avec Traefik
|
||||
```bash
|
||||
docker compose -f docker-compose-traefik.yml up -d
|
||||
```
|
||||
|
||||
# Utilisation
|
||||
|
||||
## Accueil
|
||||
|
||||
Ouvrir une page web avec l'url :
|
||||
Pour une utilisation tout seul
|
||||
|
||||
http://10.0.4.29:3000
|
||||
|
||||
Pour une utilisation avec Traefik
|
||||
|
||||
https://Fichier-Stockage.10.0.4.29.traefik.me`)"
|
||||
|
||||
|
||||
# More info
|
||||
- more information on the website [Tips-Of-Mine](https://www.tips-of-mine.fr/)
|
||||
|
||||
# Buy me a coffe
|
||||
<a href='https://ko-fi.com/R5R2KNI3N' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi4.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
8
Video/MeTube/docker-compose.yml
Normal file
@ -0,0 +1,8 @@
|
||||
#### NETWORKS
|
||||
networks:
|
||||
back_network:
|
||||
driver: bridge
|
||||
attachable: true
|
||||
|
||||
#### SERVICES
|
||||
services:
|
1
Video/MiroTalk SFU/.prettierignore
Normal file
@ -0,0 +1 @@
|
||||
.github
|
7
Video/MiroTalk SFU/.prettierrc.js
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
semi: true,
|
||||
trailingComma: 'all',
|
||||
singleQuote: true,
|
||||
printWidth: 120,
|
||||
tabWidth: 4,
|
||||
};
|
109
Video/MiroTalk SFU/CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,109 @@
|
||||
# MiroTalk Open Source Community Code of Conduct
|
||||
|
||||
## About the Code of Conduct
|
||||
|
||||
Equality is a core value at MiroTalk. We believe a diverse and inclusive
|
||||
community fosters innovation and creativity, and are committed to building a
|
||||
culture where everyone feels included.
|
||||
|
||||
MiroTalk open-source projects are committed to providing a friendly, safe, and
|
||||
welcoming environment for all, regardless of gender identity and expression,
|
||||
sexual orientation, disability, physical appearance, body size, ethnicity, nationality,
|
||||
race, age, religion, level of experience, education, socioeconomic status, or
|
||||
other similar personal characteristics.
|
||||
|
||||
The goal of this code of conduct is to specify a baseline standard of behavior so
|
||||
that people with different social values and communication styles can work
|
||||
together effectively, productively, and respectfully in our open source community.
|
||||
It also establishes a mechanism for reporting issues and resolving conflicts.
|
||||
|
||||
All questions and reports of abusive, harassing, or otherwise unacceptable behavior
|
||||
in a MiroTalk open-source project may be reported by contacting the MiroTalk
|
||||
Open Source Conduct Committee at ossconduct.mirotalk@gmail.com.
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of gender
|
||||
identity and expression, sexual orientation, disability, physical appearance,
|
||||
body size, ethnicity, nationality, race, age, religion, level of experience, education,
|
||||
socioeconomic status, or other similar personal characteristics.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints and experiences
|
||||
- Gracefully accepting constructive criticism
|
||||
- Focusing on what is best for the community
|
||||
- Showing empathy toward other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
- The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
- Personal attacks, insulting/derogatory comments, or trolling
|
||||
- Public or private harassment
|
||||
- Publishing, or threatening to publish, others' private information—such as
|
||||
a physical or electronic address—without explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
- Advocating for or encouraging any of the above behaviors
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned with this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project email
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the MiroTalk Open Source Conduct Committee
|
||||
at ossconduct.mirotalk@gmail.com. All complaints will be reviewed and investigated
|
||||
and will result in a response that is deemed necessary and appropriate to the
|
||||
circumstances. The committee is obligated to maintain confidentiality with
|
||||
regard to the reporter of an incident. Further details of specific enforcement
|
||||
policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership and the MiroTalk Open Source Conduct
|
||||
Committee.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][contributor-covenant-home],
|
||||
version 1.4, available at [https://www.contributor-covenant.org/version/1/4/code_of_conduct.html][v1.4].
|
||||
It includes adaptions and additions from [Go Community Code of Conduct][golang-coc],
|
||||
[CNCF Code of Conduct][cncf-coc], and [Microsoft Open Source Code of Conduct][microsoft-coc].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[contributor-covenant-home]: https://www.contributor-covenant.org
|
||||
[v1.4]: https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
[golang-coc]: https://golang.org/conduct
|
||||
[cncf-coc]: https://github.com/cncf/foundation/blob/master/code-of-conduct.md
|
||||
[microsoft-coc]: https://opensource.microsoft.com/codeofconduct/
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
22
Video/MiroTalk SFU/Dockerfile
Normal file
@ -0,0 +1,22 @@
|
||||
FROM node:18-slim
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
# https://mediasoup.org/documentation/v3/mediasoup/installation/
|
||||
ENV MEDIASOUP_SKIP_WORKER_PREBUILT_DOWNLOAD="true"
|
||||
|
||||
COPY package.json .
|
||||
|
||||
RUN \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get update && \
|
||||
apt-get install -y --no-install-recommends build-essential python3-pip && \
|
||||
npm install && \
|
||||
apt-get -y purge --auto-remove build-essential python3-pip && \
|
||||
apt-get install -y --no-install-recommends python3 && \
|
||||
npm cache clean --force && \
|
||||
rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/* /usr/share/doc/*
|
||||
|
||||
COPY app app
|
||||
COPY public public
|
||||
|
||||
CMD npm start
|
3
Video/MiroTalk SFU/LICENSE
Normal file
@ -0,0 +1,3 @@
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or combining it with [name of library] (or a modified version of that library), containing parts covered by the terms of [name of library's license], the licensors of this Program grant you additional permission to convey the resulting work. Corresponding Source for a non-source form of such a combination shall include the source code for the parts of [name of library] used as well as that of the covered work.
|
32
Video/MiroTalk SFU/README.md
Normal file
@ -0,0 +1,32 @@
|
||||

|
||||
|
||||
# Adminer
|
||||
|
||||
Adminer est un outil de gestion de base de données complet écrit en PHP. Inversement à phpMyAdmin, il consiste en un seul fichier prêt à être déployé sur le serveur cible. Adminer est disponible pour MySQL, MariaDB, PostgreSQL, SQLite, MS SQL, Oracle, Elasticsearch, MongoDB et autres via plugin
|
||||
|
||||
# Installation
|
||||
|
||||
Pour utiliser Adminer tout seul
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Pour utiliser Adminer avec Traefik
|
||||
```bash
|
||||
docker compose -f docker-compose-traefik.yml up -d
|
||||
```
|
||||
|
||||
Pour utiliser Adminer avec Nginx
|
||||
```bash
|
||||
docker compose -f docker-compose-nginx.yml up -d
|
||||
```
|
||||
# Utilisation
|
||||
|
||||
## Accueil
|
||||

|
||||
|
||||
# More info
|
||||
- more information on the website [Tips-Of-Mine](https://www.tips-of-mine.fr/)
|
||||
|
||||
# Buy me a coffe
|
||||
<a href='https://ko-fi.com/R5R2KNI3N' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi4.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
33
Video/MiroTalk SFU/SECURITY.md
Normal file
@ -0,0 +1,33 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Security is very important to us.
|
||||
|
||||
If you have discovered a security issue, please contact miroslav.pejic.85@gmail.com directly. Please refrain from directly creating a GitHub issue and publicly disclosing the vulnerability.
|
||||
We prefer a Coordinated Vulnerability Disclosure (CVD) to properly understand and fix the root cause problem.
|
||||
|
||||
Your report should include:
|
||||
|
||||
- Product version ([GitHub](https://github.com/miroslavpejic85/mirotalksfu/commits/main) commit hash or [DockerHub](https://hub.docker.com/r/mirotalk/sfu) sha256 digest hash)
|
||||
- The affected component if possible (RoomClient.js, Server.js, etc.)
|
||||
- A vulnerability description
|
||||
- Reproduction steps
|
||||
|
||||
A member of the security team will confirm the vulnerability, determine its impact, and develop a fix.
|
||||
The fix will be applied to the master branch, tested, and packaged in the next security release.
|
||||
|
||||
Thanks in advance for your support to make our products safer!
|
||||
|
||||
---
|
||||
|
||||
## 🙏 Acknowledgments
|
||||
|
||||
We would like to extend our gratitude to the following individuals for their responsible disclosure of security vulnerabilities:
|
||||
|
||||
| Name | Contact |
|
||||
| ----------------- | ---------------------- |
|
||||
| `Hendrik Siewert` | hendrik.siewert@upb.de |
|
||||
| `Caio Fook` | caio.fook@gmail.com |
|
||||
|
||||
Their dedication to security has contributed to the continuous improvement of our systems, ensuring the safety and privacy of our users and data.
|
62
Video/MiroTalk SFU/app/api/README.md
Normal file
@ -0,0 +1,62 @@
|
||||

|
||||
|
||||
## Create a meeting
|
||||
|
||||
Create a meeting with a `HTTP request` containing the `API_KEY` sent to MiroTalk’s server. The response contains a `meeting` URL that can be `embedded` in your client within an `iframe`.
|
||||
|
||||
The `API_KEY` is defined in the `app/src/config.js`, change it with your own.
|
||||
|
||||
```js
|
||||
api: {
|
||||
// app/api
|
||||
keySecret: 'mirotalksfu_default_secret',
|
||||
}
|
||||
```
|
||||
|
||||
Some examples demonstrating how to call the API:
|
||||
|
||||
```bash
|
||||
# js
|
||||
node meetings.js
|
||||
node meeting.js
|
||||
node join.js
|
||||
|
||||
# php
|
||||
php meetings.php
|
||||
php meeting.php
|
||||
php join.php
|
||||
|
||||
# python
|
||||
python3 meetings.py
|
||||
python3 meeting.py
|
||||
python3 join.py
|
||||
|
||||
# bash
|
||||
./meetings.sh
|
||||
./meeting.sh
|
||||
./join.sh
|
||||
```
|
||||
|
||||
## Embed a meeting
|
||||
|
||||
Embedding a meeting into a `service` or `app` requires using an `iframe` with the `src` attribute specified as the `meeting` from `HTTP response`.
|
||||
|
||||
```html
|
||||
<iframe
|
||||
allow="camera; microphone; display-capture; fullscreen; clipboard-read; clipboard-write; autoplay"
|
||||
src="https://sfu.mirotalk.com/join/your_room_name"
|
||||
style="height: 100vh; width: 100vw; border: 0px;"
|
||||
></iframe>
|
||||
```
|
||||
|
||||
## Fast Integration
|
||||
|
||||
Develop your `website` or `application`, and bring `video meetings` in with a simple `iframe`.
|
||||
|
||||
```html
|
||||
<iframe
|
||||
allow="camera; microphone; display-capture; fullscreen; clipboard-read; clipboard-write; autoplay"
|
||||
src="https://sfu.mirotalk.com/newroom"
|
||||
style="height: 100vh; width: 100vw; border: 0px;"
|
||||
></iframe>
|
||||
```
|
46
Video/MiroTalk SFU/app/api/join/join.js
Normal file
@ -0,0 +1,46 @@
|
||||
'use strict';
|
||||
|
||||
async function getJoin() {
|
||||
try {
|
||||
// Use dynamic import with await
|
||||
const { default: fetch } = await import('node-fetch');
|
||||
|
||||
const API_KEY_SECRET = 'mirotalksfu_default_secret';
|
||||
const MIROTALK_URL = 'https://sfu.mirotalk.com/api/v1/join';
|
||||
//const MIROTALK_URL = 'http://localhost:3010/api/v1/join';
|
||||
|
||||
const response = await fetch(MIROTALK_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
authorization: API_KEY_SECRET,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
room: 'test',
|
||||
roomPassword: false,
|
||||
name: 'mirotalksfu',
|
||||
audio: true,
|
||||
video: true,
|
||||
screen: true,
|
||||
hide: false,
|
||||
notify: true,
|
||||
token: {
|
||||
username: 'username',
|
||||
password: 'password',
|
||||
presenter: true,
|
||||
expire: '1h',
|
||||
},
|
||||
}),
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.error) {
|
||||
console.log('Error:', data.error);
|
||||
} else {
|
||||
console.log('join:', data.join);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
}
|
||||
}
|
||||
|
||||
getJoin();
|
45
Video/MiroTalk SFU/app/api/join/join.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
$API_KEY_SECRET = "mirotalksfu_default_secret";
|
||||
$MIROTALK_URL = "https://sfu.mirotalk.com/api/v1/join";
|
||||
// $MIROTALK_URL = "http://localhost:3010/api/v1/join";
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $MIROTALK_URL);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
|
||||
$headers = [
|
||||
'authorization:' . $API_KEY_SECRET,
|
||||
'Content-Type: application/json'
|
||||
];
|
||||
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
|
||||
$data = array(
|
||||
"room" => "test",
|
||||
"roomPassword" => false,
|
||||
"name" => "mirotalksfu",
|
||||
"audio" => true,
|
||||
"video" => true,
|
||||
"screen" => true,
|
||||
"hide" => false,
|
||||
"notify" => true,
|
||||
"token" => array(
|
||||
"username" => "username",
|
||||
"password" => "password",
|
||||
"presenter" => true,
|
||||
"expire" => "1h",
|
||||
),
|
||||
);
|
||||
$data_string = json_encode($data);
|
||||
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
|
||||
$response = curl_exec($ch);
|
||||
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
echo "Status code: $httpcode \n";
|
||||
$data = json_decode($response);
|
||||
echo "join: ", $data->{'join'}, "\n";
|
39
Video/MiroTalk SFU/app/api/join/join.py
Normal file
@ -0,0 +1,39 @@
|
||||
# pip3 install requests
|
||||
import requests
|
||||
import json
|
||||
|
||||
API_KEY_SECRET = "mirotalksfu_default_secret"
|
||||
MIROTALK_URL = "https://sfu.mirotalk.com/api/v1/join"
|
||||
# MIROTALK_URL = "http://localhost:3010/api/v1/join"
|
||||
|
||||
headers = {
|
||||
"authorization": API_KEY_SECRET,
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
data = {
|
||||
"room": "test",
|
||||
"roomPassword": "false",
|
||||
"name": "mirotalksfu",
|
||||
"audio": "true",
|
||||
"video": "true",
|
||||
"screen": "true",
|
||||
"hide": "false",
|
||||
"notify": "true",
|
||||
"token": {
|
||||
"username": "username",
|
||||
"password": "password",
|
||||
"presenter": "true",
|
||||
"expire": "1h",
|
||||
}
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
MIROTALK_URL,
|
||||
headers=headers,
|
||||
json=data,
|
||||
)
|
||||
|
||||
print("Status code:", response.status_code)
|
||||
data = json.loads(response.text)
|
||||
print("join:", data["join"])
|
11
Video/MiroTalk SFU/app/api/join/join.sh
Normal file
@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
API_KEY_SECRET="mirotalksfu_default_secret"
|
||||
MIROTALK_URL="https://sfu.mirotalk.com/api/v1/join"
|
||||
# MIROTALK_URL="http://localhost:3010/api/v1/join"
|
||||
|
||||
curl $MIROTALK_URL \
|
||||
--header "authorization: $API_KEY_SECRET" \
|
||||
--header "Content-Type: application/json" \
|
||||
--data '{"room":"test","roomPassword":"false","name":"mirotalksfu","audio":"true","video":"true","screen":"false","hide":"false","notify":"true","token":{"username":"username","password":"password","presenter":"true", "expire":"1h"}}' \
|
||||
--request POST
|
30
Video/MiroTalk SFU/app/api/meeting/meeting.js
Normal file
@ -0,0 +1,30 @@
|
||||
'use strict';
|
||||
|
||||
async function getMeeting() {
|
||||
try {
|
||||
// Use dynamic import with await
|
||||
const { default: fetch } = await import('node-fetch');
|
||||
|
||||
const API_KEY_SECRET = 'mirotalksfu_default_secret';
|
||||
const MIROTALK_URL = 'https://sfu.mirotalk.com/api/v1/meeting';
|
||||
// const MIROTALK_URL = 'http://localhost:3010/api/v1/meeting';
|
||||
|
||||
const response = await fetch(MIROTALK_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
authorization: API_KEY_SECRET,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.error) {
|
||||
console.log('Error:', data.error);
|
||||
} else {
|
||||
console.log('meeting:', data.meeting);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
}
|
||||
}
|
||||
|
||||
getMeeting();
|
25
Video/MiroTalk SFU/app/api/meeting/meeting.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
$API_KEY_SECRET = "mirotalksfu_default_secret";
|
||||
$MIROTALK_URL = "https://sfu.mirotalk.com/api/v1/meeting";
|
||||
// $MIROTALK_URL = "http://localhost:3010/api/v1/meeting";
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $MIROTALK_URL);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
|
||||
$headers = [
|
||||
'authorization:' . $API_KEY_SECRET,
|
||||
'Content-Type: application/json'
|
||||
];
|
||||
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
$response = curl_exec($ch);
|
||||
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
echo "Status code: $httpcode \n";
|
||||
$data = json_decode($response);
|
||||
echo "meeting: ", $data->{'meeting'}, "\n";
|
21
Video/MiroTalk SFU/app/api/meeting/meeting.py
Normal file
@ -0,0 +1,21 @@
|
||||
# pip3 install requests
|
||||
import requests
|
||||
import json
|
||||
|
||||
API_KEY_SECRET = "mirotalksfu_default_secret"
|
||||
MIROTALK_URL = "https://sfu.mirotalk.com/api/v1/meeting"
|
||||
# MIROTALK_URL = "http://localhost:3010/api/v1/meeting"
|
||||
|
||||
headers = {
|
||||
"authorization": API_KEY_SECRET,
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
MIROTALK_URL,
|
||||
headers=headers
|
||||
)
|
||||
|
||||
print("Status code:", response.status_code)
|
||||
data = json.loads(response.text)
|
||||
print("meeting:", data["meeting"])
|
10
Video/MiroTalk SFU/app/api/meeting/meeting.sh
Normal file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
API_KEY_SECRET="mirotalksfu_default_secret"
|
||||
MIROTALK_URL="https://sfu.mirotalk.com/api/v1/meeting"
|
||||
# MIROTALK_URL="http://localhost:3010/api/v1/meeting"
|
||||
|
||||
curl $MIROTALK_URL \
|
||||
--header "authorization: $API_KEY_SECRET" \
|
||||
--header "Content-Type: application/json" \
|
||||
--request POST
|
34
Video/MiroTalk SFU/app/api/meetings/meetings.js
Normal file
@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
async function getMeetings() {
|
||||
try {
|
||||
// Use dynamic import with await
|
||||
const { default: fetch } = await import('node-fetch');
|
||||
|
||||
const API_KEY_SECRET = 'mirotalksfu_default_secret';
|
||||
const MIROTALK_URL = 'https://sfu.mirotalk.com/api/v1/meetings';
|
||||
//const MIROTALK_URL = 'http://localhost:3010/api/v1/meetings';
|
||||
|
||||
const response = await fetch(MIROTALK_URL, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
authorization: API_KEY_SECRET,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.error) {
|
||||
console.log('Error:', data.error);
|
||||
} else {
|
||||
if (data && data.meetings) {
|
||||
const meetings = data.meetings;
|
||||
const formattedData = JSON.stringify({ meetings }, null, 2);
|
||||
console.log(formattedData);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
}
|
||||
}
|
||||
|
||||
getMeetings();
|
29
Video/MiroTalk SFU/app/api/meetings/meetings.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
$API_KEY_SECRET = "mirotalksfu_default_secret";
|
||||
$MIROTALK_URL = "https://sfu.mirotalk.com/api/v1/meetings";
|
||||
//$MIROTALK_URL = "http://localhost:3010/api/v1/meetings";
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $MIROTALK_URL);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_HTTPGET, true);
|
||||
|
||||
$headers = [
|
||||
'authorization:' . $API_KEY_SECRET,
|
||||
'Content-Type: application/json'
|
||||
];
|
||||
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
$response = curl_exec($ch);
|
||||
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
echo "Status code: $httpcode \n";
|
||||
|
||||
if ($response) {
|
||||
echo json_encode(json_decode($response), JSON_PRETTY_PRINT);
|
||||
} else {
|
||||
echo "Failed to retrieve data.\n";
|
||||
}
|
26
Video/MiroTalk SFU/app/api/meetings/meetings.py
Normal file
@ -0,0 +1,26 @@
|
||||
# pip3 install requests
|
||||
import requests
|
||||
import json
|
||||
|
||||
API_KEY_SECRET = "mirotalksfu_default_secret"
|
||||
MIROTALK_URL = "https://sfu.mirotalk.com/api/v1/meetings"
|
||||
#MIROTALK_URL = "http://localhost:3010/api/v1/meetings"
|
||||
|
||||
headers = {
|
||||
"authorization": API_KEY_SECRET,
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
response = requests.get(
|
||||
MIROTALK_URL,
|
||||
headers=headers
|
||||
)
|
||||
|
||||
print("Status code:", response.status_code)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
pretty_printed_data = json.dumps(data, indent=4)
|
||||
print(data)
|
||||
else:
|
||||
print("Failed to retrieve data. Error:", response.text)
|
10
Video/MiroTalk SFU/app/api/meetings/meetings.sh
Normal file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
API_KEY_SECRET="mirotalksfu_default_secret"
|
||||
MIROTALK_URL="https://sfu.mirotalk.com/api/v1/meetings"
|
||||
#MIROTALK_URL="http://localhost:3010/api/v1/meetings"
|
||||
|
||||
curl $MIROTALK_URL \
|
||||
--header "authorization: $API_KEY_SECRET" \
|
||||
--header "Content-Type: application/json" \
|
||||
--request GET
|
BIN
Video/MiroTalk SFU/app/api/restAPI.png
Normal file
After Width: | Height: | Size: 13 KiB |
204
Video/MiroTalk SFU/app/api/swagger.yaml
Normal file
@ -0,0 +1,204 @@
|
||||
swagger: '2.0'
|
||||
|
||||
info:
|
||||
title: MiroTalk SFU API
|
||||
description: API description for external applications that integrate with MiroTalk SFU.
|
||||
version: 1.0.1
|
||||
|
||||
basePath: /api/v1
|
||||
|
||||
schemes:
|
||||
- https
|
||||
- http
|
||||
|
||||
paths:
|
||||
/meetings:
|
||||
get:
|
||||
tags:
|
||||
- 'meetings'
|
||||
summary: 'Get meetings'
|
||||
description: 'Get meetings'
|
||||
produces:
|
||||
- 'application/json'
|
||||
security:
|
||||
- secretApiKey: []
|
||||
responses:
|
||||
'200':
|
||||
description: 'Get Meetings done'
|
||||
schema:
|
||||
$ref: '#/definitions/MeetingsResponse'
|
||||
'403':
|
||||
description: 'Unauthorized!'
|
||||
/meeting:
|
||||
post:
|
||||
tags:
|
||||
- 'meeting'
|
||||
summary: 'Create meeting'
|
||||
description: 'Create meeting'
|
||||
consumes:
|
||||
- 'application/json'
|
||||
produces:
|
||||
- 'application/json'
|
||||
security:
|
||||
- secretApiKey: []
|
||||
responses:
|
||||
'200':
|
||||
description: 'Meeting created'
|
||||
schema:
|
||||
$ref: '#/definitions/MeetingResponse'
|
||||
'403':
|
||||
description: 'Unauthorized!'
|
||||
/join:
|
||||
post:
|
||||
tags:
|
||||
- 'join'
|
||||
summary: 'Create direct join'
|
||||
description: 'Create join'
|
||||
parameters:
|
||||
- in: body
|
||||
name: Join
|
||||
description: Custom Join URL.
|
||||
schema:
|
||||
$ref: '#/definitions/JoinRequest'
|
||||
consumes:
|
||||
- 'application/json'
|
||||
produces:
|
||||
- 'application/json'
|
||||
security:
|
||||
- secretApiKey: []
|
||||
responses:
|
||||
'200':
|
||||
description: 'Direct join created'
|
||||
schema:
|
||||
$ref: '#/definitions/JoinResponse'
|
||||
'403':
|
||||
description: 'Unauthorized!'
|
||||
/token:
|
||||
post:
|
||||
tags:
|
||||
- 'token'
|
||||
summary: 'Get token'
|
||||
description: 'Get token'
|
||||
parameters:
|
||||
- in: body
|
||||
name: token
|
||||
description: Custom Token.
|
||||
schema:
|
||||
$ref: '#/definitions/TokenRequest'
|
||||
consumes:
|
||||
- 'application/json'
|
||||
produces:
|
||||
- 'application/json'
|
||||
security:
|
||||
- secretApiKey: []
|
||||
responses:
|
||||
'200':
|
||||
description: 'Get token done'
|
||||
schema:
|
||||
$ref: '#/definitions/TokenResponse'
|
||||
'403':
|
||||
description: 'Unauthorized!'
|
||||
|
||||
securityDefinitions:
|
||||
secretApiKey:
|
||||
type: 'apiKey'
|
||||
name: 'authorization'
|
||||
in: 'header'
|
||||
description: 'Format like this: authorization: {API_KEY_SECRET}'
|
||||
|
||||
definitions:
|
||||
MeetingsResponse:
|
||||
type: object
|
||||
properties:
|
||||
meetings:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/Meeting'
|
||||
MeetingResponse:
|
||||
type: 'object'
|
||||
properties:
|
||||
meeting:
|
||||
type: string
|
||||
JoinRequest:
|
||||
type: object
|
||||
properties:
|
||||
room:
|
||||
type: string
|
||||
default: 'test'
|
||||
roomPassword:
|
||||
type: ['boolean', 'string'] # Allow boolean or string type
|
||||
default: false
|
||||
name:
|
||||
type: string
|
||||
default: 'mirotalksfu'
|
||||
audio:
|
||||
type: boolean
|
||||
default: false
|
||||
video:
|
||||
type: boolean
|
||||
default: false
|
||||
screen:
|
||||
type: boolean
|
||||
default: false
|
||||
hide:
|
||||
type: boolean
|
||||
default: false
|
||||
notify:
|
||||
type: boolean
|
||||
default: false
|
||||
token:
|
||||
$ref: '#/definitions/TokenRequest'
|
||||
TokenRequest:
|
||||
type: object
|
||||
properties:
|
||||
username:
|
||||
type: string
|
||||
default: 'username'
|
||||
password:
|
||||
type: string
|
||||
default: 'password'
|
||||
presenter:
|
||||
type: boolean
|
||||
default: true
|
||||
expire:
|
||||
type: string
|
||||
default: '1h'
|
||||
JoinResponse:
|
||||
type: 'object'
|
||||
properties:
|
||||
join:
|
||||
type: string
|
||||
TokenResponse:
|
||||
type: 'object'
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
Peer:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
presenter:
|
||||
type: boolean
|
||||
video:
|
||||
type: boolean
|
||||
audio:
|
||||
type: boolean
|
||||
screen:
|
||||
type: boolean
|
||||
hand:
|
||||
type: boolean
|
||||
os:
|
||||
type: string
|
||||
browser:
|
||||
type: string
|
||||
|
||||
Meeting:
|
||||
type: object
|
||||
properties:
|
||||
roomId:
|
||||
type: string
|
||||
peers:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/Peer'
|
36
Video/MiroTalk SFU/app/api/token/token.js
Normal file
@ -0,0 +1,36 @@
|
||||
'use strict';
|
||||
|
||||
async function getToken() {
|
||||
try {
|
||||
// Use dynamic import with await
|
||||
const { default: fetch } = await import('node-fetch');
|
||||
|
||||
const API_KEY_SECRET = 'mirotalksfu_default_secret';
|
||||
const MIROTALK_URL = 'https://sfu.mirotalk.com/api/v1/token';
|
||||
//const MIROTALK_URL = 'http://localhost:3010/api/v1/token';
|
||||
|
||||
const response = await fetch(MIROTALK_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
authorization: API_KEY_SECRET,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: 'username',
|
||||
password: 'password',
|
||||
presenter: true,
|
||||
expire: '1h',
|
||||
}),
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.error) {
|
||||
console.log('Error:', data.error);
|
||||
} else {
|
||||
console.log('token:', data.token);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
}
|
||||
}
|
||||
|
||||
getToken();
|
37
Video/MiroTalk SFU/app/api/token/token.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
$API_KEY_SECRET = "mirotalksfu_default_secret";
|
||||
$MIROTALK_URL = "https://sfu.mirotalk.com/api/v1/token";
|
||||
#$MIROTALK_URL = "http://localhost:3010/api/v1/token";
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $MIROTALK_URL);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
|
||||
$headers = [
|
||||
'authorization:' . $API_KEY_SECRET,
|
||||
'Content-Type: application/json'
|
||||
];
|
||||
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
|
||||
$data = array(
|
||||
"username" => "username",
|
||||
"password" => "password",
|
||||
"presenter" => true,
|
||||
"expire" => "1h",
|
||||
);
|
||||
|
||||
$data_string = json_encode($data);
|
||||
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
echo "Status code: $httpcode \n";
|
||||
$data = json_decode($response);
|
||||
echo "token: ", $data->{'token'}, "\n";
|
29
Video/MiroTalk SFU/app/api/token/token.py
Normal file
@ -0,0 +1,29 @@
|
||||
# pip3 install requests
|
||||
import requests
|
||||
import json
|
||||
|
||||
API_KEY_SECRET = "mirotalksfu_default_secret"
|
||||
MIROTALK_URL = "https://sfu.mirotalk.com/api/v1/token"
|
||||
#MIROTALK_URL = "http://localhost:3010/api/v1/token"
|
||||
|
||||
headers = {
|
||||
"authorization": API_KEY_SECRET,
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
data = {
|
||||
"username": "username",
|
||||
"password": "password",
|
||||
"presenter": "true",
|
||||
"expire": "1h"
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
MIROTALK_URL,
|
||||
headers=headers,
|
||||
json=data
|
||||
)
|
||||
|
||||
print("Status code:", response.status_code)
|
||||
data = json.loads(response.text)
|
||||
print("token:", data["token"])
|
11
Video/MiroTalk SFU/app/api/token/token.sh
Normal file
@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
API_KEY_SECRET="mirotalksfu_default_secret"
|
||||
MIROTALK_URL="https://sfu.mirotalk.com/api/v1/token"
|
||||
#MIROTALK_URL="http://localhost:3010/api/v1/token"
|
||||
|
||||
curl $MIROTALK_URL \
|
||||
--header "authorization: $API_KEY_SECRET" \
|
||||
--header "Content-Type: application/json" \
|
||||
--data '{"username":"username","password":"password","presenter":"true", "expire":"1h"}' \
|
||||
--request POST
|
42
Video/MiroTalk SFU/app/src/Host.js
Normal file
@ -0,0 +1,42 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = class Host {
|
||||
constructor() {
|
||||
this.authorizedIPs = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authorized IPs
|
||||
* @returns object
|
||||
*/
|
||||
getAuthorizedIPs() {
|
||||
return Object.fromEntries(this.authorizedIPs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set authorized IP
|
||||
* @param {string} ip
|
||||
* @param {boolean} authorized
|
||||
*/
|
||||
setAuthorizedIP(ip, authorized) {
|
||||
this.authorizedIPs.set(ip, authorized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if IP is authorized
|
||||
* @param {string} ip
|
||||
* @returns boolean
|
||||
*/
|
||||
isAuthorizedIP(ip) {
|
||||
return this.authorizedIPs.has(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete ip from authorized IPs
|
||||
* @param {string} ip
|
||||
* @returns boolean
|
||||
*/
|
||||
deleteIP(ip) {
|
||||
return this.authorizedIPs.delete(ip);
|
||||
}
|
||||
};
|
90
Video/MiroTalk SFU/app/src/Logger.js
Normal file
@ -0,0 +1,90 @@
|
||||
'use strict';
|
||||
|
||||
const util = require('util');
|
||||
|
||||
const colors = require('colors');
|
||||
|
||||
const config = require('./config');
|
||||
|
||||
config.console.colors ? colors.enable() : colors.disable();
|
||||
|
||||
const options = {
|
||||
depth: null,
|
||||
colors: true,
|
||||
};
|
||||
module.exports = class Logger {
|
||||
constructor(appName = 'miroTalkSfu') {
|
||||
this.appName = colors.yellow(appName);
|
||||
this.debugOn = config.console.debug;
|
||||
this.timeStart = Date.now();
|
||||
this.timeEnd = null;
|
||||
this.timeElapsedMs = null;
|
||||
this.tzOptions = {
|
||||
timeZone: process.env.TZ || config.console.timeZone || 'UTC',
|
||||
hour12: false,
|
||||
};
|
||||
}
|
||||
|
||||
debug(msg, op = '') {
|
||||
if (this.debugOn) {
|
||||
this.timeEnd = Date.now();
|
||||
this.timeElapsedMs = this.getFormatTime(Math.floor(this.timeEnd - this.timeStart));
|
||||
console.debug(
|
||||
'[' + this.getDateTime() + '] [' + this.appName + '] ' + msg,
|
||||
util.inspect(op, options),
|
||||
this.timeElapsedMs,
|
||||
);
|
||||
this.timeStart = Date.now();
|
||||
}
|
||||
}
|
||||
|
||||
log(msg, op = '') {
|
||||
console.log('[' + this.getDateTime() + '] [' + this.appName + '] ' + msg, util.inspect(op, options));
|
||||
}
|
||||
|
||||
info(msg, op = '') {
|
||||
console.info(
|
||||
'[' + this.getDateTime() + '] [' + this.appName + '] ' + colors.green(msg),
|
||||
util.inspect(op, options),
|
||||
);
|
||||
}
|
||||
|
||||
warn(msg, op = '') {
|
||||
console.warn(
|
||||
'[' + this.getDateTime() + '] [' + this.appName + '] ' + colors.yellow(msg),
|
||||
util.inspect(op, options),
|
||||
);
|
||||
}
|
||||
|
||||
error(msg, op = '') {
|
||||
console.error(
|
||||
'[' + this.getDateTime() + '] [' + this.appName + '] ' + colors.red(msg),
|
||||
util.inspect(op, options),
|
||||
);
|
||||
}
|
||||
|
||||
getDateTime() {
|
||||
const currentTime = new Date().toLocaleString('en-US', this.tzOptions);
|
||||
const milliseconds = String(new Date().getMilliseconds()).padStart(3, '0');
|
||||
return colors.cyan(`${currentTime}:${milliseconds}`);
|
||||
}
|
||||
|
||||
getFormatTime(ms) {
|
||||
let time = Math.floor(ms);
|
||||
let type = 'ms';
|
||||
|
||||
if (ms >= 1000) {
|
||||
time = Math.floor((ms / 1000) % 60);
|
||||
type = 's';
|
||||
}
|
||||
if (ms >= 60000) {
|
||||
time = Math.floor((ms / 1000 / 60) % 60);
|
||||
type = 'm';
|
||||
}
|
||||
if (ms >= (3, 6e6)) {
|
||||
time = Math.floor((ms / 1000 / 60 / 60) % 24);
|
||||
type = 'h';
|
||||
}
|
||||
return colors.magenta('+' + time + type);
|
||||
}
|
||||
};
|
316
Video/MiroTalk SFU/app/src/Peer.js
Normal file
@ -0,0 +1,316 @@
|
||||
'use strict';
|
||||
|
||||
const Logger = require('./Logger');
|
||||
const log = new Logger('Peer');
|
||||
|
||||
module.exports = class Peer {
|
||||
constructor(socket_id, data) {
|
||||
const { peer_info } = data;
|
||||
|
||||
const { peer_name, peer_presenter, peer_audio, peer_video, peer_video_privacy, peer_recording, peer_hand } =
|
||||
peer_info;
|
||||
|
||||
this.id = socket_id;
|
||||
this.peer_info = peer_info;
|
||||
this.peer_name = peer_name;
|
||||
this.peer_presenter = peer_presenter;
|
||||
this.peer_audio = peer_audio;
|
||||
this.peer_video = peer_video;
|
||||
this.peer_video_privacy = peer_video_privacy;
|
||||
this.peer_recording = peer_recording;
|
||||
this.peer_hand = peer_hand;
|
||||
|
||||
this.transports = new Map();
|
||||
this.consumers = new Map();
|
||||
this.producers = new Map();
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// UPDATE PEER INFO
|
||||
// ####################################################
|
||||
|
||||
updatePeerInfo(data) {
|
||||
log.debug('Update peer info', data);
|
||||
switch (data.type) {
|
||||
case 'audio':
|
||||
case 'audioType':
|
||||
this.peer_info.peer_audio = data.status;
|
||||
this.peer_audio = data.status;
|
||||
break;
|
||||
case 'video':
|
||||
case 'videoType':
|
||||
this.peer_info.peer_video = data.status;
|
||||
this.peer_video = data.status;
|
||||
if (data.status == false) {
|
||||
this.peer_info.peer_video_privacy = data.status;
|
||||
this.peer_video_privacy = data.status;
|
||||
}
|
||||
break;
|
||||
case 'screen':
|
||||
case 'screenType':
|
||||
this.peer_info.peer_screen = data.status;
|
||||
break;
|
||||
case 'hand':
|
||||
this.peer_info.peer_hand = data.status;
|
||||
this.peer_hand = data.status;
|
||||
break;
|
||||
case 'privacy':
|
||||
this.peer_info.peer_video_privacy = data.status;
|
||||
this.peer_video_privacy = data.status;
|
||||
break;
|
||||
case 'presenter':
|
||||
this.peer_info.peer_presenter = data.status;
|
||||
this.peer_presenter = data.status;
|
||||
break;
|
||||
case 'recording':
|
||||
this.peer_info.peer_recording = data.status;
|
||||
this.peer_recording = data.status;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// TRANSPORT
|
||||
// ####################################################
|
||||
|
||||
getTransports() {
|
||||
return JSON.parse(JSON.stringify([...this.transports]));
|
||||
}
|
||||
|
||||
getTransport(transport_id) {
|
||||
return this.transports.get(transport_id);
|
||||
}
|
||||
|
||||
delTransport(transport_id) {
|
||||
this.transports.delete(transport_id);
|
||||
}
|
||||
|
||||
addTransport(transport) {
|
||||
this.transports.set(transport.id, transport);
|
||||
}
|
||||
|
||||
async connectTransport(transport_id, dtlsParameters) {
|
||||
if (!this.transports.has(transport_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
await this.transports.get(transport_id).connect({
|
||||
dtlsParameters: dtlsParameters,
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
close() {
|
||||
this.transports.forEach((transport, transport_id) => {
|
||||
log.debug('Close and delete peer transports', {
|
||||
transport_id: transport_id,
|
||||
//transportInternal: transport.internal,
|
||||
});
|
||||
transport.close();
|
||||
this.delTransport(transport_id);
|
||||
});
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// PRODUCER
|
||||
// ####################################################
|
||||
|
||||
getProducers() {
|
||||
return JSON.parse(JSON.stringify([...this.producers]));
|
||||
}
|
||||
|
||||
getProducer(producer_id) {
|
||||
return this.producers.get(producer_id);
|
||||
}
|
||||
|
||||
delProducer(producer_id) {
|
||||
this.producers.delete(producer_id);
|
||||
}
|
||||
|
||||
async createProducer(producerTransportId, producer_rtpParameters, producer_kind, producer_type) {
|
||||
try {
|
||||
if (!producerTransportId) {
|
||||
return 'Invalid producer transport ID';
|
||||
}
|
||||
|
||||
const producerTransport = this.transports.get(producerTransportId);
|
||||
|
||||
if (!producerTransport) {
|
||||
return `Producer transport with ID ${producerTransportId} not found`;
|
||||
}
|
||||
|
||||
const producer = await producerTransport.produce({
|
||||
kind: producer_kind,
|
||||
rtpParameters: producer_rtpParameters,
|
||||
});
|
||||
|
||||
if (!producer) {
|
||||
return `Producer type: ${producer_type} kind: ${producer_kind} not found`;
|
||||
}
|
||||
|
||||
const { id, appData, type, kind, rtpParameters } = producer;
|
||||
|
||||
appData.mediaType = producer_type;
|
||||
|
||||
this.producers.set(id, producer);
|
||||
|
||||
if (['simulcast', 'svc'].includes(type)) {
|
||||
const { scalabilityMode } = rtpParameters.encodings[0];
|
||||
const spatialLayer = parseInt(scalabilityMode.substring(1, 2)); // 1/2/3
|
||||
const temporalLayer = parseInt(scalabilityMode.substring(3, 4)); // 1/2/3
|
||||
log.debug(`Producer [${type}-${kind}] ----->`, {
|
||||
scalabilityMode,
|
||||
spatialLayer,
|
||||
temporalLayer,
|
||||
});
|
||||
} else {
|
||||
log.debug('Producer ----->', { type: type, kind: kind });
|
||||
}
|
||||
|
||||
producer.on('transportclose', () => {
|
||||
log.debug('Producer "transportclose" event');
|
||||
this.closeProducer(id);
|
||||
});
|
||||
|
||||
return producer;
|
||||
} catch (error) {
|
||||
log.error('Error creating producer', error.message);
|
||||
return error.message;
|
||||
}
|
||||
}
|
||||
|
||||
closeProducer(producer_id) {
|
||||
if (!this.producers.has(producer_id)) return;
|
||||
|
||||
const producer = this.getProducer(producer_id);
|
||||
const { id, kind, type, appData } = producer;
|
||||
|
||||
try {
|
||||
producer.close();
|
||||
} catch (error) {
|
||||
log.warn('Close Producer', error.message);
|
||||
}
|
||||
|
||||
this.delProducer(producer_id);
|
||||
|
||||
log.debug('Producer closed and deleted', {
|
||||
peer_name: this.peer_name,
|
||||
kind: kind,
|
||||
type: type,
|
||||
appData: appData,
|
||||
producer_id: id,
|
||||
});
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// CONSUMER
|
||||
// ####################################################
|
||||
|
||||
getConsumers() {
|
||||
return JSON.parse(JSON.stringify([...this.consumers]));
|
||||
}
|
||||
|
||||
getConsumer(consumer_id) {
|
||||
return this.consumers.get(consumer_id);
|
||||
}
|
||||
|
||||
delConsumer(consumer_id) {
|
||||
this.consumers.delete(consumer_id);
|
||||
}
|
||||
|
||||
async createConsumer(consumer_transport_id, producer_id, rtpCapabilities) {
|
||||
try {
|
||||
if (!consumer_transport_id) {
|
||||
return 'Invalid consumer transport ID';
|
||||
}
|
||||
|
||||
const consumerTransport = this.transports.get(consumer_transport_id);
|
||||
|
||||
if (!consumerTransport) {
|
||||
return `Consumer transport with id ${consumer_transport_id} not found`;
|
||||
}
|
||||
|
||||
const consumer = await consumerTransport.consume({
|
||||
producerId: producer_id,
|
||||
rtpCapabilities,
|
||||
enableRtx: true, // Enable NACK for OPUS.
|
||||
paused: false,
|
||||
});
|
||||
|
||||
if (!consumer) {
|
||||
return `Consumer for producer ID ${producer_id} not found`;
|
||||
}
|
||||
|
||||
const { id, type, kind, rtpParameters, producerPaused } = consumer;
|
||||
|
||||
if (['simulcast', 'svc'].includes(type)) {
|
||||
// simulcast - L1T3/L2T3/L3T3 | svc - L3T3
|
||||
const { scalabilityMode } = rtpParameters.encodings[0];
|
||||
const spatialLayer = parseInt(scalabilityMode.substring(1, 2)); // 1/2/3
|
||||
const temporalLayer = parseInt(scalabilityMode.substring(3, 4)); // 1/2/3
|
||||
try {
|
||||
await consumer.setPreferredLayers({
|
||||
spatialLayer: spatialLayer,
|
||||
temporalLayer: temporalLayer,
|
||||
});
|
||||
log.debug(`Consumer [${type}-${kind}] ----->`, {
|
||||
scalabilityMode,
|
||||
spatialLayer,
|
||||
temporalLayer,
|
||||
});
|
||||
} catch (error) {
|
||||
return `Error to set Consumer preferred layers: ${error.message}`;
|
||||
}
|
||||
} else {
|
||||
log.debug('Consumer ----->', { type: type, kind: kind });
|
||||
}
|
||||
|
||||
this.consumers.set(id, consumer);
|
||||
|
||||
consumer.on('transportclose', () => {
|
||||
log.debug('Consumer "transportclose" event');
|
||||
this.removeConsumer(id);
|
||||
});
|
||||
|
||||
return {
|
||||
consumer: consumer,
|
||||
params: {
|
||||
producerId: producer_id,
|
||||
id: id,
|
||||
kind: kind,
|
||||
rtpParameters: rtpParameters,
|
||||
type: type,
|
||||
producerPaused: producerPaused,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
log.error('Error creating consumer', error.message);
|
||||
return error.message;
|
||||
}
|
||||
}
|
||||
|
||||
removeConsumer(consumer_id) {
|
||||
if (!this.consumers.has(consumer_id)) return;
|
||||
|
||||
const consumer = this.getConsumer(consumer_id);
|
||||
const { id, kind, type } = consumer;
|
||||
|
||||
try {
|
||||
consumer.close();
|
||||
} catch (error) {
|
||||
log.warn('Close Consumer', error.message);
|
||||
}
|
||||
|
||||
this.delConsumer(consumer_id);
|
||||
|
||||
log.debug('Consumer closed and deleted', {
|
||||
peer_name: this.peer_name,
|
||||
kind: kind,
|
||||
type: type,
|
||||
consumer_id: id,
|
||||
});
|
||||
}
|
||||
};
|
577
Video/MiroTalk SFU/app/src/Room.js
Normal file
@ -0,0 +1,577 @@
|
||||
'use strict';
|
||||
|
||||
const config = require('./config');
|
||||
const Logger = require('./Logger');
|
||||
const log = new Logger('Room');
|
||||
|
||||
module.exports = class Room {
|
||||
constructor(room_id, worker, io) {
|
||||
this.id = room_id;
|
||||
this.worker = worker;
|
||||
this.webRtcServer = worker.appData.webRtcServer;
|
||||
this.webRtcServerActive = config.mediasoup.webRtcServerActive;
|
||||
this.io = io;
|
||||
this.audioLevelObserver = null;
|
||||
this.audioLevelObserverEnabled = true;
|
||||
this.audioLastUpdateTime = 0;
|
||||
// ##########################
|
||||
this._isBroadcasting = false;
|
||||
// ##########################
|
||||
this._isLocked = false;
|
||||
this._isLobbyEnabled = false;
|
||||
this._roomPassword = null;
|
||||
this._hostOnlyRecording = false;
|
||||
// ##########################
|
||||
this._recSyncServerRecording = config?.server?.recording?.enabled || false;
|
||||
// ##########################
|
||||
this._moderator = {
|
||||
audio_start_muted: false,
|
||||
video_start_hidden: false,
|
||||
audio_cant_unmute: false,
|
||||
video_cant_unhide: false,
|
||||
screen_cant_share: false,
|
||||
chat_cant_privately: false,
|
||||
chat_cant_chatgpt: false,
|
||||
};
|
||||
this.survey = config.survey;
|
||||
this.redirect = config.redirect;
|
||||
this.peers = new Map();
|
||||
this.bannedPeers = [];
|
||||
this.webRtcTransport = config.mediasoup.webRtcTransport;
|
||||
this.router = null;
|
||||
this.routerSettings = config.mediasoup.router;
|
||||
this.createTheRouter();
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// ROOM INFO
|
||||
// ####################################################
|
||||
|
||||
toJson() {
|
||||
return {
|
||||
id: this.id,
|
||||
broadcasting: this._isBroadcasting,
|
||||
recSyncServerRecording: this._recSyncServerRecording,
|
||||
config: {
|
||||
isLocked: this._isLocked,
|
||||
isLobbyEnabled: this._isLobbyEnabled,
|
||||
hostOnlyRecording: this._hostOnlyRecording,
|
||||
},
|
||||
moderator: this._moderator,
|
||||
survey: this.survey,
|
||||
redirect: this.redirect,
|
||||
peers: JSON.stringify([...this.peers]),
|
||||
};
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// ROUTER
|
||||
// ####################################################
|
||||
|
||||
createTheRouter() {
|
||||
const { mediaCodecs } = this.routerSettings;
|
||||
this.worker
|
||||
.createRouter({
|
||||
mediaCodecs,
|
||||
})
|
||||
.then((router) => {
|
||||
this.router = router;
|
||||
if (this.audioLevelObserverEnabled) {
|
||||
this.startAudioLevelObservation();
|
||||
}
|
||||
this.router.observer.on('close', () => {
|
||||
log.info('---------------> Router is now closed as the last peer has left the room', {
|
||||
room: this.id,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
closeRouter() {
|
||||
this.router.close();
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// PRODUCER AUDIO LEVEL OBSERVER
|
||||
// ####################################################
|
||||
|
||||
async startAudioLevelObservation() {
|
||||
log.debug('Start audioLevelObserver for signaling active speaker...');
|
||||
|
||||
this.audioLevelObserver = await this.router.createAudioLevelObserver({
|
||||
maxEntries: 1,
|
||||
threshold: -70,
|
||||
interval: 100,
|
||||
});
|
||||
|
||||
this.audioLevelObserver.on('volumes', (volumes) => {
|
||||
this.sendActiveSpeakerVolume(volumes);
|
||||
});
|
||||
this.audioLevelObserver.on('silence', () => {
|
||||
//log.debug('audioLevelObserver', { volume: 'silence' });
|
||||
});
|
||||
}
|
||||
|
||||
sendActiveSpeakerVolume(volumes) {
|
||||
try {
|
||||
if (!Array.isArray(volumes) || volumes.length === 0) {
|
||||
throw new Error('Invalid volumes array');
|
||||
}
|
||||
|
||||
if (Date.now() > this.audioLastUpdateTime + 100) {
|
||||
this.audioLastUpdateTime = Date.now();
|
||||
|
||||
const { producer, volume } = volumes[0];
|
||||
const audioVolume = Math.round(Math.pow(10, volume / 70) * 10); // Scale volume to 1-10
|
||||
|
||||
if (audioVolume > 1) {
|
||||
this.peers.forEach((peer) => {
|
||||
const { id, peer_audio, peer_name } = peer;
|
||||
peer.producers.forEach((peerProducer) => {
|
||||
if (peerProducer.id === producer.id && peerProducer.kind === 'audio' && peer_audio) {
|
||||
const data = {
|
||||
peer_id: id,
|
||||
peer_name: peer_name,
|
||||
audioVolume: audioVolume,
|
||||
};
|
||||
// Uncomment the following line for debugging
|
||||
// log.debug('Sending audio volume', data);
|
||||
this.sendToAll('audioVolume', data);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
log.error('Error sending active speaker volume', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
addProducerToAudioLevelObserver(producer) {
|
||||
if (this.audioLevelObserverEnabled) {
|
||||
this.audioLevelObserver.addProducer(producer);
|
||||
}
|
||||
}
|
||||
|
||||
getRtpCapabilities() {
|
||||
return this.router.rtpCapabilities;
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// ROOM MODERATOR
|
||||
// ####################################################
|
||||
|
||||
updateRoomModeratorALL(data) {
|
||||
this._moderator = data;
|
||||
log.debug('Update room moderator all data', this._moderator);
|
||||
}
|
||||
|
||||
updateRoomModerator(data) {
|
||||
log.debug('Update room moderator', data);
|
||||
switch (data.type) {
|
||||
case 'audio_start_muted':
|
||||
this._moderator.audio_start_muted = data.status;
|
||||
break;
|
||||
case 'video_start_hidden':
|
||||
this._moderator.video_start_hidden = data.status;
|
||||
case 'audio_cant_unmute':
|
||||
this._moderator.audio_cant_unmute = data.status;
|
||||
break;
|
||||
case 'video_cant_unhide':
|
||||
this._moderator.video_cant_unhide = data.status;
|
||||
case 'screen_cant_share':
|
||||
this._moderator.screen_cant_share = data.status;
|
||||
break;
|
||||
case 'chat_cant_privately':
|
||||
this._moderator.chat_cant_privately = data.status;
|
||||
break;
|
||||
case 'chat_cant_chatgpt':
|
||||
this._moderator.chat_cant_chatgpt = data.status;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// PEERS
|
||||
// ####################################################
|
||||
|
||||
addPeer(peer) {
|
||||
this.peers.set(peer.id, peer);
|
||||
}
|
||||
|
||||
getPeer(socket_id) {
|
||||
//
|
||||
if (!this.peers.has(socket_id)) {
|
||||
log.error('---> Peer not found for socket ID', socket_id);
|
||||
return null;
|
||||
}
|
||||
|
||||
const peer = this.peers.get(socket_id);
|
||||
|
||||
return peer;
|
||||
}
|
||||
|
||||
getPeers() {
|
||||
return this.peers;
|
||||
}
|
||||
|
||||
getPeersCount() {
|
||||
return this.peers.size;
|
||||
}
|
||||
|
||||
getProducerListForPeer() {
|
||||
const producerList = [];
|
||||
this.peers.forEach((peer) => {
|
||||
const { peer_name, peer_info } = peer;
|
||||
peer.producers.forEach((producer) => {
|
||||
producerList.push({
|
||||
producer_id: producer.id,
|
||||
peer_name: peer_name,
|
||||
peer_info: peer_info,
|
||||
type: producer.appData.mediaType,
|
||||
});
|
||||
});
|
||||
});
|
||||
return producerList;
|
||||
}
|
||||
|
||||
async removePeer(socket_id) {
|
||||
const peer = this.getPeer(socket_id);
|
||||
|
||||
if (!peer || typeof peer !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
const { id, peer_name } = peer;
|
||||
|
||||
peer.close();
|
||||
|
||||
this.peers.delete(socket_id);
|
||||
|
||||
if (this.getPeers().size === 0) {
|
||||
this.closeRouter();
|
||||
}
|
||||
|
||||
const peerTransports = peer.getTransports();
|
||||
const peerProducers = peer.getProducers();
|
||||
const peerConsumers = peer.getConsumers();
|
||||
|
||||
log.debug('REMOVE PEER', {
|
||||
peer_id: id,
|
||||
peer_name: peer_name,
|
||||
peerTransports: peerTransports,
|
||||
peerProducers: peerProducers,
|
||||
peerConsumers: peerConsumers,
|
||||
});
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// WebRTC TRANSPORT
|
||||
// ####################################################
|
||||
|
||||
async createWebRtcTransport(socket_id) {
|
||||
const { maxIncomingBitrate, initialAvailableOutgoingBitrate, listenInfos } = this.webRtcTransport;
|
||||
|
||||
const webRtcTransportOptions = {
|
||||
...(this.webRtcServerActive ? { webRtcServer: this.webRtcServer } : { listenInfos: listenInfos }),
|
||||
enableUdp: true,
|
||||
enableTcp: true,
|
||||
preferUdp: true,
|
||||
iceConsentTimeout: 20,
|
||||
initialAvailableOutgoingBitrate,
|
||||
};
|
||||
|
||||
log.debug('webRtcTransportOptions ----->', webRtcTransportOptions);
|
||||
|
||||
const transport = await this.router.createWebRtcTransport(webRtcTransportOptions);
|
||||
|
||||
if (!transport) {
|
||||
return this.callback('[Room|createWebRtcTransport] Failed to create WebRTC transport');
|
||||
}
|
||||
|
||||
const { id, iceParameters, iceCandidates, dtlsParameters } = transport;
|
||||
|
||||
if (maxIncomingBitrate) {
|
||||
try {
|
||||
await transport.setMaxIncomingBitrate(maxIncomingBitrate);
|
||||
} catch (error) {
|
||||
log.debug('Transport setMaxIncomingBitrate error', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
const peer = this.getPeer(socket_id);
|
||||
|
||||
if (!peer || typeof peer !== 'object') {
|
||||
return this.callback(`[Room|createWebRtcTransport] Peer object not found for socket ID: ${socket_id}`);
|
||||
}
|
||||
|
||||
const { peer_name } = peer;
|
||||
|
||||
transport.on('icestatechange', (iceState) => {
|
||||
if (iceState === 'disconnected' || iceState === 'closed') {
|
||||
log.debug('Transport closed "icestatechange" event', {
|
||||
peer_name: peer_name,
|
||||
transport_id: id,
|
||||
iceState: iceState,
|
||||
});
|
||||
transport.close();
|
||||
}
|
||||
});
|
||||
|
||||
transport.on('sctpstatechange', (sctpState) => {
|
||||
log.debug('Transport "sctpstatechange" event', {
|
||||
peer_name: peer_name,
|
||||
transport_id: id,
|
||||
sctpState: sctpState,
|
||||
});
|
||||
});
|
||||
|
||||
transport.on('dtlsstatechange', (dtlsState) => {
|
||||
if (dtlsState === 'failed' || dtlsState === 'closed') {
|
||||
log.debug('Transport closed "dtlsstatechange" event', {
|
||||
peer_name: peer_name,
|
||||
transport_id: id,
|
||||
dtlsState: dtlsState,
|
||||
});
|
||||
transport.close();
|
||||
}
|
||||
});
|
||||
|
||||
transport.on('close', () => {
|
||||
log.debug('Transport closed', { peer_name: peer_name, transport_id: transport.id });
|
||||
});
|
||||
|
||||
peer.addTransport(transport);
|
||||
|
||||
log.debug('Transport created', { transportId: id });
|
||||
|
||||
return {
|
||||
id: id,
|
||||
iceParameters: iceParameters,
|
||||
iceCandidates: iceCandidates,
|
||||
dtlsParameters: dtlsParameters,
|
||||
};
|
||||
}
|
||||
|
||||
async connectPeerTransport(socket_id, transport_id, dtlsParameters) {
|
||||
try {
|
||||
if (!socket_id || !transport_id || !dtlsParameters) {
|
||||
return this.callback('[Room|connectPeerTransport] Invalid input parameters');
|
||||
}
|
||||
|
||||
const peer = this.getPeer(socket_id);
|
||||
|
||||
if (!peer || typeof peer !== 'object') {
|
||||
return this.callback(`[Room|connectPeerTransport] Peer object not found for socket ID: ${socket_id}`);
|
||||
}
|
||||
|
||||
const connectTransport = await peer.connectTransport(transport_id, dtlsParameters);
|
||||
|
||||
if (!connectTransport) {
|
||||
return this.callback(`[Room|connectPeerTransport] error: Transport with ID ${transport_id} not found`);
|
||||
}
|
||||
|
||||
return '[Room|connectPeerTransport] done';
|
||||
} catch (error) {
|
||||
log.error('Error connecting peer transport', error.message);
|
||||
return this.callback(`[Room|connectPeerTransport] error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// PRODUCE
|
||||
// ####################################################
|
||||
|
||||
async produce(socket_id, producerTransportId, rtpParameters, kind, type) {
|
||||
//
|
||||
if (!socket_id || !producerTransportId || !rtpParameters || !kind || !type) {
|
||||
return this.callback('[Room|produce] Invalid input parameters');
|
||||
}
|
||||
|
||||
const peer = this.getPeer(socket_id);
|
||||
|
||||
if (!peer || typeof peer !== 'object') {
|
||||
return this.callback(`[Room|produce] Peer object not found for socket ID: ${socket_id}`);
|
||||
}
|
||||
|
||||
const peerProducer = await peer.createProducer(producerTransportId, rtpParameters, kind, type);
|
||||
|
||||
if (!peerProducer || !peerProducer.id) {
|
||||
return this.callback(`[Room|produce] Peer producer error: '${peerProducer}'`);
|
||||
}
|
||||
|
||||
const { id } = peerProducer;
|
||||
|
||||
const { peer_name, peer_info } = peer;
|
||||
|
||||
this.broadCast(socket_id, 'newProducers', [
|
||||
{
|
||||
producer_id: id,
|
||||
producer_socket_id: socket_id,
|
||||
peer_name: peer_name,
|
||||
peer_info: peer_info,
|
||||
type: type,
|
||||
},
|
||||
]);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
closeProducer(socket_id, producer_id) {
|
||||
if (!socket_id || !producer_id) return;
|
||||
|
||||
const peer = this.getPeer(socket_id);
|
||||
|
||||
if (!peer || typeof peer !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
peer.closeProducer(producer_id);
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// CONSUME
|
||||
// ####################################################
|
||||
|
||||
async consume(socket_id, consumer_transport_id, producer_id, rtpCapabilities) {
|
||||
try {
|
||||
if (!socket_id || !consumer_transport_id || !producer_id || !rtpCapabilities) {
|
||||
return this.callback('[Room|consume] Invalid input parameters');
|
||||
}
|
||||
|
||||
if (!this.router.canConsume({ producerId: producer_id, rtpCapabilities })) {
|
||||
log.warn('Cannot consume', {
|
||||
socket_id,
|
||||
consumer_transport_id,
|
||||
producer_id,
|
||||
});
|
||||
return this.callback(`[Room|consume] Room router cannot consume producer_id: '${producer_id}'`);
|
||||
}
|
||||
|
||||
const peer = this.getPeer(socket_id);
|
||||
|
||||
if (!peer || typeof peer !== 'object') {
|
||||
return this.callback(`[Room|consume] Peer object not found for socket ID: ${socket_id}`);
|
||||
}
|
||||
|
||||
const peerConsumer = await peer.createConsumer(consumer_transport_id, producer_id, rtpCapabilities);
|
||||
|
||||
if (!peerConsumer || !peerConsumer.consumer || !peerConsumer.params) {
|
||||
log.debug('peerConsumer or params are not defined');
|
||||
return this.callback(`[Room|consume] peerConsumer error: '${peerConsumer}'`);
|
||||
}
|
||||
|
||||
const { consumer, params } = peerConsumer;
|
||||
|
||||
const { id, kind } = consumer;
|
||||
|
||||
consumer.on('producerclose', () => {
|
||||
log.debug('Consumer closed due to "producerclose" event');
|
||||
peer.removeConsumer(id);
|
||||
|
||||
// Notify the client that consumer is closed
|
||||
this.send(socket_id, 'consumerClosed', {
|
||||
consumer_id: id,
|
||||
consumer_kind: kind,
|
||||
});
|
||||
});
|
||||
|
||||
return params;
|
||||
} catch (error) {
|
||||
log.error('Error occurred during consumption', error.message);
|
||||
return this.callback(`[Room|consume] ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// HANDLE BANNED PEERS
|
||||
// ####################################################
|
||||
|
||||
addBannedPeer(uuid) {
|
||||
if (!this.bannedPeers.includes(uuid)) {
|
||||
this.bannedPeers.push(uuid);
|
||||
log.debug('Added to the banned list', {
|
||||
uuid: uuid,
|
||||
banned: this.bannedPeers,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isBanned(uuid) {
|
||||
return this.bannedPeers.includes(uuid);
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// ROOM STATUS
|
||||
// ####################################################
|
||||
|
||||
// GET
|
||||
isBroadcasting() {
|
||||
return this._isBroadcasting;
|
||||
}
|
||||
getPassword() {
|
||||
return this._roomPassword;
|
||||
}
|
||||
|
||||
// BOOL
|
||||
isLocked() {
|
||||
return this._isLocked;
|
||||
}
|
||||
isLobbyEnabled() {
|
||||
return this._isLobbyEnabled;
|
||||
}
|
||||
isHostOnlyRecording() {
|
||||
return this._hostOnlyRecording;
|
||||
}
|
||||
|
||||
// SET
|
||||
setIsBroadcasting(status) {
|
||||
this._isBroadcasting = status;
|
||||
}
|
||||
setLocked(status, password) {
|
||||
this._isLocked = status;
|
||||
this._roomPassword = password;
|
||||
}
|
||||
setLobbyEnabled(status) {
|
||||
this._isLobbyEnabled = status;
|
||||
}
|
||||
setHostOnlyRecording(status) {
|
||||
this._hostOnlyRecording = status;
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// ERRORS
|
||||
// ####################################################
|
||||
|
||||
callback(message) {
|
||||
return { error: message };
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// SENDER
|
||||
// ####################################################
|
||||
|
||||
broadCast(socket_id, action, data) {
|
||||
for (let otherID of Array.from(this.peers.keys()).filter((id) => id !== socket_id)) {
|
||||
this.send(otherID, action, data);
|
||||
}
|
||||
}
|
||||
|
||||
sendTo(socket_id, action, data) {
|
||||
for (let peer_id of Array.from(this.peers.keys()).filter((id) => id === socket_id)) {
|
||||
this.send(peer_id, action, data);
|
||||
}
|
||||
}
|
||||
|
||||
sendToAll(action, data) {
|
||||
for (let peer_id of Array.from(this.peers.keys())) {
|
||||
this.send(peer_id, action, data);
|
||||
}
|
||||
}
|
||||
|
||||
send(socket_id, action, data) {
|
||||
this.io.to(socket_id).emit(action, data);
|
||||
}
|
||||
};
|
2058
Video/MiroTalk SFU/app/src/Server.js
Normal file
121
Video/MiroTalk SFU/app/src/ServerApi.js
Normal file
@ -0,0 +1,121 @@
|
||||
'use strict';
|
||||
|
||||
const jwt = require('jsonwebtoken');
|
||||
const CryptoJS = require('crypto-js');
|
||||
|
||||
const config = require('./config');
|
||||
const { v4: uuidV4 } = require('uuid');
|
||||
|
||||
const JWT_KEY = (config.jwt && config.jwt.key) || 'mirotalksfu_jwt_secret';
|
||||
const JWT_EXP = (config.jwt && config.jwt.exp) || '1h';
|
||||
|
||||
module.exports = class ServerApi {
|
||||
constructor(host = null, authorization = null) {
|
||||
this._host = host;
|
||||
this._authorization = authorization;
|
||||
this._api_key_secret = config.api.keySecret;
|
||||
}
|
||||
|
||||
isAuthorized() {
|
||||
if (this._authorization != this._api_key_secret) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
getMeetings(roomList) {
|
||||
const meetings = Array.from(roomList.entries()).map(([id, room]) => {
|
||||
const peers = Array.from(room.peers.values()).map(
|
||||
({
|
||||
peer_info: {
|
||||
peer_name,
|
||||
peer_presenter,
|
||||
peer_video,
|
||||
peer_audio,
|
||||
peer_screen,
|
||||
peer_hand,
|
||||
os_name,
|
||||
os_version,
|
||||
browser_name,
|
||||
browser_version,
|
||||
},
|
||||
}) => ({
|
||||
name: peer_name,
|
||||
presenter: peer_presenter,
|
||||
video: peer_video,
|
||||
audio: peer_audio,
|
||||
screen: peer_screen,
|
||||
hand: peer_hand,
|
||||
os: os_name ? `${os_name} ${os_version}` : '',
|
||||
browser: browser_name ? `${browser_name} ${browser_version}` : '',
|
||||
}),
|
||||
);
|
||||
return {
|
||||
roomId: id,
|
||||
peers: peers,
|
||||
};
|
||||
});
|
||||
return meetings;
|
||||
}
|
||||
|
||||
getMeetingURL() {
|
||||
return 'https://' + this._host + '/join/' + uuidV4();
|
||||
}
|
||||
|
||||
getJoinURL(data) {
|
||||
// Get data
|
||||
const { room, roomPassword, name, audio, video, screen, hide, notify, token } = data;
|
||||
|
||||
const roomValue = room || uuidV4();
|
||||
const nameValue = name || 'User-' + this.getRandomNumber();
|
||||
const roomPasswordValue = roomPassword || false;
|
||||
const audioValue = audio || false;
|
||||
const videoValue = video || false;
|
||||
const screenValue = screen || false;
|
||||
const hideValue = hide || false;
|
||||
const notifyValue = notify || false;
|
||||
const jwtToken = token ? '&token=' + this.getToken(token) : '';
|
||||
|
||||
const joinURL =
|
||||
'https://' +
|
||||
this._host +
|
||||
'/join?' +
|
||||
`room=${roomValue}` +
|
||||
`&roomPassword=${roomPasswordValue}` +
|
||||
`&name=${encodeURIComponent(nameValue)}` +
|
||||
`&audio=${audioValue}` +
|
||||
`&video=${videoValue}` +
|
||||
`&screen=${screenValue}` +
|
||||
`&hide=${hideValue}` +
|
||||
`¬ify=${notifyValue}` +
|
||||
jwtToken;
|
||||
|
||||
return joinURL;
|
||||
}
|
||||
|
||||
getToken(token) {
|
||||
if (!token) return '';
|
||||
|
||||
const { username = 'username', password = 'password', presenter = false, expire } = token;
|
||||
|
||||
const expireValue = expire || JWT_EXP;
|
||||
|
||||
// Constructing payload
|
||||
const payload = {
|
||||
username: String(username),
|
||||
password: String(password),
|
||||
presenter: String(presenter),
|
||||
};
|
||||
|
||||
// Encrypt payload using AES encryption
|
||||
const payloadString = JSON.stringify(payload);
|
||||
const encryptedPayload = CryptoJS.AES.encrypt(payloadString, JWT_KEY).toString();
|
||||
|
||||
// Constructing JWT token
|
||||
const jwtToken = jwt.sign({ data: encryptedPayload }, JWT_KEY, { expiresIn: expireValue });
|
||||
|
||||
return jwtToken;
|
||||
}
|
||||
|
||||
getRandomNumber() {
|
||||
return Math.floor(Math.random() * 999999);
|
||||
}
|
||||
};
|
66
Video/MiroTalk SFU/app/src/XSS.js
Normal file
@ -0,0 +1,66 @@
|
||||
'use strict';
|
||||
|
||||
const xss = require('xss');
|
||||
const Logger = require('./Logger');
|
||||
const log = new Logger('Xss');
|
||||
|
||||
const checkXSS = (dataObject) => {
|
||||
try {
|
||||
if (Array.isArray(dataObject)) {
|
||||
if (Object.keys(dataObject).length > 0 && typeof dataObject[0] === 'object') {
|
||||
dataObject.forEach((obj) => {
|
||||
for (const key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
let objectJson = objectToJSONString(obj[key]);
|
||||
if (objectJson) {
|
||||
let jsonString = xss(objectJson);
|
||||
let jsonObject = JSONStringToObject(jsonString);
|
||||
if (jsonObject) {
|
||||
obj[key] = jsonObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
log.debug('XSS Array of Object sanitization done');
|
||||
return dataObject;
|
||||
}
|
||||
} else if (typeof dataObject === 'object') {
|
||||
let objectJson = objectToJSONString(dataObject);
|
||||
if (objectJson) {
|
||||
let jsonString = xss(objectJson);
|
||||
let jsonObject = JSONStringToObject(jsonString);
|
||||
if (jsonObject) {
|
||||
log.debug('XSS Object sanitization done');
|
||||
return jsonObject;
|
||||
}
|
||||
}
|
||||
} else if (typeof dataObject === 'string' || dataObject instanceof String) {
|
||||
log.debug('XSS String sanitization done');
|
||||
return xss(dataObject);
|
||||
}
|
||||
log.warn('XSS not sanitized', dataObject);
|
||||
return dataObject;
|
||||
} catch (error) {
|
||||
log.error('XSS error', { data: dataObject, error: error });
|
||||
return dataObject;
|
||||
}
|
||||
};
|
||||
|
||||
function objectToJSONString(dataObject) {
|
||||
try {
|
||||
return JSON.stringify(dataObject);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function JSONStringToObject(jsonString) {
|
||||
try {
|
||||
return JSON.parse(jsonString);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = checkXSS;
|
433
Video/MiroTalk SFU/app/src/config.template.js
Normal file
@ -0,0 +1,433 @@
|
||||
'use strict';
|
||||
|
||||
const os = require('os');
|
||||
|
||||
// https://api.ipify.org
|
||||
|
||||
function getIPv4() {
|
||||
const ifaces = os.networkInterfaces();
|
||||
for (const interfaceName in ifaces) {
|
||||
const iface = ifaces[interfaceName];
|
||||
for (const { address, family, internal } of iface) {
|
||||
if (family === 'IPv4' && !internal) {
|
||||
return address;
|
||||
}
|
||||
}
|
||||
}
|
||||
return '0.0.0.0'; // Default to 0.0.0.0 if no external IPv4 address found
|
||||
}
|
||||
|
||||
const IPv4 = getIPv4();
|
||||
|
||||
const numWorkers = require('os').cpus().length;
|
||||
|
||||
module.exports = {
|
||||
console: {
|
||||
/*
|
||||
timeZone: Time Zone corresponding to timezone identifiers from the IANA Time Zone Database es 'Europe/Rome' default UTC
|
||||
*/
|
||||
timeZone: 'UTC',
|
||||
debug: true,
|
||||
colors: true,
|
||||
},
|
||||
server: {
|
||||
listen: {
|
||||
// app listen on
|
||||
ip: '0.0.0.0',
|
||||
port: process.env.PORT || 3010,
|
||||
},
|
||||
ssl: {
|
||||
// ssl/README.md
|
||||
cert: '../ssl/cert.pem',
|
||||
key: '../ssl/key.pem',
|
||||
},
|
||||
cors: {
|
||||
/*
|
||||
origin: Allow specified origin es ['https://example.com', 'https://subdomain.example.com', 'http://localhost:3010'] or all origins if not specified
|
||||
methods: Allow only GET and POST methods
|
||||
*/
|
||||
origin: '*',
|
||||
methods: ['GET', 'POST'],
|
||||
},
|
||||
recording: {
|
||||
/*
|
||||
The recording will be saved to the directory designated within your Server app/<dir>
|
||||
Note: if you use Docker: Create the "app/rec" directory, configure it as a volume in docker-compose.yml,
|
||||
ensure proper permissions, and start the Docker container.
|
||||
*/
|
||||
dir: 'rec',
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
middleware: {
|
||||
/*
|
||||
Middleware:
|
||||
- IP Whitelist: Access to the instance is restricted to only the specified IP addresses in the allowed list. This feature is disabled by default.
|
||||
- ...
|
||||
*/
|
||||
IpWhitelist: {
|
||||
enabled: false,
|
||||
allowed: ['127.0.0.1', '::1'],
|
||||
},
|
||||
},
|
||||
api: {
|
||||
// Default secret key for app/api
|
||||
keySecret: 'mirotalksfu_default_secret',
|
||||
// Define which endpoints are allowed
|
||||
allowed: {
|
||||
meetings: false,
|
||||
meeting: true,
|
||||
join: true,
|
||||
token: false,
|
||||
slack: true,
|
||||
//...
|
||||
},
|
||||
},
|
||||
jwt: {
|
||||
/*
|
||||
JWT https://jwt.io/
|
||||
Securely manages credentials for host configurations and user authentication, enhancing security and streamlining processes.
|
||||
*/
|
||||
key: 'mirotalksfu_jwt_secret',
|
||||
exp: '1h',
|
||||
},
|
||||
host: {
|
||||
/*
|
||||
Host Protection (default: false)
|
||||
To enhance host security, enable host protection - user auth and provide valid
|
||||
usernames and passwords in the users array or active users_from_db using users_api_endpoint for check.
|
||||
*/
|
||||
protected: false,
|
||||
user_auth: false,
|
||||
users_from_db: false, // if true ensure that api.token is also set to true.
|
||||
//users_api_endpoint: 'http://localhost:9000/api/v1/user/isAuth',
|
||||
users_api_endpoint: 'https://webrtc.mirotalk.com/api/v1/user/isAuth',
|
||||
users_api_secret_key: 'mirotalkweb_default_secret',
|
||||
users: [
|
||||
{
|
||||
username: 'username',
|
||||
password: 'password',
|
||||
},
|
||||
{
|
||||
username: 'username2',
|
||||
password: 'password2',
|
||||
},
|
||||
//...
|
||||
],
|
||||
},
|
||||
presenters: {
|
||||
list: [
|
||||
/*
|
||||
By default, the presenter is identified as the first participant to join the room, distinguished by their username and UUID.
|
||||
Additional layers can be added to specify valid presenters and co-presenters by setting designated usernames.
|
||||
*/
|
||||
'Miroslav Pejic',
|
||||
'miroslav.pejic.85@gmail.com',
|
||||
],
|
||||
join_first: true, // Set to true for traditional behavior, false to prioritize presenters
|
||||
},
|
||||
chatGPT: {
|
||||
/*
|
||||
ChatGPT
|
||||
1. Goto https://platform.openai.com/
|
||||
2. Create your account
|
||||
3. Generate your APIKey https://platform.openai.com/account/api-keys
|
||||
*/
|
||||
enabled: false,
|
||||
basePath: 'https://api.openai.com/v1/',
|
||||
apiKey: '',
|
||||
model: 'gpt-3.5-turbo',
|
||||
max_tokens: 1000,
|
||||
temperature: 0,
|
||||
},
|
||||
email: {
|
||||
/*
|
||||
Configure email settings for notifications or alerts
|
||||
Refer to the documentation for Gmail configuration: https://support.google.com/mail/answer/185833?hl=en
|
||||
*/
|
||||
alert: false,
|
||||
host: 'smtp.gmail.com',
|
||||
port: 587,
|
||||
username: 'your_username',
|
||||
password: 'your_password',
|
||||
sendTo: 'sfu.mirotalk@gmail.com',
|
||||
},
|
||||
ngrok: {
|
||||
/*
|
||||
Ngrok
|
||||
1. Goto https://ngrok.com
|
||||
2. Get started for free
|
||||
3. Copy YourNgrokAuthToken: https://dashboard.ngrok.com/get-started/your-authtoken
|
||||
*/
|
||||
authToken: '',
|
||||
},
|
||||
sentry: {
|
||||
/*
|
||||
Sentry
|
||||
1. Goto https://sentry.io/
|
||||
2. Create account
|
||||
3. On dashboard goto Settings/Projects/YourProjectName/Client Keys (DSN)
|
||||
*/
|
||||
enabled: false,
|
||||
DSN: '',
|
||||
tracesSampleRate: 0.5,
|
||||
},
|
||||
slack: {
|
||||
/*
|
||||
Slack
|
||||
1. Goto https://api.slack.com/apps/
|
||||
2. Create your app
|
||||
3. On Settings - Basic Information - App Credentials, chose your Signing Secret
|
||||
4. Create a Slash Commands and put as Request URL: https://your.domain.name/slack
|
||||
*/
|
||||
enabled: false,
|
||||
signingSecret: '',
|
||||
},
|
||||
IPLookup: {
|
||||
/*
|
||||
GeoJS
|
||||
https://www.geojs.io/docs/v1/endpoints/geo/
|
||||
*/
|
||||
enabled: false,
|
||||
getEndpoint(ip) {
|
||||
return `https://get.geojs.io/v1/ip/geo/${ip}.json`;
|
||||
},
|
||||
},
|
||||
survey: {
|
||||
/*
|
||||
QuestionPro
|
||||
1. GoTo https://www.questionpro.com/
|
||||
2. Create your account
|
||||
3. Create your custom survey
|
||||
*/
|
||||
enabled: false,
|
||||
url: '',
|
||||
},
|
||||
redirect: {
|
||||
/*
|
||||
Redirect URL on leave room
|
||||
Upon leaving the room, users who either opt out of providing feedback or if the survey is disabled
|
||||
will be redirected to a specified URL. If enabled false the default '/newroom' URL will be used.
|
||||
*/
|
||||
enabled: false,
|
||||
url: '',
|
||||
},
|
||||
ui: {
|
||||
/*
|
||||
Customize your MiroTalk instance
|
||||
*/
|
||||
brand: {
|
||||
app: {
|
||||
name: 'MiroTalk SFU',
|
||||
title: 'MiroTalk SFU<br />Free browser based Real-time video calls.<br />Simple, Secure, Fast.',
|
||||
description:
|
||||
'Start your next video call with a single click. No download, plug-in, or login is required. Just get straight to talking, messaging, and sharing your screen.',
|
||||
},
|
||||
site: {
|
||||
title: 'MiroTalk SFU, Free Video Calls, Messaging and Screen Sharing',
|
||||
icon: '../images/logo.svg',
|
||||
appleTouchIcon: '../images/logo.svg',
|
||||
},
|
||||
meta: {
|
||||
description:
|
||||
'MiroTalk SFU powered by WebRTC and mediasoup, Real-time Simple Secure Fast video calls, messaging and screen sharing capabilities in the browser.',
|
||||
keywords:
|
||||
'webrtc, miro, mediasoup, mediasoup-client, self hosted, voip, sip, real-time communications, chat, messaging, meet, webrtc stun, webrtc turn, webrtc p2p, webrtc sfu, video meeting, video chat, video conference, multi video chat, multi video conference, peer to peer, p2p, sfu, rtc, alternative to, zoom, microsoft teams, google meet, jitsi, meeting',
|
||||
},
|
||||
og: {
|
||||
type: 'app-webrtc',
|
||||
siteName: 'MiroTalk SFU',
|
||||
title: 'Click the link to make a call.',
|
||||
description: 'MiroTalk SFU calling provides real-time video calls, messaging and screen sharing.',
|
||||
image: 'https://sfu.mirotalk.com/images/mirotalksfu.png',
|
||||
},
|
||||
html: {
|
||||
features: true,
|
||||
teams: true, // Please keep me always visible, thank you!
|
||||
tryEasier: true,
|
||||
poweredBy: true,
|
||||
sponsors: true,
|
||||
advertisers: true,
|
||||
footer: true,
|
||||
},
|
||||
//...
|
||||
},
|
||||
/*
|
||||
Toggle the visibility of specific HTML elements within the room
|
||||
*/
|
||||
buttons: {
|
||||
main: {
|
||||
shareButton: true, // presenter
|
||||
hideMeButton: true,
|
||||
startAudioButton: true,
|
||||
startVideoButton: true,
|
||||
startScreenButton: true,
|
||||
swapCameraButton: true,
|
||||
chatButton: true,
|
||||
raiseHandButton: true,
|
||||
transcriptionButton: true,
|
||||
whiteboardButton: true,
|
||||
emojiRoomButton: true,
|
||||
settingsButton: true,
|
||||
aboutButton: true, // Please keep me always visible, thank you!
|
||||
exitButton: true,
|
||||
},
|
||||
settings: {
|
||||
fileSharing: true,
|
||||
lockRoomButton: true, // presenter
|
||||
unlockRoomButton: true, // presenter
|
||||
broadcastingButton: true, // presenter
|
||||
lobbyButton: true, // presenter
|
||||
sendEmailInvitation: true, // presenter
|
||||
micOptionsButton: true, // presenter
|
||||
tabModerator: true, // presenter
|
||||
tabRecording: true,
|
||||
host_only_recording: true, // presenter
|
||||
pushToTalk: true,
|
||||
},
|
||||
producerVideo: {
|
||||
videoPictureInPicture: true,
|
||||
fullScreenButton: true,
|
||||
snapShotButton: true,
|
||||
muteAudioButton: true,
|
||||
videoPrivacyButton: true,
|
||||
},
|
||||
consumerVideo: {
|
||||
videoPictureInPicture: true,
|
||||
fullScreenButton: true,
|
||||
snapShotButton: true,
|
||||
sendMessageButton: true,
|
||||
sendFileButton: true,
|
||||
sendVideoButton: true,
|
||||
muteVideoButton: true,
|
||||
muteAudioButton: true,
|
||||
audioVolumeInput: true, // Disabled for mobile
|
||||
geolocationButton: true, // Presenter
|
||||
banButton: true, // presenter
|
||||
ejectButton: true, // presenter
|
||||
},
|
||||
videoOff: {
|
||||
sendMessageButton: true,
|
||||
sendFileButton: true,
|
||||
sendVideoButton: true,
|
||||
muteAudioButton: true,
|
||||
audioVolumeInput: true, // Disabled for mobile
|
||||
geolocationButton: true, // Presenter
|
||||
banButton: true, // presenter
|
||||
ejectButton: true, // presenter
|
||||
},
|
||||
chat: {
|
||||
chatPinButton: true,
|
||||
chatMaxButton: true,
|
||||
chatSaveButton: true,
|
||||
chatEmojiButton: true,
|
||||
chatMarkdownButton: true,
|
||||
chatSpeechStartButton: true,
|
||||
chatGPT: true,
|
||||
},
|
||||
participantsList: {
|
||||
saveInfoButton: true, // presenter
|
||||
sendFileAllButton: true, // presenter
|
||||
ejectAllButton: true, // presenter
|
||||
sendFileButton: true, // presenter & guests
|
||||
geoLocationButton: true, // presenter
|
||||
banButton: true, // presenter
|
||||
ejectButton: true, // presenter
|
||||
},
|
||||
whiteboard: {
|
||||
whiteboardLockButton: true, // presenter
|
||||
},
|
||||
//...
|
||||
},
|
||||
},
|
||||
stats: {
|
||||
/*
|
||||
Umami: https://github.com/umami-software/umami
|
||||
We use our Self-hosted Umami to track aggregated usage statistics in order to improve our service.
|
||||
*/
|
||||
enabled: true,
|
||||
src: 'https://stats.mirotalk.com/script.js',
|
||||
id: '41d26670-f275-45bb-af82-3ce91fe57756',
|
||||
},
|
||||
mediasoup: {
|
||||
// Worker settings
|
||||
numWorkers: numWorkers,
|
||||
worker: {
|
||||
logLevel: 'error',
|
||||
logTags: ['info', 'ice', 'dtls', 'rtp', 'srtp', 'rtcp', 'rtx', 'bwe', 'score', 'simulcast', 'svc', 'sctp'],
|
||||
},
|
||||
// Router settings
|
||||
router: {
|
||||
mediaCodecs: [
|
||||
{
|
||||
kind: 'audio',
|
||||
mimeType: 'audio/opus',
|
||||
clockRate: 48000,
|
||||
channels: 2,
|
||||
},
|
||||
{
|
||||
kind: 'video',
|
||||
mimeType: 'video/VP8',
|
||||
clockRate: 90000,
|
||||
parameters: {
|
||||
'x-google-start-bitrate': 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'video',
|
||||
mimeType: 'video/VP9',
|
||||
clockRate: 90000,
|
||||
parameters: {
|
||||
'profile-id': 2,
|
||||
'x-google-start-bitrate': 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'video',
|
||||
mimeType: 'video/h264',
|
||||
clockRate: 90000,
|
||||
parameters: {
|
||||
'packetization-mode': 1,
|
||||
'profile-level-id': '4d0032',
|
||||
'level-asymmetry-allowed': 1,
|
||||
'x-google-start-bitrate': 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'video',
|
||||
mimeType: 'video/h264',
|
||||
clockRate: 90000,
|
||||
parameters: {
|
||||
'packetization-mode': 1,
|
||||
'profile-level-id': '42e01f',
|
||||
'level-asymmetry-allowed': 1,
|
||||
'x-google-start-bitrate': 1000,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// WebRtcServerOptions
|
||||
webRtcServerActive: false,
|
||||
webRtcServerOptions: {
|
||||
listenInfos: [
|
||||
{ protocol: 'udp', ip: '0.0.0.0', announcedAddress: IPv4, port: 44444 },
|
||||
{ protocol: 'tcp', ip: '0.0.0.0', announcedAddress: IPv4, port: 44444 },
|
||||
// { protocol: 'udp', ip: '0.0.0.0', announcedAddress: IPv4, portRange: { min: 44444, max: 44444 + numWorkers }},
|
||||
// { protocol: 'tcp', ip: '0.0.0.0', announcedAddress: IPv4, portRange: { min: 44444, max: 44444 + numWorkers }},
|
||||
],
|
||||
},
|
||||
// WebRtcTransportOptions
|
||||
webRtcTransport: {
|
||||
listenInfos: [
|
||||
{ protocol: 'udp', ip: '0.0.0.0', announcedAddress: IPv4, portRange: { min: 40000, max: 40100 } },
|
||||
{ protocol: 'tcp', ip: '0.0.0.0', announcedAddress: IPv4, portRange: { min: 40000, max: 40100 } },
|
||||
],
|
||||
initialAvailableOutgoingBitrate: 1000000,
|
||||
minimumAvailableOutgoingBitrate: 600000,
|
||||
maxSctpMessageSize: 262144,
|
||||
maxIncomingBitrate: 1500000,
|
||||
},
|
||||
//announcedAddress: replace by 'public static IPV4 address' https://api.ipify.org (type string --> 'xx.xxx.xxx.xx' not xx.xxx.xxx.xx)
|
||||
//announcedAddress: '' will be auto-detected on server start, for docker localPC set '127.0.0.1' otherwise the 'public static IPV4 address'
|
||||
},
|
||||
};
|
150
Video/MiroTalk SFU/app/src/lib/nodemailer.js
Normal file
@ -0,0 +1,150 @@
|
||||
'use-strict';
|
||||
|
||||
const nodemailer = require('nodemailer');
|
||||
const config = require('../config');
|
||||
const Logger = require('../Logger');
|
||||
const log = new Logger('NodeMailer');
|
||||
|
||||
// ####################################################
|
||||
// EMAIL CONFIG
|
||||
// ####################################################
|
||||
|
||||
const EMAIL_HOST = config.email ? config.email.host : false;
|
||||
const EMAIL_PORT = config.email ? config.email.port : false;
|
||||
const EMAIL_USERNAME = config.email ? config.email.username : false;
|
||||
const EMAIL_PASSWORD = config.email ? config.email.password : false;
|
||||
const EMAIL_SEND_TO = config.email ? config.email.sendTo : false;
|
||||
const EMAIL_ALERT = config.email ? config.email.alert : false;
|
||||
|
||||
log.info('Email', {
|
||||
alert: EMAIL_ALERT,
|
||||
host: EMAIL_HOST,
|
||||
port: EMAIL_PORT,
|
||||
username: EMAIL_USERNAME,
|
||||
password: EMAIL_PASSWORD,
|
||||
});
|
||||
|
||||
const transport = nodemailer.createTransport({
|
||||
host: EMAIL_HOST,
|
||||
port: EMAIL_PORT,
|
||||
auth: {
|
||||
user: EMAIL_USERNAME,
|
||||
pass: EMAIL_PASSWORD,
|
||||
},
|
||||
});
|
||||
|
||||
// ####################################################
|
||||
// EMAIL SEND ALERTS AND NOTIFICATIONS
|
||||
// ####################################################
|
||||
|
||||
function sendEmailAlert(event, data) {
|
||||
if (!EMAIL_ALERT || !EMAIL_HOST || !EMAIL_PORT || !EMAIL_USERNAME || !EMAIL_PASSWORD || !EMAIL_SEND_TO) return;
|
||||
|
||||
log.info('sendEMailAlert', {
|
||||
event: event,
|
||||
data: data,
|
||||
});
|
||||
|
||||
let subject = false;
|
||||
let body = false;
|
||||
|
||||
switch (event) {
|
||||
case 'join':
|
||||
subject = getJoinRoomSubject(data);
|
||||
body = getJoinRoomBody(data);
|
||||
break;
|
||||
// ...
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (subject && body) sendEmail(subject, body);
|
||||
}
|
||||
|
||||
function sendEmail(subject, body) {
|
||||
transport
|
||||
.sendMail({
|
||||
from: EMAIL_USERNAME,
|
||||
to: EMAIL_SEND_TO,
|
||||
subject: subject,
|
||||
html: body,
|
||||
})
|
||||
.catch((err) => log.error(err));
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// EMAIL TEMPLATES
|
||||
// ####################################################
|
||||
|
||||
function getJoinRoomSubject(data) {
|
||||
const { room_id } = data;
|
||||
return `MiroTalk SFU - New user Join to Room ${room_id}`;
|
||||
}
|
||||
function getJoinRoomBody(data) {
|
||||
const { peer_name, room_id, domain, os, browser } = data;
|
||||
|
||||
const currentDataTime = getCurrentDataTime();
|
||||
|
||||
const localDomains = ['localhost', '127.0.0.1'];
|
||||
|
||||
const currentDomain = localDomains.some((localDomain) => domain.includes(localDomain))
|
||||
? `${domain}:${config.server.listen.port}`
|
||||
: domain;
|
||||
|
||||
const room_join = `https://${currentDomain}/join/`;
|
||||
|
||||
return `
|
||||
<h1>New user join</h1>
|
||||
<style>
|
||||
table {
|
||||
font-family: arial, sans-serif;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
td {
|
||||
border: 1px solid #dddddd;
|
||||
text-align: left;
|
||||
padding: 8px;
|
||||
}
|
||||
tr:nth-child(even) {
|
||||
background-color: #dddddd;
|
||||
}
|
||||
</style>
|
||||
<table>
|
||||
<tr>
|
||||
<td>User</td>
|
||||
<td>${peer_name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Os</td>
|
||||
<td>${os}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Browser</td>
|
||||
<td>${browser}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Room</td>
|
||||
<td>${room_join}${room_id}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Date, Time</td>
|
||||
<td>${currentDataTime}</td>
|
||||
</tr>
|
||||
</table>
|
||||
`;
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// UTILITY
|
||||
// ####################################################
|
||||
|
||||
function getCurrentDataTime() {
|
||||
const currentTime = new Date().toLocaleString('en-US', log.tzOptions);
|
||||
const milliseconds = String(new Date().getMilliseconds()).padStart(3, '0');
|
||||
return `${currentTime}:${milliseconds}`;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sendEmailAlert,
|
||||
};
|
24
Video/MiroTalk SFU/app/src/middleware/IpWhitelist.js
Normal file
@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
const config = require('../config');
|
||||
const Logger = require('../Logger');
|
||||
const log = new Logger('RestrictAccessByIP');
|
||||
|
||||
const IpWhitelistEnabled = config.middleware ? config.middleware.IpWhitelist.enabled : false;
|
||||
const allowedIPs = config.middleware ? config.middleware.IpWhitelist.allowed : [];
|
||||
|
||||
const restrictAccessByIP = (req, res, next) => {
|
||||
if (!IpWhitelistEnabled) return next();
|
||||
//
|
||||
const clientIP =
|
||||
req.headers['x-forwarded-for'] || req.headers['X-Forwarded-For'] || req.socket.remoteAddress || req.ip;
|
||||
log.debug('Check IP', clientIP);
|
||||
if (allowedIPs.includes(clientIP)) {
|
||||
next();
|
||||
} else {
|
||||
log.info('Forbidden: Access denied from this IP address', { clientIP: clientIP });
|
||||
res.status(403).json({ error: 'Forbidden', message: 'Access denied from this IP address.' });
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = restrictAccessByIP;
|
159
Video/MiroTalk SFU/app/src/scripts/bindable.js
Normal file
@ -0,0 +1,159 @@
|
||||
'use strict';
|
||||
|
||||
const config = require('../config');
|
||||
|
||||
const net = require('net');
|
||||
|
||||
/*
|
||||
Run: node bindable.js
|
||||
|
||||
In networking, "bindable" refers to the ability to assign or allocate a specific IP address and port combination
|
||||
to a network service or application. Binding an IP address and port allows the service or application to listen for
|
||||
incoming network connections on that particular address and port.
|
||||
|
||||
When we say an IP address and port are "bindable," it means that there are no conflicts or issues preventing the service
|
||||
or application from using that specific combination. In other words, the IP address is available, and the port is not already
|
||||
in use by another process or service on the same machine.
|
||||
|
||||
If an IP address and port are bindable, it indicates that the network service or application can successfully bind to that
|
||||
combination, allowing it to accept incoming connections and communicate over the network. On the other hand, if the IP address
|
||||
and port are not bindable, it suggests that there may be conflicts or restrictions preventing the service or application
|
||||
from using them, such as another process already listening on the same IP address and port.
|
||||
*/
|
||||
|
||||
async function main() {
|
||||
// Server listen
|
||||
const serverListenIp = config.server.listen.ip;
|
||||
const serverListenPort = config.server.listen.port;
|
||||
|
||||
// WebRtcServerActive
|
||||
const webRtcServerActive = config.mediasoup.webRtcServerActive;
|
||||
|
||||
// WebRtcTransportOptions
|
||||
const webRtcTransportIpInfo = config.mediasoup.webRtcTransport.listenInfos[0];
|
||||
const webRtcTransportIpAddress =
|
||||
webRtcTransportIpInfo.ip !== '0.0.0.0' ? webRtcTransportIpInfo.ip : webRtcTransportIpInfo.announcedAddress;
|
||||
|
||||
// WorkersOptions | webRtcTransportOptions
|
||||
const workers = config.mediasoup.numWorkers;
|
||||
const { min, max } = config.mediasoup.webRtcTransport.listenInfos[0].portRange;
|
||||
const rtcMinPort = config.mediasoup.worker.rtcMinPort || min || 40000;
|
||||
const rtcMaxPort = config.mediasoup.worker.rtcMaxPort || max || 40100;
|
||||
|
||||
console.log('==================================');
|
||||
console.log('checkServerListenPorts');
|
||||
console.log('==================================');
|
||||
|
||||
await checkServerListenPorts(serverListenIp, serverListenPort);
|
||||
|
||||
console.log('==================================');
|
||||
console.log('checkWebRtcTransportPorts');
|
||||
console.log('==================================');
|
||||
|
||||
await checkWebRtcTransportPorts(webRtcTransportIpAddress, rtcMinPort, rtcMaxPort);
|
||||
|
||||
if (webRtcServerActive) {
|
||||
console.log('==================================');
|
||||
console.log('checkWebRtcServerPorts');
|
||||
console.log('==================================');
|
||||
|
||||
// WebRtcServerOptions
|
||||
const webRtcServerIpInfo = config.mediasoup.webRtcServerOptions.listenInfos[0];
|
||||
const webRtcServerIpAddress =
|
||||
webRtcServerIpInfo.ip !== '0.0.0.0' ? webRtcServerIpInfo.ip : webRtcServerIpInfo.announcedAddress;
|
||||
const webRtcServerStartPort = webRtcServerIpInfo.port;
|
||||
|
||||
await checkWebRtcServerPorts(webRtcServerIpAddress, webRtcServerStartPort, workers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Server listen port is bindable
|
||||
* @param {string} ipAddress
|
||||
* @param {integer} port
|
||||
*/
|
||||
async function checkServerListenPorts(ipAddress, port) {
|
||||
const bindable = await isBindable(ipAddress, port);
|
||||
if (bindable) {
|
||||
console.log(`${ipAddress}:${port} is bindable 🟢`);
|
||||
} else {
|
||||
console.log(`${ipAddress}:${port} is not bindable 🔴`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if WebRtcServer ports are bindable
|
||||
* @param {string} ipAddress
|
||||
* @param {integer} startPort
|
||||
* @param {integer} workers
|
||||
*/
|
||||
async function checkWebRtcServerPorts(ipAddress, startPort, workers) {
|
||||
let port = startPort;
|
||||
for (let i = 0; i < workers; i++) {
|
||||
try {
|
||||
const bindable = await isBindable(ipAddress, port);
|
||||
if (bindable) {
|
||||
console.log(`${ipAddress}:${port} is bindable 🟢`);
|
||||
} else {
|
||||
console.log(`${ipAddress}:${port} is not bindable 🔴`);
|
||||
}
|
||||
port++;
|
||||
} catch (err) {
|
||||
console.error('Error occurred:', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if WebRtcTransport Worker ports are bindable
|
||||
* @param {string} ipAddress
|
||||
* @param {integer} minPort
|
||||
* @param {integer} maxPort
|
||||
*/
|
||||
async function checkWebRtcTransportPorts(ipAddress, minPort, maxPort) {
|
||||
let port = minPort;
|
||||
for (let i = 0; i <= maxPort - minPort; i++) {
|
||||
try {
|
||||
const bindable = await isBindable(ipAddress, port);
|
||||
if (bindable) {
|
||||
console.log(`${ipAddress}:${port} is bindable 🟢`);
|
||||
} else {
|
||||
console.log(`${ipAddress}:${port} is not bindable 🔴`);
|
||||
}
|
||||
port++;
|
||||
} catch (err) {
|
||||
console.error('Error occurred:', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if ipAddress:port are bindable
|
||||
* @param {string} ipAddress
|
||||
* @param {integer} port
|
||||
* @returns {Promise<boolean>} A promise that resolves to true if the address is bindable, false otherwise.
|
||||
*/
|
||||
async function isBindable(ipAddress, port) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const server = net.createServer();
|
||||
|
||||
server.once('error', (err) => {
|
||||
if (err.code === 'EADDRINUSE') {
|
||||
resolve(false); // Address is already in use
|
||||
} else {
|
||||
reject(err); // Other error occurred
|
||||
}
|
||||
});
|
||||
|
||||
server.once('listening', () => {
|
||||
server.close();
|
||||
resolve(true); // Address is bindable
|
||||
});
|
||||
|
||||
server.listen(port, ipAddress);
|
||||
});
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Error occurred in main function:', err.message);
|
||||
});
|
22
Video/MiroTalk SFU/app/ssl/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
## Self-signed certificate
|
||||
|
||||
[What is self-signed-certificate](https://en.wikipedia.org/wiki/Self-signed_certificate)
|
||||
|
||||

|
||||
|
||||
```bash
|
||||
# install openssl 4 ubuntu
|
||||
apt install openssl
|
||||
# install openssl 4 mac
|
||||
brew install openssl
|
||||
|
||||
# self-signed certificate
|
||||
openssl genrsa -out key.pem
|
||||
openssl req -new -key key.pem -out csr.pem
|
||||
openssl x509 -req -days 9999 -in csr.pem -signkey key.pem -out cert.pem
|
||||
rm csr.pem
|
||||
|
||||
# https://www.sslchecker.com/certdecoder
|
||||
```
|
||||
|
||||
For trusted certificate, take a look at [Let's Encrypt](https://letsencrypt.org/i) and [Certbot](https://certbot.eff.org/).
|
22
Video/MiroTalk SFU/app/ssl/cert.pem
Normal file
@ -0,0 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDlTCCAn0CFBM91H+g2aRKsaRrCmo3NdYjwfWUMA0GCSqGSIb3DQEBCwUAMIGG
|
||||
MQswCQYDVQQGEwJJVDEOMAwGA1UECAwFSXRhbHkxETAPBgNVBAoMCE1pcm9UYWxr
|
||||
MQ8wDQYDVQQLDAZXZWJSVEMxFzAVBgNVBAMMDk1pcm9zbGF2IFBlamljMSowKAYJ
|
||||
KoZIhvcNAQkBFhttaXJvc2xhdi5wZWppYy44NUBnbWFpbC5jb20wHhcNMjEwODEx
|
||||
MTUwOTUzWhcNNDgxMjI2MTUwOTUzWjCBhjELMAkGA1UEBhMCSVQxDjAMBgNVBAgM
|
||||
BUl0YWx5MREwDwYDVQQKDAhNaXJvVGFsazEPMA0GA1UECwwGV2ViUlRDMRcwFQYD
|
||||
VQQDDA5NaXJvc2xhdiBQZWppYzEqMCgGCSqGSIb3DQEJARYbbWlyb3NsYXYucGVq
|
||||
aWMuODVAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
|
||||
rn2tC9W6wqjDI7B/4LfEnE4ILBOdwa9889QjmWUToKua7iXTpaSNP3SefKY50Q8T
|
||||
BFfkZXEGyqAESBUn2rYeHtebgLQTKHsixhSCdHqpBDOyYFeTywGiRP4gQHFKbExd
|
||||
X2AAD1ptTjHVuSlg/ojWstESBh/4TktifKzy3PKVKX6p889eDfyJtlv0PADAkon/
|
||||
rZp3hHq0FORhvQEER1sm6g58WyIfqGWjW7bb7/bkyS1baQI16fPeexfu1Rs7y4kx
|
||||
gX7+9/oA40D3rz0Wf378PTwVzbYCF+hZo/H9yJGTUAZSz84zNbSLvKBZFPfabA2A
|
||||
l92uPgNWoct06uf7ubEJhwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAyH68yi+mf
|
||||
2HNwEscSLN1oU9uXNC4hwHi2xoPrpxoLsbhoc/aVhgd5peOEmIlOQPQofCO/JSKt
|
||||
HqidURSt8U+WrcsXz3HTdq+m/Qw3E/BA5CDXL/LUmIh43cZzkWSawx2EocJr7g1W
|
||||
JeAtUt8xpDtuLlTMjoGGmTsKQG7ub8NcYN7EEqWa2v+2qSTqvhASMs+cf7DT2HZI
|
||||
I3q2v6l1N+DcpO8ey8dbLhbhd4d+bGjyjEcT+clDHFrKsqiYDCS99sOmedmHoyZk
|
||||
+h+CzXICtqFSrAAGE/PoetQtJlojwnu9mJN/xj3i/zJTZTRh3jOGF8Hfg2bvwgdg
|
||||
vMYRLwtknqya
|
||||
-----END CERTIFICATE-----
|
BIN
Video/MiroTalk SFU/app/ssl/https.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
27
Video/MiroTalk SFU/app/ssl/key.pem
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEArn2tC9W6wqjDI7B/4LfEnE4ILBOdwa9889QjmWUToKua7iXT
|
||||
paSNP3SefKY50Q8TBFfkZXEGyqAESBUn2rYeHtebgLQTKHsixhSCdHqpBDOyYFeT
|
||||
ywGiRP4gQHFKbExdX2AAD1ptTjHVuSlg/ojWstESBh/4TktifKzy3PKVKX6p889e
|
||||
DfyJtlv0PADAkon/rZp3hHq0FORhvQEER1sm6g58WyIfqGWjW7bb7/bkyS1baQI1
|
||||
6fPeexfu1Rs7y4kxgX7+9/oA40D3rz0Wf378PTwVzbYCF+hZo/H9yJGTUAZSz84z
|
||||
NbSLvKBZFPfabA2Al92uPgNWoct06uf7ubEJhwIDAQABAoIBAAhskNota2LSevlS
|
||||
IBpdROS277YRDGC5dDLhXwac1qG/Jy+wK9OnahpSKwShkdECBU0EYUZ0ent11j8U
|
||||
pmPsvu+GQT+pcfNWXotpmhK9iUNmq4nzMHNwlMD3896omYs49JkSLW6QUw6fYU4b
|
||||
LU+ck6D2bwRUrsw433xdbSw1mfXyzyCIWfPNzRmkEcUkCe1RHkGqFv8FrePhezOB
|
||||
tByAwQQLtBt7FMioTSCedOe7B+tuxwqj5Px7Vr8K3x/PKccSId6hS2ihnptYB+n7
|
||||
3eAxoa049wazsW3SXJQrTxUB1z2bh2p2lA0AedgVNme1FCq4zzA7qa2WppcV2ava
|
||||
Gu+dCgECgYEA1xjLFQmiUqCJVqA99DZNvgiPecuHSe2+2QRIk10uUQcxQAF8K9XT
|
||||
ORpO05lc0ccPZt7tIbQytsnt/NxL2mnvXQ+dzzrQCsPu/HH8fLEaJ4xBdxuIFeDU
|
||||
qCBKYlckCQkDwnNYUqCZCNfxb0Csx98RBDYlwDwZa0hFsLPbGen538cCgYEAz6wh
|
||||
iRXZVTqfhy3meWYFmHqeMb0agFugl4d0Lwl/kI/0M62Jc1u1OU+uI6u5fuevEeBB
|
||||
xYjnaDpBuCWccLw6R5luc98QIbxldbx2A07rUGo2JlQafmDX8wI1GVBXgzOw7HAK
|
||||
jHhCw+ZgtvF2c1XjaTPaunKDomPX6Pjt6R23CEECgYEArRRvPbNt4Wz6djElCSC1
|
||||
N+ftg4TJjSx4eGog+CtvvJW8BJPtVdyORZGswknSzZ6O/yj8yTUV5c3g6apegxbh
|
||||
HBIX2wupIjB9WrdiAvgDYrVSbEREIc6zb8Hj+PPDtF2Dn/FurbY6zkntJad2ILKX
|
||||
H7tubxwtHA2gvkpLULPcdDsCgYAxm3WbUHvM7ycCXIWMhEFb7hZx3TFCbiDLcZDg
|
||||
V42AU9LKsW5+/u4oVY9MeA3kcaWRSJeNfyl/7UKboWhgSaZGSjFnPmaVGHLIEA/E
|
||||
tIpjeCudNkPp4mpTYziZ5mYxMhzWLeFnMqcIMrTxnnZkEKU1ESzzkr09AkqmHSh/
|
||||
ohiBwQKBgQCvaDQS7aBS/1+iBrOyMwxARwFirReJHdgEtkBVrB+sasbj1B4Jd3zO
|
||||
gL6FzxKCKBMIF+sSAjKs0XoRG1K6OPGFg1b5naEq023gObO6aBZqSXhHCajGK790
|
||||
Xhrvj6BojWkJUnc8T0cocrwhMJrTFC0u00KgAnRNyNYw1vccd5q2uQ==
|
||||
-----END RSA PRIVATE KEY-----
|
66
Video/MiroTalk SFU/docker-compose-traefik.yml
Normal file
@ -0,0 +1,66 @@
|
||||

|
||||
URL : HHHHH
|
||||
|
||||
# Fichier-Stockage
|
||||
|
||||
GGGGG
|
||||
|
||||
# Téléchargement, Configuration et Lancement
|
||||
|
||||
## Téléchargement de Fichier-Stockage
|
||||
|
||||
Saisir la commande pour télécharger la source
|
||||
```bash
|
||||
git clone https://git.tips-of-mine.fr/Tips-Of-Mine/Docker.git
|
||||
```
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd AAAAA\Fichier-Stockage
|
||||
```
|
||||
|
||||
## Modifier la configuration de Fichier-Stockage
|
||||
|
||||
Saisir la commande pour vous rendre dans le dossier
|
||||
```bash
|
||||
cd AAAAA\Fichier-Stockage
|
||||
```
|
||||
|
||||
Nous éditons le fichier de configuration
|
||||
```bash
|
||||
nano .env
|
||||
```
|
||||
|
||||
Nous modifions les variables dont nous avons besoin.
|
||||
|
||||
## Lancement de Fichier-Stockage
|
||||
|
||||
Pour utiliser Fichier-Stockage tout seul
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Pour utiliser Fichier-Stockage avec Traefik
|
||||
```bash
|
||||
docker compose -f docker-compose-traefik.yml up -d
|
||||
```
|
||||
|
||||
# Utilisation
|
||||
|
||||
## Accueil
|
||||
|
||||
Ouvrir une page web avec l'url :
|
||||
Pour une utilisation tout seul
|
||||
|
||||
http://10.0.4.29:3000
|
||||
|
||||
Pour une utilisation avec Traefik
|
||||
|
||||
https://Fichier-Stockage.10.0.4.29.traefik.me`)"
|
||||
|
||||
|
||||
# More info
|
||||
- more information on the website [Tips-Of-Mine](https://www.tips-of-mine.fr/)
|
||||
|
||||
# Buy me a coffe
|
||||
<a href='https://ko-fi.com/R5R2KNI3N' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi4.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
22
Video/MiroTalk SFU/docker-compose.template.yml
Normal file
@ -0,0 +1,22 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
mirotalksfu:
|
||||
image: mirotalk/sfu:latest
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: mirotalksfu
|
||||
hostname: mirotalksfu
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./app/src/config.js:/src/app/src/config.js:ro
|
||||
# These volume is mandatory if server.recording.enabled in the app/src/config.js
|
||||
# - ./app/rec:/src/app/rec
|
||||
# These volumes are not mandatory, comment if you want to use it
|
||||
# - ./app/:/src/app/:ro
|
||||
# - ./public/:/src/public/:ro
|
||||
ports:
|
||||
- '3010:3010/tcp'
|
||||
- '40000-40100:40000-40100/tcp'
|
||||
- '40000-40100:40000-40100/udp'
|
8
Video/MiroTalk SFU/docker-compose.yml
Normal file
@ -0,0 +1,8 @@
|
||||
#### NETWORKS
|
||||
networks:
|
||||
back_network:
|
||||
driver: bridge
|
||||
attachable: true
|
||||
|
||||
#### SERVICES
|
||||
services:
|
11
Video/MiroTalk SFU/docs/ngrok.md
Normal file
@ -0,0 +1,11 @@
|
||||
# MiroTalk SFU - Ngrok
|
||||
|
||||
### What is the purpose and functionality of Ngrok?
|
||||
|
||||
[https://docs.mirotalk.com/ngrok/ngrok/](https://docs.mirotalk.com/ngrok/ngrok/)
|
||||
|
||||
### How to exposing MiroTalk SFU with Ngrok?
|
||||
|
||||
[https://docs.mirotalk.com/mirotalk-sfu/ngrok/](https://docs.mirotalk.com/mirotalk-sfu/ngrok/)
|
||||
|
||||
---
|
7
Video/MiroTalk SFU/docs/self-hosting.md
Normal file
@ -0,0 +1,7 @@
|
||||
# MiroTalk SFU - Self Hosting
|
||||
|
||||
### How can I self-host MiroTalk SFU on my own server?
|
||||
|
||||
[https://docs.mirotalk.com/mirotalk-sfu/self-hosting/](https://docs.mirotalk.com/mirotalk-sfu/self-hosting/)
|
||||
|
||||
---
|
160
Video/MiroTalk SFU/install.sh
Normal file
@ -0,0 +1,160 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ============================================
|
||||
# RUN sudo ./install.sh
|
||||
# ============================================
|
||||
|
||||
set -e # Exit immediately if a command exits with a non-zero status
|
||||
|
||||
# -------------------------------------------------------
|
||||
# bash colors for log
|
||||
# -------------------------------------------------------
|
||||
|
||||
black=`tput setaf 0`
|
||||
red=`tput setaf 1`
|
||||
green=`tput setaf 2`
|
||||
yellow=`tput setaf 3`
|
||||
blue=`tput setaf 4`
|
||||
magenta=`tput setaf 5`
|
||||
cyan=`tput setaf 6`
|
||||
white=`tput setaf 7`
|
||||
reset=`tput sgr0`
|
||||
|
||||
# -------------------------------------------------------
|
||||
# print log level
|
||||
# -------------------------------------------------------
|
||||
function log() {
|
||||
date_now=`date '+%Y-%m-%d %H:%M:%S'`
|
||||
case $1 in
|
||||
debug) echo -e "${date_now} :: ${2}" ;;
|
||||
warning) echo -e "${date_now} :: ${yellow}${2}${reset}" ;;
|
||||
error) echo -e "${date_now} :: ${red}${2}${reset}" ;;
|
||||
*) echo -e "${date_now} :: ${magenta}${1}${reset}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Check if Linux OS
|
||||
# -------------------------------------------------------
|
||||
unamestr=$(uname)
|
||||
if [[ "$unamestr" != 'Linux' ]]; then
|
||||
log warning "This install script is supported only on Linux OS"
|
||||
exit
|
||||
fi
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Check if run as root
|
||||
# -------------------------------------------------------
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
log warning "Please run as root: sudo ./install.sh"
|
||||
exit
|
||||
fi
|
||||
|
||||
# ============================================
|
||||
# Start the installation...
|
||||
# ============================================
|
||||
|
||||
printf 'Install the dependences (y/n)? '
|
||||
read answer
|
||||
|
||||
if [ "$answer" != "${answer#[Yy]}" ] ;then
|
||||
|
||||
log "Update package lists"
|
||||
|
||||
apt-get update
|
||||
|
||||
log "Install essential build tools: gcc, g++, make"
|
||||
|
||||
apt-get install -y build-essential
|
||||
|
||||
|
||||
log "Install Python 3.8 and pip"
|
||||
|
||||
apt-get install -y software-properties-common
|
||||
|
||||
add-apt-repository -y ppa:deadsnakes/ppa
|
||||
|
||||
apt-get update
|
||||
|
||||
apt-get install -y python3.8 python3-pip
|
||||
|
||||
|
||||
log "Install Node.js 18.x and npm"
|
||||
|
||||
apt install -y curl dirmngr apt-transport-https lsb-release ca-certificates
|
||||
|
||||
curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
|
||||
|
||||
apt-get install -y nodejs
|
||||
|
||||
npm install -g npm@latest
|
||||
fi
|
||||
|
||||
CONFIG=app/src/config.js
|
||||
|
||||
if ! [ -f "$CONFIG" ]; then
|
||||
|
||||
log "Copy the configuration file"
|
||||
|
||||
cp app/src/config.template.js $CONFIG
|
||||
|
||||
fi
|
||||
|
||||
printf 'Use docker (y/n)? '
|
||||
read answer
|
||||
|
||||
if [ "$answer" != "${answer#[Yy]}" ] ;then
|
||||
|
||||
log "Install Docker and Docker Compose"
|
||||
|
||||
sudo apt install -y docker.io
|
||||
|
||||
sudo apt install -y docker-compose
|
||||
|
||||
|
||||
log "Add the current user to the docker group"
|
||||
|
||||
usermod -aG docker $USER
|
||||
|
||||
|
||||
YAML=docker-compose.yml
|
||||
|
||||
if ! [ -f "$YAML" ]; then
|
||||
|
||||
log "Copy Docker compose yaml file"
|
||||
|
||||
cp docker-compose.template.yml $YAML
|
||||
fi
|
||||
|
||||
printf 'Use official docker image (y/n)? '
|
||||
read answer
|
||||
|
||||
if [ "$answer" != "${answer#[Yy]}" ] ;then
|
||||
|
||||
log "Get latest official image from Docker Hub"
|
||||
|
||||
docker pull mirotalk/sfu:latest
|
||||
else
|
||||
log "Build image from source"
|
||||
|
||||
docker-compose build
|
||||
|
||||
|
||||
log "Remove old and unused docker images"
|
||||
|
||||
docker images |grep '<none>' |awk '{print $3}' |xargs docker rmi
|
||||
fi
|
||||
|
||||
log "Start containers"
|
||||
|
||||
docker-compose up #-d
|
||||
else
|
||||
log "Install dependencies"
|
||||
|
||||
npm install
|
||||
|
||||
|
||||
log "Start the server"
|
||||
|
||||
npm start
|
||||
fi
|
72
Video/MiroTalk SFU/package.json
Normal file
@ -0,0 +1,72 @@
|
||||
{
|
||||
"name": "mirotalksfu",
|
||||
"version": "1.4.20",
|
||||
"description": "WebRTC SFU browser-based video calls",
|
||||
"main": "Server.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node app/src/Server.js",
|
||||
"start-dev": "nodemon app/src/Server.js",
|
||||
"debug": "DEBUG='mediasoup*' node app/src/Server.js",
|
||||
"compile": "npx browserify public/sfu/MediasoupClientCompile.js -o public/sfu/MediasoupClient.js",
|
||||
"lint": "npx prettier --write .",
|
||||
"docker-build": "docker build --tag mirotalk/sfu:latest .",
|
||||
"docker-rmi": "docker images |grep '<none>' |awk '{print $3}' |xargs docker rmi",
|
||||
"docker-push": "docker push mirotalk/sfu:latest",
|
||||
"docker-pull": "docker pull mirotalk/sfu:latest",
|
||||
"docker-rmc": "docker container rm mirotalksfu --force",
|
||||
"docker-run": "docker run -d -p 40000-40100:40000-40100 -p 3010:3010 -v ./app/src/config.js:/src/app/src/config.js:ro --name mirotalksfu mirotalk/sfu:latest",
|
||||
"docker-run-vm": "docker run -d -p 40000-40100:40000-40100 -p 3010:3010 -v ./app/:/src/app/:ro -v ./public/:/src/public/:ro --name mirotalksfu mirotalk/sfu:latest",
|
||||
"docker-start": "docker start mirotalksfu",
|
||||
"docker-stop": "docker stop mirotalksfu"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/miroslavpejic85/mirotalksfu"
|
||||
},
|
||||
"keywords": [
|
||||
"webrtc",
|
||||
"socket.io",
|
||||
"broadcasting",
|
||||
"sfu",
|
||||
"nodejs",
|
||||
"video",
|
||||
"audio",
|
||||
"openai",
|
||||
"chatgpt"
|
||||
],
|
||||
"author": "Miroslav Pejic",
|
||||
"license": "AGPL-3.0",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/integrations": "7.110.1",
|
||||
"@sentry/node": "7.110.1",
|
||||
"axios": "^1.6.8",
|
||||
"body-parser": "1.20.2",
|
||||
"colors": "1.4.0",
|
||||
"compression": "1.7.4",
|
||||
"cors": "2.8.5",
|
||||
"crypto-js": "4.2.0",
|
||||
"express": "4.19.2",
|
||||
"httpolyglot": "0.1.2",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mediasoup": "3.14.1",
|
||||
"mediasoup-client": "3.7.7",
|
||||
"ngrok": "^5.0.0-beta.2",
|
||||
"nodemailer": "^6.9.13",
|
||||
"openai": "^4.37.0",
|
||||
"qs": "6.12.1",
|
||||
"socket.io": "4.7.5",
|
||||
"swagger-ui-express": "5.0.0",
|
||||
"uuid": "9.0.1",
|
||||
"xss": "^1.0.15",
|
||||
"yamljs": "0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"node-fetch": "^3.3.2",
|
||||
"nodemon": "^3.1.0",
|
||||
"prettier": "3.2.5"
|
||||
}
|
||||
}
|
BIN
Video/MiroTalk SFU/public/advertisers/Contabo.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
Video/MiroTalk SFU/public/advertisers/ContaboLogo.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
365
Video/MiroTalk SFU/public/css/GroupChat.css
Normal file
@ -0,0 +1,365 @@
|
||||
.container {
|
||||
padding: 2px !important;
|
||||
transition:
|
||||
width 0.5s,
|
||||
background 2s ease !important;
|
||||
/* overflow-y: auto;
|
||||
overflow-x: hidden; */
|
||||
}
|
||||
|
||||
/* Chat Room */
|
||||
.chat-container {
|
||||
z-index: 5;
|
||||
position: relative;
|
||||
width: var(--msger-width);
|
||||
height: var(--msger-height);
|
||||
min-width: var(--msger-width);
|
||||
min-height: var(--msger-height);
|
||||
padding: 3px;
|
||||
background: var(--msger-bg);
|
||||
border: var(--border);
|
||||
border-radius: 10px;
|
||||
box-shadow: var(--box-shadow);
|
||||
transition: background 1s;
|
||||
/* border: 1px solid lime; */
|
||||
}
|
||||
|
||||
/* Chat app container */
|
||||
.chat-app {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
/* border: 1px solid lime; */
|
||||
}
|
||||
|
||||
/* Chat app people container */
|
||||
.chat-app .people-list {
|
||||
z-index: 6;
|
||||
position: absolute;
|
||||
padding: 20px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 300px;
|
||||
height: 99%;
|
||||
background: var(--msger-bg);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
/* border: 1px solid lime; */
|
||||
}
|
||||
|
||||
/* Chat app people list container */
|
||||
.people-list {
|
||||
-moz-transition: 0.5s;
|
||||
-o-transition: 0.5s;
|
||||
-webkit-transition: 0.5s;
|
||||
transition: 0.5s;
|
||||
/* border: 1px solid lime; */
|
||||
}
|
||||
|
||||
.people-list .chat-list li {
|
||||
padding: 10px 15px;
|
||||
list-style: none;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.people-list .chat-list li:hover {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.people-list .chat-list li.active {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.people-list .chat-list li .name {
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.people-list .chat-list img {
|
||||
width: 45px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.people-list img {
|
||||
float: left;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.people-list .about {
|
||||
float: left;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.people-list .about-buttons {
|
||||
margin-top: 35px;
|
||||
width: auto;
|
||||
/* display: inline-flex; */
|
||||
}
|
||||
|
||||
.people-list .status {
|
||||
color: #999;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Chat app people list container */
|
||||
.chat-app .chat-list {
|
||||
height: auto;
|
||||
/* border: 1px solid lime; */
|
||||
}
|
||||
|
||||
/* Chat app container */
|
||||
.chat-app .chat {
|
||||
position: relative;
|
||||
margin-left: 300px;
|
||||
border-left: var(--border);
|
||||
border-radius: 10px;
|
||||
/* border: 1px solid lime; */
|
||||
}
|
||||
|
||||
/* Chat header */
|
||||
.chat .chat-header {
|
||||
padding: 15px 20px; /* top, right, bottom, left */
|
||||
border-bottom: var(--border);
|
||||
height: 70px;
|
||||
max-height: 70px;
|
||||
cursor: move;
|
||||
/* overflow-x: auto; */
|
||||
/* border: 1px solid lime; */
|
||||
}
|
||||
|
||||
.all-participants-img {
|
||||
border: var(--border);
|
||||
width: 40px;
|
||||
margin-right: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.all-participants-img:hover {
|
||||
background-color: lime;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.chat .chat-header img {
|
||||
float: left;
|
||||
border-radius: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.chat .chat-header .chat-about {
|
||||
float: left;
|
||||
padding-left: 10px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.chat .chat-header .status {
|
||||
color: #999;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.chat .chat-header .chat-option-buttons {
|
||||
position: absolute;
|
||||
display: inline-flex;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
/* Chat history */
|
||||
.chat .chat-history {
|
||||
padding: 20px;
|
||||
height: calc(100vh - 210px);
|
||||
min-height: 490px;
|
||||
max-height: 490px;
|
||||
border-bottom: var(--border);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
/* border: 1px solid lime; */
|
||||
}
|
||||
|
||||
.chat .chat-history ul {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.chat .chat-history ul li {
|
||||
list-style: none;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.chat .chat-history ul li:last-child {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.chat .chat-history .message-data {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.chat .chat-history .message-data img {
|
||||
border-radius: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.chat .chat-history .message-data-time {
|
||||
color: #eeeeee;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
/* chat message bubble */
|
||||
.chat .chat-history .message {
|
||||
color: #fff;
|
||||
padding: 18px 20px;
|
||||
line-height: 26px;
|
||||
font-size: 16px;
|
||||
max-width: 100%;
|
||||
border-radius: 7px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
/* border: 1px solid lime; */
|
||||
}
|
||||
|
||||
.chat .chat-history .message:after {
|
||||
bottom: 100%;
|
||||
left: 7%;
|
||||
border: solid transparent;
|
||||
content: ' ';
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border-bottom-color: grey;
|
||||
border-width: 10px;
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
.chat .chat-history .my-message {
|
||||
background: var(--right-msg-bg);
|
||||
}
|
||||
|
||||
.chat .chat-history .my-message:after {
|
||||
bottom: 100%;
|
||||
left: 30px;
|
||||
border: solid transparent;
|
||||
content: ' ';
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border-bottom-color: #999;
|
||||
border-width: 10px;
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
.chat .chat-history .other-message {
|
||||
background: var(--left-msg-bg);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.chat .chat-history .other-message:after {
|
||||
border-bottom-color: grey;
|
||||
left: 93%;
|
||||
}
|
||||
|
||||
/* Chat message */
|
||||
.chat .chat-message {
|
||||
padding: 20px;
|
||||
max-height: 140px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
/* border: 1px solid lime; */
|
||||
}
|
||||
|
||||
/* Chat emoji */
|
||||
.chatEmojiPicker {
|
||||
z-index: 0;
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
bottom: 135px;
|
||||
}
|
||||
|
||||
/* status */
|
||||
.online,
|
||||
.offline,
|
||||
.me {
|
||||
margin-right: 2px;
|
||||
font-size: 8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.online {
|
||||
color: #86c541;
|
||||
}
|
||||
.offline {
|
||||
color: #e47297;
|
||||
}
|
||||
.me {
|
||||
color: #1d8ecd;
|
||||
}
|
||||
|
||||
.float-right {
|
||||
float: right;
|
||||
}
|
||||
.float-left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.inline {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.absolute {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.clearfix:after {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
font-size: 0;
|
||||
content: ' ';
|
||||
clear: both;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/** common **/
|
||||
.mt5 {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.mt10 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.mr5 {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.ml5 {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.ml10 {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
/* Chat search and input message */
|
||||
textarea,
|
||||
input[type='text'] {
|
||||
background: var(--msger-bg) !important;
|
||||
color: #fff !important;
|
||||
transition: height 0.5s !important;
|
||||
}
|
||||
|
||||
.form-check-input {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.hr {
|
||||
border: 0;
|
||||
display: block;
|
||||
height: 1px;
|
||||
background: #000000;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 10px;
|
||||
}
|
1302
Video/MiroTalk SFU/public/css/Room.css
Normal file
47
Video/MiroTalk SFU/public/css/Snow.css
Normal file
@ -0,0 +1,47 @@
|
||||
#snow-container {
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
transition: opacity 500ms;
|
||||
}
|
||||
|
||||
.snow {
|
||||
position: absolute;
|
||||
animation:
|
||||
fall ease-in infinite,
|
||||
sway ease-in-out infinite;
|
||||
color: skyblue;
|
||||
}
|
||||
|
||||
@keyframes fall {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 100vh;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sway {
|
||||
0% {
|
||||
margin-left: 0;
|
||||
}
|
||||
25% {
|
||||
margin-left: 50px;
|
||||
}
|
||||
50% {
|
||||
margin-left: -50px;
|
||||
}
|
||||
75% {
|
||||
margin-left: 50px;
|
||||
}
|
||||
100% {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
244
Video/MiroTalk SFU/public/css/VideoGrid.css
Normal file
@ -0,0 +1,244 @@
|
||||
/*--------------------------------------------------------------
|
||||
# Video grid
|
||||
--------------------------------------------------------------*/
|
||||
|
||||
#videoMediaContainer {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
align-content: center;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
vertical-align: middle;
|
||||
overflow: hidden;
|
||||
/* border: 3px solid blue; */
|
||||
}
|
||||
|
||||
#videoPinMediaContainer {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
display: none;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 75%;
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
box-shadow: var(--box-shadow);
|
||||
overflow: hidden;
|
||||
/* animation: show 0.4s ease; */
|
||||
/* border: 3px solid lime; */
|
||||
}
|
||||
|
||||
.Camera {
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
align-self: center;
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
background: transparent;
|
||||
border-radius: 10px;
|
||||
border: var(--border);
|
||||
box-shadow: var(--box-shadow);
|
||||
animation: show 0.4s ease;
|
||||
}
|
||||
|
||||
/* .Camera:hover {
|
||||
border: 3px solid rgb(113, 157, 239);
|
||||
} */
|
||||
|
||||
#videoMediaContainer i {
|
||||
position: absolute;
|
||||
display: none;
|
||||
top: 0;
|
||||
color: rgb(0, 255, 71);
|
||||
font-size: 14px;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
width: auto;
|
||||
height: 25px;
|
||||
border-radius: 5px;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.videoAvatarImage {
|
||||
z-index: 7;
|
||||
position: absolute;
|
||||
display: none;
|
||||
width: var(--vmi-wh);
|
||||
height: var(--vmi-wh);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.audio {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
color: #fff;
|
||||
margin: 5px;
|
||||
width: auto;
|
||||
height: 25px;
|
||||
border-radius: 5px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.username {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
color: #fff;
|
||||
font-size: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
width: auto;
|
||||
height: 25px;
|
||||
border-radius: 5px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.fscreen {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0px;
|
||||
color: #fff;
|
||||
margin: 5px;
|
||||
width: auto;
|
||||
height: 25px;
|
||||
border-radius: 5px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.videoMenuBar {
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
display: inline;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding: 10px;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
font-size: small;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
cursor: default;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.videoMenuBar input,
|
||||
.videoMenuBar button {
|
||||
float: right;
|
||||
color: #fff;
|
||||
background: transparent;
|
||||
border-radius: 5px;
|
||||
display: inline;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.videoMenuBar button:hover {
|
||||
color: grey;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.expand-video-content {
|
||||
position: relative;
|
||||
display: none;
|
||||
float: right;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.expand-video:hover .expand-video-content {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
#videoMediaContainer video {
|
||||
position: absolute;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.videoCircle {
|
||||
position: absolute;
|
||||
width: var(--vmi-wh);
|
||||
height: var(--vmi-wh);
|
||||
border-radius: 50%;
|
||||
/* center */
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.videoDefault {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: '10px';
|
||||
}
|
||||
|
||||
video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: var(--videoObjFit);
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
video:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
video:fullscreen {
|
||||
object-fit: contain;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.mirror {
|
||||
-webkit-transform: rotateY(180deg);
|
||||
-moz-transform: rotateY(180deg);
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
.blur {
|
||||
-webkit-filter: blur(5px);
|
||||
-moz-filter: blur(5px);
|
||||
-o-filter: blur(5px);
|
||||
-ms-filter: blur(5px);
|
||||
filter: blur(5px);
|
||||
}
|
||||
|
||||
input[type='range'] {
|
||||
/* display: none; */
|
||||
color: #fff;
|
||||
width: 50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@keyframes show {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scale(0.4) translateY(20px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.username {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 500px) {
|
||||
.username {
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
2031
Video/MiroTalk SFU/public/css/landing.css
Normal file
BIN
Video/MiroTalk SFU/public/images/AGPLv3.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
Video/MiroTalk SFU/public/images/all.png
Normal file
After Width: | Height: | Size: 9.3 KiB |
590
Video/MiroTalk SFU/public/images/architecture.svg
Normal file
@ -0,0 +1,590 @@
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1516px" height="1313px" viewBox="-0.5 -0.5 1516 1313">
|
||||
<defs>
|
||||
<linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="mx-gradient-e3e3e3-1-9c9c9c-1-s-0">
|
||||
<stop offset="0%" style="stop-color:#E3E3E3"/>
|
||||
<stop offset="100%" style="stop-color:#9C9C9C"/>
|
||||
</linearGradient>
|
||||
<linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="mx-gradient-ffffff-1-e3e3e3-1-s-0">
|
||||
<stop offset="0%" style="stop-color:#ffffff"/>
|
||||
<stop offset="100%" style="stop-color:#E3E3E3"/>
|
||||
</linearGradient>
|
||||
<linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="mx-gradient-ea6b66-1-ff3333-1-s-0">
|
||||
<stop offset="0%" style="stop-color:#EA6B66"/>
|
||||
<stop offset="100%" style="stop-color:#FF3333"/>
|
||||
</linearGradient>
|
||||
<linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="mx-gradient-66cc00-1-4d9900-1-s-0">
|
||||
<stop offset="0%" style="stop-color:#66CC00"/>
|
||||
<stop offset="100%" style="stop-color:#4D9900"/>
|
||||
</linearGradient>
|
||||
<linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="mx-gradient-70a9ff-1-2e89ff-1-s-0">
|
||||
<stop offset="0%" style="stop-color:#70A9FF"/>
|
||||
<stop offset="100%" style="stop-color:#2E89FF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g>
|
||||
<rect x="275" y="21" width="980" height="1240" rx="19.6" ry="19.6" fill="url(#mx-gradient-e3e3e3-1-9c9c9c-1-s-0)" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(743.5,1270.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="42" height="22" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 20px; font-family: Helvetica; color: rgb(120, 120, 120); line-height: 1.2; vertical-align: top; width: 42px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Host</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="21" y="21" fill="#787878" text-anchor="middle" font-size="20px" font-family="Helvetica">Host</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="325" y="71" width="883" height="640" rx="19.2" ry="19.2" fill="url(#mx-gradient-ffffff-1-e3e3e3-1-s-0)" stroke="#616161" stroke-width="2" pointer-events="none"/>
|
||||
<g transform="translate(725.5,721.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="80" height="22" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 20px; font-family: Helvetica; color: rgb(97, 97, 97); line-height: 1.2; vertical-align: top; width: 82px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Worker 1</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="40" y="21" fill="#616161" text-anchor="middle" font-size="20px" font-family="Helvetica">Worker 1</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="357.5" y="121" width="150" height="150" rx="22.5" ry="22.5" fill="#ffffff" stroke="#666666" stroke-width="2" stroke-dasharray="2 4" pointer-events="none"/>
|
||||
<g transform="translate(369.5,278.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="125" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(102, 102, 102); line-height: 1.2; vertical-align: top; width: 125px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">WebRtcTransport</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="63" y="17" fill="#666666" text-anchor="middle" font-size="16px" font-family="Helvetica">WebRtcTransport</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 508 196 L 709.76 196" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 717.76 196 L 709.76 200 L 709.76 192 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 382.5 136 L 472.5 136 L 472.5 136 L 482.5 151 L 472.5 166 L 472.5 166 L 382.5 166 L 392.5 151 Z" fill="url(#mx-gradient-ea6b66-1-ff3333-1-s-0)" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(377.5,172.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="110" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(255, 51, 51); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Audio Producer</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="55" y="17" fill="#FF3333" text-anchor="middle" font-size="16px" font-family="Helvetica">Audio Producer</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 382.5 206 L 472.5 206 L 472.5 206 L 482.5 221 L 472.5 236 L 472.5 236 L 382.5 236 L 392.5 221 Z" fill="url(#mx-gradient-ea6b66-1-ff3333-1-s-0)" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(377.5,242.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="110" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(255, 51, 51); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Video Producer</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="55" y="17" fill="#FF3333" text-anchor="middle" font-size="16px" font-family="Helvetica">Video Producer</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 820 196 L 1004.85 172.3" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1012.78 171.28 L 1005.36 176.27 L 1004.34 168.33 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 820 196 L 1011.57 328.19" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1018.16 332.73 L 1009.3 331.48 L 1013.85 324.89 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<rect x="357.5" y="366" width="150" height="90" rx="13.5" ry="13.5" fill="#ffffff" stroke="#666666" stroke-width="2" stroke-dasharray="2 4" pointer-events="none"/>
|
||||
<g transform="translate(367.5,463.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="129" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(102, 102, 102); line-height: 1.2; vertical-align: top; width: 129px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">PlainRtpTransport</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="65" y="17" fill="#666666" text-anchor="middle" font-size="16px" font-family="Helvetica">PlainRtpTransport</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 382.5 391 L 472.5 391 L 472.5 391 L 482.5 406 L 472.5 421 L 472.5 421 L 382.5 421 L 392.5 406 Z" fill="url(#mx-gradient-ea6b66-1-ff3333-1-s-0)" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(377.5,427.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="110" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(255, 51, 51); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Video Producer</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="55" y="17" fill="#FF3333" text-anchor="middle" font-size="16px" font-family="Helvetica">Video Producer</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 483 406 L 709.76 406" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 717.76 406 L 709.76 410 L 709.76 402 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<rect x="555" y="548.5" width="155" height="130" rx="19.5" ry="19.5" fill="#ffffff" stroke="#666666" stroke-width="2" stroke-dasharray="2 4" pointer-events="none"/>
|
||||
<g transform="translate(668.5,613.5)rotate(-90,49.5,0)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="99" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(102, 102, 102); line-height: 1.2; vertical-align: top; width: 101px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">PipeTransport</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="50" y="17" fill="#666666" text-anchor="middle" font-size="16px" font-family="Helvetica">PipeTransport</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 582 598.5 L 672 598.5 L 672 598.5 L 682 613.5 L 672 628.5 L 672 628.5 L 582 628.5 L 592 613.5 Z" fill="url(#mx-gradient-66cc00-1-4d9900-1-s-0)" stroke="none" transform="rotate(90,632,613.5)" pointer-events="none"/>
|
||||
<g transform="translate(602.5,604.5)rotate(-90,59.5,8.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="119" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(77, 153, 0); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Video Consumer</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="60" y="17" fill="#4D9900" text-anchor="middle" font-size="16px" font-family="Helvetica">Video Consumer</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 770 456 L 641.47 543.25" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 634.85 547.74 L 639.22 539.94 L 643.72 546.56 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 114 196 L 347.26 196" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 355.26 196 L 347.26 200 L 347.26 192 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#999999" font-family="Helvetica" text-anchor="middle" font-size="14px">
|
||||
<rect fill="#ffffff" stroke="none" x="217" y="189" width="39" height="17" stroke-width="0"/>
|
||||
<text x="235" y="200.5">SRTP</text>
|
||||
</g>
|
||||
<path d="M 1175 171 L 1414.76 169.08" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1422.76 169.02 L 1414.8 173.08 L 1414.73 165.08 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#999999" font-family="Helvetica" text-anchor="middle" font-size="14px">
|
||||
<rect fill="#ffffff" stroke="none" x="1280" y="163" width="39" height="17" stroke-width="0"/>
|
||||
<text x="1299" y="174.5">SRTP</text>
|
||||
</g>
|
||||
<path d="M 89.53 210.86 C 90.09 210.86 90.48 210.64 90.37 210.48 L 89.26 208.86 C 89.12 208.61 88.92 208.57 88.59 208.57 L 81.41 208.57 C 81.06 208.57 80.88 208.62 80.71 208.87 L 79.68 210.47 C 79.48 210.72 80.08 210.86 80.51 210.86 Z M 106.32 205.61 L 106.32 181.96 L 63.65 181.96 L 63.65 205.61 Z M 59 213 C 57.87 212.99 56.85 212.62 56.42 212.03 C 56 211.46 56.17 210.89 56.53 210.5 L 60.66 206.35 L 60.66 181.83 C 60.66 180.6 61.78 179 63.63 179 L 106.33 179 C 107.77 179 109.31 180.14 109.31 181.99 L 109.31 206.35 L 113.48 210.54 C 113.83 210.93 114 211.45 113.58 212.01 C 113.03 212.72 111.99 212.95 111.02 213 Z" fill="#505050" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(23.5,219.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="122" height="36" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(120, 120, 120); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Participant<br />
|
||||
(mic/webcam on)<br />
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="61" y="26" fill="#787878" text-anchor="middle" font-size="16px" font-family="Helvetica">Participant<br>(mic/webcam on)<br></text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 1443.63 187.3 L 1484.45 187.3 L 1484.45 167.14 L 1443.63 167.14 Z M 1442.65 190.29 C 1441.41 190.29 1440.08 189.41 1440.08 188.09 L 1440.08 166.3 C 1440.08 165.24 1441.14 164.15 1442.69 164.15 L 1485.4 164.15 C 1486.96 164.15 1488 165.27 1488 166.29 L 1488 188 C 1488 189.32 1486.89 190.29 1485.27 190.29 L 1469.72 190.29 C 1469.41 191.2 1469.11 192.17 1469.05 192.99 C 1468.92 194.69 1470.19 195.17 1472.47 195.44 C 1473.99 195.6 1475.34 195.63 1476.78 195.66 C 1477.66 195.66 1478.5 196.2 1478.5 197.08 C 1478.5 197.92 1477.78 198.5 1476.8 198.5 L 1451.34 198.5 C 1450.44 198.5 1449.67 197.88 1449.67 197.08 C 1449.67 196.36 1450.34 195.66 1451.34 195.66 C 1453.02 195.61 1454.73 195.61 1456.49 195.32 C 1458.19 195.05 1459.23 194.52 1459.04 192.9 C 1458.97 192.17 1458.67 191.2 1458.36 190.29 Z M 1431.21 151.46 L 1450.73 151.46 L 1450.73 149.22 L 1431.21 149.22 Z M 1425 194.77 L 1425 145.43 C 1425 143.74 1426.81 142.5 1428.4 142.5 L 1453.5 142.5 C 1455.25 142.5 1456.94 143.82 1456.94 145.43 L 1456.94 161.91 L 1442.56 161.91 C 1439.86 161.91 1437.42 164.02 1437.42 166.25 L 1437.42 179.83 L 1431.21 179.83 L 1431.21 182.07 L 1437.42 182.07 L 1437.42 186.55 L 1431.21 186.55 L 1431.21 188.79 L 1437.49 188.79 C 1438 191.15 1440.47 192.53 1442.55 192.53 L 1456.23 192.53 C 1456.23 192.71 1456.33 192.9 1456.32 193.04 C 1455.42 193.29 1453.39 193.42 1451.68 193.42 C 1450.92 193.39 1450.27 193.47 1449.61 193.7 C 1448.96 193.92 1448.39 194.28 1447.9 194.77 Z" fill="#505050" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(1418.5,205.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="76" height="36" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(120, 120, 120); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Participant<br />
|
||||
(viewer)<br />
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="38" y="26" fill="#787878" text-anchor="middle" font-size="16px" font-family="Helvetica">[Not supported by viewer]</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 1175 334 L 1423.76 334.44" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1431.76 334.46 L 1423.76 338.44 L 1423.77 330.44 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#999999" font-family="Helvetica" text-anchor="middle" font-size="14px">
|
||||
<rect fill="#ffffff" stroke="none" x="1290" y="327" width="30" height="17" stroke-width="0"/>
|
||||
<text x="1304" y="338.73">RTP</text>
|
||||
</g>
|
||||
<path d="M 1461.13 335.37 C 1461.51 334.99 1461.76 334.05 1461.03 333.31 L 1447.88 320.84 C 1446.97 320.1 1445.62 319.95 1444.53 320.91 C 1443.45 322.03 1443.76 323.6 1444.56 324.37 L 1455.04 334.31 L 1444.68 343.47 C 1443.82 344.27 1443.46 345.56 1444.14 346.7 C 1445.05 348.16 1446.84 348.07 1447.82 347.23 Z M 1468.15 347.92 C 1468.97 347.92 1469.98 347.24 1469.98 346.03 C 1469.98 345.03 1469.22 344.15 1468.13 344.15 L 1457.66 344.15 C 1456.99 344.15 1455.86 344.74 1455.86 345.99 C 1455.86 347.13 1456.74 347.92 1457.69 347.92 Z M 1436.88 357 C 1435.4 357 1434 355.74 1434 354.13 L 1434 314.82 C 1434 313.19 1435.53 312 1436.79 312 L 1476.05 312 C 1477.64 312 1479 313.26 1479 314.91 L 1479 354.11 C 1479 355.9 1477.5 357 1476.21 357 Z" fill="#505050" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(1417.5,363.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="77" height="36" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(120, 120, 120); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">FFmpeg<br />
|
||||
(recording)<br />
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="39" y="26" fill="#787878" text-anchor="middle" font-size="16px" font-family="Helvetica">[Not supported by viewer]</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 89.42 411.87 C 89.8 411.49 90.05 410.55 89.32 409.81 L 76.18 397.34 C 75.27 396.6 73.91 396.45 72.82 397.41 C 71.74 398.53 72.05 400.1 72.85 400.87 L 83.33 410.81 L 72.97 419.97 C 72.11 420.77 71.75 422.06 72.43 423.2 C 73.34 424.66 75.14 424.57 76.12 423.73 Z M 96.44 424.42 C 97.27 424.42 98.28 423.74 98.28 422.53 C 98.28 421.53 97.52 420.65 96.42 420.65 L 85.96 420.65 C 85.28 420.65 84.15 421.24 84.15 422.49 C 84.15 423.63 85.03 424.42 85.99 424.42 Z M 65.17 433.5 C 63.7 433.5 62.29 432.24 62.29 430.63 L 62.29 391.32 C 62.29 389.69 63.83 388.5 65.09 388.5 L 104.35 388.5 C 105.93 388.5 107.29 389.76 107.29 391.41 L 107.29 430.61 C 107.29 432.4 105.79 433.5 104.5 433.5 Z" fill="#505050" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(18.5,440.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="131" height="36" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(120, 120, 120); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">GStreamer<br />
|
||||
(mp4 broadcaster)<br />
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="66" y="26" fill="#787878" text-anchor="middle" font-size="16px" font-family="Helvetica">GStreamer<br>(mp4 broadcaster)<br></text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 107.29 411 L 347.76 411" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 355.76 411 L 347.76 415 L 347.76 407 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#999999" font-family="Helvetica" text-anchor="middle" font-size="14px">
|
||||
<rect fill="#ffffff" stroke="none" x="217" y="404" width="30" height="17" stroke-width="0"/>
|
||||
<text x="231.29" y="415.5">RTP</text>
|
||||
</g>
|
||||
<path d="M 780 382 L 794 382 L 794 396 L 800 396 L 800 386 L 820 406 L 800 426 L 800 416 L 794 416 L 794 430 L 780 430 L 780 436 L 790 436 L 770 456 L 750 436 L 760 436 L 760 430 L 746 430 L 746 416 L 740 416 L 740 426 L 720 406 L 740 386 L 740 396 L 746 396 L 746 382 L 760 382 L 760 376 L 750 376 L 770 356 L 790 376 L 780 376 Z" fill="url(#mx-gradient-70a9ff-1-2e89ff-1-s-0)" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(831.5,394.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="77" height="22" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 20px; font-family: Helvetica; color: rgb(46, 137, 255); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Router 2</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="39" y="21" fill="#2E89FF" text-anchor="middle" font-size="20px" font-family="Helvetica">Router 2</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 780 172 L 794 172 L 794 186 L 800 186 L 800 176 L 820 196 L 800 216 L 800 206 L 794 206 L 794 220 L 780 220 L 780 226 L 790 226 L 770 246 L 750 226 L 760 226 L 760 220 L 746 220 L 746 206 L 740 206 L 740 216 L 720 196 L 740 176 L 740 186 L 746 186 L 746 172 L 760 172 L 760 166 L 750 166 L 770 146 L 790 166 L 780 166 Z" fill="url(#mx-gradient-70a9ff-1-2e89ff-1-s-0)" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(731.5,252.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="77" height="22" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 20px; font-family: Helvetica; color: rgb(46, 137, 255); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Router 1</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="39" y="21" fill="#2E89FF" text-anchor="middle" font-size="20px" font-family="Helvetica">Router 1</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="325" y="761" width="425" height="450" rx="12.75" ry="12.75" fill="url(#mx-gradient-ffffff-1-e3e3e3-1-s-0)" stroke="#616161" stroke-width="2" pointer-events="none"/>
|
||||
<g transform="translate(496.5,1221.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="80" height="22" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 20px; font-family: Helvetica; color: rgb(97, 97, 97); line-height: 1.2; vertical-align: top; width: 82px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Worker 2</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="40" y="21" fill="#616161" text-anchor="middle" font-size="20px" font-family="Helvetica">Worker 2</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="819.5" y="548.5" width="155" height="130" rx="19.5" ry="19.5" fill="#ffffff" stroke="#666666" stroke-width="2" stroke-dasharray="2 4" pointer-events="none"/>
|
||||
<g transform="translate(932.5,613.5)rotate(-90,49.5,0)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="99" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(102, 102, 102); line-height: 1.2; vertical-align: top; width: 101px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">PipeTransport</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="50" y="17" fill="#666666" text-anchor="middle" font-size="16px" font-family="Helvetica">PipeTransport</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 846.5 598.5 L 936.5 598.5 L 936.5 598.5 L 946.5 613.5 L 936.5 628.5 L 936.5 628.5 L 846.5 628.5 L 856.5 613.5 Z" fill="url(#mx-gradient-66cc00-1-4d9900-1-s-0)" stroke="none" transform="rotate(90,896.5,613.5)" pointer-events="none"/>
|
||||
<g transform="translate(866.5,604.5)rotate(-90,59.5,8.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="119" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(77, 153, 0); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Video Consumer</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="60" y="17" fill="#4D9900" text-anchor="middle" font-size="16px" font-family="Helvetica">Video Consumer</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 770 456 L 888.74 542.95" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 895.2 547.68 L 886.38 546.18 L 891.1 539.73 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 642 1022 L 656 1022 L 656 1036 L 662 1036 L 662 1026 L 682 1046 L 662 1066 L 662 1056 L 656 1056 L 656 1070 L 642 1070 L 642 1076 L 652 1076 L 632 1096 L 612 1076 L 622 1076 L 622 1070 L 608 1070 L 608 1056 L 602 1056 L 602 1066 L 582 1046 L 602 1026 L 602 1036 L 608 1036 L 608 1022 L 622 1022 L 622 1016 L 612 1016 L 632 996 L 652 1016 L 642 1016 Z" fill="url(#mx-gradient-70a9ff-1-2e89ff-1-s-0)" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(593.5,1102.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="77" height="22" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 20px; font-family: Helvetica; color: rgb(46, 137, 255); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Router 3</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="39" y="21" fill="#2E89FF" text-anchor="middle" font-size="20px" font-family="Helvetica">Router 3</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="554.5" y="791" width="155" height="130" rx="19.5" ry="19.5" fill="#ffffff" stroke="#666666" stroke-width="2" stroke-dasharray="2 4" pointer-events="none"/>
|
||||
<g transform="translate(667.5,856.5)rotate(-90,49.5,0)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="99" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(102, 102, 102); line-height: 1.2; vertical-align: top; width: 101px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">PipeTransport</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="50" y="17" fill="#666666" text-anchor="middle" font-size="16px" font-family="Helvetica">PipeTransport</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 582 841 L 672 841 L 672 841 L 682 856 L 672 871 L 672 871 L 582 871 L 592 856 Z" fill="url(#mx-gradient-ea6b66-1-ff3333-1-s-0)" stroke="none" transform="rotate(90,632,856)" pointer-events="none"/>
|
||||
<g transform="translate(606.5,847.5)rotate(-90,55,8.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="110" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(255, 51, 51); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Video Producer</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="55" y="17" fill="#FF3333" text-anchor="middle" font-size="16px" font-family="Helvetica">Video Producer</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="785" y="761" width="425" height="450" rx="12.75" ry="12.75" fill="url(#mx-gradient-ffffff-1-e3e3e3-1-s-0)" stroke="#616161" stroke-width="2" pointer-events="none"/>
|
||||
<g transform="translate(956.5,1221.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="80" height="22" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 20px; font-family: Helvetica; color: rgb(97, 97, 97); line-height: 1.2; vertical-align: top; width: 82px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Worker 3</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="40" y="21" fill="#616161" text-anchor="middle" font-size="20px" font-family="Helvetica">Worker 3</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="824.5" y="791" width="150" height="130" rx="19.5" ry="19.5" fill="#ffffff" stroke="#666666" stroke-width="2" stroke-dasharray="2 4" pointer-events="none"/>
|
||||
<g transform="translate(932.5,856.5)rotate(-90,49.5,0)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="99" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(102, 102, 102); line-height: 1.2; vertical-align: top; width: 101px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">PipeTransport</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="50" y="17" fill="#666666" text-anchor="middle" font-size="16px" font-family="Helvetica">PipeTransport</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 847 841 L 937 841 L 937 841 L 947 856 L 937 871 L 937 871 L 847 871 L 857 856 Z" fill="url(#mx-gradient-ea6b66-1-ff3333-1-s-0)" stroke="none" transform="rotate(90,897,856)" pointer-events="none"/>
|
||||
<g transform="translate(871.5,847.5)rotate(-90,55,8.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="110" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(255, 51, 51); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Video Producer</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="55" y="17" fill="#FF3333" text-anchor="middle" font-size="16px" font-family="Helvetica">Video Producer</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 907.5 1022 L 921.5 1022 L 921.5 1036 L 927.5 1036 L 927.5 1026 L 947.5 1046 L 927.5 1066 L 927.5 1056 L 921.5 1056 L 921.5 1070 L 907.5 1070 L 907.5 1076 L 917.5 1076 L 897.5 1096 L 877.5 1076 L 887.5 1076 L 887.5 1070 L 873.5 1070 L 873.5 1056 L 867.5 1056 L 867.5 1066 L 847.5 1046 L 867.5 1026 L 867.5 1036 L 873.5 1036 L 873.5 1022 L 887.5 1022 L 887.5 1016 L 877.5 1016 L 897.5 996 L 917.5 1016 L 907.5 1016 Z" fill="url(#mx-gradient-70a9ff-1-2e89ff-1-s-0)" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(858.5,1102.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="77" height="22" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 20px; font-family: Helvetica; color: rgb(46, 137, 255); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Router 4</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="39" y="21" fill="#2E89FF" text-anchor="middle" font-size="20px" font-family="Helvetica">Router 4</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 633 679 L 632.09 780.76" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 632.02 788.76 L 628.09 780.73 L 636.09 780.8 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#999999" font-family="Helvetica" text-anchor="middle" font-size="14px">
|
||||
<rect fill="#ffffff" stroke="none" x="618" y="727" width="30" height="17" stroke-width="0"/>
|
||||
<text x="631.5" y="739.5">RTP</text>
|
||||
</g>
|
||||
<path d="M 897 679 L 899.73 780.77" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 899.94 788.76 L 895.73 780.87 L 903.72 780.66 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#999999" font-family="Helvetica" text-anchor="middle" font-size="14px">
|
||||
<rect fill="#ffffff" stroke="none" x="883" y="727" width="30" height="17" stroke-width="0"/>
|
||||
<text x="897.5" y="739.48">RTP</text>
|
||||
</g>
|
||||
<path d="M 632 921 L 632 985.76" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 632 993.76 L 628 985.76 L 636 985.76 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 900 921 L 898.27 985.77" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 898.06 993.76 L 894.27 985.66 L 902.27 985.87 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1443.63 992.8 L 1484.45 992.8 L 1484.45 972.64 L 1443.63 972.64 Z M 1442.65 995.79 C 1441.41 995.79 1440.08 994.91 1440.08 993.59 L 1440.08 971.8 C 1440.08 970.74 1441.14 969.65 1442.69 969.65 L 1485.4 969.65 C 1486.96 969.65 1488 970.77 1488 971.79 L 1488 993.5 C 1488 994.82 1486.89 995.79 1485.27 995.79 L 1469.72 995.79 C 1469.41 996.7 1469.11 997.67 1469.05 998.49 C 1468.92 1000.19 1470.19 1000.67 1472.47 1000.94 C 1473.99 1001.1 1475.34 1001.13 1476.78 1001.16 C 1477.66 1001.16 1478.5 1001.7 1478.5 1002.58 C 1478.5 1003.42 1477.78 1004 1476.8 1004 L 1451.34 1004 C 1450.44 1004 1449.67 1003.38 1449.67 1002.58 C 1449.67 1001.86 1450.34 1001.16 1451.34 1001.16 C 1453.02 1001.11 1454.73 1001.11 1456.49 1000.82 C 1458.19 1000.55 1459.23 1000.02 1459.04 998.4 C 1458.97 997.67 1458.67 996.7 1458.36 995.79 Z M 1431.21 956.96 L 1450.73 956.96 L 1450.73 954.72 L 1431.21 954.72 Z M 1425 1000.27 L 1425 950.93 C 1425 949.24 1426.81 948 1428.4 948 L 1453.5 948 C 1455.25 948 1456.94 949.32 1456.94 950.93 L 1456.94 967.41 L 1442.56 967.41 C 1439.86 967.41 1437.42 969.52 1437.42 971.75 L 1437.42 985.33 L 1431.21 985.33 L 1431.21 987.57 L 1437.42 987.57 L 1437.42 992.05 L 1431.21 992.05 L 1431.21 994.29 L 1437.49 994.29 C 1438 996.65 1440.47 998.03 1442.55 998.03 L 1456.23 998.03 C 1456.23 998.21 1456.33 998.4 1456.32 998.54 C 1455.42 998.79 1453.39 998.92 1451.68 998.92 C 1450.92 998.89 1450.27 998.97 1449.61 999.2 C 1448.96 999.42 1448.39 999.78 1447.9 1000.27 Z" fill="#505050" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(1418.5,1010.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="76" height="36" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(120, 120, 120); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Participant<br />
|
||||
(viewer)<br />
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="38" y="26" fill="#787878" text-anchor="middle" font-size="16px" font-family="Helvetica">[Not supported by viewer]</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 1459.2 1098.25 C 1459.4 1098.25 1459.52 1098.06 1459.52 1097.85 C 1459.52 1097.67 1459.38 1097.5 1459.21 1097.5 L 1453.89 1097.5 C 1453.7 1097.5 1453.55 1097.63 1453.55 1097.85 C 1453.56 1098.11 1453.72 1098.25 1453.87 1098.25 Z M 1458.87 1134.63 C 1459.23 1134.63 1459.52 1134.37 1459.52 1134.18 L 1459.52 1133.57 C 1459.52 1133.26 1459.17 1133.08 1458.76 1133.08 L 1454.16 1133.08 C 1453.77 1133.08 1453.48 1133.34 1453.48 1133.54 L 1453.48 1134.14 C 1453.48 1134.36 1453.76 1134.63 1454.14 1134.63 Z M 1446.68 1130.92 L 1466.33 1130.92 L 1466.33 1100.47 L 1446.68 1100.47 Z M 1444.5 1100.49 C 1444.5 1098.29 1445.73 1096.39 1447.81 1095.52 C 1451.39 1094.36 1460.92 1094 1465.33 1095.64 C 1467.28 1096.49 1468.5 1098.19 1468.5 1100.54 L 1468.5 1131.73 C 1468.5 1133.34 1467.59 1135.58 1465.47 1136.5 C 1461.54 1137.97 1450.96 1138 1447.54 1136.41 C 1445.52 1135.46 1444.58 1133.7 1444.5 1131.85 Z" fill="#505050" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(1418.5,1144.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="76" height="36" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(120, 120, 120); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Participant<br style="font-size: 16px" />
|
||||
(viewer)<br style="font-size: 16px" />
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="38" y="26" fill="#787878" text-anchor="middle" font-size="16px" font-family="Helvetica">[Not supported by viewer]</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 1175 976 L 1414.76 976" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1422.76 976 L 1414.76 980 L 1414.76 972 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#999999" font-family="Helvetica" text-anchor="middle" font-size="14px">
|
||||
<rect fill="#ffffff" stroke="none" x="1281" y="969" width="39" height="17" stroke-width="0"/>
|
||||
<text x="1299" y="980.5">SRTP</text>
|
||||
</g>
|
||||
<path d="M 1175 1116 L 1434.26 1116" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1442.26 1116 L 1434.26 1120 L 1434.26 1112 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#999999" font-family="Helvetica" text-anchor="middle" font-size="14px">
|
||||
<rect fill="#ffffff" stroke="none" x="1291" y="1109" width="39" height="17" stroke-width="0"/>
|
||||
<text x="1309" y="1120.5">SRTP</text>
|
||||
</g>
|
||||
<path d="M 948 1046 L 1012.66 983.14" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1018.4 977.56 L 1015.45 986 L 1009.87 980.27 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 948 1046 L 1012.66 1108.86" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1018.4 1114.44 L 1009.87 1111.73 L 1015.45 1106 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 582 1046 L 517.34 983.14" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 511.6 977.56 L 520.13 980.27 L 514.55 986 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 582 1046 L 517.34 1108.86" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 511.6 1114.44 L 514.55 1106 L 520.13 1111.73 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 355 976 L 124.24 976" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 116.24 976 L 124.24 972 L 124.24 980 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#999999" font-family="Helvetica" text-anchor="middle" font-size="14px">
|
||||
<rect fill="#ffffff" stroke="none" x="215" y="969" width="39" height="17" stroke-width="0"/>
|
||||
<text x="233" y="980.5">SRTP</text>
|
||||
</g>
|
||||
<path d="M 89.53 992.17 C 90.09 992.17 90.48 991.94 90.37 991.75 L 89.26 990 C 89.12 989.73 88.92 989.67 88.59 989.67 L 81.41 989.67 C 81.06 989.67 80.88 989.74 80.71 990.01 L 79.68 991.74 C 79.48 992.02 80.08 992.17 80.51 992.17 Z M 106.32 986.46 L 106.32 960.72 L 63.65 960.72 L 63.65 986.46 Z M 59 994.5 C 57.87 994.49 56.85 994.08 56.42 993.45 C 56 992.83 56.17 992.2 56.53 991.78 L 60.66 987.26 L 60.66 960.58 C 60.66 959.24 61.78 957.5 63.63 957.5 L 106.33 957.5 C 107.77 957.5 109.31 958.74 109.31 960.75 L 109.31 987.26 L 113.48 991.82 C 113.83 992.25 114 992.82 113.58 993.43 C 113.03 994.2 111.99 994.45 111.02 994.5 Z" fill="#505050" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(46.5,1001.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="76" height="36" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(120, 120, 120); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Participant<br />
|
||||
(viewer)<br />
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="38" y="26" fill="#787878" text-anchor="middle" font-size="16px" font-family="Helvetica">[Not supported by viewer]</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="354.86" y="1071" width="155" height="90" rx="13.5" ry="13.5" fill="#ffffff" stroke="#666666" stroke-width="2" stroke-dasharray="2 4" pointer-events="none"/>
|
||||
<g transform="translate(369.5,1168.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="124" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(102, 102, 102); line-height: 1.2; vertical-align: top; width: 126px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">WebRtcTransport</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="62" y="17" fill="#666666" text-anchor="middle" font-size="16px" font-family="Helvetica">WebRtcTransport</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 382.36 1096 L 472.36 1096 L 472.36 1096 L 482.36 1111 L 472.36 1126 L 472.36 1126 L 382.36 1126 L 392.36 1111 Z" fill="url(#mx-gradient-66cc00-1-4d9900-1-s-0)" stroke="none" transform="translate(432.36,0)scale(-1,1)translate(-432.36,0)" pointer-events="none"/>
|
||||
<g transform="translate(372.5,1132.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="119" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(77, 153, 0); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Video Consumer</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="60" y="17" fill="#4D9900" text-anchor="middle" font-size="16px" font-family="Helvetica">Video Consumer</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="354.86" y="931" width="155" height="90" rx="13.5" ry="13.5" fill="#ffffff" stroke="#666666" stroke-width="2" stroke-dasharray="2 4" pointer-events="none"/>
|
||||
<g transform="translate(369.5,1028.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="124" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(102, 102, 102); line-height: 1.2; vertical-align: top; width: 126px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">WebRtcTransport</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="62" y="17" fill="#666666" text-anchor="middle" font-size="16px" font-family="Helvetica">WebRtcTransport</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 382.36 956 L 472.36 956 L 472.36 956 L 482.36 971 L 472.36 986 L 472.36 986 L 382.36 986 L 392.36 971 Z" fill="url(#mx-gradient-66cc00-1-4d9900-1-s-0)" stroke="none" transform="translate(432.36,0)scale(-1,1)translate(-432.36,0)" pointer-events="none"/>
|
||||
<g transform="translate(372.5,992.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="119" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(77, 153, 0); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Video Consumer</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="60" y="17" fill="#4D9900" text-anchor="middle" font-size="16px" font-family="Helvetica">Video Consumer</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="1019.86" y="931" width="155" height="90" rx="13.5" ry="13.5" fill="#ffffff" stroke="#666666" stroke-width="2" stroke-dasharray="2 4" pointer-events="none"/>
|
||||
<g transform="translate(1034.5,1028.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="124" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(102, 102, 102); line-height: 1.2; vertical-align: top; width: 126px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">WebRtcTransport</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="62" y="17" fill="#666666" text-anchor="middle" font-size="16px" font-family="Helvetica">WebRtcTransport</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 1047.36 956 L 1137.36 956 L 1137.36 956 L 1147.36 971 L 1137.36 986 L 1137.36 986 L 1047.36 986 L 1057.36 971 Z" fill="url(#mx-gradient-66cc00-1-4d9900-1-s-0)" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(1037.5,992.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="119" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(77, 153, 0); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Video Consumer</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="60" y="17" fill="#4D9900" text-anchor="middle" font-size="16px" font-family="Helvetica">Video Consumer</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="1019.86" y="1071" width="155" height="90" rx="13.5" ry="13.5" fill="#ffffff" stroke="#666666" stroke-width="2" stroke-dasharray="2 4" pointer-events="none"/>
|
||||
<g transform="translate(1034.5,1168.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="124" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(102, 102, 102); line-height: 1.2; vertical-align: top; width: 126px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">WebRtcTransport</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="62" y="17" fill="#666666" text-anchor="middle" font-size="16px" font-family="Helvetica">WebRtcTransport</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 1047.36 1096 L 1137.36 1096 L 1137.36 1096 L 1147.36 1111 L 1137.36 1126 L 1137.36 1126 L 1047.36 1126 L 1057.36 1111 Z" fill="url(#mx-gradient-66cc00-1-4d9900-1-s-0)" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(1037.5,1132.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="119" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(77, 153, 0); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Video Consumer</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="60" y="17" fill="#4D9900" text-anchor="middle" font-size="16px" font-family="Helvetica">Video Consumer</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 89.53 1127.17 C 90.09 1127.17 90.48 1126.94 90.37 1126.75 L 89.26 1125 C 89.12 1124.73 88.92 1124.67 88.59 1124.67 L 81.41 1124.67 C 81.06 1124.67 80.88 1124.74 80.71 1125.01 L 79.68 1126.74 C 79.48 1127.02 80.08 1127.17 80.51 1127.17 Z M 106.32 1121.46 L 106.32 1095.72 L 63.65 1095.72 L 63.65 1121.46 Z M 59 1129.5 C 57.87 1129.49 56.85 1129.08 56.42 1128.45 C 56 1127.83 56.17 1127.2 56.53 1126.78 L 60.66 1122.26 L 60.66 1095.58 C 60.66 1094.24 61.78 1092.5 63.63 1092.5 L 106.33 1092.5 C 107.77 1092.5 109.31 1093.74 109.31 1095.75 L 109.31 1122.26 L 113.48 1126.82 C 113.83 1127.25 114 1127.82 113.58 1128.43 C 113.03 1129.2 111.99 1129.45 111.02 1129.5 Z" fill="#505050" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(46.5,1136.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="76" height="36" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(120, 120, 120); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Participant<br />
|
||||
(viewer)<br />
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="38" y="26" fill="#787878" text-anchor="middle" font-size="16px" font-family="Helvetica">[Not supported by viewer]</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 355 1116 L 119.24 1114.08" fill="none" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 111.24 1114.02 L 119.27 1110.08 L 119.2 1118.08 Z" fill="#999999" stroke="#999999" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#999999" font-family="Helvetica" text-anchor="middle" font-size="14px">
|
||||
<rect fill="#ffffff" stroke="none" x="213" y="1108" width="39" height="17" stroke-width="0"/>
|
||||
<text x="231" y="1119.5">SRTP</text>
|
||||
</g>
|
||||
<rect x="1015" y="95.5" width="160" height="150" rx="22.5" ry="22.5" fill="#ffffff" stroke="#666666" stroke-width="2" stroke-dasharray="2 4" pointer-events="none"/>
|
||||
<g transform="translate(1031.5,253.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="125" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(102, 102, 102); line-height: 1.2; vertical-align: top; width: 125px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">WebRtcTransport</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="63" y="17" fill="#666666" text-anchor="middle" font-size="16px" font-family="Helvetica">WebRtcTransport</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 1045 109 L 1135 109 L 1135 109 L 1145 124 L 1135 139 L 1135 139 L 1045 139 L 1055 124 Z" fill="url(#mx-gradient-66cc00-1-4d9900-1-s-0)" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(1035.5,145.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="119" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(77, 153, 0); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Audio Consumer</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="60" y="17" fill="#4D9900" text-anchor="middle" font-size="16px" font-family="Helvetica">Audio Consumer</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 1045 184 L 1135 184 L 1135 184 L 1145 199 L 1135 214 L 1135 214 L 1045 214 L 1055 199 Z" fill="url(#mx-gradient-66cc00-1-4d9900-1-s-0)" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(1035.5,220.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="119" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(77, 153, 0); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Video Consumer</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="60" y="17" fill="#4D9900" text-anchor="middle" font-size="16px" font-family="Helvetica">Video Consumer</text>
|
||||
</switch>
|
||||
</g>
|
||||
<rect x="1020" y="289" width="155" height="90" rx="13.5" ry="13.5" fill="#ffffff" stroke="#666666" stroke-width="2" stroke-dasharray="2 4" pointer-events="none"/>
|
||||
<g transform="translate(1032.5,386.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="128" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(102, 102, 102); line-height: 1.2; vertical-align: top; width: 130px; white-space: nowrap; overflow-wrap: normal; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">PlainRtpTransport</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="64" y="17" fill="#666666" text-anchor="middle" font-size="16px" font-family="Helvetica">PlainRtpTransport</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 1047.5 314 L 1137.5 314 L 1137.5 314 L 1147.5 329 L 1137.5 344 L 1137.5 344 L 1047.5 344 L 1057.5 329 Z" fill="url(#mx-gradient-66cc00-1-4d9900-1-s-0)" stroke="none" pointer-events="none"/>
|
||||
<g transform="translate(1037.5,350.5)">
|
||||
<switch>
|
||||
<foreignObject style="overflow:visible;" pointer-events="all" width="119" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(77, 153, 0); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Audio Consumer</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="60" y="17" fill="#4D9900" text-anchor="middle" font-size="16px" font-family="Helvetica">Audio Consumer</text>
|
||||
</switch>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 55 KiB |
BIN
Video/MiroTalk SFU/public/images/audio.gif
Normal file
After Width: | Height: | Size: 460 KiB |
BIN
Video/MiroTalk SFU/public/images/background.jpg
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
Video/MiroTalk SFU/public/images/broadcasting.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
Video/MiroTalk SFU/public/images/browsers.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
Video/MiroTalk SFU/public/images/chatgpt.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
1
Video/MiroTalk SFU/public/images/cta-illustration.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="160" height="187" xmlns="http://www.w3.org/2000/svg"><g fill="#0270D7" fill-rule="evenodd"><path fill-opacity=".24" d="M110.211 0l49.45 89.211-89.21 49.45L21 49.452z"/><path fill-opacity=".16" d="M33.812 171.385l-18.385 15.427L0 168.427 18.385 153z"/></g></svg>
|
After Width: | Height: | Size: 273 B |
BIN
Video/MiroTalk SFU/public/images/delete.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
Video/MiroTalk SFU/public/images/docker.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
Video/MiroTalk SFU/public/images/email.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
Video/MiroTalk SFU/public/images/exit.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
1
Video/MiroTalk SFU/public/images/feature-icon-01.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="112" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><filter x="-90%" y="-90%" width="280%" height="280%" filterUnits="objectBoundingBox" id="a"><feGaussianBlur stdDeviation="12" in="SourceGraphic"/></filter><linearGradient x1="99.316%" y1="21.974%" x2="0%" y2="69.777%" id="b"><stop stop-color="#2C3039" offset="0%"/><stop stop-color="#8A94A7" offset="48.131%"/><stop stop-color="#2C3039" offset="100%"/></linearGradient><linearGradient x1="49.892%" y1=".428%" x2="24.856%" y2="100%" id="d"><stop stop-color="#3B404C" offset="0%"/><stop stop-color="#333843" offset="100%"/></linearGradient><path d="M32.833 63.264c-14.9 1.866-25.108-6.384-22.797-18.428 2.31-12.043 16.264-23.319 31.166-25.184C56.103 17.786 66.31 26.036 64 38.08c-2.311 12.043-16.264 23.319-31.167 25.184z" id="c"/></defs><g fill="none" fill-rule="evenodd"><path fill="#0270D7" d="M35.521 6.938L12.04 35.843l48.939 16.136L84.46 23.073z"/><path fill="#02CBB1" d="M20 65.494L35.822 74 36 26.506 20.176 18z"/><g transform="translate(28 31)"><path fill-opacity=".48" fill="#1D2026" filter="url(#a)" d="M1 0h40v40H1z"/><path d="M11.261 54.752l-9.71-18.785C.096 33.152-.389 29.783.327 26.051 2.637 14.01 16.59 2.732 31.492.867 41.776-.42 49.824 3.11 53.065 9.38l9.71 18.785c-3.242-6.27-11.29-9.8-21.573-8.514C26.3 21.518 12.347 32.793 10.036 44.837c-.716 3.732-.23 7.1 1.225 9.915" fill="url(#b)"/><use fill="url(#d)" xlink:href="#c"/></g><path fill="#00BFFB" d="M22.991 85.677l.826-6.614L7.855 84.8l-.825 6.616z"/><path fill-opacity=".32" fill="#00BFFB" d="M106.721 46.737l4.408-2.801-13.699-6.737L93.022 40z"/></g></svg>
|
After Width: | Height: | Size: 1.6 KiB |
1
Video/MiroTalk SFU/public/images/feature-icon-02.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="108" height="100" xmlns="http://www.w3.org/2000/svg"><defs><filter x="-90%" y="-90%" width="280%" height="280%" filterUnits="objectBoundingBox" id="a"><feGaussianBlur stdDeviation="12" in="SourceGraphic"/></filter><linearGradient x1="17.713%" y1="0%" x2="77.754%" y2="68.424%" id="b"><stop stop-color="#2C3039" offset="0%"/><stop stop-color="#8A94A7" offset="100%"/></linearGradient><linearGradient x1="49.892%" y1=".428%" x2="24.856%" y2="100%" id="c"><stop stop-color="#3B404C" offset="0%"/><stop stop-color="#333843" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path fill-opacity=".32" fill="#00BFFB" d="M31.292 84.984l1.313-5.055-14.613 4.415-1.313 5.056z"/><path d="M41.203 74.416L.222 46.516l30.541-21.314 23.908 16.277-11.69 10.84-1.706 22-.072.097z" fill="#0270D7"/><path fill="#00BFFB" d="M103.305 14.443l4.556-4.866-16.287-4.74-4.556 4.867z"/><path fill="#02CBB1" d="M56.9 77.244L54.771 92.89 94.416 77.84l2.128-15.648z"/><path fill-opacity=".48" fill="#1D2026" filter="url(#a)" d="M31.778 38.241h40v40h-40z" transform="translate(.222 -2.241)"/><path d="M88.023 31.352a2.962 2.962 0 0 0-1.296-1.359l-29.464-15.06a2.888 2.888 0 0 0-2.634.001L25.147 30.03a2.972 2.972 0 0 0-1.298 1.361l32.078 16.398 32.096-16.436z" fill="url(#b)" fill-rule="nonzero" transform="rotate(31 66.542 55.443)"/><path d="M43.266 11.908a3.154 3.154 0 0 0-.96.977L23.763 43.707c-.586.974-.605 2.174-.048 3.1l16.423 27.335c.228.379.543.693.917.917l20.09-33.39-17.878-29.76z" fill="#2C3039" fill-rule="nonzero"/><path d="M38.935 50.59v38.956a3.04 3.04 0 0 0 1.35-.3L70.47 74.263a2.994 2.994 0 0 0 1.67-2.697V35.608a2.98 2.98 0 0 0-.342-1.33L38.935 50.59z" fill="url(#c)" transform="rotate(31 66.143 86.153)"/></g></svg>
|
After Width: | Height: | Size: 1.7 KiB |
1
Video/MiroTalk SFU/public/images/feature-icon-03.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="103" height="100" xmlns="http://www.w3.org/2000/svg"><defs><filter x="-90%" y="-90%" width="280%" height="280%" filterUnits="objectBoundingBox" id="a"><feGaussianBlur stdDeviation="12" in="SourceGraphic"/></filter><linearGradient x1="49.892%" y1=".428%" x2="24.856%" y2="100%" id="b"><stop stop-color="#3B404C" offset="0%"/><stop stop-color="#333843" offset="100%"/></linearGradient><linearGradient x1="17.713%" y1="0%" x2="77.754%" y2="68.424%" id="c"><stop stop-color="#2C3039" offset="0%"/><stop stop-color="#8A94A7" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M48.028 64.452L.086 77.076l3.95-37.033 27.97-7.364c.1 3.076.27 8.387.512 15.934l15.485 15.72.025.119z" fill="#0270D7"/><path fill="#02CBB1" d="M91.767 72.042l2.455-13.396L58.895 70.67 56.44 84.067z"/><path fill="#00BFFB" d="M40.783 98.37l6.378-1.937-11.735-12.248-6.379 1.937z"/><path fill-opacity=".32" fill="#00BFFB" d="M23.783 14.37l6.378-1.937L18.426.185l-6.379 1.937z"/><path fill-opacity=".48" fill="#1D2026" filter="url(#a)" d="M50 43h40v40H50z" transform="translate(-16 -12)"/><path d="M51.759 16.34a.94.94 0 0 1 .922.399l23.35 40.193c.096.151.143.35.143.545-.001.629-.481 1.21-1.067 1.292l-46.872 6.553a.909.909 0 0 1-.527-.081c-.507-.237-.688-.912-.39-1.5L50.84 16.996c.076-.134.183-.262.307-.372.19-.16.403-.255.612-.283" fill="url(#b)" transform="rotate(27 42.978 77.641)"/><path d="M25.338.52c-.01-.006-.022-.01-.033-.017a.893.893 0 0 0-.174-.066c-.01-.002-.022.001-.034-.001a.925.925 0 0 0-.346-.018 1.064 1.064 0 0 0-.315.096l-.004.001c-.06.03-.12.064-.178.105a1.172 1.172 0 0 0-.107.083l-.008.008a1.495 1.495 0 0 0-.295.368L.616 48.344a1.469 1.469 0 0 0-.064.148c-.02.057-.02.113-.033.171-.012.058-.028.116-.033.174-.007.084.002.164.012.246.007.052.006.106.02.156a.99.99 0 0 0 .103.233c.02.037.031.08.056.113a.877.877 0 0 0 .28.25l26.938 14.927a.868.868 0 0 1-.28-.252c-.024-.034-.037-.076-.057-.113-.04-.075-.08-.15-.103-.232-.013-.051-.013-.104-.02-.156-.01-.082-.02-.163-.012-.248.005-.058.021-.115.033-.173.024-.107.046-.216.097-.32L50.78 16.006c.076-.136.18-.265.304-.376.091-.08.19-.142.289-.19a.96.96 0 0 1 .662-.078.95.95 0 0 1 .24.084L25.337.52z" transform="rotate(27 42.028 77.95)" fill="url(#c)" fill-rule="nonzero"/></g></svg>
|
After Width: | Height: | Size: 2.2 KiB |
1
Video/MiroTalk SFU/public/images/feature-icon-04.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="98" height="100" xmlns="http://www.w3.org/2000/svg"><defs><filter x="-90%" y="-90%" width="280%" height="280%" filterUnits="objectBoundingBox" id="a"><feGaussianBlur stdDeviation="12" in="SourceGraphic"/></filter><linearGradient x1="49.892%" y1=".428%" x2="24.856%" y2="100%" id="b"><stop stop-color="#3B404C" offset="0%"/><stop stop-color="#333843" offset="100%"/></linearGradient><linearGradient x1="17.713%" y1="0%" x2="77.754%" y2="68.424%" id="c"><stop stop-color="#2C3039" offset="0%"/><stop stop-color="#8A94A7" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M49.028 61.452L1.086 74.076l3.95-37.033 27.97-7.364c.1 3.076.27 8.387.512 15.934l15.485 15.72.025.119z" fill="#0270D7"/><path fill-opacity=".32" fill="#00BFFB" d="M23.725 84.328l-5.66 3.52 14.505 8.794 5.66-3.522z"/><path fill="#02CBB1" d="M89.345 72.466l-1.72-15.697L52.8 80.964l1.72 15.698z"/><path fill-opacity=".48" fill="#1D2026" filter="url(#a)" d="M44 41h40v40H44z" transform="translate(-15 -10)"/><path fill="url(#b)" d="M37.841 71.977L0 54.169 37.231 0z" transform="rotate(-36 55.277 18.264)"/><path fill="url(#c)" fill-rule="nonzero" transform="scale(-1 1) rotate(36 .538 -153.515)" d="M73.788 71.977L37.229 54 74.4 0z"/><path fill-opacity=".32" fill="#00BFFB" d="M58.57 10.221l-1.048 5.117 14.362-5.174 1.047-5.118z"/></g></svg>
|
After Width: | Height: | Size: 1.3 KiB |
1
Video/MiroTalk SFU/public/images/feature-icon-05.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="98" height="100" xmlns="http://www.w3.org/2000/svg"><defs><filter x="-90%" y="-90%" width="280%" height="280%" filterUnits="objectBoundingBox" id="a"><feGaussianBlur stdDeviation="12" in="SourceGraphic"/></filter><linearGradient x1="7.786%" y1="0%" x2="90.938%" y2="49.407%" id="b"><stop stop-color="#2C3039" offset="0%"/><stop stop-color="#8A94A7" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path fill-opacity=".48" fill="#1D2026" filter="url(#a)" d="M38 48h40v40H38z" transform="translate(-9 -17)"/><path fill="#02CBB1" d="M86.755 88.926l3.46-15.26-39.363 10.387-3.459 15.261z"/><path fill="#0270D7" d="M90.735 53.81l7.137-28.53-77.08 20.354-7.137 28.533z"/><path fill-opacity=".32" fill="#00BFFB" d="M77.35 14.62l6.442-1.712-11.3-12.65-6.443 1.713z"/><path fill="#474C59" d="M46.63 33.718L28.384 61.923l43.659 19.72 18.244-28.206z"/><path fill="#00BFFB" d="M29.746 92.298l3.792-3.59-14.732-4-3.793 3.59z"/><path fill="#2C3039" fill-rule="nonzero" d="M17.685 36.372l10.7 25.55 18.339-28.026L35.015 8.122z"/><path fill="url(#b)" fill-rule="nonzero" d="M49.401 21.254L1.988 27.601l23.588 15.653 47.412-6.346z" transform="rotate(32 52.468 75.451)"/></g></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
Video/MiroTalk SFU/public/images/feature-icon-06.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="115" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><filter x="-90%" y="-90%" width="280%" height="280%" filterUnits="objectBoundingBox" id="a"><feGaussianBlur stdDeviation="12" in="SourceGraphic"/></filter><path id="b" d="M0 .856h63.533v59.675H0z"/><linearGradient x1="56.146%" y1="10.87%" x2="25.695%" y2="72.649%" id="c"><stop stop-color="#2C3039" offset="0%"/><stop stop-color="#8A94A7" offset="48.131%"/><stop stop-color="#2C3039" offset="100%"/></linearGradient><path id="e" d="M.062.344h40.511v44.1H.062z"/><linearGradient x1="49.892%" y1=".428%" x2="24.856%" y2="100%" id="f"><stop stop-color="#3B404C" offset="0%"/><stop stop-color="#333843" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path fill="#0270D7" d="M23.302 63.083L.112 44.995l73.273-31.416 23.19 18.091z"/><path fill="#00BFFB" d="M35.902 83.663l1.17-6.562-16.24 4.895-1.17 6.563z"/><path fill-opacity=".32" fill="#00BFFB" d="M41.972 92.478l-2.962 3.376 11.56 2.714 2.961-3.376z"/><path fill-opacity=".48" fill="#1D2026" filter="url(#a)" d="M36.056 33.707h40v40h-40z" transform="rotate(16 55.276 48.942)"/><g transform="rotate(16 -28.89 116.929)"><mask id="d" fill="#fff"><use xlink:href="#b"/></mask><path d="M32.628 40.394c.06-.485.116-.972.204-1.45.055-.295.135-.583.2-.874.096-.427.181-.856.296-1.276.084-.303.192-.596.286-.894.128-.401.246-.808.393-1.202.05-.141.113-.275.169-.414.195-.5.4-.997.624-1.483.103-.22.214-.434.322-.65a28.007 28.007 0 0 1 2.005-3.412c.07-.1.15-.192.219-.29.448-.622.922-1.222 1.418-1.801.172-.198.347-.391.523-.584.464-.508.946-.993 1.444-1.46.175-.162.343-.334.522-.493.13-.113.263-.22.392-.332a25.56 25.56 0 0 1 1.147-.91c.146-.11.291-.22.44-.325.356-.254.723-.49 1.093-.723.212-.134.42-.276.637-.402.428-.252.868-.48 1.311-.702.157-.08.307-.169.465-.244a22.326 22.326 0 0 1 1.727-.721c.162-.06.326-.111.49-.168.45-.155.905-.293 1.366-.417.178-.047.354-.097.532-.14a20.012 20.012 0 0 1 1.862-.362 18.96 18.96 0 0 1 1.675-.155c.175-.01.347-.008.52-.013.382-.008.76-.008 1.134.005a17.935 17.935 0 0 1 1.654.144c.174.022.347.042.518.07.44.071.874.161 1.301.266.075.019.154.03.229.05.508.132 1.003.29 1.49.467.143.05.28.11.42.166.347.136.691.282 1.025.44.288.135.575.268.852.419L31.118 2.89a18.16 18.16 0 0 0-.619-.319c-.075-.038-.156-.065-.233-.1-.337-.16-.68-.305-1.028-.442-.14-.055-.276-.115-.417-.165-.49-.176-.985-.335-1.493-.466l-.03-.01c-.063-.016-.13-.024-.192-.04-.43-.105-.865-.195-1.307-.267-.17-.027-.344-.047-.518-.07a17.934 17.934 0 0 0-1.654-.144 17.699 17.699 0 0 0-1.133-.004c-.174.004-.346.003-.52.012-.554.03-1.112.076-1.678.155a20.56 20.56 0 0 0-1.86.364c-.178.04-.355.09-.532.139-.46.122-.917.262-1.368.417-.162.055-.326.106-.488.168-.566.209-1.126.436-1.674.694l-.054.027c-.155.074-.304.162-.458.24a22.56 22.56 0 0 0-1.318.705c-.215.127-.421.268-.633.401-.276.174-.558.338-.826.524-.093.064-.181.135-.272.2-.148.106-.293.217-.438.325-.39.291-.77.594-1.145.91-.132.112-.264.219-.394.333-.065.058-.136.11-.2.169-.113.102-.21.22-.32.324-.5.465-.982.952-1.445 1.46-.097.106-.208.197-.303.304-.079.09-.143.19-.22.281a26.06 26.06 0 0 0-1.42 1.8c-.057.08-.125.152-.182.233-.013.018-.023.038-.036.057a26.58 26.58 0 0 0-1.459 2.366c-.047.087-.108.167-.156.253-.138.26-.26.528-.391.792-.107.217-.218.43-.32.65-.225.485-.43.98-.625 1.481-.054.14-.118.276-.17.417l-.029.07c-.135.368-.242.749-.361 1.126-.094.3-.204.594-.287.899-.119.425-.204.859-.3 1.29-.065.287-.143.57-.197.86-.09.484-.145.974-.205 1.463-.03.247-.08.488-.102.734-.07.74-.107 1.485-.108 2.233-.014 7.778 3.736 14.079 9.395 17.158L41.813 60.53c-5.66-3.08-9.41-9.38-9.395-17.156.001-.75.037-1.495.107-2.235.024-.25.072-.496.103-.746" fill="url(#c)" mask="url(#d)"/></g><g transform="rotate(16 -109.581 222.973)"><mask id="g" fill="#fff"><use xlink:href="#e"/></mask><path d="M20.358.531C31.545-1.04 40.595 7.473 40.574 19.548c-.023 12.075-9.11 23.137-20.297 24.71C9.09 45.83.04 37.316.062 25.24.084 13.166 9.172 2.103 20.358.531" fill="url(#f)" mask="url(#g)"/></g><path fill="#02CBB1" d="M114.324 47.62l-10.196-8.59-7.761 33.025 10.197 8.59z"/></g></svg>
|
After Width: | Height: | Size: 4.0 KiB |
BIN
Video/MiroTalk SFU/public/images/feedback.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
Video/MiroTalk SFU/public/images/forbidden.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
Video/MiroTalk SFU/public/images/geolocation.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
Video/MiroTalk SFU/public/images/github.png
Normal file
After Width: | Height: | Size: 6.5 KiB |