Compare commits

..

No commits in common. "master" and "v3.6.1" have entirely different histories.

53 changed files with 858 additions and 1805 deletions

View File

@ -34,8 +34,6 @@ jobs:
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install safe-chain
uses: OpenVidu/actions/install-safe-chain@58e9bb7b49e14849ee3cde9b532c4af48fe1d827 # v1.0.19
- name: Commit URL
run: echo https://github.com/OpenVidu/openvidu/commit/${{ inputs.commit_sha || github.sha }}
- name: Send Dispatch Event
@ -95,8 +93,6 @@ jobs:
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install safe-chain
uses: OpenVidu/actions/install-safe-chain@58e9bb7b49e14849ee3cde9b532c4af48fe1d827 # v1.0.19
- name: Install wait-on package
run: npm install -g wait-on
- name: Run Chrome
@ -107,15 +103,15 @@ jobs:
docker run --network=host -d -p 4444:4444 ${{ env.CHROME_IMAGE }}
fi
- name: Run openvidu-local-deployment
uses: OpenVidu/actions/start-openvidu-local-deployment@58e9bb7b49e14849ee3cde9b532c4af48fe1d827 # v1.0.19
uses: OpenVidu/actions/start-openvidu-local-deployment@0f5592e91f0dca4c62e7a3cf412a6c17cf432b6d # v1.0.4
- name: Start OpenVidu Call backend
uses: OpenVidu/actions/start-openvidu-call@58e9bb7b49e14849ee3cde9b532c4af48fe1d827 # v1.0.19
uses: OpenVidu/actions/start-openvidu-call@0f5592e91f0dca4c62e7a3cf412a6c17cf432b6d # v1.0.4
- name: Build and Serve openvidu-components-angular Testapp
uses: OpenVidu/actions/start-openvidu-components-testapp@58e9bb7b49e14849ee3cde9b532c4af48fe1d827 # v1.0.19
uses: OpenVidu/actions/start-openvidu-components-testapp@0f5592e91f0dca4c62e7a3cf412a6c17cf432b6d # v1.0.4
- name: Run Tests
env:
LAUNCH_MODE: CI
run: npm run ${{ matrix.script }} --prefix openvidu-components-angular
- name: Cleanup
if: always()
uses: OpenVidu/actions/cleanup@58e9bb7b49e14849ee3cde9b532c4af48fe1d827 # v1.0.19
uses: OpenVidu/actions/cleanup@0f5592e91f0dca4c62e7a3cf412a6c17cf432b6d # v1.0.4

View File

@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Configure OpenVidu Local Deployment
uses: OpenVidu/actions/start-openvidu-local-deployment@58e9bb7b49e14849ee3cde9b532c4af48fe1d827 # v1.0.19
uses: OpenVidu/actions/start-openvidu-local-deployment@0f5592e91f0dca4c62e7a3cf412a6c17cf432b6d # v1.0.4
with:
ref-openvidu-local-deployment: development
pre_startup_commands: |
@ -34,8 +34,6 @@ jobs:
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 24
- name: Install safe-chain
uses: OpenVidu/actions/install-safe-chain@58e9bb7b49e14849ee3cde9b532c4af48fe1d827 # v1.0.19
- name: Install dependencies
working-directory: ./openvidu/openvidu-test-integration
@ -54,5 +52,5 @@ jobs:
retention-days: 7
- name: Cleanup
if: always()
uses: OpenVidu/actions/cleanup@58e9bb7b49e14849ee3cde9b532c4af48fe1d827 # v1.0.19
uses: OpenVidu/actions/cleanup@0f5592e91f0dca4c62e7a3cf412a6c17cf432b6d # v1.0.4

View File

@ -1,12 +1,12 @@
{
"name": "openvidu-components-testapp",
"version": "3.7.0",
"version": "3.6.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openvidu-components-testapp",
"version": "3.7.0",
"version": "3.6.1",
"dependencies": {
"@angular/animations": "20.3.15",
"@angular/cdk": "20.2.14",

View File

@ -106,5 +106,5 @@
"simulate:multiparty": "livekit-cli load-test --url ws://localhost:7880 --api-key devkey --api-secret secret --room daily-call --publishers 8 --audio-publishers 8 --identity-prefix Participant --identity publisher",
"husky": "cd .. && husky install"
},
"version": "3.7.0"
"version": "3.6.1"
}

View File

@ -18,5 +18,5 @@
"livekit-client": "^2.16.0",
"@livekit/track-processors": "^0.7.2"
},
"version": "3.7.0"
"version": "3.6.1"
}

View File

@ -1,7 +1,7 @@
services:
generate-scripts:
image: alpine:3.23.4
image: alpine:3.23.3
entrypoint: ["/bin/sh", "-c"]
restart: "no"
user: root

View File

@ -1,7 +1,7 @@
services:
caddy-proxy:
image: docker.io/openvidu/openvidu-caddy-local:main
image: docker.io/openvidu/openvidu-caddy-local:3.6.1
restart: unless-stopped
extra_hosts:
- host.docker.internal:host-gateway
@ -33,7 +33,7 @@ services:
condition: service_completed_successfully
redis:
image: docker.io/redis:8.6.2-alpine
image: docker.io/redis:8.6.1-alpine
restart: unless-stopped
ports:
- 6379:6379
@ -49,7 +49,7 @@ services:
condition: service_completed_successfully
minio:
image: docker.io/openvidu/minio:RELEASE.2026-05-04T00-27-21Z-r0
image: docker.io/openvidu/minio:RELEASE.2026-03-04T16-04-53Z-r0
restart: unless-stopped
ports:
- 9000:9000
@ -69,7 +69,7 @@ services:
condition: service_completed_successfully
mongo:
image: docker.io/openvidu/mongodb:8.0.21-r0
image: docker.io/openvidu/mongodb:8.0.19-r2
restart: unless-stopped
ports:
- 27017:27017
@ -88,7 +88,7 @@ services:
condition: service_completed_successfully
dashboard:
image: docker.io/openvidu/openvidu-dashboard:main
image: docker.io/openvidu/openvidu-dashboard:3.6.1
restart: unless-stopped
environment:
- SERVER_PORT=5000
@ -102,7 +102,7 @@ services:
condition: service_completed_successfully
openvidu:
image: docker.io/openvidu/openvidu-server:main
image: docker.io/openvidu/openvidu-server:3.6.1
restart: unless-stopped
extra_hosts:
- host.docker.internal:host-gateway
@ -123,7 +123,7 @@ services:
condition: service_completed_successfully
ingress:
image: docker.io/openvidu/ingress:main
image: docker.io/openvidu/ingress:3.6.1
restart: unless-stopped
extra_hosts:
- host.docker.internal:host-gateway
@ -141,7 +141,7 @@ services:
condition: service_completed_successfully
egress:
image: docker.io/openvidu/egress:main
image: docker.io/openvidu/egress:3.6.1
restart: unless-stopped
extra_hosts:
- host.docker.internal:host-gateway
@ -156,7 +156,7 @@ services:
condition: service_completed_successfully
operator:
image: docker.io/openvidu/openvidu-operator:main
image: docker.io/openvidu/openvidu-operator:3.6.1
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
@ -179,7 +179,7 @@ services:
condition: service_completed_successfully
openvidu-meet:
image: docker.io/openvidu/openvidu-meet:main
image: docker.io/openvidu/openvidu-meet:3.6.1
restart: on-failure
extra_hosts:
- host.docker.internal:host-gateway
@ -219,7 +219,7 @@ services:
condition: service_completed_successfully
openvidu-meet-init:
image: docker.io/openvidu/openvidu-operator:main
image: docker.io/openvidu/openvidu-operator:3.6.1
restart: on-failure
environment:
- MODE=local-ready-check

View File

@ -680,9 +680,9 @@ Resources:
'/usr/local/bin/install.sh':
content: !Sub |
#!/bin/bash -x
OPENVIDU_VERSION=main
OPENVIDU_VERSION=3.6.1
DOMAIN=
YQ_VERSION=v4.53.2
YQ_VERSION=v4.52.4
apt-get update && apt-get install -y \
curl \
@ -692,7 +692,7 @@ Resources:
wget https://github.com/mikefarah/yq/releases/download/${!YQ_VERSION}/yq_linux_$(dpkg --print-architecture).tar.gz -O - |\
tar xz && mv yq_linux_$(dpkg --print-architecture) /usr/bin/yq
AWS_CLI_VERSION=2.34.41
AWS_CLI_VERSION=2.34.0
# Install aws-cli if not already installed
if ! command -v aws &> /dev/null; then
curl "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m)-${!AWS_CLI_VERSION}.zip" -o "awscliv2.zip"

View File

@ -163,7 +163,7 @@ var stringInterpolationParams = {
var installScriptTemplate = '''
#!/bin/bash -x
OPENVIDU_VERSION=main
OPENVIDU_VERSION=3.6.1
DOMAIN=
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
@ -692,7 +692,7 @@ echo ${base64config_blobStorage} | base64 -d > /usr/local/bin/config_blobStorage
chmod +x /usr/local/bin/config_blobStorage.sh
# Install azure cli
AZURE_CLI_VERSION=2.85.0
AZURE_CLI_VERSION=2.83.0
apt-get install -y apt-transport-https ca-certificates gnupg lsb-release
curl -sLS https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /etc/apt/trusted.gpg.d/microsoft.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/azure-cli.list

File diff suppressed because one or more lines are too long

View File

@ -148,9 +148,9 @@ locals {
#!/bin/bash -x
set -e
OPENVIDU_VERSION=main
OPENVIDU_VERSION=3.6.1
DOMAIN=
YQ_VERSION=v4.53.2
YQ_VERSION=v4.52.4
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
apt-get update && apt-get install -y \
@ -636,7 +636,7 @@ CONFIG_S3_EOF
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
apt-get update && apt-get install -y
GCLOUD_VERSION=566.0.0
GCLOUD_VERSION=558.0.0
# Install google cli
if ! command -v gcloud >/dev/null 2>&1; then
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg

View File

@ -1,14 +1,14 @@
#!/bin/sh
# Docker & Docker Compose will need to be installed on the machine
set -eu
export DOCKER_VERSION="${DOCKER_VERSION:-29.4.2}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.1.3}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-main}"
export DOCKER_VERSION="${DOCKER_VERSION:-29.2.1}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.0.2}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-3.6.1}"
export INSTALLER_IMAGE="${INSTALLER_IMAGE:-docker.io/openvidu/openvidu-installer:${OPENVIDU_VERSION}}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-05-04T00-27-21Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-05-04T15-44-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.21}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.2-alpine}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-03-04T16-04-53Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-03-12T12-23-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.19}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.1-alpine}"
export BUSYBOX_IMAGE="${BUSYBOX_IMAGE:-docker.io/busybox:1.37.0}"
export CADDY_SERVER_IMAGE="${CADDY_SERVER_IMAGE:-docker.io/openvidu/openvidu-caddy:${OPENVIDU_VERSION}}"
export CADDY_SERVER_PRO_IMAGE="${CADDY_SERVER_PRO_IMAGE:-docker.io/openvidu/openvidu-pro-caddy:${OPENVIDU_VERSION}}"
@ -23,11 +23,11 @@ export OPENVIDU_AGENT_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_SPEECH_PROCESSIN
export OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE:-docker.io/openvidu/agent-speech-processing-sherpa:${OPENVIDU_VERSION}}"
export LIVEKIT_INGRESS_SERVER_IMAGE="${LIVEKIT_INGRESS_SERVER_IMAGE:-docker.io/openvidu/ingress:${OPENVIDU_VERSION}}"
export LIVEKIT_EGRESS_SERVER_IMAGE="${LIVEKIT_EGRESS_SERVER_IMAGE:-docker.io/openvidu/egress:${OPENVIDU_VERSION}}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.11.3}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.12}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.12}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.6-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.6}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.9.1}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.11}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.11}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.4-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.4}"
# Function to compare two version strings
compare_versions() {

View File

@ -1,14 +1,14 @@
#!/bin/sh
# Docker & Docker Compose will need to be installed on the machine
set -eu
export DOCKER_VERSION="${DOCKER_VERSION:-29.4.2}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.1.3}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-main}"
export DOCKER_VERSION="${DOCKER_VERSION:-29.2.1}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.0.2}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-3.6.1}"
export INSTALLER_IMAGE="${INSTALLER_IMAGE:-docker.io/openvidu/openvidu-installer:${OPENVIDU_VERSION}}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-05-04T00-27-21Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-05-04T15-44-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.21}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.2-alpine}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-03-04T16-04-53Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-03-12T12-23-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.19}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.1-alpine}"
export BUSYBOX_IMAGE="${BUSYBOX_IMAGE:-docker.io/busybox:1.37.0}"
export CADDY_SERVER_IMAGE="${CADDY_SERVER_IMAGE:-docker.io/openvidu/openvidu-caddy:${OPENVIDU_VERSION}}"
export CADDY_SERVER_PRO_IMAGE="${CADDY_SERVER_PRO_IMAGE:-docker.io/openvidu/openvidu-pro-caddy:${OPENVIDU_VERSION}}"
@ -23,11 +23,11 @@ export OPENVIDU_AGENT_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_SPEECH_PROCESSIN
export OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE:-docker.io/openvidu/agent-speech-processing-sherpa:${OPENVIDU_VERSION}}"
export LIVEKIT_INGRESS_SERVER_IMAGE="${LIVEKIT_INGRESS_SERVER_IMAGE:-docker.io/openvidu/ingress:${OPENVIDU_VERSION}}"
export LIVEKIT_EGRESS_SERVER_IMAGE="${LIVEKIT_EGRESS_SERVER_IMAGE:-docker.io/openvidu/egress:${OPENVIDU_VERSION}}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.11.3}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.12}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.12}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.6-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.6}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.9.1}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.11}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.11}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.4-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.4}"
# Function to compare two version strings
compare_versions() {

View File

@ -1441,9 +1441,9 @@ Resources:
content: !Sub |
#!/bin/bash
set -e
OPENVIDU_VERSION=main
OPENVIDU_VERSION=3.6.1
DOMAIN=
YQ_VERSION=v4.53.2
YQ_VERSION=v4.52.4
# Install dependencies
apt-get update && apt-get install -y \
@ -1454,7 +1454,7 @@ Resources:
wget https://github.com/mikefarah/yq/releases/download/${!YQ_VERSION}/yq_linux_$(dpkg --print-architecture).tar.gz -O - |\
tar xz && mv yq_linux_$(dpkg --print-architecture) /usr/bin/yq
AWS_CLI_VERSION=2.34.41
AWS_CLI_VERSION=2.34.0
# Install aws-cli if not already installed
if ! command -v aws &> /dev/null; then
curl "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m)-${!AWS_CLI_VERSION}.zip" -o "awscliv2.zip"
@ -1977,7 +1977,7 @@ Resources:
#!/bin/bash
set -e
DOMAIN=
YQ_VERSION=v4.53.2
YQ_VERSION=v4.52.4
# Install dependencies
apt-get update && apt-get install -y \
@ -1988,7 +1988,7 @@ Resources:
wget https://github.com/mikefarah/yq/releases/download/${!YQ_VERSION}/yq_linux_$(dpkg --print-architecture).tar.gz -O - |\
tar xz && mv yq_linux_$(dpkg --print-architecture) /usr/bin/yq
AWS_CLI_VERSION=2.34.41
AWS_CLI_VERSION=2.34.0
# Install aws-cli if not already installed
if ! command -v aws &> /dev/null; then
curl "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m)-${!AWS_CLI_VERSION}.zip" -o "awscliv2.zip"

View File

@ -211,7 +211,7 @@ var stringInterpolationParamsMaster = {
var installScriptTemplateMaster = '''
#!/bin/bash -x
OPENVIDU_VERSION=main
OPENVIDU_VERSION=3.6.1
DOMAIN=
# Assume azure cli is installed
@ -790,7 +790,7 @@ echo ${base64config_blobStorage} | base64 -d > /usr/local/bin/config_blobStorage
chmod +x /usr/local/bin/config_blobStorage.sh
# Install azure cli
AZURE_CLI_VERSION=2.85.0
AZURE_CLI_VERSION=2.83.0
apt-get install -y apt-transport-https ca-certificates gnupg lsb-release
curl -sLS https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /etc/apt/trusted.gpg.d/microsoft.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/azure-cli.list
@ -1039,7 +1039,7 @@ apt-get update && apt-get install -y
apt-get install -y jq
# Install azure cli
AZURE_CLI_VERSION=2.85.0
AZURE_CLI_VERSION=2.83.0
apt-get install -y apt-transport-https ca-certificates gnupg lsb-release
curl -sLS https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /etc/apt/trusted.gpg.d/microsoft.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/azure-cli.list

File diff suppressed because one or more lines are too long

View File

@ -617,9 +617,9 @@ locals {
#!/bin/bash -x
set -e
OPENVIDU_VERSION=main
OPENVIDU_VERSION=3.6.1
DOMAIN=
YQ_VERSION=v4.53.2
YQ_VERSION=v4.52.4
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
apt-get update && apt-get install -y \
@ -1131,7 +1131,7 @@ CONFIG_S3_EOF
apt-get update && apt-get install -y
GCLOUD_VERSION=566.0.0
GCLOUD_VERSION=558.0.0
# Install google cli
if ! command -v gcloud >/dev/null 2>&1; then
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg
@ -1327,7 +1327,7 @@ echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
apt-get update && apt-get install -y
GCLOUD_VERSION=566.0.0
GCLOUD_VERSION=558.0.0
# Install google cli
if ! command -v gcloud >/dev/null 2>&1; then
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg

View File

@ -1,14 +1,14 @@
#!/bin/sh
# Docker & Docker Compose will need to be installed on the machine
set -eu
export DOCKER_VERSION="${DOCKER_VERSION:-29.4.2}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.1.3}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-main}"
export DOCKER_VERSION="${DOCKER_VERSION:-29.2.1}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.0.2}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-3.6.1}"
export INSTALLER_IMAGE="${INSTALLER_IMAGE:-docker.io/openvidu/openvidu-installer:${OPENVIDU_VERSION}}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-05-04T00-27-21Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-05-04T15-44-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.21}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.2-alpine}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-03-04T16-04-53Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-03-12T12-23-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.19}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.1-alpine}"
export BUSYBOX_IMAGE="${BUSYBOX_IMAGE:-docker.io/busybox:1.37.0}"
export CADDY_SERVER_IMAGE="${CADDY_SERVER_IMAGE:-docker.io/openvidu/openvidu-caddy:${OPENVIDU_VERSION}}"
export CADDY_SERVER_PRO_IMAGE="${CADDY_SERVER_PRO_IMAGE:-docker.io/openvidu/openvidu-pro-caddy:${OPENVIDU_VERSION}}"
@ -23,11 +23,11 @@ export OPENVIDU_AGENT_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_SPEECH_PROCESSIN
export OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE:-docker.io/openvidu/agent-speech-processing-sherpa:${OPENVIDU_VERSION}}"
export LIVEKIT_INGRESS_SERVER_IMAGE="${LIVEKIT_INGRESS_SERVER_IMAGE:-docker.io/openvidu/ingress:${OPENVIDU_VERSION}}"
export LIVEKIT_EGRESS_SERVER_IMAGE="${LIVEKIT_EGRESS_SERVER_IMAGE:-docker.io/openvidu/egress:${OPENVIDU_VERSION}}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.11.3}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.12}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.12}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.6-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.6}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.9.1}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.11}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.11}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.4-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.4}"
# Function to compare two version strings
compare_versions() {

View File

@ -1,14 +1,14 @@
#!/bin/sh
# Docker & Docker Compose will need to be installed on the machine
set -eu
export DOCKER_VERSION="${DOCKER_VERSION:-29.4.2}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.1.3}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-main}"
export DOCKER_VERSION="${DOCKER_VERSION:-29.2.1}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.0.2}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-3.6.1}"
export INSTALLER_IMAGE="${INSTALLER_IMAGE:-docker.io/openvidu/openvidu-installer:${OPENVIDU_VERSION}}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-05-04T00-27-21Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-05-04T15-44-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.21}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.2-alpine}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-03-04T16-04-53Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-03-12T12-23-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.19}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.1-alpine}"
export BUSYBOX_IMAGE="${BUSYBOX_IMAGE:-docker.io/busybox:1.37.0}"
export CADDY_SERVER_IMAGE="${CADDY_SERVER_IMAGE:-docker.io/openvidu/openvidu-caddy:${OPENVIDU_VERSION}}"
export CADDY_SERVER_PRO_IMAGE="${CADDY_SERVER_PRO_IMAGE:-docker.io/openvidu/openvidu-pro-caddy:${OPENVIDU_VERSION}}"
@ -23,11 +23,11 @@ export OPENVIDU_AGENT_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_SPEECH_PROCESSIN
export OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE:-docker.io/openvidu/agent-speech-processing-sherpa:${OPENVIDU_VERSION}}"
export LIVEKIT_INGRESS_SERVER_IMAGE="${LIVEKIT_INGRESS_SERVER_IMAGE:-docker.io/openvidu/ingress:${OPENVIDU_VERSION}}"
export LIVEKIT_EGRESS_SERVER_IMAGE="${LIVEKIT_EGRESS_SERVER_IMAGE:-docker.io/openvidu/egress:${OPENVIDU_VERSION}}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.11.3}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.12}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.12}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.6-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.6}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.9.1}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.11}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.11}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.4-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.4}"
# Function to compare two version strings
compare_versions() {

View File

@ -1544,9 +1544,9 @@ Resources:
content: !Sub |
#!/bin/bash -x
set -e
OPENVIDU_VERSION=main
OPENVIDU_VERSION=3.6.1
DOMAIN=
YQ_VERSION=v4.53.2
YQ_VERSION=v4.52.4
# Install dependencies
apt-get update && apt-get install -y \
@ -1557,7 +1557,7 @@ Resources:
wget https://github.com/mikefarah/yq/releases/download/${!YQ_VERSION}/yq_linux_$(dpkg --print-architecture).tar.gz -O - |\
tar xz && mv yq_linux_$(dpkg --print-architecture) /usr/bin/yq
AWS_CLI_VERSION=2.34.41
AWS_CLI_VERSION=2.34.0
# Install aws-cli if not already installed
if ! command -v aws &> /dev/null; then
curl "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m)-${!AWS_CLI_VERSION}.zip" -o "awscliv2.zip"
@ -2316,7 +2316,7 @@ Resources:
content: !Sub |
#!/bin/bash
set -e
YQ_VERSION=v4.53.2
YQ_VERSION=v4.52.4
# Install dependencies
apt-get update && apt-get install -y \
@ -2327,7 +2327,7 @@ Resources:
wget https://github.com/mikefarah/yq/releases/download/${!YQ_VERSION}/yq_linux_$(dpkg --print-architecture).tar.gz -O - |\
tar xz && mv yq_linux_$(dpkg --print-architecture) /usr/bin/yq
AWS_CLI_VERSION=2.34.41
AWS_CLI_VERSION=2.34.0
# Install aws-cli if not already installed
if ! command -v aws &> /dev/null; then
curl "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m)-${!AWS_CLI_VERSION}.zip" -o "awscliv2.zip"

View File

@ -287,7 +287,7 @@ var stringInterpolationParamsMaster4 = {
var installScriptTemplateMaster = '''
#!/bin/bash -x
set -e
OPENVIDU_VERSION=main
OPENVIDU_VERSION=3.6.1
DOMAIN=
# Assume azure cli is installed
@ -990,7 +990,7 @@ echo ${base64config_blobStorage} | base64 -d > /usr/local/bin/config_blobStorage
chmod +x /usr/local/bin/config_blobStorage.sh
# Install azure cli
AZURE_CLI_VERSION=2.85.0
AZURE_CLI_VERSION=2.83.0
apt-get install -y apt-transport-https ca-certificates gnupg lsb-release
curl -sLS https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /etc/apt/trusted.gpg.d/microsoft.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/azure-cli.list
@ -1371,7 +1371,7 @@ apt-get update && apt-get install -y
apt-get install -y jq
# Install azure cli
AZURE_CLI_VERSION=2.85.0
AZURE_CLI_VERSION=2.83.0
apt-get install -y apt-transport-https ca-certificates gnupg lsb-release
curl -sLS https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /etc/apt/trusted.gpg.d/microsoft.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/azure-cli.list

File diff suppressed because one or more lines are too long

View File

@ -942,9 +942,9 @@ locals {
#!/bin/bash -x
set -e
OPENVIDU_VERSION=main
OPENVIDU_VERSION=3.6.1
DOMAIN=
YQ_VERSION=v4.53.2
YQ_VERSION=v4.52.4
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
@ -1501,7 +1501,7 @@ CONFIG_S3_EOF
apt-get update && apt-get install -y
GCLOUD_VERSION=566.0.0
GCLOUD_VERSION=558.0.0
# Install google cli
if ! command -v gcloud >/dev/null 2>&1; then
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg
@ -1689,7 +1689,7 @@ echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
apt-get update && apt-get install -y
GCLOUD_VERSION=566.0.0
GCLOUD_VERSION=558.0.0
# Install google cli
if ! command -v gcloud >/dev/null 2>&1; then
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg

View File

@ -1,14 +1,14 @@
#!/bin/sh
# Docker & Docker Compose will need to be installed on the machine
set -eu
export DOCKER_VERSION="${DOCKER_VERSION:-29.4.2}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.1.3}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-main}"
export DOCKER_VERSION="${DOCKER_VERSION:-29.2.1}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.0.2}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-3.6.1}"
export INSTALLER_IMAGE="${INSTALLER_IMAGE:-docker.io/openvidu/openvidu-installer:${OPENVIDU_VERSION}}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-05-04T00-27-21Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-05-04T15-44-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.21}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.2-alpine}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-03-04T16-04-53Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-03-12T12-23-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.19}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.1-alpine}"
export BUSYBOX_IMAGE="${BUSYBOX_IMAGE:-docker.io/busybox:1.37.0}"
export CADDY_SERVER_IMAGE="${CADDY_SERVER_IMAGE:-docker.io/openvidu/openvidu-caddy:${OPENVIDU_VERSION}}"
export CADDY_SERVER_PRO_IMAGE="${CADDY_SERVER_PRO_IMAGE:-docker.io/openvidu/openvidu-pro-caddy:${OPENVIDU_VERSION}}"
@ -23,11 +23,11 @@ export OPENVIDU_AGENT_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_SPEECH_PROCESSIN
export OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE:-docker.io/openvidu/agent-speech-processing-sherpa:${OPENVIDU_VERSION}}"
export LIVEKIT_INGRESS_SERVER_IMAGE="${LIVEKIT_INGRESS_SERVER_IMAGE:-docker.io/openvidu/ingress:${OPENVIDU_VERSION}}"
export LIVEKIT_EGRESS_SERVER_IMAGE="${LIVEKIT_EGRESS_SERVER_IMAGE:-docker.io/openvidu/egress:${OPENVIDU_VERSION}}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.11.3}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.12}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.12}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.6-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.6}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.9.1}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.11}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.11}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.4-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.4}"
# Function to compare two version strings
compare_versions() {

View File

@ -1,14 +1,14 @@
#!/bin/sh
# Docker & Docker Compose will need to be installed on the machine
set -eu
export DOCKER_VERSION="${DOCKER_VERSION:-29.4.2}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.1.3}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-main}"
export DOCKER_VERSION="${DOCKER_VERSION:-29.2.1}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.0.2}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-3.6.1}"
export INSTALLER_IMAGE="${INSTALLER_IMAGE:-docker.io/openvidu/openvidu-installer:${OPENVIDU_VERSION}}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-05-04T00-27-21Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-05-04T15-44-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.21}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.2-alpine}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-03-04T16-04-53Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-03-12T12-23-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.19}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.1-alpine}"
export BUSYBOX_IMAGE="${BUSYBOX_IMAGE:-docker.io/busybox:1.37.0}"
export CADDY_SERVER_IMAGE="${CADDY_SERVER_IMAGE:-docker.io/openvidu/openvidu-caddy:${OPENVIDU_VERSION}}"
export CADDY_SERVER_PRO_IMAGE="${CADDY_SERVER_PRO_IMAGE:-docker.io/openvidu/openvidu-pro-caddy:${OPENVIDU_VERSION}}"
@ -23,11 +23,11 @@ export OPENVIDU_AGENT_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_SPEECH_PROCESSIN
export OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE:-docker.io/openvidu/agent-speech-processing-sherpa:${OPENVIDU_VERSION}}"
export LIVEKIT_INGRESS_SERVER_IMAGE="${LIVEKIT_INGRESS_SERVER_IMAGE:-docker.io/openvidu/ingress:${OPENVIDU_VERSION}}"
export LIVEKIT_EGRESS_SERVER_IMAGE="${LIVEKIT_EGRESS_SERVER_IMAGE:-docker.io/openvidu/egress:${OPENVIDU_VERSION}}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.11.3}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.12}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.12}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.6-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.6}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.9.1}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.11}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.11}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.4-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.4}"
# Function to compare two version strings
compare_versions() {

View File

@ -1,7 +1,7 @@
services:
generate-scripts:
image: alpine:3.23.4
image: alpine:3.23.3
entrypoint: ["/bin/sh", "-c"]
restart: "no"
user: root

View File

@ -1,6 +1,6 @@
services:
caddy-proxy:
image: docker.io/openvidu/openvidu-caddy-local:main
image: docker.io/openvidu/openvidu-caddy-local:3.6.1
restart: unless-stopped
extra_hosts:
- host.docker.internal:host-gateway
@ -33,7 +33,7 @@ services:
condition: service_completed_successfully
redis:
image: docker.io/redis:8.6.2-alpine
image: docker.io/redis:8.6.1-alpine
restart: unless-stopped
ports:
- 6379:6379
@ -49,7 +49,7 @@ services:
condition: service_completed_successfully
minio:
image: docker.io/openvidu/minio:RELEASE.2026-05-04T00-27-21Z-r0
image: docker.io/openvidu/minio:RELEASE.2026-03-04T16-04-53Z-r0
restart: unless-stopped
ports:
- 9000:9000
@ -69,7 +69,7 @@ services:
condition: service_completed_successfully
mongo:
image: docker.io/openvidu/mongodb:8.0.21-r0
image: docker.io/openvidu/mongodb:8.0.19-r2
restart: unless-stopped
ports:
- 27017:27017
@ -88,7 +88,7 @@ services:
condition: service_completed_successfully
dashboard:
image: docker.io/openvidu/openvidu-dashboard:main
image: docker.io/openvidu/openvidu-dashboard:3.6.1
restart: unless-stopped
volumes:
- /etc/localtime:/etc/localtime:ro
@ -102,7 +102,7 @@ services:
condition: service_completed_successfully
openvidu:
image: docker.io/openvidu/openvidu-server-pro:main
image: docker.io/openvidu/openvidu-server-pro:3.6.1
restart: unless-stopped
extra_hosts:
- host.docker.internal:host-gateway
@ -125,7 +125,7 @@ services:
condition: service_completed_successfully
ingress:
image: docker.io/openvidu/ingress:main
image: docker.io/openvidu/ingress:3.6.1
restart: unless-stopped
extra_hosts:
- host.docker.internal:host-gateway
@ -143,7 +143,7 @@ services:
condition: service_completed_successfully
egress:
image: docker.io/openvidu/egress:main
image: docker.io/openvidu/egress:3.6.1
restart: unless-stopped
extra_hosts:
- host.docker.internal:host-gateway
@ -157,7 +157,7 @@ services:
setup:
condition: service_completed_successfully
operator:
image: docker.io/openvidu/openvidu-operator:main
image: docker.io/openvidu/openvidu-operator:3.6.1
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
@ -181,7 +181,7 @@ services:
openvidu-meet:
image: docker.io/openvidu/openvidu-meet:main
image: docker.io/openvidu/openvidu-meet:3.6.1
restart: on-failure
extra_hosts:
- host.docker.internal:host-gateway
@ -221,7 +221,7 @@ services:
condition: service_completed_successfully
openvidu-v2compatibility:
image: docker.io/openvidu/openvidu-v2compatibility:main
image: docker.io/openvidu/openvidu-v2compatibility:3.6.1
restart: unless-stopped
entrypoint: /bin/sh /scripts/entrypoint_openvidu_v2_compat.sh
extra_hosts:
@ -258,7 +258,7 @@ services:
condition: service_completed_successfully
openvidu-meet-init:
image: docker.io/openvidu/openvidu-operator:main
image: docker.io/openvidu/openvidu-operator:3.6.1
restart: on-failure
environment:
- MODE=local-ready-check

View File

@ -782,9 +782,9 @@ Resources:
'/usr/local/bin/install.sh':
content: !Sub |
#!/bin/bash -x
OPENVIDU_VERSION=main
OPENVIDU_VERSION=3.6.1
DOMAIN=
YQ_VERSION=v4.53.2
YQ_VERSION=v4.52.4
apt-get update && apt-get install -y \
curl \
@ -794,7 +794,7 @@ Resources:
wget https://github.com/mikefarah/yq/releases/download/${!YQ_VERSION}/yq_linux_$(dpkg --print-architecture).tar.gz -O - |\
tar xz && mv yq_linux_$(dpkg --print-architecture) /usr/bin/yq
AWS_CLI_VERSION=2.34.41
AWS_CLI_VERSION=2.34.0
# Install aws-cli if not already installed
if ! command -v aws &> /dev/null; then
curl "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m)-${!AWS_CLI_VERSION}.zip" -o "awscliv2.zip"

View File

@ -174,7 +174,7 @@ var stringInterpolationParams = {
var installScriptTemplate = '''
#!/bin/bash -x
OPENVIDU_VERSION=main
OPENVIDU_VERSION=3.6.1
DOMAIN=
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
@ -713,7 +713,7 @@ echo ${base64config_blobStorage} | base64 -d > /usr/local/bin/config_blobStorage
chmod +x /usr/local/bin/config_blobStorage.sh
# Install azure cli
AZURE_CLI_VERSION=2.85.0
AZURE_CLI_VERSION=2.83.0
apt-get install -y apt-transport-https ca-certificates gnupg lsb-release
curl -sLS https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /etc/apt/trusted.gpg.d/microsoft.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/azure-cli.list

File diff suppressed because one or more lines are too long

View File

@ -148,9 +148,9 @@ locals {
#!/bin/bash -x
set -e
OPENVIDU_VERSION=main
OPENVIDU_VERSION=3.6.1
DOMAIN=
YQ_VERSION=v4.53.2
YQ_VERSION=v4.52.4
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
apt-get update && apt-get install -y \
@ -648,7 +648,7 @@ CONFIG_S3_EOF
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
apt-get update && apt-get install -y
GCLOUD_VERSION=566.0.0
GCLOUD_VERSION=558.0.0
# Install google cli
if ! command -v gcloud >/dev/null 2>&1; then
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg

View File

@ -1,14 +1,14 @@
#!/bin/sh
# Docker & Docker Compose will need to be installed on the machine
set -eu
export DOCKER_VERSION="${DOCKER_VERSION:-29.4.2}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.1.3}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-main}"
export DOCKER_VERSION="${DOCKER_VERSION:-29.2.1}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.0.2}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-3.6.1}"
export INSTALLER_IMAGE="${INSTALLER_IMAGE:-docker.io/openvidu/openvidu-installer:${OPENVIDU_VERSION}}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-05-04T00-27-21Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-05-04T15-44-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.21}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.2-alpine}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-03-04T16-04-53Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-03-12T12-23-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.19}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.1-alpine}"
export BUSYBOX_IMAGE="${BUSYBOX_IMAGE:-docker.io/busybox:1.37.0}"
export CADDY_SERVER_IMAGE="${CADDY_SERVER_IMAGE:-docker.io/openvidu/openvidu-caddy:${OPENVIDU_VERSION}}"
export CADDY_SERVER_PRO_IMAGE="${CADDY_SERVER_PRO_IMAGE:-docker.io/openvidu/openvidu-pro-caddy:${OPENVIDU_VERSION}}"
@ -23,11 +23,11 @@ export OPENVIDU_AGENT_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_SPEECH_PROCESSIN
export OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE:-docker.io/openvidu/agent-speech-processing-sherpa:${OPENVIDU_VERSION}}"
export LIVEKIT_INGRESS_SERVER_IMAGE="${LIVEKIT_INGRESS_SERVER_IMAGE:-docker.io/openvidu/ingress:${OPENVIDU_VERSION}}"
export LIVEKIT_EGRESS_SERVER_IMAGE="${LIVEKIT_EGRESS_SERVER_IMAGE:-docker.io/openvidu/egress:${OPENVIDU_VERSION}}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.11.3}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.12}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.12}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.6-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.6}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.9.1}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.11}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.11}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.4-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.4}"
# Function to compare two version strings
compare_versions() {

View File

@ -1,17 +1,14 @@
#!/bin/sh
set -eu
export INSTALL_PREFIX="${INSTALL_PREFIX:-/opt/openvidu}"
export DOCKER_VERSION="${DOCKER_VERSION:-29.4.2}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.1.3}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-main}"
export UPDATE_BASE_URL="${UPDATE_BASE_URL:-http://get.openvidu.io/update}"
export DOCKER_VERSION="${DOCKER_VERSION:-29.2.1}"
export DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-v5.0.2}"
export OPENVIDU_VERSION="${OPENVIDU_VERSION:-3.6.1}"
export UPDATER_IMAGE="${UPDATER_IMAGE:-docker.io/openvidu/openvidu-updater:${OPENVIDU_VERSION}}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-05-04T00-27-21Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-05-04T15-44-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.21}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.2-alpine}"
export MINIO_SERVER_IMAGE="${MINIO_SERVER_IMAGE:-docker.io/openvidu/minio:RELEASE.2026-03-04T16-04-53Z-r0}"
export MINIO_CLIENT_IMAGE="${MINIO_CLIENT_IMAGE:-docker.io/openvidu/minio-client:RELEASE.2026-03-12T12-23-10Z}"
export MONGO_SERVER_IMAGE="${MONGO_SERVER_IMAGE:-docker.io/mongo:8.0.19}"
export REDIS_SERVER_IMAGE="${REDIS_SERVER_IMAGE:-docker.io/redis:8.6.1-alpine}"
export BUSYBOX_IMAGE="${BUSYBOX_IMAGE:-docker.io/busybox:1.37.0}"
export CADDY_SERVER_IMAGE="${CADDY_SERVER_IMAGE:-docker.io/openvidu/openvidu-caddy:${OPENVIDU_VERSION}}"
export CADDY_SERVER_PRO_IMAGE="${CADDY_SERVER_PRO_IMAGE:-docker.io/openvidu/openvidu-pro-caddy:${OPENVIDU_VERSION}}"
@ -26,11 +23,11 @@ export OPENVIDU_AGENT_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_SPEECH_PROCESSIN
export OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE="${OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE:-docker.io/openvidu/agent-speech-processing-sherpa:${OPENVIDU_VERSION}}"
export LIVEKIT_INGRESS_SERVER_IMAGE="${LIVEKIT_INGRESS_SERVER_IMAGE:-docker.io/openvidu/ingress:${OPENVIDU_VERSION}}"
export LIVEKIT_EGRESS_SERVER_IMAGE="${LIVEKIT_EGRESS_SERVER_IMAGE:-docker.io/openvidu/egress:${OPENVIDU_VERSION}}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.11.3}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.12}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.12}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.6-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.6}"
export PROMETHEUS_IMAGE="${PROMETHEUS_IMAGE:-docker.io/prom/prometheus:v3.9.1}"
export PROMTAIL_IMAGE="${PROMTAIL_IMAGE:-docker.io/grafana/promtail:3.5.11}"
export LOKI_IMAGE="${LOKI_IMAGE:-docker.io/grafana/loki:3.5.11}"
export MIMIR_IMAGE="${MIMIR_IMAGE:-docker.io/openvidu/grafana-mimir:3.0.4-r0}"
export GRAFANA_IMAGE="${GRAFANA_IMAGE:-docker.io/grafana/grafana:12.3.4}"
get_next_version() {
case "$1" in
@ -42,22 +39,10 @@ get_next_version() {
"3.4.1") echo "3.5.0" ;;
"3.5.0") echo "3.6.0" ;;
"3.6.0") echo "3.6.1" ;;
"3.6.1") echo "3.7.0" ;;
*) echo "" ;;
esac
}
# Existing versions use update-new.sh to keep the original update.sh intact.
# Future versions (3.7.x+) will use update.sh normally.
get_update_script() {
case "$1" in
"3.1.0"|"3.2.0"|"3.3.0"|"3.4.0"|"3.4.1"|"3.5.0"|"3.6.0"|"3.6.1")
echo "update-new.sh" ;;
*)
echo "update.sh" ;;
esac
}
# Function to compare two version strings
compare_versions() {
# Remove 'v' prefix if present
@ -106,37 +91,6 @@ validate_upgrade() {
current="$1"
target="$2"
if [ "$current" = "$target" ]; then
echo "Your installed version is $current"
return 0
fi
# Only upgrades from 3.4.0 or 3.4.1 targeting a version > 3.5.0 must stop
# at 3.5.0 first.
checkpoint="3.5.0"
if [ "$current" = "3.4.0" ] || [ "$current" = "3.4.1" ]; then
if [ "$target" = "main" ] || ( printf '%s\n%s\n' "$checkpoint" "$target" | sort -V -C && [ "$target" != "$checkpoint" ] ); then
echo "WARNING: Upgrading through OpenVidu ${checkpoint} requires special steps."
echo "The upgrade process must stop at version ${checkpoint} before continuing."
echo ""
echo "Please follow these steps:"
echo ""
echo " 1. Upgrade ALL cluster nodes to version ${checkpoint}:"
echo " sh <(curl -fsSL ${UPDATE_BASE_URL}/${checkpoint}/update.sh)"
echo ""
echo " 2. Start OpenVidu on every node:"
echo " systemctl start openvidu"
echo ""
echo " 3. Wait for initialization."
echo ""
echo " 4. Stop OpenVidu on every node:"
echo " systemctl stop openvidu"
echo ""
echo "After completing these steps, re-run this upgrade script to continue."
exit 1
fi
fi
if [ "$target" = "main" ]; then
echo "WARNING: You are trying to upgrade to 'main' version."
echo "This version is for OpenVidu developers and may be unstable."
@ -157,79 +111,17 @@ validate_upgrade() {
if [ "$target" = "$next_version" ]; then
return 0
else
echo "ERROR: Version $current can only be upgraded to version $next_version"
echo "Please upgrade first to version $next_version"
echo "You can do it by running the following command:"
echo ""
echo ""
echo " sh <(curl -fsSL http://get.openvidu.io/update/$next_version/update.sh)"
echo ""
echo ""
exit 1
fi
while [ "$next_version" != "$target" ]; do
if [ -z "$next_version" ]; then
echo "ERROR: No upgrade path defined for version $current"
exit 1
fi
if [ "$NO_TTY_REQUESTED" != "yes" ]; then
echo "Upgrading to $next_version before the target version."
while true; do
printf "Proceed with upgrading to $next_version? [y/N]: "
read -r response
if [ "$response" = "y" ] || [ "$response" = "Y" ]; then
break
elif [ "$response" = "n" ] || [ "$response" = "N" ]; then
echo "Update cancelled"
exit 1
else
echo "Please answer 'y' or 'n'."
fi
done
fi
echo "Upgrading from $current to $next_version first..."
TMP_UPDATE="$(mktemp /tmp/ov_update.XXXXXX)"
update_script="$(get_update_script "$next_version")"
if ! curl -fsSL "${UPDATE_BASE_URL}/$next_version/${update_script}" -o "$TMP_UPDATE"; then
rm -f "$TMP_UPDATE"
echo "ERROR: Failed to download update script for $next_version"
exit 1
fi
if ! env \
-u OPENVIDU_VERSION \
-u DOCKER_VERSION \
-u DOCKER_COMPOSE_VERSION \
-u UPDATER_IMAGE \
-u MINIO_SERVER_IMAGE \
-u MINIO_CLIENT_IMAGE \
-u MONGO_SERVER_IMAGE \
-u REDIS_SERVER_IMAGE \
-u BUSYBOX_IMAGE \
-u CADDY_SERVER_IMAGE \
-u CADDY_SERVER_PRO_IMAGE \
-u OPENVIDU_OPERATOR_IMAGE \
-u OPENVIDU_SERVER_PRO_IMAGE \
-u OPENVIDU_SERVER_IMAGE \
-u OPENVIDU_MEET_SERVER_IMAGE \
-u OPENVIDU_DASHBOARD_PRO_IMAGE \
-u OPENVIDU_DASHBOARD_IMAGE \
-u OPENVIDU_V2COMPATIBILITY_IMAGE \
-u OPENVIDU_AGENT_SPEECH_PROCESSING_IMAGE \
-u OPENVIDU_AGENT_PRO_SPEECH_PROCESSING_IMAGE \
-u LIVEKIT_INGRESS_SERVER_IMAGE \
-u LIVEKIT_EGRESS_SERVER_IMAGE \
-u PROMETHEUS_IMAGE \
-u PROMTAIL_IMAGE \
-u LOKI_IMAGE \
-u MIMIR_IMAGE \
-u GRAFANA_IMAGE \
sh "$TMP_UPDATE" $NO_TTY_FLAG; then
rm -f "$TMP_UPDATE"
echo "ERROR: Intermediate upgrade from $current to $next_version failed"
exit 1
fi
rm -f "$TMP_UPDATE"
current="$(grep version "${INSTALL_PREFIX}/deployment-info.yaml" | cut -d':' -f2 | sed 's/^ *"//;s/"$//')"
next_version="$(get_next_version "$current")"
if [ -z "$next_version" ]; then
echo "ERROR: No upgrade path found from version $current to $target"
exit 1
fi
done
return 0
}
# Check if executing as root
@ -238,91 +130,6 @@ if [ "$(id -u)" -ne 0 ]; then
exit 1
fi
# Check --no-tty
if [ -z "${NO_TTY_REQUESTED:+x}" ]; then
NO_TTY_REQUESTED="no"
for arg in "$@"; do
if [ "$arg" = "--no-tty" ]; then
NO_TTY_REQUESTED="yes"
break
fi
done
export NO_TTY_REQUESTED
fi
NO_TTY_FLAG=""
if [ "$NO_TTY_REQUESTED" = "yes" ]; then
NO_TTY_FLAG="--no-tty"
fi
# Ensure docker-compose shim exists
if ! command -v docker-compose > /dev/null 2>&1; then
if docker compose version > /dev/null 2>&1; then
cat > /usr/local/bin/docker-compose <<'EOF'
#!/bin/sh
exec docker compose "$@"
EOF
chmod 755 /usr/local/bin/docker-compose
mkdir -p /usr/local/lib/docker/cli-plugins
ln -sf /usr/local/bin/docker-compose /usr/local/lib/docker/cli-plugins/docker-compose
fi
fi
# Check Docker installation and version
if [ "${OPENVIDU_SKIP_DOCKER_VERSION_CHECK:-}" != "true" ]; then
if ! command -v docker > /dev/null 2>&1; then
echo "ERROR: Docker is not installed. Docker is required to continue."
exit 1
else
CURRENT_DOCKER_VERSION=$(docker --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
VERSION_COMPARISON=$(compare_versions "$CURRENT_DOCKER_VERSION" "$DOCKER_VERSION")
if [ "$VERSION_COMPARISON" = "lower" ]; then
echo "WARNING: Docker version $CURRENT_DOCKER_VERSION is older than the recommended version $DOCKER_VERSION."
printf "Continue anyway? [Y/n]: "
read -r response
if [ "$response" != "n" ] && [ "$response" != "N" ]; then
export OPENVIDU_SKIP_DOCKER_VERSION_CHECK=true
else
echo "Update cancelled"
exit 1
fi
fi
fi
fi
# Check Docker Compose installation and version
if [ "${OPENVIDU_SKIP_DOCKER_COMPOSE_VERSION_CHECK:-}" != "true" ]; then
DOCKER_COMPOSE_CMD=""
if command -v docker-compose > /dev/null 2>&1; then
DOCKER_COMPOSE_CMD="docker-compose"
elif docker compose version > /dev/null 2>&1; then
DOCKER_COMPOSE_CMD="docker compose"
fi
if [ -n "$DOCKER_COMPOSE_CMD" ]; then
CURRENT_DC_VERSION=$($DOCKER_COMPOSE_CMD --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
# Add 'v' prefix for proper comparison
CURRENT_DC_VERSION="v${CURRENT_DC_VERSION}"
VERSION_COMPARISON=$(compare_versions "$CURRENT_DC_VERSION" "$DOCKER_COMPOSE_VERSION")
if [ "$VERSION_COMPARISON" = "lower" ]; then
echo "WARNING: Docker Compose version $CURRENT_DC_VERSION is older than the recommended version $DOCKER_COMPOSE_VERSION."
printf "Continue anyway? [Y/n]: "
read -r response
if [ "$response" != "n" ] && [ "$response" != "N" ]; then
export OPENVIDU_SKIP_DOCKER_COMPOSE_VERSION_CHECK=true
else
echo "Update cancelled"
exit 1
fi
fi
else
echo "ERROR: Docker Compose is not installed. Docker Compose is required to continue."
exit 1
fi
fi
# Validate the upgrade path
CURRENT_VERSION="$(grep version "${INSTALL_PREFIX}/deployment-info.yaml" | cut -d':' -f2 | sed 's/^ *"//;s/"$//')"
validate_upgrade "$CURRENT_VERSION" "$OPENVIDU_VERSION"
@ -331,6 +138,87 @@ validate_upgrade "$CURRENT_VERSION" "$OPENVIDU_VERSION"
echo "Stopping OpenVidu service..."
systemctl stop openvidu
# Check Docker installation and version
DOCKER_NEEDED=false
if ! command -v docker > /dev/null 2>&1; then
echo "Docker not found. Will install Docker version ${DOCKER_VERSION}."
DOCKER_NEEDED=true
else
CURRENT_DOCKER_VERSION=$(docker --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
VERSION_COMPARISON=$(compare_versions "$CURRENT_DOCKER_VERSION" "$DOCKER_VERSION")
if [ "$VERSION_COMPARISON" = "lower" ]; then
echo "Docker version $CURRENT_DOCKER_VERSION is older than required version $DOCKER_VERSION."
echo "Please update Docker to version $DOCKER_VERSION or later."
exit 1
else
echo "Docker version $CURRENT_DOCKER_VERSION is compatible with required version $DOCKER_VERSION."
fi
fi
# Install Docker if needed
if [ "$DOCKER_NEEDED" = true ]; then
curl -fsSL https://get.docker.com -o /tmp/get-docker.sh
sh /tmp/get-docker.sh --version "${DOCKER_VERSION}" || { echo "Can't install Docker automatically. Install it manually and run this script again"; exit 1; }
fi
# Check Docker Compose installation and version
DOCKER_COMPOSE_NEEDED=false
if ! command -v docker-compose > /dev/null 2>&1; then
echo "Docker Compose not found. Will install Docker Compose version ${DOCKER_COMPOSE_VERSION}."
DOCKER_COMPOSE_NEEDED=true
else
CURRENT_DC_VERSION=$(docker-compose --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
# Add 'v' prefix for proper comparison
CURRENT_DC_VERSION="v${CURRENT_DC_VERSION}"
VERSION_COMPARISON=$(compare_versions "$CURRENT_DC_VERSION" "$DOCKER_COMPOSE_VERSION")
if [ "$VERSION_COMPARISON" = "lower" ]; then
echo "Docker Compose version $CURRENT_DC_VERSION is older than required version $DOCKER_COMPOSE_VERSION."
echo "Will update Docker Compose to version $DOCKER_COMPOSE_VERSION."
DOCKER_COMPOSE_NEEDED=true
else
echo "Docker Compose version $CURRENT_DC_VERSION is compatible with required version $DOCKER_COMPOSE_VERSION."
fi
fi
# Install or update Docker Compose if needed
if [ "$DOCKER_COMPOSE_NEEDED" = true ]; then
TIME_LIMIT_SECONDS=20
START_TIME=$(awk 'BEGIN{srand(); print srand()}')
while true
do
CURRENT_TIME=$(awk 'BEGIN{srand(); print srand()}')
if [ $((CURRENT_TIME-START_TIME)) -gt $TIME_LIMIT_SECONDS ]; then
echo "Error downloading docker-compose. Could not download it in $TIME_LIMIT_SECONDS seconds"
rm -f /usr/local/bin/docker-compose
exit 1
fi
STATUS_RECEIVED=$(curl --retry 5 --retry-max-time 40 --write-out "%{http_code}\n" -L "https://github.com/docker/compose/releases/download/$DOCKER_COMPOSE_VERSION/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose)
CURL_EXIT_CODE=$?
if [ $CURL_EXIT_CODE -ne 0 ]; then
echo "Error downloading docker-compose. curl failed with exit code $CURL_EXIT_CODE. There are still $((TIME_LIMIT_SECONDS - (CURRENT_TIME - START_TIME))) seconds left to retry..."
rm -f /usr/local/bin/docker-compose
sleep 2
continue
fi
if [ "${STATUS_RECEIVED}" -ne "200" ]; then
echo "Error downloading docker-compose. Received HTTP status code $STATUS_RECEIVED. There are still $((TIME_LIMIT_SECONDS - (CURRENT_TIME - START_TIME))) seconds left to retry..."
rm -f /usr/local/bin/docker-compose
sleep 2
continue
fi
echo "Success downloading docker-compose version $DOCKER_COMPOSE_VERSION"
chmod 755 /usr/local/bin/docker-compose
break
done
# Create a symbolic link to docker-compose in the Docker CLI plugins directory
# so docker compose can be used also
mkdir -p /usr/local/lib/docker/cli-plugins
ln -sf /usr/local/bin/docker-compose /usr/local/lib/docker/cli-plugins/docker-compose
fi
# Check if docker is running with docker info
if ! docker info >/dev/null 2>&1; then
echo "Docker is not running. Starting Docker..."

@ -1 +1 @@
Subproject commit 18f44d6e166cfdc8a7ee9acc55835f6d685f6bd0
Subproject commit 5f592e68f16a2144c13116bd045e9ce8ce946043

View File

@ -49,8 +49,6 @@ public class FirefoxUser extends BrowserUser {
// ATTENTION: WITHOUT THIS FLAG H264 DOES NOT WORK IN SELENIUM-MANAGED FIREFOX
options.addPreference("media.webrtc.hw.h264.enabled", true);
// This flag makes livekit-server think that this is not a Firefox in Linux
options.addPreference("general.useragent.override", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0");
if (headless) {
options.addArguments("--headless");

View File

@ -3,7 +3,6 @@ package io.openvidu.test.e2e;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
@ -52,7 +51,7 @@ public class OpenViduTestE2e {
private final static WaitStrategy waitBrowser = Wait.forLogMessage("^.*Started Selenium Standalone.*$", 1);
protected static String RTSP_SERVER_IMAGE = "bluenviron/mediamtx:1.17.1-ffmpeg";
protected static String RTSP_SERVER_IMAGE = "bluenviron/mediamtx:latest-ffmpeg";
protected static int RTSP_SRT_PORT = 8554;
// Key is the common name of the video codec. It must match the output log of
@ -70,7 +69,7 @@ public class OpenViduTestE2e {
put("VP8", Triple.of("libvpx", "", "VP8"));
put("VP9", Triple.of("libvpx-vp9", "", "VP9"));
put("MPEG-4", Triple.of("mpeg4", "", "MPEG-4"));
put("M-JPEG", Triple.of("mjpeg", "-force_duplicated_matrix:v 1 -huffman:v 0", "M-JPEG"));
put("M-JPEG", Triple.of("mjpeg", "-force_duplicated_matrix:v 1 -huffman:v 0", "MJPEG"));
// put("AV1", Triple.of("libaom-av1", "", "AV1")); // NOT SUPPORTED BY THE RTSP SERVER
// (maybe gstreamer?)
// put("H265", Triple.of("libx265", "", "H265")); // NOT SUPPORTED BY INGRESS
@ -88,7 +87,7 @@ public class OpenViduTestE2e {
put("AAC", Triple.of("aac", "-ac 2 -b:a 128k", "MPEG-4 Audio"));
put("AC3", Triple.of("ac3", "-b:a 128k", null));
put("OPUS", Triple.of("libopus", "-ac 2", "Opus"));
put("MP3", Triple.of("libmp3lame", "", "MPEG-1/2 Audio"));
put("MP3", Triple.of("libmp3lame", "", "MPEG-1 Audio"));
put("VORBIS", Triple.of("libvorbis", "", null));
put("G711", Triple.of("pcm_mulaw", "", "G711"));
}
@ -192,18 +191,13 @@ public class OpenViduTestE2e {
*/
public String startRtspServer(String videoCodec, String audioCodec) throws Exception {
int rtspPort;
try (ServerSocket socket = new ServerSocket(0)) {
rtspPort = socket.getLocalPort();
}
GenericContainer<?> rtspServerContainer = new GenericContainer<>(DockerImageName.parse(RTSP_SERVER_IMAGE))
.withCreateContainerCmdModifier(cmd -> cmd.withName("rtsp-" + Math.random() * 100000))
.withEnv(Map.of("MTX_LOGLEVEL", "info", "MTX_RTSPTRANSPORTS", "tcp", "MTX_RTSPADDRESS", ":" + rtspPort,
"MTX_HLS", "no", "MTX_RTSP", "yes", "MTX_WEBRTC", "no", "MTX_SRT", "no", "MTX_RTMP", "no",
.withEnv(Map.of("MTX_LOGLEVEL", "info", "MTX_RTSPTRANSPORTS", "tcp", "MTX_RTSPADDRESS", ":" + RTSP_SRT_PORT,
"MTX_HLS", "no", "MTX_RTSP", "yes", "MTX_WEBRTC", "yes", "MTX_SRT", "no", "MTX_RTMP", "no",
"MTX_API", "no"))
.withNetworkMode("host")
.waitingFor(Wait.forLogMessage("^.*\\[RTSP\\] listener opened on :" + rtspPort + ".*$", 1));
.waitingFor(Wait.forLogMessage("^.*\\[RTSP\\] listener opened on :" + RTSP_SRT_PORT + ".*$", 1));
rtspServerContainer.start();
containers.add(rtspServerContainer);
@ -214,7 +208,7 @@ public class OpenViduTestE2e {
String rtspServerIp = "host.docker.internal";
String ffmpegCommand = "ffmpeg -i " + fileUrl + " " + codecs + " "
+ " -async 50 -strict -2 -f rtsp -rtsp_transport tcp rtsp://" + rtspServerIp + ":" + rtspPort + "/"
+ " -async 50 -strict -2 -f rtsp -rtsp_transport tcp rtsp://" + rtspServerIp + ":" + RTSP_SRT_PORT + "/"
+ RTSP_PATH;
// Clean adjacent white spaces or the ffmpeg command will fail
@ -241,7 +235,7 @@ public class OpenViduTestE2e {
waitUntilLog(rtspServerContainer, regex, 15);
}
return "rtsp://host.docker.internal:" + rtspPort + "/" + RTSP_PATH;
return "rtsp://host.docker.internal:" + RTSP_SRT_PORT + "/" + RTSP_PATH;
}
/**

View File

@ -24,7 +24,6 @@ import java.time.Duration;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
@ -47,7 +46,6 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
@ -75,8 +73,6 @@ import io.openvidu.test.e2e.annotations.OnlyPion;
import livekit.LivekitIngress.IngressInfo;
import livekit.LivekitIngress.IngressState;
import static org.openqa.selenium.OutputType.BASE64;
/**
* E2E tests for openvidu-testapp.
*
@ -165,26 +161,10 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
}
@Test
@DisplayName("Signal Reliable DataChannel")
void signalReliableTest() throws Exception {
@DisplayName("Signal")
void signalTest() throws Exception {
OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome");
log.info("Signal Reliable DataChannel");
signalReliableLossyAux(user, true);
}
@Test
@DisplayName("Signal Lossy DataChannel")
void signalLossyTest() throws Exception {
OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome");
log.info("Signal Lossy DataChannel");
signalReliableLossyAux(user, false);
}
private void signalReliableLossyAux(OpenViduTestappUser user, boolean reliable) throws Exception {
final int expectedKind = reliable ? 0 : 1; // DataPacket_Kind: RELIABLE=0, LOSSY=1
final String expectedKindStr = reliable ? "RELIABLE" : "LOSSY";
final String btnClass = reliable ? ".message-reliable-btn" : ".message-lossy-btn";
log.info("Signal");
for (int i = 0; i < 2; i++) {
WebElement addUserBtn = user.getDriver().findElement(By.id("add-user-btn"));
addUserBtn.click();
@ -198,306 +178,129 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
user.getEventManager().waitUntilEventReaches("participantConnected", "RoomEvent", 1);
user.getEventManager().waitUntilEventReaches("participantActive", "RoomEvent", 1);
// Broadcast signal
Collection<Entry<String, String>> assertions = new ArrayList<>();
List<Integer> kindAssertions = Collections.synchronizedList(new ArrayList<>());
// Broadcast from TestParticipant0
final CountDownLatch broadcastLatch0 = new CountDownLatch(2);
final CountDownLatch signalEventLatch1 = new CountDownLatch(2);
user.getEventManager().on(1, "dataReceived", "RoomEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant0 to all room (kind: " + expectedKindStr + ")",
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant0 to all room",
json.getAsJsonObject().get("eventDescription").getAsString()));
kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
broadcastLatch0.countDown();
signalEventLatch1.countDown();
});
user.getEventManager().on(1, "dataReceived", "ParticipantEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant0 to all room (kind: " + expectedKindStr + ")",
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant0 to all room",
json.getAsJsonObject().get("eventDescription").getAsString()));
kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
broadcastLatch0.countDown();
signalEventLatch1.countDown();
});
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 " + btnClass)).click();
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 .message-btn")).click();
user.getEventManager().waitUntilEventReaches(1, "dataReceived", "RoomEvent", 1);
user.getEventManager().waitUntilEventReaches(1, "dataReceived", "ParticipantEvent", 1);
// Do not trigger own signals
Assertions.assertEquals(0, user.getEventManager().getNumEvents(0, "dataReceived-RoomEvent").get());
Assertions.assertEquals(0, user.getEventManager().getNumEvents(0, "dataReceived-ParticipantEvent").get());
if (!broadcastLatch0.await(3, TimeUnit.SECONDS)) {
Assertions.fail("Timeout waiting for broadcast signal event from TestParticipant0");
if (!signalEventLatch1.await(3, TimeUnit.SECONDS)) {
Assertions.fail("Timeout waiting for signal event content check");
}
assertions.forEach(assertion -> Assertions.assertEquals(assertion.getKey(), assertion.getValue()));
kindAssertions.forEach(
kind -> Assertions.assertEquals(expectedKind, kind, "Expected DataPacket_Kind " + expectedKind));
user.getEventManager().off(1, "dataReceived", "RoomEvent");
user.getEventManager().off(1, "dataReceived", "ParticipantEvent");
assertions.clear();
kindAssertions.clear();
user.getEventManager().clearAllCurrentEvents();
// Broadcast from TestParticipant1
final CountDownLatch broadcastLatch1 = new CountDownLatch(2);
final CountDownLatch signalEventLatch2 = new CountDownLatch(2);
user.getEventManager().on(0, "dataReceived", "RoomEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant1 to all room (kind: " + expectedKindStr + ")",
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant1 to all room",
json.getAsJsonObject().get("eventDescription").getAsString()));
kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
broadcastLatch1.countDown();
signalEventLatch2.countDown();
});
user.getEventManager().on(0, "dataReceived", "ParticipantEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant1 to all room (kind: " + expectedKindStr + ")",
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant1 to all room",
json.getAsJsonObject().get("eventDescription").getAsString()));
kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
broadcastLatch1.countDown();
signalEventLatch2.countDown();
});
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 " + btnClass)).click();
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .message-btn")).click();
user.getEventManager().waitUntilEventReaches(0, "dataReceived", "RoomEvent", 1);
user.getEventManager().waitUntilEventReaches(0, "dataReceived", "ParticipantEvent", 1);
// Do not trigger own signals
Assertions.assertEquals(1, user.getEventManager().getNumEvents(0, "dataReceived-RoomEvent").get());
Assertions.assertEquals(1, user.getEventManager().getNumEvents(0, "dataReceived-ParticipantEvent").get());
if (!broadcastLatch1.await(3, TimeUnit.SECONDS)) {
Assertions.fail("Timeout waiting for broadcast signal event from TestParticipant1");
if (!signalEventLatch2.await(3, TimeUnit.SECONDS)) {
Assertions.fail("Timeout waiting for signal event content check");
}
assertions.forEach(assertion -> Assertions.assertEquals(assertion.getKey(), assertion.getValue()));
kindAssertions.forEach(
kind -> Assertions.assertEquals(expectedKind, kind, "Expected DataPacket_Kind " + expectedKind));
user.getEventManager().off(0, "dataReceived", "RoomEvent");
user.getEventManager().off(0, "dataReceived", "ParticipantEvent");
assertions.clear();
kindAssertions.clear();
user.getEventManager().clearAllCurrentEvents();
// Signal specific participant
// Signal from TestParticipant0 to TestParticipant1
final CountDownLatch directLatch0 = new CountDownLatch(2);
final CountDownLatch signalEventLatch3 = new CountDownLatch(2);
user.getEventManager().on(1, "dataReceived", "RoomEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant0 to TestParticipant1 (kind: " + expectedKindStr + ")",
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant0 to TestParticipant1",
json.getAsJsonObject().get("eventDescription").getAsString()));
kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
directLatch0.countDown();
signalEventLatch3.countDown();
});
user.getEventManager().on(1, "dataReceived", "ParticipantEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant0 to TestParticipant1 (kind: " + expectedKindStr + ")",
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant0 to TestParticipant1",
json.getAsJsonObject().get("eventDescription").getAsString()));
kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
directLatch0.countDown();
signalEventLatch3.countDown();
});
user.getDriver()
.findElement(
By.cssSelector("#openvidu-instance-0 app-participant.remote-participant " + btnClass))
.findElement(By.cssSelector("#openvidu-instance-0 app-participant.remote-participant .message-btn"))
.click();
user.getEventManager().waitUntilEventReaches(1, "dataReceived", "RoomEvent", 1);
user.getEventManager().waitUntilEventReaches(1, "dataReceived", "ParticipantEvent", 1);
// Do not trigger own signals
Assertions.assertEquals(0, user.getEventManager().getNumEvents(0, "dataReceived-RoomEvent").get());
Assertions.assertEquals(0, user.getEventManager().getNumEvents(0, "dataReceived-ParticipantEvent").get());
if (!directLatch0.await(3, TimeUnit.SECONDS)) {
Assertions.fail("Timeout waiting for direct signal event from TestParticipant0");
if (!signalEventLatch3.await(3, TimeUnit.SECONDS)) {
Assertions.fail("Timeout waiting for signal event content check");
}
assertions.forEach(assertion -> Assertions.assertEquals(assertion.getKey(), assertion.getValue()));
kindAssertions.forEach(
kind -> Assertions.assertEquals(expectedKind, kind, "Expected DataPacket_Kind " + expectedKind));
user.getEventManager().off(1, "dataReceived", "RoomEvent");
user.getEventManager().off(1, "dataReceived", "ParticipantEvent");
assertions.clear();
kindAssertions.clear();
user.getEventManager().clearAllCurrentEvents();
// Signal from TestParticipant1 to TestParticipant0
final CountDownLatch directLatch1 = new CountDownLatch(2);
final CountDownLatch signalEventLatch4 = new CountDownLatch(2);
user.getEventManager().on(0, "dataReceived", "RoomEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant1 to TestParticipant0 (kind: " + expectedKindStr + ")",
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant1 to TestParticipant0",
json.getAsJsonObject().get("eventDescription").getAsString()));
kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
directLatch1.countDown();
signalEventLatch4.countDown();
});
user.getEventManager().on(0, "dataReceived", "ParticipantEvent", json -> {
assertions.add(new AbstractMap.SimpleEntry<>(
"Message from TestParticipant1 to TestParticipant0 (kind: " + expectedKindStr + ")",
assertions.add(new AbstractMap.SimpleEntry<>("Message from TestParticipant1 to TestParticipant0",
json.getAsJsonObject().get("eventDescription").getAsString()));
kindAssertions.add(json.getAsJsonObject().get("eventContent").getAsJsonObject().get("kind").getAsInt());
directLatch1.countDown();
signalEventLatch4.countDown();
});
user.getDriver()
.findElement(
By.cssSelector("#openvidu-instance-1 app-participant.remote-participant " + btnClass))
.findElement(By.cssSelector("#openvidu-instance-1 app-participant.remote-participant .message-btn"))
.click();
user.getEventManager().waitUntilEventReaches(0, "dataReceived", "RoomEvent", 1);
user.getEventManager().waitUntilEventReaches(0, "dataReceived", "ParticipantEvent", 1);
// Do not trigger own signals
Assertions.assertEquals(0, user.getEventManager().getNumEvents(1, "dataReceived-RoomEvent").get());
Assertions.assertEquals(0, user.getEventManager().getNumEvents(1, "dataReceived-ParticipantEvent").get());
if (!directLatch1.await(3, TimeUnit.SECONDS)) {
Assertions.fail("Timeout waiting for direct signal event from TestParticipant1");
if (!signalEventLatch4.await(3, TimeUnit.SECONDS)) {
Assertions.fail("Timeout waiting for signal event content check");
}
assertions.forEach(assertion -> Assertions.assertEquals(assertion.getKey(), assertion.getValue()));
kindAssertions.forEach(
kind -> Assertions.assertEquals(expectedKind, kind, "Expected DataPacket_Kind " + expectedKind));
gracefullyLeaveParticipants(user, 2);
}
@Test
@DisplayName("ConnectionQualityChanged")
void connectionQualityChangedTest() throws Exception {
OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome");
log.info("ConnectionQualityChanged");
user.getDriver().findElement(By.id("auto-join-checkbox")).click();
user.getDriver().findElement(By.id("one2one-btn")).click();
user.getEventManager().waitUntilEventReaches("signalConnected", "RoomEvent", 2);
user.getEventManager().waitUntilEventReaches("connected", "RoomEvent", 2);
user.getEventManager().waitUntilEventReaches("localTrackPublished", "RoomEvent", 4);
user.getEventManager().waitUntilEventReaches("trackSubscribed", "RoomEvent", 4);
user.getEventManager().waitUntilEventReaches("connectionQualityChanged", "RoomEvent", 4);
user.getEventManager().waitUntilEventReaches("connectionQualityChanged", "ParticipantEvent", 4);
// Expect the connection quality events to include as text content: "excellent"
user.getDriver().findElements(By.cssSelector(".connectionQualityChanged-TestParticipant0 .event-content"))
.forEach(el -> Assertions.assertTrue(el.getText().contains("excellent"),
"Expected connection quality to be excellent"));
user.getDriver().findElements(By.cssSelector(".connectionQualityChanged-TestParticipant1 .event-content"))
.forEach(el -> Assertions.assertTrue(el.getText().contains("excellent"),
"Expected connection quality to be excellent"));
gracefullyLeaveParticipants(user, 2);
}
@Test
@DisplayName("Data Tracks publish, subscribe, send and receive")
void dataTracksTest() throws Exception {
OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome");
log.info("Data Tracks publish, subscribe, send and receive");
// Two participants, no audio/video publishing
for (int i = 0; i < 2; i++) {
WebElement addUserBtn = user.getDriver().findElement(By.id("add-user-btn"));
addUserBtn.click();
user.getDriver().findElement(By.cssSelector("#openvidu-instance-" + i + " .subscriber-checkbox")).click();
user.getDriver().findElement(By.cssSelector("#openvidu-instance-" + i + " .publisher-checkbox")).click();
}
user.getDriver().findElements(By.className("connect-btn")).forEach(el -> el.sendKeys(Keys.ENTER));
user.getEventManager().waitUntilEventReaches("signalConnected", "RoomEvent", 2);
user.getEventManager().waitUntilEventReaches("connected", "RoomEvent", 2);
user.getEventManager().waitUntilEventReaches("participantConnected", "RoomEvent", 1);
user.getEventManager().waitUntilEventReaches("participantActive", "RoomEvent", 1);
// Participant 0 publishes a data track
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 .add-data-track-btn")).click();
// Wait for localDataTrackPublished on participant 0 and dataTrackPublished on participant 1
user.getEventManager().waitUntilEventReaches(0, "localDataTrackPublished", "RoomEvent", 1);
user.getEventManager().waitUntilEventReaches(1, "dataTrackPublished", "RoomEvent", 1);
// Verify event descriptions
user.getDriver().findElements(By.cssSelector(".localDataTrackPublished-TestParticipant0 .event-content"))
.forEach(el -> Assertions.assertTrue(el.getText().contains("data_track_1"),
"Expected localDataTrackPublished to contain track name 'data_track_1'"));
user.getDriver().findElements(By.cssSelector(".dataTrackPublished-TestParticipant1 .event-content"))
.forEach(el -> Assertions.assertTrue(
el.getText().contains("TestParticipant0") && el.getText().contains("data_track_1"),
"Expected dataTrackPublished to contain publisher identity and track name"));
// Participant 0 does not receive its own dataTrackPublished
Assertions.assertEquals(0, user.getEventManager().getNumEvents(0, "dataTrackPublished-RoomEvent").get(),
"Publisher should not receive dataTrackPublished for its own data track");
// Participant 0 sends data frames
org.openqa.selenium.JavascriptExecutor js = (org.openqa.selenium.JavascriptExecutor) user.getDriver();
js.executeScript("document.querySelector('#openvidu-instance-0 .send-data-frame-btn').click()");
js.executeScript("document.querySelector('#openvidu-instance-0 .send-data-frame-btn').click()");
js.executeScript("document.querySelector('#openvidu-instance-0 .send-data-frame-btn').click()");
// Wait for frames to arrive at participant 1
Thread.sleep(1000);
Long frameCount = (Long) js.executeScript(
"var el = document.querySelector('#openvidu-instance-1 .data-track-frame-count');" +
"return el ? parseInt(el.textContent) : 0;");
Assertions.assertEquals(frameCount, 3, "Expected 3 data track frames received, got " + frameCount);
String lastPayload = (String) js.executeScript(
"var el = document.querySelector('#openvidu-instance-1 .data-track-last-payload');" +
"return el ? el.textContent : '';");
Assertions.assertTrue(lastPayload.contains("DataTrackFrame from TestParticipant0"),
"Expected last payload to contain 'DataTrackFrame from TestParticipant0', got: " + lastPayload);
// Participant 0 unpublishes the data track
js.executeScript("document.querySelector('#openvidu-instance-0 .unpublish-data-track-btn').click()");
// Wait for unpublish events
user.getEventManager().waitUntilEventReaches(0, "localDataTrackUnpublished", "RoomEvent", 1);
user.getEventManager().waitUntilEventReaches(1, "dataTrackUnpublished", "RoomEvent", 1);
// Participant 0 does not receive its own dataTrackUnpublished
Assertions.assertEquals(0, user.getEventManager().getNumEvents(0, "dataTrackUnpublished-RoomEvent").get(),
"Publisher should not receive dataTrackUnpublished for its own data track");
user.getEventManager().clearAllCurrentEvents();
// Now participant 1 publishes a data track with custom name (bidirectional test)
String customTrackName = "my_custom_data_track";
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .options-data-track-btn")).click();
Thread.sleep(500);
WebElement trackNameInput = user.getDriver().findElement(By.id("dataTrack-name"));
trackNameInput.clear();
trackNameInput.sendKeys(customTrackName);
user.getDriver().findElement(By.id("close-dialog-btn")).click();
Thread.sleep(500);
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .add-data-track-btn")).click();
user.getEventManager().waitUntilEventReaches(1, "localDataTrackPublished", "RoomEvent", 1);
user.getEventManager().waitUntilEventReaches(0, "dataTrackPublished", "RoomEvent", 1);
// Verify participant 0 sees the custom track name on the remote data track
Thread.sleep(500);
String remoteTrackName = (String) js.executeScript(
"var el = document.querySelector('#openvidu-instance-0 .data-track-name');" +
"return el ? el.textContent.trim() : '';");
Assertions.assertEquals(customTrackName, remoteTrackName,
"Remote data track name should be '" + customTrackName + "', got: " + remoteTrackName);
// Participant 1 sends a data frame
js.executeScript("document.querySelector('#openvidu-instance-1 .send-data-frame-btn').click()");
// Wait for frame to arrive at participant 0
Thread.sleep(1000);
Long frameCount0 = (Long) js.executeScript(
"var el = document.querySelector('#openvidu-instance-0 .data-track-frame-count');" +
"return el ? parseInt(el.textContent) : 0;");
Assertions.assertTrue(frameCount0 >= 1,
"Expected at least 1 data track frame received by participant 0, got " + frameCount0);
String lastPayload0 = (String) js.executeScript(
"var el = document.querySelector('#openvidu-instance-0 .data-track-last-payload');" +
"return el ? el.textContent : '';");
Assertions.assertTrue(lastPayload0.contains("DataTrackFrame from TestParticipant1"),
"Expected last payload to contain 'DataTrackFrame from TestParticipant1', got: " + lastPayload0);
// Participant 1 unpublishes
js.executeScript("document.querySelector('#openvidu-instance-1 .unpublish-data-track-btn').click()");
user.getEventManager().waitUntilEventReaches(1, "localDataTrackUnpublished", "RoomEvent", 1);
user.getEventManager().waitUntilEventReaches(0, "dataTrackUnpublished", "RoomEvent", 1);
gracefullyLeaveParticipants(user, 2);
}
@ -842,11 +645,12 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
private void forceCodecTest(OpenViduTestappUser user, String codec) throws Exception {
this.addOnlyPublisherVideo(user, false, false, false);
this.waitForBackdropAndClick(user, "#room-options-btn-0");
user.getDriver().findElement(By.id("room-options-btn-0")).click();
Thread.sleep(300);
user.getDriver().findElement(By.id("trackPublish-backupCodec")).click();
user.getDriver().findElement(By.id("trackPublish-videoCodec")).click();
this.waitForBackdropAndClick(user, "#mat-option-" + codec.toLowerCase());
Thread.sleep(300);
user.getDriver().findElement(By.id("mat-option-" + codec.toLowerCase())).click();
this.waitForBackdropAndClick(user, "#close-dialog-btn");
Thread.sleep(300);
@ -942,12 +746,13 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
WebElement participantNameInput = chromeUser.getDriver().findElement(By.id("participant-name-input-0"));
participantNameInput.clear();
participantNameInput.sendKeys("CHROME_USER");
this.waitForBackdropAndClick(chromeUser, "#room-options-btn-0");
chromeUser.getDriver().findElement(By.id("room-options-btn-0")).click();
Thread.sleep(300);
chromeUser.getDriver().findElement(By.id("trackPublish-backupCodec")).click();
chromeUser.getDriver().findElement(By.id("trackPublish-videoCodec")).click();
this.waitForBackdropAndClick(chromeUser, "#mat-option-" + codec.toLowerCase());
this.waitForBackdropAndClick(chromeUser, "#close-dialog-btn");
Thread.sleep(300);
chromeUser.getDriver().findElement(By.id("mat-option-" + codec.toLowerCase())).click();
chromeUser.getDriver().findElement(By.id("close-dialog-btn")).click();
Thread.sleep(300);
chromeUser.getDriver().findElement(By.className("connect-btn")).click();
chromeUser.getEventManager().waitUntilEventReaches("localTrackSubscribed", "ParticipantEvent", 1);
@ -1158,11 +963,13 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
// Manually change video quality of first subscriber to q
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 #max-video-quality")).click();
this.waitForBackdropAndClick(user, "mat-option.mode-LOW");
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("mat-option.mode-LOW")).click();
// Manually change video quality of second subscriber to f
user.getDriver().findElement(By.cssSelector("#openvidu-instance-2 #max-video-quality")).click();
this.waitForBackdropAndClick(user, "mat-option.mode-HIGH");
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("mat-option.mode-HIGH")).click();
subscriberVideo1 = user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 video.remote"));
WebElement subscriberVideo2 = user.getDriver().findElement(By.cssSelector("#openvidu-instance-2 video.remote"));
@ -1189,7 +996,8 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
// Manually change video quality of second subscriber to h
user.getDriver().findElement(By.cssSelector("#openvidu-instance-2 #max-video-quality")).click();
this.waitForBackdropAndClick(user, "mat-option.mode-MEDIUM");
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("mat-option.mode-MEDIUM")).click();
this.waitUntilPublisherLayerActive(user, publisherVideo, "q", true);
this.waitUntilPublisherLayerActive(user, publisherVideo, "h", true);
@ -1351,17 +1159,20 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
// Manually change video quality of subscriber to h
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 #max-video-quality")).click();
this.waitForBackdropAndClick(user, "mat-option.mode-MEDIUM");
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("mat-option.mode-MEDIUM")).click();
this.waitUntilSubscriberFrameWidthIs(user, subscriberVideo, h);
// Manually change video quality of subscriber to q
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 #max-video-quality")).click();
this.waitForBackdropAndClick(user, "mat-option.mode-LOW");
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("mat-option.mode-LOW")).click();
this.waitUntilSubscriberFrameWidthIs(user, subscriberVideo, q);
// Manually change video quality of subscriber to f
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 #max-video-quality")).click();
this.waitForBackdropAndClick(user, "mat-option.mode-HIGH");
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("mat-option.mode-HIGH")).click();
this.waitUntilSubscriberFrameWidthIs(user, subscriberVideo, f);
gracefullyLeaveParticipants(user, 2);
@ -1750,8 +1561,11 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
user.getDriver().findElement(By.cssSelector("#start-" + egressType + "-egress-api-btn")).click();
user.getEventManager().waitUntilEventReaches("recordingStatusChanged",
"RoomEvent", 1);
// TODO: UNCOMMENT WHEN MEDIASOUP IS ABLE TO MANAGE ABRUPT
// CONNECTIONSTATECHANGED DISOCONNECTED/FAILED
// https://mediasoup.discourse.group/t/mediasoup-3-13-20-released-with-server-side-ice-consent-check-and-a-critical-fix/5864
// user.getEventManager().waitUntilEventReaches("recordingStatusChanged",
// "RoomEvent", 1);
WebElement egressIdField = user.getDriver().findElement(By.id("egress-id-field"));
WebDriverWait wait = new WebDriverWait(user.getDriver(), Duration.ofSeconds(10));
@ -1772,8 +1586,11 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
this.checkRecordingInEgressBackupFolder(egress);
}
user.getEventManager().waitUntilEventReaches("recordingStatusChanged",
"RoomEvent", 2);
// TODO: UNCOMMENT WHEN MEDIASOUP IS ABLE TO MANAGE ABRUPT
// CONNECTIONSTATECHANGED DISOCONNECTED/FAILED
// https://mediasoup.discourse.group/t/mediasoup-3-13-20-released-with-server-side-ice-consent-check-and-a-critical-fix/5864
// user.getEventManager().waitUntilEventReaches("recordingStatusChanged",
// "RoomEvent", 2);
}
private JsonObject waitUntilEgressStatus(OpenViduTestappUser user, String egressId, String egressStatus,
@ -2603,13 +2420,16 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
// Check manual simulcast changes
this.waitUntilSubscriberFrameWidthIs(user, subscriberVideo, 1920);
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 #max-video-quality")).click();
this.waitForBackdropAndClick(user, "mat-option.mode-LOW");
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("mat-option.mode-LOW")).click();
this.waitUntilSubscriberFrameWidthIs(user, subscriberVideo, 640);
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 #max-video-quality")).click();
this.waitForBackdropAndClick(user, "mat-option.mode-MEDIUM");
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("mat-option.mode-MEDIUM")).click();
this.waitUntilSubscriberFrameWidthIs(user, subscriberVideo, 1280);
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 #max-video-quality")).click();
this.waitForBackdropAndClick(user, "mat-option.mode-HIGH");
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("mat-option.mode-HIGH")).click();
this.waitUntilSubscriberFrameWidthIs(user, subscriberVideo, 1920);
}
@ -2617,23 +2437,28 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
// Check manual simulcast changes
this.waitUntilSubscriberFrameWidthIs(user, subscriberVideo, 960);
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 #max-video-quality")).click();
this.waitForBackdropAndClick(user, "mat-option.mode-LOW");
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("mat-option.mode-LOW")).click();
this.waitUntilSubscriberFrameWidthIs(user, subscriberVideo, 480);
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 #max-video-quality")).click();
this.waitForBackdropAndClick(user, "mat-option.mode-MEDIUM");
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("mat-option.mode-MEDIUM")).click();
this.waitUntilSubscriberFrameWidthIs(user, subscriberVideo, 960);
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 #max-video-quality")).click();
this.waitForBackdropAndClick(user, "mat-option.mode-LOW");
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("mat-option.mode-LOW")).click();
this.waitUntilSubscriberFrameWidthIs(user, subscriberVideo, 480);
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 #max-video-quality")).click();
this.waitForBackdropAndClick(user, "mat-option.mode-HIGH");
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("mat-option.mode-HIGH")).click();
this.waitUntilSubscriberFrameWidthIs(user, subscriberVideo, 960);
}
private void testNoSimulcast(OpenViduTestappUser user, WebElement subscriberVideo) throws InterruptedException {
this.waitUntilSubscriberFrameWidthIs(user, subscriberVideo, 1920);
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 #max-video-quality")).click();
this.waitForBackdropAndClick(user, "mat-option.mode-LOW");
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("mat-option.mode-LOW")).click();
// Without simulcast video should remain in high quality
Thread.sleep(4000);
this.waitUntilSubscriberFrameWidthIs(user, subscriberVideo, 1920);
@ -2877,7 +2702,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
user.getDriver().findElement(By.cssSelector("#openvidu-instance-" + numberOfUser + " .subscriber-checkbox"))
.click();
}
this.waitForBackdropAndClick(user, "#room-options-btn-" + numberOfUser);
user.getDriver().findElement(By.id("room-options-btn-" + numberOfUser)).click();
Thread.sleep(300);
if (!hasAudio) {
user.getDriver().findElement(By.id("audio-capture-false")).click();
@ -2915,8 +2740,9 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
user.getDriver().findElement(By.cssSelector("#openvidu-instance-" + numberOfUser + " .publisher-checkbox"))
.click();
if (!adaptiveStream) {
this.waitForBackdropAndClick(user, "#room-options-btn-" + numberOfUser);
this.waitForBackdropAndClick(user, "#room-adaptiveStream");
user.getDriver().findElement(By.id("room-options-btn-" + numberOfUser)).click();
Thread.sleep(300);
user.getDriver().findElement(By.id("room-adaptiveStream")).click();
user.getDriver().findElement(By.id("close-dialog-btn")).click();
Thread.sleep(300);
}
@ -2931,18 +2757,21 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
user.getDriver().findElement(By.xpath("//button[contains(@title,'Room API')]")).click();
if (preset != null) {
this.waitForBackdropAndClick(user, "#ingress-preset-select");
this.waitForBackdropAndClick(user, "#mat-option-" + preset.toUpperCase());
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("#mat-option-" + preset.toUpperCase())).click();
} else {
if (!simulcast) {
this.waitForBackdropAndClick(user, "#ingress-simulcast");
Thread.sleep(300);
}
this.waitForBackdropAndClick(user, "#ingress-video-codec-select");
this.waitForBackdropAndClick(user, "#mat-option-" + codec.toUpperCase());
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("#mat-option-" + codec.toUpperCase())).click();
}
if (urlType != null) {
this.waitForBackdropAndClick(user, "#ingress-url-type-select");
this.waitForBackdropAndClick(user, "#mat-option-" + urlType.toUpperCase());
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("#mat-option-" + urlType.toUpperCase())).click();
}
if (urlUri != null) {
user.getDriver().findElement(By.cssSelector("#ingress-url-uri-field")).sendKeys(urlUri);
@ -2968,7 +2797,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
}
if (scalabilityMode != null) {
user.getDriver().findElement(By.id("trackPublish-scalabilityMode")).click();
this.waitForBackdropAndClick(user, ".mode-" + scalabilityMode);
user.getDriver().findElement(By.className("mode-" + scalabilityMode)).click();
}
}
@ -3006,47 +2835,35 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
try {
Thread.sleep(retryIntervalMillis);
} catch (InterruptedException e) {
// Print screenshot
String screenshot = "data:image/png;base64,"
+ ((TakesScreenshot) user.getDriver()).getScreenshotAs(BASE64);
System.out.println("INTERRUPTED EXCEPTION WHILE WAITING FOR ELEMENT TO BE CLICKABLE: " + cssSelector);
System.out.println(screenshot);
Thread.currentThread().interrupt();
throw new RuntimeException("Thread interrupted while waiting for backdrop to clear", e);
}
}
String screenshot = "data:image/png;base64," + ((TakesScreenshot) user.getDriver()).getScreenshotAs(BASE64);
System.out.println("TIMEOUT WAITING FOR ELEMENT TO BE CLICKABLE (): " + cssSelector);
System.out.println(screenshot);
// If we get here, we've timed out
throw new RuntimeException("Timeout waiting for element '" + cssSelector
+ "' to be clickable without backdrop interference after " + timeoutMillis + "ms");
}
public boolean assertAllElementsHaveTracks(OpenViduTestappUser user, String selector, boolean hasAudio,
boolean hasVideo) {
public boolean assertAllElementsHaveTracks(OpenViduTestappUser user, String selector, boolean hasAudio, boolean hasVideo) {
org.openqa.selenium.JavascriptExecutor js = (org.openqa.selenium.JavascriptExecutor) user.getDriver();
String script = "var elements = document.querySelectorAll(arguments[0]);" +
"for (var i = 0; i < elements.length; i++) {" +
" var el = elements[i];" +
" if (!el.srcObject) return false;" +
" if (arguments[1] && el.srcObject.getAudioTracks().length === 0) return false;" +
" if (!arguments[1] && el.srcObject.getAudioTracks().length > 0) return false;" +
" if (arguments[2] && el.srcObject.getVideoTracks().length === 0) return false;" +
" if (!arguments[2] && el.srcObject.getVideoTracks().length > 0) return false;" +
"}" +
"return true;";
String script =
"var elements = document.querySelectorAll(arguments[0]);" +
"for (var i = 0; i < elements.length; i++) {" +
" var el = elements[i];" +
" if (!el.srcObject) return false;" +
" if (arguments[1] && el.srcObject.getAudioTracks().length === 0) return false;" +
" if (!arguments[1] && el.srcObject.getAudioTracks().length > 0) return false;" +
" if (arguments[2] && el.srcObject.getVideoTracks().length === 0) return false;" +
" if (!arguments[2] && el.srcObject.getVideoTracks().length > 0) return false;" +
"}" +
"return true;";
return (Boolean) js.executeScript(script, selector, hasAudio, hasVideo);
}
public void changeElementSize(OpenViduTestappUser user, org.openqa.selenium.WebElement element, int width,
int height) {
public void changeElementSize(OpenViduTestappUser user, org.openqa.selenium.WebElement element, int width, int height) {
org.openqa.selenium.JavascriptExecutor js = (org.openqa.selenium.JavascriptExecutor) user.getDriver();
js.executeScript(
"arguments[0].style.width = '" + width + "px'; arguments[0].style.height = '" + height + "px';",
element);
js.executeScript("arguments[0].style.width = '" + width + "px'; arguments[0].style.height = '" + height + "px';", element);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -10,29 +10,28 @@
"ng": "ng",
"start": "ng serve --ssl --host 0.0.0.0",
"start-insecure": "ng serve --host 0.0.0.0",
"start:ci": "ng build && http-server dist/openvidu-testapp-livekit/browser -p 4200 -a 0.0.0.0 -c-1",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"private": true,
"dependencies": {
"@angular/animations": "^21.2.9",
"@angular/cdk": "^21.2.7",
"@angular/common": "^21.2.9",
"@angular/compiler": "^21.2.9",
"@angular/core": "^21.2.9",
"@angular/forms": "^21.2.9",
"@angular/material": "^21.2.7",
"@angular/platform-browser": "^21.2.9",
"@angular/router": "^21.2.9",
"@livekit/protocol": "^1.45.3",
"@angular/animations": "^21.2.6",
"@angular/cdk": "^21.2.4",
"@angular/common": "^21.2.6",
"@angular/compiler": "^21.2.6",
"@angular/core": "^21.2.6",
"@angular/forms": "^21.2.6",
"@angular/material": "^21.2.4",
"@angular/platform-browser": "^21.2.6",
"@angular/router": "^21.2.6",
"@livekit/protocol": "^1.45.1",
"@livekit/track-processors": "^0.7.2",
"buffer": "^6.0.3",
"crypto-browserify": "^3.12.1",
"json-stringify-safe": "5.0.1",
"livekit-client": "2.18.4",
"livekit-server-sdk": "^2.15.1",
"livekit-client": "^2.18.0",
"livekit-server-sdk": "^2.15.0",
"rxjs": "~7.8.2",
"stream-browserify": "^3.0.0",
"tslib": "^2.8.1",
@ -40,16 +39,15 @@
"zone.js": "~0.16.1"
},
"devDependencies": {
"@angular/build": "^21.2.7",
"@angular/cli": "~21.2.7",
"@angular/compiler-cli": "^21.2.9",
"@angular/build": "^21.2.4",
"@angular/cli": "~21.2.4",
"@angular/compiler-cli": "^21.2.6",
"@types/dom-mediacapture-transform": "^0.1.11",
"@types/events": "^3.0.3",
"@types/jasmine": "~6.0.0",
"@types/json-stringify-safe": "^5.0.3",
"@types/node": "^25.6.0",
"http-server": "^14.1.1",
"jasmine-core": "~6.2.0",
"@types/node": "^25.5.0",
"jasmine-core": "~6.1.0",
"karma": "~6.4.4",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.1",

View File

@ -1,52 +0,0 @@
.parent-div {
display: grid;
margin-bottom: 4px;
background-color: #fcfcfc;
padding: 2px;
border-radius: 2px;
}
.data-track-name {
font-size: 10px;
}
.bottom-div {
display: flex;
justify-content: space-around;
margin-bottom: -2px;
}
.data-btn {
border: none;
background: rgba(255, 255, 255, 0.75);
cursor: pointer;
padding: 0;
height: 16px;
float: left;
}
.data-btn:hover {
color: #4d4d4d;
}
.data-btn mat-icon {
font-size: 14px;
width: 14px;
height: 14px;
line-height: 16px;
}
.data-track-info {
font-size: 10px;
padding: 2px 0;
}
.data-track-frame-count {
font-weight: bold;
margin-right: 4px;
}
.data-track-last-payload {
color: #555;
word-break: break-all;
}

View File

@ -1,25 +0,0 @@
<div class="parent-div">
<span class="data-track-name">{{getTrackName()}}</span>
<div class="bottom-div">
@if (localParticipant && localDataTrack) {
<button (click)="sendDataFrame()" class="data-btn send-data-frame-btn" matTooltip="Send data frame"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Send data frame" class="mat-icon material-icons" role="img"
aria-hidden="true">send</mat-icon>
</button>
}
@if (localParticipant && localDataTrack) {
<button (click)="unpublishDataTrack()" class="data-btn unpublish-data-track-btn" matTooltip="Unpublish data track"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Unpublish data track" class="mat-icon material-icons" role="img"
aria-hidden="true">stop</mat-icon>
</button>
}
</div>
@if (frameCount > 0) {
<div class="data-track-info">
<span class="data-track-frame-count">{{frameCount}}</span>
<span class="data-track-last-payload">{{lastPayload}}</span>
</div>
}
</div>

View File

@ -1,98 +0,0 @@
import { Component, EventEmitter, Input, Output, ChangeDetectorRef } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import {
LocalDataTrack,
LocalParticipant,
RemoteDataTrack,
} from 'livekit-client';
import {
TestAppEvent,
TestFeedService,
} from 'src/app/services/test-feed.service';
@Component({
selector: 'app-data-track',
templateUrl: './data-track.component.html',
styleUrl: './data-track.component.css',
imports: [MatIconModule, MatTooltipModule],
})
export class DataTrackComponent {
@Input()
localParticipant: LocalParticipant | undefined;
@Input()
index: number;
@Input()
localDataTrack?: LocalDataTrack;
@Input()
remoteDataTrack?: RemoteDataTrack;
@Output()
newTrackEvent = new EventEmitter<TestAppEvent>();
@Output()
trackUnpublished = new EventEmitter<LocalDataTrack>();
// Received frame info
frameCount: number = 0;
lastPayload: string = '';
private decoder = new TextDecoder();
constructor(
private testFeedService: TestFeedService,
private cdr: ChangeDetectorRef
) {}
ngOnInit() {
if (this.remoteDataTrack) {
this.subscribeToRemoteDataTrack(this.remoteDataTrack);
}
}
sendDataFrame() {
if (this.localDataTrack) {
const payload = new TextEncoder().encode(
`DataTrackFrame from ${this.localParticipant?.identity}`
);
this.localDataTrack.tryPush({ payload });
}
}
async unpublishDataTrack() {
if (this.localDataTrack) {
const track = this.localDataTrack;
await track.unpublish();
this.trackUnpublished.emit(track);
}
}
private async subscribeToRemoteDataTrack(track: RemoteDataTrack) {
const stream = track.subscribe();
const reader = stream.getReader();
try {
while (true) {
const { value, done } = await reader.read();
if (done) break;
this.frameCount++;
this.lastPayload = this.decoder.decode(value.payload);
this.cdr.detectChanges();
}
} catch (_) {
// Stream closed
}
}
getTrackName(): string {
if (this.localDataTrack?.info) {
return this.localDataTrack.info.name;
}
if (this.remoteDataTrack) {
return this.remoteDataTrack.info.name;
}
return '';
}
}

View File

@ -233,16 +233,6 @@
</mat-form-field>
</div>
}
@if (dataTrackName !== undefined) {
<mat-divider></mat-divider>
<div>
<label>DataTrackOptions</label><br>
<mat-form-field>
<mat-label>Track Name</mat-label>
<input matInput id="dataTrack-name" placeholder="data_track_1" [(ngModel)]="dataTrackName"/>
</mat-form-field>
</div>
}
</mat-dialog-content>
<mat-dialog-actions>

View File

@ -38,8 +38,6 @@ export class OptionsDialogComponent {
allowDisablingVideo = true;
allowDisablingScreen = true;
dataTrackName?: string;
videoOption: true | false | 'custom';
audioOption: true | false | 'custom';
screenOption: true | false | 'custom';
@ -64,7 +62,6 @@ export class OptionsDialogComponent {
allowDisablingAudio?: boolean;
allowDisablingVideo?: boolean;
allowDisablingScreen?: boolean;
dataTrackName?: string;
}>(MAT_DIALOG_DATA);
constructor(
@ -117,9 +114,6 @@ export class OptionsDialogComponent {
if (this.data.allowDisablingScreen === false) {
this.allowDisablingScreen = false;
}
if (this.data.dataTrackName !== undefined) {
this.dataTrackName = this.data.dataTrackName;
}
Room.getLocalDevices('videoinput').then((devices) => {
this.inputVideoDevices = devices;
});
@ -158,7 +152,6 @@ export class OptionsDialogComponent {
createLocalTracksOptions: this.createLocalTracksOptions,
screenShareCaptureOptions: this.screenShareCaptureOptions,
trackPublishOptions: this.trackPublishOptions,
dataTrackName: this.dataTrackName,
});
}

View File

@ -38,7 +38,6 @@ mat-card.room-card {
cursor: pointer;
padding: 0;
margin-right: 4px;
font-size: 22px;
}
.room-actions button:hover {

View File

@ -58,11 +58,8 @@
<button class="peer-info-btn" (click)="openInfoDialog()" title="PCTransports info">
<mat-icon aria-label="PCTransports info button">info</mat-icon>
</button>
<button class="message-reliable-btn" (click)="sendDataReliable()" title="Broadcast reliable message to room">
<mat-icon aria-label="Send reliable message button">chat_bubble</mat-icon>
</button>
<button class="message-lossy-btn" (click)="sendDataLossy()" title="Broadcast lossy message to room">
<mat-icon aria-label="Send lossy message button">chat_dashed</mat-icon>
<button class="message-btn" (click)="sendData()" title="Broadcast message to room">
<mat-icon aria-label="Send message button">chat</mat-icon>
</button>
<button class="disconnect-btn" (click)="disconnectRoom()" title="Disconnect room">
<mat-icon aria-label="Disconnect button">clear</mat-icon>
@ -92,9 +89,7 @@
[index]="index"></app-participant>
@for (participant of room.remoteParticipants | keyvalue; track participant) {
<app-participant class="remote-participant"
[participant]="participant.value" [room]="room" [index]="index"
(sendReliableDataToOneParticipant)="sendDataReliable($event)"
(sendLossyDataToOneParticipant)="sendDataLossy($event)"></app-participant>
[participant]="participant.value" [room]="room" [index]="index" (sendDataToOneParticipant)="sendData($event)"></app-participant>
}
</div>
</mat-card-content>

View File

@ -21,7 +21,6 @@ import {
DataPublishOptions,
DisconnectReason,
LocalAudioTrack,
LocalDataTrack,
LocalParticipant,
LocalTrack,
LocalTrackPublication,
@ -29,7 +28,6 @@ import {
MediaDeviceFailure,
Participant,
RemoteAudioTrack,
RemoteDataTrack,
RemoteParticipant,
RemoteTrack,
RemoteTrackPublication,
@ -145,7 +143,7 @@ export class OpenviduInstanceComponent {
this.participantName += this.index;
if (this.roomConf.startSession) {
const token = await this.roomApiService.createToken(
{ roomJoin: true, canPublishData: true },
{ roomJoin: true },
this.participantName,
this.roomName
);
@ -165,7 +163,7 @@ export class OpenviduInstanceComponent {
async createTokenAndConnectRoom() {
this.connectRoom(
await this.roomApiService.createToken(
{ roomJoin: true, canPublishData: true },
{ roomJoin: true },
this.participantName,
this.roomName
)
@ -772,8 +770,7 @@ export class OpenviduInstanceComponent {
kind?: DataPacket_Kind,
topic?: string
) => {
let decodedPayload = this.decoder.decode(payload);
decodedPayload += ` (kind: ${DataPacket_Kind[kind!]})`;
const decodedPayload = this.decoder.decode(payload);
this.updateEventList(
RoomEvent.DataReceived,
{ payload: decodedPayload, participant, kind, topic },
@ -999,7 +996,7 @@ export class OpenviduInstanceComponent {
if (this.roomEvents.get(RoomEvent.DCBufferStatusChanged)) {
this.room!.on(
RoomEvent.DCBufferStatusChanged,
(isLow: boolean, kind: any) => {
(isLow: boolean, kind: DataPacket_Kind) => {
this.updateEventList(
RoomEvent.DCBufferStatusChanged,
{ isLow, kind },
@ -1080,86 +1077,6 @@ export class OpenviduInstanceComponent {
);
}
}
if (
firstTime ||
this.roomEvents.get(RoomEvent.DataTrackPublished) !==
oldValues.get(RoomEvent.DataTrackPublished)
) {
this.room?.removeAllListeners(RoomEvent.DataTrackPublished);
if (this.roomEvents.get(RoomEvent.DataTrackPublished)) {
this.room!.on(
RoomEvent.DataTrackPublished,
(track: RemoteDataTrack) => {
this.updateEventList(
RoomEvent.DataTrackPublished,
{ name: track.info.name, sid: track.info.sid, publisherIdentity: track.publisherIdentity },
`${track.publisherIdentity} (${track.info.name})`
);
}
);
}
}
if (
firstTime ||
this.roomEvents.get(RoomEvent.DataTrackUnpublished) !==
oldValues.get(RoomEvent.DataTrackUnpublished)
) {
this.room?.removeAllListeners(RoomEvent.DataTrackUnpublished);
if (this.roomEvents.get(RoomEvent.DataTrackUnpublished)) {
this.room!.on(
RoomEvent.DataTrackUnpublished,
(sid: string) => {
this.updateEventList(
RoomEvent.DataTrackUnpublished,
{ sid },
`sid: ${sid}`
);
}
);
}
}
if (
firstTime ||
this.roomEvents.get(RoomEvent.LocalDataTrackPublished) !==
oldValues.get(RoomEvent.LocalDataTrackPublished)
) {
this.room?.removeAllListeners(RoomEvent.LocalDataTrackPublished);
if (this.roomEvents.get(RoomEvent.LocalDataTrackPublished)) {
this.room!.on(
RoomEvent.LocalDataTrackPublished,
(track: LocalDataTrack) => {
this.updateEventList(
RoomEvent.LocalDataTrackPublished,
{ name: track.info?.name, sid: track.info?.sid },
`${track.info?.name}`
);
}
);
}
}
if (
firstTime ||
this.roomEvents.get(RoomEvent.LocalDataTrackUnpublished) !==
oldValues.get(RoomEvent.LocalDataTrackUnpublished)
) {
this.room?.removeAllListeners(RoomEvent.LocalDataTrackUnpublished);
if (this.roomEvents.get(RoomEvent.LocalDataTrackUnpublished)) {
this.room!.on(
RoomEvent.LocalDataTrackUnpublished,
(sid: string) => {
this.updateEventList(
RoomEvent.LocalDataTrackUnpublished,
{ sid },
`sid: ${sid}`
);
}
);
}
}
}
updateEventList(
@ -1278,14 +1195,14 @@ export class OpenviduInstanceComponent {
});
}
sendData(destinationIdentity?: string, reliable: boolean = true) {
sendData(destinationIdentity?: string) {
let strData = `Message from ${this.room?.localParticipant.identity}`;
strData += destinationIdentity
? ` to ${destinationIdentity}`
: ' to all room';
const data = new TextEncoder().encode(strData);
let options: DataPublishOptions = {
reliable,
reliable: true,
};
if (destinationIdentity) {
options.destinationIdentities = [destinationIdentity];
@ -1293,14 +1210,6 @@ export class OpenviduInstanceComponent {
this.room?.localParticipant.publishData(data, options);
}
sendDataReliable(destinationIdentity?: string) {
this.sendData(destinationIdentity, true);
}
sendDataLossy(destinationIdentity?: string) {
this.sendData(destinationIdentity, false);
}
openInfoDialog() {
const updateFunction = async (): Promise<string> => {
const pub: PCTransport = this.getPublisherPC()!;

View File

@ -3,18 +3,6 @@
<p class="participant-identity" [ngClass]="{'local-participant-identity' : participant.isLocal}">
{{participant.identity}}</p>
<div class="participant-buttons">
@if (participant.isLocal) {
<button class="add-data-track-btn" (click)="addDataTrack()" title="New data track"
matTooltip="New data track" matTooltipClass="custom-tooltip">
<mat-icon aria-label="New data track">stream</mat-icon>
</button>
}
@if (participant.isLocal) {
<button class="options-data-track-btn" (click)="openDataTrackOptionsDialog()"
title="Data track options" matTooltip="Data track options" matTooltipClass="custom-tooltip">
<mat-icon aria-label="Data track options">more_vert</mat-icon>
</button>
}
@if (participant.isLocal) {
<button class="add-audio-btn" (click)="addAudioTrack()" title="New audio track"
matTooltip="New audio track" matTooltipClass="custom-tooltip">
@ -58,11 +46,8 @@
</button>
}
@if (!participant.isLocal) {
<button class="message-reliable-btn" (click)="sendDataReliable()" title="Send reliable message to this participant">
<mat-icon aria-label="Send reliable message button">chat_bubble</mat-icon>
</button>
<button class="message-lossy-btn" (click)="sendDataLossy()" title="Send lossy message to this participant">
<mat-icon aria-label="Send lossy message button">chat_dashed</mat-icon>
<button class="message-btn" (click)="sendData()" title="Send message to this participant">
<mat-icon aria-label="Send message button">chat</mat-icon>
</button>
}
</div>
@ -83,24 +68,6 @@
}
</mat-accordion>
</div>
<div class="data-tracks-container">
@for (track of localDataTracks; track track.info?.sid) {
<app-data-track
[index]="index"
[localDataTrack]="track"
[localParticipant]="localParticipant"
(trackUnpublished)="onLocalDataTrackUnpublished($event)"
(newTrackEvent)="onTrackEvent($event)">
</app-data-track>
}
@for (track of remoteDataTracks; track track.info.sid) {
<app-data-track
[index]="index"
[remoteDataTrack]="track"
(newTrackEvent)="onTrackEvent($event)">
</app-data-track>
}
</div>
<div class="audio-tracks-container">
@for (trackPublication of participant.audioTrackPublications| keyvalue; track trackPublication) {
<app-audio-track

View File

@ -10,18 +10,15 @@ import {
CreateLocalTracksOptions,
DataPacket_Kind,
LocalAudioTrack,
LocalDataTrack,
LocalParticipant,
LocalTrack,
LocalTrackPublication,
LocalVideoTrack,
Participant,
ParticipantEvent,
RemoteDataTrack,
RemoteTrack,
RemoteTrackPublication,
Room,
RoomEvent,
ScreenShareCaptureOptions,
SubscriptionError,
Track,
@ -41,14 +38,13 @@ import {
import { OptionsDialogComponent } from '../dialogs/options-dialog/options-dialog.component';
import { VideoTrackComponent } from '../video-track/video-track.component';
import { AudioTrackComponent } from '../audio-track/audio-track.component';
import { DataTrackComponent } from '../data-track/data-track.component';
import { ParticipantEventCallbacks } from 'node_modules/livekit-client/dist/src/room/participant/Participant';
@Component({
selector: 'app-participant',
templateUrl: './participant.component.html',
styleUrl: './participant.component.css',
imports: [NgClass, KeyValuePipe, MatIconModule, MatTooltipModule, MatExpansionModule, VideoTrackComponent, AudioTrackComponent, DataTrackComponent],
imports: [NgClass, KeyValuePipe, MatIconModule, MatTooltipModule, MatExpansionModule, VideoTrackComponent, AudioTrackComponent],
})
export class ParticipantComponent {
@Input()
@ -61,20 +57,12 @@ export class ParticipantComponent {
index: number;
@Output()
sendReliableDataToOneParticipant = new EventEmitter<string>();
@Output()
sendLossyDataToOneParticipant = new EventEmitter<string>();
sendDataToOneParticipant = new EventEmitter<string>();
localParticipant: LocalParticipant | undefined;
events: TestAppEvent[] = [];
localDataTracks: LocalDataTrack[] = [];
remoteDataTracks: RemoteDataTrack[] = [];
dataTrackCounter: number = 1;
dataTrackName: string = 'data_track_1';
createLocalTracksOptions: CreateLocalTracksOptions;
screenShareCaptureOptions: ScreenShareCaptureOptions = {};
trackPublishOptions?: TrackPublishOptions;
@ -100,9 +88,6 @@ export class ParticipantComponent {
this.trackPublishOptions = JSON.parse(
JSON.stringify(this.room.options.publishDefaults)
);
if (!this.participant.isLocal) {
this.setupDataTrackListeners();
}
}
onTrackEvent(event: TestAppEvent) {
@ -110,31 +95,6 @@ export class ParticipantComponent {
this.cdr.detectChanges();
}
async addDataTrack() {
const localParticipant = this.participant as LocalParticipant;
const track = await localParticipant.publishDataTrack({ name: this.dataTrackName });
this.localDataTracks.push(track);
this.dataTrackCounter++;
this.dataTrackName = 'data_track_' + this.dataTrackCounter;
this.cdr.detectChanges();
}
openDataTrackOptionsDialog() {
const dialogRef = this.dialog.open(OptionsDialogComponent, {
data: { dataTrackName: this.dataTrackName },
});
dialogRef.afterClosed().subscribe((result) => {
if (!!result) {
this.dataTrackName = result.dataTrackName;
}
});
}
onLocalDataTrackUnpublished(track: LocalDataTrack) {
this.localDataTracks = this.localDataTracks.filter((t) => t !== track);
this.cdr.detectChanges();
}
async addVideoTrack() {
const options =
this.createLocalTracksOptions.video === true
@ -380,8 +340,7 @@ export class ParticipantComponent {
.on(
ParticipantEvent.DataReceived,
(payload: Uint8Array, kind: DataPacket_Kind) => {
let decodedPayload = this.decoder.decode(payload);
decodedPayload += ` (kind: ${DataPacket_Kind[kind]})`;
const decodedPayload = this.decoder.decode(payload);
this.updateEventList(
ParticipantEvent.DataReceived,
'ParticipantEvent',
@ -509,32 +468,7 @@ export class ParticipantComponent {
this.testFeedService.pushNewEvent({ user: this.index, event });
}
sendDataReliable() {
this.sendReliableDataToOneParticipant.emit(this.participant.identity);
}
sendDataLossy() {
this.sendLossyDataToOneParticipant.emit(this.participant.identity);
}
private setupDataTrackListeners() {
this.room.on(
RoomEvent.DataTrackPublished,
(track: RemoteDataTrack) => {
if (track.publisherIdentity === this.participant.identity) {
this.remoteDataTracks.push(track);
this.cdr.detectChanges();
}
}
);
this.room.on(
RoomEvent.DataTrackUnpublished,
(sid: string) => {
this.remoteDataTracks = this.remoteDataTracks.filter(
(t) => t.info.sid !== sid
);
this.cdr.detectChanges();
}
);
sendData() {
this.sendDataToOneParticipant.emit(this.participant.identity);
}
}

View File

@ -198,8 +198,6 @@ export class TestScenariosComponent implements OnInit, OnDestroy {
);
const room: Room = user.room;
room.setMaxListeners(300);
room.on(RoomEvent.SignalConnected, () => {
this.updateEventList(RoomEvent.SignalConnected);
});

View File

@ -53,21 +53,31 @@ video {
line-height: 16px;
}
/* Keep the form-field visually compact (16×16 clipped box).
The CDK overlay uses the Popover API (top layer) so it is
immune to overflow:hidden and renders at its natural size. */
#max-video-quality {
width: 16px;
height: 16px;
overflow: hidden;
font-size: 10px;
font-weight: bold;
}
::ng-deep #max-video-quality .mdc-notched-outline * {
/* Compact the form-field chrome, but exclude the CDK overlay popover
(Angular CDK v21 renders it inside the component via the Popover API). */
::ng-deep #max-video-quality > :not(.cdk-overlay-popover),
::ng-deep #max-video-quality > :not(.cdk-overlay-popover) * {
height: 16px !important;
width: 8px !important;
min-height: 16px !important;
min-width: 8px !important;
padding: 0 !important;
border-color: transparent !important;
}
::ng-deep #max-video-quality .mat-mdc-form-field-subscript-wrapper {
display: none !important;
/* Let the dropdown panel and its options render at their natural size */
::ng-deep #max-video-quality .cdk-overlay-popover,
::ng-deep #max-video-quality .cdk-overlay-popover * {
width: auto !important;
min-width: auto !important;
height: auto !important;
min-height: auto !important;
padding: revert !important;
}

View File

@ -9,7 +9,7 @@
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp:opsz,wght,FILL,GRAD@24,500,1,-25"/>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body class="mat-typography">

View File

@ -1,9 +1,4 @@
/* You can add global styles to this file, and also import other style files */
.mat-icon {
font-family: "Material Symbols Sharp" !important;
}
html,
body {
height: 100%;
@ -13,14 +8,8 @@ body {
}
body {
font-family:
Roboto,
Helvetica Neue Light,
Helvetica Neue,
Helvetica,
Arial,
Lucida Grande,
sans-serif;
font-family: Roboto, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial,
Lucida Grande, sans-serif;
}
a {
@ -105,7 +94,6 @@ app-participant:last-child > .participant-container {
button.mat-icon-custom .mat-mdc-button-touch-target {
width: 24px;
height: 24px;
pointer-events: none;
}
.top-div {
@ -121,13 +109,3 @@ app-options-dialog .mat-mdc-form-field-infix {
.cdk-overlay-pane:has(.mat-mdc-select-panel) {
min-width: fit-content;
}
/* Disable mat-select panel CSS transitions/animations so options
are immediately clickable (prevents ElementClickInterceptedException
in Selenium when mdc-menu-surface intercepts clicks during animation). */
.mat-mdc-select-panel.mdc-menu-surface {
transition: none !important;
animation: none !important;
opacity: 1 !important;
transform: none !important;
}