diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index f8d68b77af..0000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,67 +0,0 @@ -# Contribute - -## Introduction - -First, thank you for considering contributing to openvidu! It's people like you that make the open source community such a great community! 😊 - -We welcome any type of contribution, not only code. You can help with -- **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open) -- **Marketing**: writing blog posts, howto's, printing stickers, ... -- **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ... -- **Code**: take a look at the [open issues](issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them. -- **Money**: we welcome financial contributions in full transparency on our [open collective](https://opencollective.com/openvidu). - -## Your First Contribution - -Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github). - -## Submitting code - -Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it. The pull request should also contain tests. - -## Code review process - -The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge. -It is also always helpful to have some context for your pull request. What was the purpose? Why does it matter to you? - -## Financial contributions - -We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/openvidu). -Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed. - -## Questions - -If you have any questions, create an [issue](issue) (protip: do a quick search first to see if someone else didn't ask the same question before!). -You can also reach us at hello@openvidu.opencollective.com. - -## Credits - -### Contributors - -Thank you to all the people who have already contributed to openvidu! - - - -### Backers - -Thank you to all our backers! [[Become a backer](https://opencollective.com/openvidu#backer)] - - - - -### Sponsors - -Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/openvidu#sponsor)) - - - - - - - - - - - - - \ No newline at end of file diff --git a/NOTICE b/NOTICE index 4626a07814..3bfee66144 100644 --- a/NOTICE +++ b/NOTICE @@ -1,4 +1,4 @@ -(C) Copyright 2017-2022 OpenVidu (https://openvidu.io) +(C) Copyright 2017-2024 OpenVidu (https://openvidu.io) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index a0cbe2301b..ef241abc39 100644 --- a/README.md +++ b/README.md @@ -1,59 +1 @@ -[![Backers on Open Collective](https://opencollective.com/openvidu/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/openvidu/sponsors/badge.svg)](#sponsors) -[![License badge](https://img.shields.io/badge/license-Apache2-orange.svg)](http://www.apache.org/licenses/LICENSE-2.0) -[![OpenVidu Tests](https://github.com/OpenVidu/openvidu/actions/workflows/openvidu-ce-test.yml/badge.svg)](https://github.com/OpenVidu/openvidu/actions/workflows/openvidu-ce-test.yml) -[![Npm version](https://img.shields.io/npm/v/openvidu-browser?label=npm-version)](https://npmjs.org/package/openvidu-browser) -[![Npm downloads](https://img.shields.io/npm/dw/openvidu-browser?label=npm2-downloads)](https://npmjs.org/package/openvidu-browser) - - -[![Documentation Status](https://readthedocs.org/projects/openvidu/badge/?version=stable)](https://docs.openvidu.io/en/stable/?badge=stable) -[![Docker badge](https://img.shields.io/docker/pulls/openvidu/openvidu-server-kms.svg)](https://hub.docker.com/r/openvidu/openvidu-server-kms) -[![Support badge](https://img.shields.io/badge/support-sof-yellowgreen.svg)](https://openvidu.discourse.group/) -[![Twitter Follow](https://img.shields.io/twitter/follow/openvidu.svg?style=social)](https://twitter.com/openvidu) - -[![][OpenViduLogo]](https://openvidu.io) - -openvidu -=== - -Visit [openvidu.io](https://openvidu.io) - -## Community Forum - -Visit [OpenVidu Community Forum](https://openvidu.discourse.group/) - -[OpenViduLogo]: https://secure.gravatar.com/avatar/5daba1d43042f2e4e85849733c8e5702?s=120 - -## Contributors - -This project exists thanks to all the people who contribute. - - - -## Backers - -Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/openvidu#backer)] - - - -## Acknowledgments - -OpenVidu has been supported under project "CPP2021-008720 NewGenVidu: An elastic, user-friendly and privacy-friendly videoconferencing platform", funded by MCIN/AEI/10.13039/501100011033 and by the European Union-NextGenerationEU/PRTR. - - - -## Sponsors - -Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/openvidu#sponsor)] - - - - - - - - - - - - - +Branch `v2compatibility` contains every public artifact to make OpenVidu v2 applications compatible with [OpenVidu v3](https://openvidu.io) deployments, as well as e2e tests to test this compatibility. \ No newline at end of file diff --git a/ci-scripts/commons/build.sh b/ci-scripts/commons/build.sh deleted file mode 100644 index 85ba66608a..0000000000 --- a/ci-scripts/commons/build.sh +++ /dev/null @@ -1,248 +0,0 @@ -#!/bin/bash -x -set -eu -o pipefail - -############################################################################ -# Any function offered by this file that is not path agnostic assumes that # -# the path is located where the first command of each function requires it # -############################################################################ - -CLEAN_ENVIRONMENT=false -BUILD_OV_BROWSER=false -BUILD_OV_NODE_CLIENT=false -BUILD_OV_JAVA_CLIENT=false -BUILD_OV_PARENT=false -BUILD_OV_TESTAPP=false -BUILD_OV_SERVER_DASHBOARD=false -BUILD_OV_SERVER=false -BUILD_OV_SERVER_DEPENDENCY=false -BUILD_OV_SERVER_PRO_INSPECTOR=false -BUILD_OV_SERVER_PRO=false -CHECK_AND_PREPARE_KURENTO_SNAPSHOT=false - -if [[ -n ${1:-} ]]; then - case "${1:-}" in - - --clean-environment) - CLEAN_ENVIRONMENT=true - ;; - - --build-openvidu-browser) - BUILD_OV_BROWSER=true - ;; - - --build-openvidu-node-client) - BUILD_OV_NODE_CLIENT=true - ;; - - --build-openvidu-java-client) - BUILD_OV_JAVA_CLIENT=true - ;; - - --build-openvidu-parent) - BUILD_OV_PARENT=true - ;; - - --build-openvidu-testapp) - BUILD_OV_TESTAPP=true - ;; - - --build-openvidu-server-dashboard) - if [[ -z "${2:-}" ]]; then - echo "Must provide LINK_LOCAL_DEPENDENCIES as 1st parameter" - exit 1 - fi - BUILD_OV_SERVER_DASHBOARD=true - LINK_LOCAL_DEPENDENCIES="${2}" - ;; - - --build-openvidu-server) - BUILD_OV_SERVER=true - ;; - - --build-openvidu-server-dependency) - BUILD_OV_SERVER_DEPENDENCY=true - ;; - - --build-openvidu-server-pro-inspector) - if [[ -z "${2:-}" ]]; then - echo "Must provide LINK_LOCAL_DEPENDENCIES as 1st parameter" - exit 1 - fi - BUILD_OV_SERVER_PRO_INSPECTOR=true - LINK_LOCAL_DEPENDENCIES="${2}" - ;; - - --build-openvidu-server-pro) - BUILD_OV_SERVER_PRO=true - ;; - --check-and-prepare-kurento-snapshot) - CHECK_AND_PREPARE_KURENTO_SNAPSHOT=true - ;; - - *) - echo "Unrecognized method $1" - exit 1 - ;; - - esac -else - echo "Must provide a method to execute as first parameter when calling the script" - exit 1 -fi - -# ------------- -# Clean environment -# ------------- -if [[ "${CLEAN_ENVIRONMENT}" == true ]]; then - - # Remove all running containers except test container and runner container - ids=$(docker ps -a -q) - for id in $ids; do - DOCKER_IMAGE=$(docker inspect --format='{{.Config.Image}}' $id) - if [[ "${DOCKER_IMAGE}" != *"$TEST_IMAGE"* ]] && - [[ "${DOCKER_IMAGE}" != *"runner-image"* ]]; then - echo "Removing container image '$DOCKER_IMAGE' with id '$id'" - docker stop $id && docker rm $id - fi - done - - # Clean /opt/openvidu contents - rm -rf /opt/openvidu/* - -fi - -# ------------- -# Build openvidu-browser -# ------------- -if [[ "${BUILD_OV_BROWSER}" == true ]]; then - pushd openvidu-browser || exit 1 - npm install - npm run build - npm link - npm pack - mv openvidu-browser-*.tgz /opt/openvidu - npm run browserify - npm run browserify-prod - popd -fi - -# ------------- -# Build openvidu-node-client -# ------------- -if [[ "${BUILD_OV_NODE_CLIENT}" == true ]]; then - pushd openvidu-node-client - npm install - npm run build - npm link - npm pack - mv openvidu-node-client-*.tgz /opt/openvidu - popd -fi - -# ------------- -# Build openvidu-java-client -# ------------- -if [[ "${BUILD_OV_JAVA_CLIENT}" == true ]]; then - pushd openvidu-java-client - MVN_VERSION=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec) - mvn -B clean compile package - mvn -B install:install-file -Dfile=target/openvidu-java-client-${MVN_VERSION}.jar \ - -DgroupId=io.openvidu \ - -DartifactId=openvidu-java-client \ - -Dversion=${MVN_VERSION} -Dpackaging=jar - popd -fi - -# ------------- -# Build openvidu-parent -# ------------- -if [[ "${BUILD_OV_PARENT}" == true ]]; then - mvn -B -DskipTests=true -Dmaven.artifact.threads=1 clean install -fi - -# ------------- -# Build openvidu-testapp -# ------------- -if [[ "${BUILD_OV_TESTAPP}" == true ]]; then - pushd openvidu-testapp - npm install - npm link openvidu-browser openvidu-node-client - export NG_CLI_ANALYTICS="false" && ./node_modules/@angular/cli/bin/ng.js build --configuration production --output-path=/opt/openvidu/testapp - popd -fi - -# ------------- -# Build openvidu-server dashboard -# ------------- -if [[ "${BUILD_OV_SERVER_DASHBOARD}" == true ]]; then - pushd openvidu-server/src/dashboard - npm install - if [[ "${LINK_LOCAL_DEPENDENCIES}" == true ]]; then - npm link openvidu-browser openvidu-node-client - fi - npm run build-prod - popd -fi - -# ------------- -# Build openvidu-server -# ------------- -if [[ "${BUILD_OV_SERVER}" == true ]]; then - pushd openvidu-server - mvn -B -DskipTests=true clean package - mv target/openvidu-server-*.jar /opt/openvidu - popd -fi - -# ------------- -# Build openvidu-server dependency -# ------------- -if [[ "${BUILD_OV_SERVER_DEPENDENCY}" == true ]]; then - pushd openvidu-server - mvn -B -DskipTests=true -Pdependency clean install - popd -fi - -# ------------- -# Build Inspector -# ------------- -if [[ "${BUILD_OV_SERVER_PRO_INSPECTOR}" == true ]]; then - pushd dashboard - npm install - if [[ "${LINK_LOCAL_DEPENDENCIES}" == true ]]; then - npm link openvidu-browser openvidu-node-client - fi - npm run build-server-prod - popd -fi - -# ------------- -# Build openvidu-server-pro -# ------------- -if [[ "${BUILD_OV_SERVER_PRO}" == true ]]; then - pushd openvidu-server-pro - mvn -B -DskipTests=true clean package - mv target/openvidu-server-pro-*.jar /opt/openvidu - popd -fi - -# ------------- -# Check kurento version from pom.xml -# If kurento version is a snapshot, configure snapshot builds -# ------------- -if [[ "${CHECK_AND_PREPARE_KURENTO_SNAPSHOT}" == true ]]; then - # Check if kurento version is a snapshot - KURENTO_VERSION=$(awk -F'[<>]' '// {print $3}' pom.xml) - if [[ "${KURENTO_VERSION}" == *"-SNAPSHOT" ]] && [[ -n "${KURENTO_SNAPSHOTS_URL:-}" ]]; then - echo "Kurento version is a SNAPSHOT: ${KURENTO_VERSION}" - mkdir -p /etc/maven - chmod -R 777 /etc/maven - pushd /etc/maven - rm -f settings.xml - curl https://raw.githubusercontent.com/OpenVidu/openvidu/master/ci-scripts/kurento-snapshots.xml -o settings.xml - sed -i "s|KURENTO_SNAPSHOTS_URL|${KURENTO_SNAPSHOTS_URL}|g" settings.xml - popd - else - echo "Kurento version is not a SNAPSHOT: ${KURENTO_VERSION}" - fi -fi diff --git a/ci-scripts/commons/bump.sh b/ci-scripts/commons/bump.sh deleted file mode 100644 index 6365126666..0000000000 --- a/ci-scripts/commons/bump.sh +++ /dev/null @@ -1,307 +0,0 @@ -#!/bin/bash -x -set -eu -o pipefail - -############################################################################ -# Any function offered by this file that is not path agnostic assumes that # -# the path is located where the first command of each function requires it # -############################################################################ - -# Bump versions -BUMP_NPM_PROJECT_VERSION=false -BUMP_NPM_DEPENDENCY_VERSION=false -BUMP_MAVEN_PROJECT_VERSION=false -BUMP_MAVEN_PROPERTY_VERSION=false -BUMP_MAVEN_DEPENDENCY_VERSION=false -BUMP_DOCKER_COMPOSE_SERVICE_VERSION=false -BUMP_DOCKER_COMPOSE_HEADER_VERSION=false -BUMP_DOCKER_IMAGE_VERSION_IN_FILES=false -BUMP_APPLICATION_PROPERTIES_VAR_VALUE=false -WAIT_FOR_NPM_DEPENDENCY=false -GENERIC_SED=false - -if [[ -n ${1:-} ]]; then - case "${1:-}" in - - --bump-npm-project-version) - if [[ -z "${2:-}" ]]; then - echo "Must provide VERSION as 1st parameter" - exit 1 - fi - BUMP_NPM_PROJECT_VERSION=true - VERSION="${2}" - ;; - - --bump-npm-dependency-version) - if [[ -z "${2:-}" ]]; then - echo "Must provide DEPENDENCY as 1st parameter" - exit 1 - fi - if [[ -z "${3:-}" ]]; then - echo "Must provide VERSION as 2nd parameter" - exit 1 - fi - BUMP_NPM_DEPENDENCY_VERSION=true - DEPENDENCY="${2}" - VERSION="${3}" - TYPE_OF_DEPENDENCY="${4:-dependencies}" # [dependencies, devDependencies, peerDependencies, optionalDependencies] - ;; - - --bump-maven-project-version) - if [[ -z "${2:-}" ]]; then - echo "Must provide VERSION as 1st parameter" - exit 1 - fi - BUMP_MAVEN_PROJECT_VERSION=true - VERSION="${2}" - ;; - - --bump-maven-property-version) - if [[ -z "${2:-}" ]]; then - echo "Must provide PROPERTY as 1st parameter" - exit 1 - fi - if [[ -z "${3:-}" ]]; then - echo "Must provide VERSION as 2nd parameter" - exit 1 - fi - BUMP_MAVEN_PROPERTY_VERSION=true - PROPERTY="${2}" - VERSION="${3}" - ;; - - --bump-maven-dependency-version) - if [[ -z "${2:-}" ]]; then - echo "Must provide DEPENDENCY as 1st parameter" - exit 1 - fi - if [[ -z "${3:-}" ]]; then - echo "Must provide VERSION as 2nd parameter" - exit 1 - fi - BUMP_MAVEN_DEPENDENCY_VERSION=true - DEPENDENCY="${2}" - VERSION="${3}" - ;; - - --bump-docker-compose-service-version) - if [[ -z "${2:-}" ]]; then - echo "Must provide DOCKER_COMPOSE_FILE as 1st parameter" - exit 1 - fi - if [[ -z "${3:-}" ]]; then - echo "Must provide SERVICE_IMAGE as 2nd parameter" - exit 1 - fi - if [[ -z "${4:-}" ]]; then - echo "Must provide VERSION as 3rd parameter" - exit 1 - fi - BUMP_DOCKER_COMPOSE_SERVICE_VERSION=true - DOCKER_COMPOSE_FILE="${2}" - SERVICE_IMAGE="${3}" - VERSION="${4}" - ;; - - --bump-docker-compose-header-version) - if [[ -z "${2:-}" ]]; then - echo "Must provide DOCKER_COMPOSE_FILE as 1st parameter" - exit 1 - fi - if [[ -z "${3:-}" ]]; then - echo "Must provide HEADER as 2nd parameter" - exit 1 - fi - if [[ -z "${4:-}" ]]; then - echo "Must provide VERSION as 3rd parameter" - exit 1 - fi - BUMP_DOCKER_COMPOSE_HEADER_VERSION=true - DOCKER_COMPOSE_FILE="${2}" - HEADER="${3}" - VERSION="${4}" - ;; - - --bump-docker-image-version-in-files) - if [[ -z "${3:-}" ]]; then - echo "Must provide FILE_NAME_PATTERN as 1st parameter" - exit 1 - fi - if [[ -z "${4:-}" ]]; then - echo "Must provide IMAGE as 2nd parameter" - exit 1 - fi - if [[ -z "${4:-}" ]]; then - echo "Must provide VERSION as 3rd parameter" - exit 1 - fi - BUMP_DOCKER_IMAGE_VERSION_IN_FILES=true - FILE_NAME_PATTERN="${2}" - IMAGE="${3}" - VERSION="${4}" - ;; - - --bump-application-properties-var-value) - if [[ -z "${3:-}" ]]; then - echo "Must provide APPLICATION_PROPERTIES_FILE as 2nd parameter" - exit 1 - fi - if [[ -z "${4:-}" ]]; then - echo "Must provide VARIABLE as 3rd parameter" - exit 1 - fi - if [[ -z "${4:-}" ]]; then - echo "Must provide VALUE as 4th parameter" - exit 1 - fi - BUMP_APPLICATION_PROPERTIES_VAR_VALUE=true - APPLICATION_PROPERTIES_FILE="${2}" - VARIABLE="${3}" - VALUE="${4}" - ;; - - --wait-for-npm-dependency) - if [[ -z "${2:-}" ]]; then - echo "Must provide DEPENDENCY as 1st parameter" - exit 1 - fi - if [[ -z "${3:-}" ]]; then - echo "Must provide VERSION as 2nd parameter" - exit 1 - fi - WAIT_FOR_NPM_DEPENDENCY=true - DEPENDENCY="${2}" - VERSION="${3}" - ;; - - --generic-sed) - if [[ -z "${2:-}" ]]; then - echo "Must provide FILE as 1st parameter" - exit 1 - fi - if [[ -z "${3:-}" ]]; then - echo "Must provide SED_EXPRESSION as 2nd parameter" - exit 1 - fi - GENERIC_SED=true - FILE="${2}" - SED_EXPRESSION="${3}" - ;; - - *) - echo "Unrecognized method $1" - exit 1 - ;; - - esac -else - echo "Must provide a method to execute as first parameter when calling the script" - exit 1 -fi - -compareFiles() { - if cmp -s "$1" "$1-AUX"; then - rm -f $1-AUX - echo "Error: no changes has been made to $1" - echo "Trying to change \"$2\" to \"$3\"" - exit 1 - else - cp -f "$1-AUX" "$1" - rm -f "$1-AUX" - fi -} - -# ------------- -# Bump NPM project version -# ------------- -if [[ "${BUMP_NPM_PROJECT_VERSION}" == true ]]; then - npm version ${VERSION} --git-tag-version=false --commit-hooks=false -fi - -# ------------- -# Bump NPM project dependency -# ------------- -if [[ "${BUMP_NPM_DEPENDENCY_VERSION}" == true ]]; then - jq -j ".${TYPE_OF_DEPENDENCY}.\"${DEPENDENCY}\" = \"${VERSION}\"" package.json >package.json-AUX - compareFiles package.json version $VERSION -fi - -# ------------- -# Bump Maven project version -# ------------- -if [[ "${BUMP_MAVEN_PROJECT_VERSION}" == true ]]; then - cp pom.xml pom.xml-AUX - mvn -DskipTests=true versions:set -DnewVersion="${VERSION}" - mv pom.xml changed-pom.xml && mv pom.xml-AUX pom.xml && mv changed-pom.xml pom.xml-AUX - compareFiles pom.xml "" $VERSION -fi - -# ------------- -# Bump Maven project property -# ------------- -if [[ "${BUMP_MAVEN_PROPERTY_VERSION}" == true ]]; then - mvn --batch-mode \ - -DskipTests=true \ - versions:set-property \ - -Dproperty="${PROPERTY}" \ - -DnewVersion="${VERSION}" -fi - -# ------------- -# Bump Maven dependency property -# ------------- -if [[ "${BUMP_MAVEN_DEPENDENCY_VERSION}" == true ]]; then - mvn --batch-mode versions:use-dep-version -Dincludes=$DEPENDENCY -DdepVersion=$VERSION -DforceVersion=true -fi - -# ------------- -# Bump docker-compose.yml service version -# ------------- -if [[ "${BUMP_DOCKER_COMPOSE_SERVICE_VERSION}" == true ]]; then - sed -r "s|image:\s+${SERVICE_IMAGE}:[[:alnum:]._-]+|image: ${SERVICE_IMAGE}:${VERSION}|g" ${DOCKER_COMPOSE_FILE} >${DOCKER_COMPOSE_FILE}-AUX - compareFiles $DOCKER_COMPOSE_FILE $SERVICE_IMAGE $VERSION -fi - -# ------------- -# Bump docker-compose.yml header version -# ------------- -if [[ "${BUMP_DOCKER_COMPOSE_HEADER_VERSION}" == true ]]; then - sed -r "s|#\s+${HEADER}:\s+[[:alnum:]._-]+|# ${HEADER}: ${VERSION}|g" ${DOCKER_COMPOSE_FILE} >${DOCKER_COMPOSE_FILE}-AUX - compareFiles $DOCKER_COMPOSE_FILE $HEADER $VERSION -fi - -# ------------- -# Bump Docker image version in files -# ------------- -if [[ "${BUMP_DOCKER_IMAGE_VERSION_IN_FILES}" == true ]]; then - find . -type f -name ${FILE_NAME_PATTERN} | xargs sed -i -r "s|${IMAGE}:[[:alnum:]._-]+|${IMAGE}:${VERSION}|g" -fi - -# ------------- -# Bump application.properties variable value -# ------------- -if [[ "${BUMP_APPLICATION_PROPERTIES_VAR_VALUE}" == true ]]; then - sed -r "s%${VARIABLE}((:|=)\s*).*$%${VARIABLE}\1${VALUE}%g" ${APPLICATION_PROPERTIES_FILE} >${APPLICATION_PROPERTIES_FILE}-AUX - compareFiles $APPLICATION_PROPERTIES_FILE $VARIABLE $VALUE -fi - -# ------------- -# Wait for NPM dependency to be available -# ------------- -if [[ "${WAIT_FOR_NPM_DEPENDENCY}" == true ]]; then - CHECK_VERSION_AVAILABILTY="npm show ${DEPENDENCY}@${VERSION} version || echo ''" - VERSION_AUX=$(eval "${CHECK_VERSION_AVAILABILTY}") - until [[ "${VERSION_AUX}" == "${VERSION}" ]]; do - echo "Waiting for ${DEPENDENCY}@${VERSION} to be available in NPM..." - sleep 2 - VERSION_AUX=$(eval "${CHECK_VERSION_AVAILABILTY}") - done - echo "${DEPENDENCY}@${VERSION} already available in NPM" -fi - -# ------------- -# Generic sed replacement -# ------------- -if [[ "${GENERIC_SED}" == true ]]; then - sed -r "$SED_EXPRESSION" ${FILE} >${FILE}-AUX - compareFiles $FILE "(generic sed)" "$SED_EXPRESSION" -fi diff --git a/ci-scripts/commons/test-utils.sh b/ci-scripts/commons/test-utils.sh deleted file mode 100644 index bd12207744..0000000000 --- a/ci-scripts/commons/test-utils.sh +++ /dev/null @@ -1,161 +0,0 @@ -#!/bin/bash -x -set -eu -o pipefail - -############################################################################ -# Any function offered by this file that is not path agnostic assumes that # -# the path is located where the first command of each function requires it # -############################################################################ - -# CI flags -PREPARE_TEST_ENVIRONMENT=false -USE_SPECIFIC_KURENTO_JAVA_COMMIT=false -SERVE_OV_TESTAPP=false -CHECK_AND_PREPARE_KURENTO_SNAPSHOT=false - -if [[ -n ${1:-} ]]; then - case "${1:-}" in - - --prepare-test-environment) - PREPARE_TEST_ENVIRONMENT=true - ;; - - --check-and-prepare-kurento-snapshot) - CHECK_AND_PREPARE_KURENTO_SNAPSHOT=true - ;; - - --use-specific-kurento-java-commit) - USE_SPECIFIC_KURENTO_JAVA_COMMIT=true - ;; - - --serve-openvidu-testapp) - SERVE_OV_TESTAPP=true - ;; - - *) - echo "Unrecognized method $1" - exit 1 - ;; - - esac -else - echo "Must provide a method to execute as first parameter when calling the script" - exit 1 -fi - -# ------------- -# Prepare build -# ------------- -if [[ "${PREPARE_TEST_ENVIRONMENT}" == true ]]; then - - # Connect e2e test container to network bridge so it is vissible for browser and media server containers - if [[ -n "${TEST_IMAGE}" ]]; then - E2E_CONTAINER_ID="$(docker ps | grep "$TEST_IMAGE" | awk '{ print $1 }')" || echo "Docker container not found for image ${TEST_IMAGE}" - if [[ -n "${E2E_CONTAINER_ID}" ]]; then - docker network connect bridge "${E2E_CONTAINER_ID}" - else - echo "Could not connect test docker container to docker bridge, because no running container was found for image \"${TEST_IMAGE}\"" - fi - else - echo "No TEST_IMAGE env var provided. Skipping network bridge connection" - fi - - # Prepare directory for OpenVidu recordings - sudo mkdir -p /opt/openvidu/recordings && sudo chmod 777 /opt/openvidu/recordings - # Prepare directory for OpenVidu Android apps - sudo mkdir -p /opt/openvidu/android && sudo chmod 777 /opt/openvidu/android - - # Download fake videos - FAKE_VIDEO1=/opt/openvidu/barcode.y4m - FAKE_VIDEO2=/opt/openvidu/girl.mjpeg - if [ ! -f ${FAKE_VIDEO1} ]; then - sudo curl --location https://github.com/OpenVidu/openvidu/raw/master/openvidu-test-e2e/docker/barcode.y4m --create-dirs --output /opt/openvidu/barcode.y4m - else - echo "File ${FAKE_VIDEO1} already exists" - fi - if [ ! -f ${FAKE_VIDEO2} ]; then - sudo curl --location https://github.com/OpenVidu/openvidu/raw/master/openvidu-test-e2e/docker/girl.mjpeg --create-dirs --output /opt/openvidu/girl.mjpeg - else - echo "File ${FAKE_VIDEO2} already exists" - fi - - # Download fake audios - FAKE_AUDIO1=/opt/openvidu/fakeaudio.wav - FAKE_AUDIO2=/opt/openvidu/stt-test.wav - if [ ! -f ${FAKE_AUDIO1} ]; then - sudo curl --location https://github.com/OpenVidu/openvidu/raw/master/openvidu-test-e2e/docker/fakeaudio.wav --create-dirs --output /opt/openvidu/fakeaudio.wav - else - echo "File ${FAKE_AUDIO1} already exists" - fi - if [ ! -f ${FAKE_AUDIO2} ]; then - sudo curl --location https://github.com/OpenVidu/openvidu/raw/master/openvidu-test-e2e/docker/stt-test.wav --create-dirs --output /opt/openvidu/stt-test.wav - else - echo "File ${FAKE_AUDIO2} already exists" - fi - - # Download recording custom layout - sudo curl --location https://raw.githubusercontent.com/OpenVidu/openvidu/master/openvidu-test-e2e/docker/my-custom-layout/index.html --create-dirs --output /opt/openvidu/test-layouts/layout1/index.html - - # Open permissions for /opt/openvidu folder - sudo chmod -R 777 /opt/openvidu - - # Pull browser images - # Pull chrome image if env variable CHROME_VERSION is set - if [[ -n "${CHROME_VERSION:-}" ]]; then - docker pull selenium/standalone-chrome:"${CHROME_VERSION}" - fi - # Pull firefox image if env variable FIREFOX_VERSION is set - if [[ -n "${FIREFOX_VERSION:-}" ]]; then - docker pull selenium/standalone-firefox:"${FIREFOX_VERSION}" - fi - # Pull edge image if env variable EDGE_VERSION is set - if [[ -n "${EDGE_VERSION:-}" ]]; then - docker pull selenium/standalone-edge:"${EDGE_VERSION}" - fi - # Pull Docker Android image if env variable DOCKER_ANDROID_IMAGE is set - if [[ -n "${DOCKER_ANDROID_IMAGE:-}" ]]; then - docker pull "${DOCKER_ANDROID_IMAGE}" - fi - - # Pull mediasoup and kurento - if [[ -n "${MEDIASOUP_CONTROLLER_VERSION:-}" ]]; then - docker pull openvidu/mediasoup-controller:"${MEDIASOUP_CONTROLLER_VERSION}" - fi - if [[ -n "${KURENTO_MEDIA_SERVER_IMAGE:-}" ]]; then - docker pull "${KURENTO_MEDIA_SERVER_IMAGE}" - fi - -fi - -# ------------- -# Use a specific kurento-java commit other than the configured in openvidu-parent pom.xml -# ------------- -if [[ "${USE_SPECIFIC_KURENTO_JAVA_COMMIT}" == true ]]; then - - git clone https://github.com/Kurento/kurento.git - pushd kurento/clients/java - git checkout -f "${KURENTO_JAVA_COMMIT}" - MVN_VERSION=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec) - mvn -B -Dmaven.artifact.threads=1 clean install - popd - rm -rf kurento - mvn -B versions:set-property \ - -Dproperty=version.kurento \ - -DnewVersion="${MVN_VERSION}" - -fi - -# ------------- -# Serve openvidu-testapp -# ------------- -if [[ "${SERVE_OV_TESTAPP}" == true ]]; then - # Generate certificate - openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 \ - -subj "/CN=www.mydom.com/O=My Company LTD./C=US" \ - -keyout /opt/openvidu/testapp/key.pem \ - -out /opt/openvidu/testapp/cert.pem - - # Serve TestApp - pushd /opt/openvidu/testapp - http-server -S -p 4200 &>/opt/openvidu/testapp.log & - popd -fi diff --git a/ci-scripts/kurento-snapshots.xml b/ci-scripts/kurento-snapshots.xml deleted file mode 100644 index 5b765b745e..0000000000 --- a/ci-scripts/kurento-snapshots.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - default - - true - - - - kurento-github-public - Kurento GitHub Maven packages (public access) - KURENTO_SNAPSHOTS_URL - - false - - - true - - - - - - kurento-github-public - Kurento GitHub Maven packages (public access) - KURENTO_SNAPSHOTS_URL - - false - - - true - - - - - - diff --git a/ci-scripts/openvidu-e2e-tests.sh b/ci-scripts/openvidu-e2e-tests.sh deleted file mode 100755 index ae0d442d6a..0000000000 --- a/ci-scripts/openvidu-e2e-tests.sh +++ /dev/null @@ -1,241 +0,0 @@ -#!/bin/bash -x -set -eu -o pipefail - -############################################################################ -# Any function offered by this file that is not path agnostic assumes that # -# the path is located where the first command of each function requires it # -############################################################################ - -OV_INTEGRATION_TESTS=false -OV_UNIT_TESTS=false -OV_E2E_KURENTO=false -OV_E2E_MEDIASOUP=false -LAUNCH_OV_KURENTO=false -LAUNCH_OV_MEDIASOUP=false - -function environmentLaunch { - local MEDIA_SERVER="$1" - - # Get e2e container id - local E2E_CONTAINER_ID - E2E_CONTAINER_ID="$(docker ps | grep "$TEST_IMAGE" | awk '{ print $1 }')" - - # Get e2e container IP so services running can be accessed by browser and media server containers - local E2E_CONTAINER_IP - E2E_CONTAINER_IP="$(docker inspect "$E2E_CONTAINER_ID" | awk '/bridge/,/IPAddress/' | grep IPAddress | cut -d'"' -f4)" - - # Kurento and mediasoup needs to run as network host, so we need Docker host IP. - local DOCKER_HOST_IP - DOCKER_HOST_IP="$(docker inspect bridge --format '{{with index .IPAM.Config 0}}{{or .Gateway .Subnet}}{{end}}' | sed -r 's|\.0/[[:digit:]]+$|.1|')" - - if [[ "${MEDIA_SERVER}" == "kurento" ]]; then - docker run -e KMS_UID=$(id -u) --network=host --detach=true --volume=/opt/openvidu/recordings:/opt/openvidu/recordings "${KURENTO_MEDIA_SERVER_IMAGE}" - while true; do - RC="$(curl \ - --silent \ - --no-buffer \ - --write-out '%{http_code}' \ - --header "Connection: Upgrade" \ - --header "Upgrade: websocket" \ - --header "Host: ${DOCKER_HOST_IP}" \ - --header "Origin: ${DOCKER_HOST_IP}" \ - "http://${DOCKER_HOST_IP}:8888/kurento" || echo '')" - - if [[ "$RC" == "500" ]]; then - break - else - echo "Waiting for ${MEDIA_SERVER}..." - sleep 1 - fi - done - elif [[ "${MEDIA_SERVER}" == "mediasoup" ]]; then - LOG_DATE=$(printf '%(%Y-%m-%d-%H-%M-%S)T') - docker run --network=host --restart=always \ - --env=KMS_MIN_PORT=40000 \ - --env=KMS_MAX_PORT=65535 \ - --env=OPENVIDU_PRO_LICENSE="${OPENVIDU_PRO_LICENSE}" \ - --env=OPENVIDU_PRO_LICENSE_API="${OPENVIDU_PRO_LICENSE_API}" \ - --env=WEBRTC_LISTENIPS_0_ANNOUNCEDIP="${DOCKER_HOST_IP}" \ - --env=WEBRTC_LISTENIPS_0_IP="${DOCKER_HOST_IP}" \ - --volume=/opt/openvidu/recordings:/opt/openvidu/recordings \ - openvidu/mediasoup-controller:"${MEDIASOUP_CONTROLLER_VERSION}" >& /opt/openvidu/mediasoup-controller-${LOG_DATE}.log & - until $(curl --insecure --output /dev/null --silent http://${DOCKER_HOST_IP}:8888/kurento); do - echo "Waiting for ${MEDIA_SERVER}..." - sleep 1 - done - else - echo "Not valid media server" - exit 1 - fi - - if [ "${DOCKER_RECORDING_VERSION}" != "default" ]; then - echo "Using custom openvidu-recording tag: ${DOCKER_RECORDING_VERSION}" - java -jar -DKMS_URIS="[\"ws://${DOCKER_HOST_IP}:8888/kurento\"]" \ - -DDOMAIN_OR_PUBLIC_IP="${E2E_CONTAINER_IP}" \ - -DOPENVIDU_SECRET=MY_SECRET -DHTTPS_PORT=4443 -DOPENVIDU_RECORDING=true \ - -DOPENVIDU_RECORDING_CUSTOM_LAYOUT=/opt/openvidu/test-layouts \ - -DOPENVIDU_RECORDING_VERSION="${DOCKER_RECORDING_VERSION}" -DOPENVIDU_WEBHOOK=true \ - -DOPENVIDU_WEBHOOK_ENDPOINT=http://127.0.0.1:7777/webhook \ - /opt/openvidu/openvidu-server-*.jar &>/opt/openvidu/openvidu-server-"${MEDIA_SERVER}".log & - else - echo "Using default openvidu-recording tag" - java -jar -DKMS_URIS="[\"ws://${DOCKER_HOST_IP}:8888/kurento\"]" \ - -DDOMAIN_OR_PUBLIC_IP="${E2E_CONTAINER_IP}" \ - -DOPENVIDU_SECRET=MY_SECRET -DHTTPS_PORT=4443 -DOPENVIDU_RECORDING=true \ - -DOPENVIDU_RECORDING_CUSTOM_LAYOUT=/opt/openvidu/test-layouts -DOPENVIDU_WEBHOOK=true \ - -DOPENVIDU_WEBHOOK_ENDPOINT=http://127.0.0.1:7777/webhook \ - /opt/openvidu/openvidu-server-*.jar &>/opt/openvidu/openvidu-server-"${MEDIA_SERVER}".log & - fi - until $(curl --insecure --output /dev/null --silent --head --fail https://OPENVIDUAPP:MY_SECRET@localhost:4443/); do - echo "Waiting for openvidu-server..." - sleep 2 - done -} - -function openviduE2ETests { - local MEDIA_SERVER="$1" - - # Get e2e container id - local E2E_CONTAINER_ID - E2E_CONTAINER_ID="$(docker ps | grep "$TEST_IMAGE" | awk '{ print $1 }')" - - # Get e2e container IP so services running can be accessed by browser and media server containers - local E2E_CONTAINER_IP - E2E_CONTAINER_IP="$(docker inspect "$E2E_CONTAINER_ID" | awk '/bridge/,/IPAddress/' | grep IPAddress | cut -d'"' -f4)" - - # Kurento and mediasoup needs to run as network host, so we need Docker host IP. - local DOCKER_HOST_IP - DOCKER_HOST_IP="$(docker network inspect bridge | grep Subnet | cut -d'"' -f4 | cut -d'/' -f1 | sed 's/.$/1/' | grep 172)" - - pushd openvidu-test-e2e - if [[ "${MEDIA_SERVER}" == "kurento" ]]; then - - mvn -DMEDIA_SERVER_IMAGE="${KURENTO_MEDIA_SERVER_IMAGE}" \ - -DOPENVIDU_URL="https://${E2E_CONTAINER_IP}:4443" \ - -DCHROME_VERSION="${CHROME_VERSION}" \ - -DFIREFOX_VERSION="${FIREFOX_VERSION}" \ - -DEDGE_VERSION="${EDGE_VERSION}" \ - -Dtest=OpenViduTestAppE2eTest \ - -DAPP_URL="https://${E2E_CONTAINER_IP}:4200" \ - -DEXTERNAL_CUSTOM_LAYOUT_URL="http://${E2E_CONTAINER_IP}:4114" \ - -DREMOTE_URL_CHROME="http://${DOCKER_HOST_IP}:6666/wd/hub/" \ - -DREMOTE_URL_FIREFOX="http://${DOCKER_HOST_IP}:6667/wd/hub/" \ - -DREMOTE_URL_OPERA="http://${DOCKER_HOST_IP}:6668/wd/hub/" \ - -DREMOTE_URL_EDGE="http://${DOCKER_HOST_IP}:6669/wd/hub/" \ - -DEXTERNAL_CUSTOM_LAYOUT_PARAMS="sessionId,CUSTOM_LAYOUT_SESSION,secret,MY_SECRET" \ - test - - elif [[ "${MEDIA_SERVER}" == "mediasoup" ]]; then - - mvn -DMEDIA_SERVER_IMAGE="openvidu/mediasoup-controller:${MEDIASOUP_CONTROLLER_VERSION}" \ - -DOPENVIDU_URL="https://${E2E_CONTAINER_IP}:4443" \ - -DCHROME_VERSION="${CHROME_VERSION}" \ - -DFIREFOX_VERSION="${FIREFOX_VERSION}" \ - -DEDGE_VERSION="${EDGE_VERSION}" \ - -Dtest=OpenViduTestAppE2eTest \ - -DAPP_URL="https://${E2E_CONTAINER_IP}:4200" \ - -DEXTERNAL_CUSTOM_LAYOUT_URL="http://${E2E_CONTAINER_IP}:4114" \ - -DREMOTE_URL_CHROME="http://${DOCKER_HOST_IP}:6666/wd/hub/" \ - -DREMOTE_URL_FIREFOX="http://${DOCKER_HOST_IP}:6667/wd/hub/" \ - -DREMOTE_URL_OPERA="http://${DOCKER_HOST_IP}:6668/wd/hub/" \ - -DREMOTE_URL_EDGE="http://${DOCKER_HOST_IP}:6669/wd/hub/" \ - -DEXTERNAL_CUSTOM_LAYOUT_PARAMS="sessionId,CUSTOM_LAYOUT_SESSION,secret,MY_SECRET" \ - -DOPENVIDU_PRO_LICENSE="${OPENVIDU_PRO_LICENSE}" \ - -DOPENVIDU_PRO_LICENSE_API="${OPENVIDU_PRO_LICENSE_API}" \ - test - - else - echo "Not valid media server" - exit 1 - fi - stopMediaServer - kill -9 $(pgrep -f /opt/openvidu/openvidu-server) || true - popd -} - -function stopMediaServer { - # Remove Kurento Media Server - declare -a arr=("kurento/kurento-media-server" - "openvidu/mediasoup-controller:") - for image in "${arr[@]}"; do - docker ps -a | awk '{ print $1,$2 }' | grep "${image}" | awk '{ print $1 }' | xargs -I {} docker rm -f {} || true - done - docker ps -a -} - -# Environment variables -if [[ -n ${1:-} ]]; then - case "${1:-}" in - --openvidu-server-unit-tests) - OV_UNIT_TESTS=true - ;; - --openvidu-server-integration-tests) - OV_INTEGRATION_TESTS=true - ;; - --openvidu-e2e-tests-kurento) - OV_E2E_KURENTO=true - ;; - --openvidu-e2e-tests-mediasoup) - OV_E2E_MEDIASOUP=true - ;; - --environment-launch-kurento) - LAUNCH_OV_KURENTO=true - ;; - --environment-launch-mediasoup) - LAUNCH_OV_MEDIASOUP=true - ;; - *) - echo "Unrecognized method $1" - exit 1 - ;; - esac -else - echo "Must provide a method to execute as first parameter when calling the script" - exit 1 -fi - -# ------------- -# openvidu-server unit tests -# ------------- -if [[ "${OV_UNIT_TESTS}" == true ]]; then - pushd openvidu-server - mvn -B -Dtest=io.openvidu.server.test.unit.*Test test - popd -fi - -# ------------- -# openvidu-server integration tests -# ------------- -if [[ "${OV_INTEGRATION_TESTS}" == true ]]; then - pushd openvidu-server - mvn -B -Dtest=io.openvidu.server.test.integration.*Test test - popd -fi - -# ------------- -# OpenVidu E2E Tests Kurento -# ------------- -if [[ "${OV_E2E_KURENTO}" == true ]]; then - openviduE2ETests "kurento" -fi - -# ------------- -# OpenVidu E2E Tests mediasoup -# ------------- -if [[ "${OV_E2E_MEDIASOUP}" == true ]]; then - openviduE2ETests "mediasoup" -fi - -# ------------- -# Environment launch Kurento -# ------------- -if [[ "${LAUNCH_OV_KURENTO}" == true ]]; then - environmentLaunch "kurento" -fi - -# ------------- -# Environment launch mediasoup -# ------------- -if [[ "${LAUNCH_OV_MEDIASOUP}" == true ]]; then - environmentLaunch "mediasoup" -fi diff --git a/openvidu-browser/.gitignore b/openvidu-browser/.gitignore deleted file mode 100644 index 83622e643d..0000000000 --- a/openvidu-browser/.gitignore +++ /dev/null @@ -1,62 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Typescript v1 declaration files -typings/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env - -docs/ -lib/ -static/** \ No newline at end of file diff --git a/openvidu-browser/.npmignore b/openvidu-browser/.npmignore deleted file mode 100644 index 77f12ae2e5..0000000000 --- a/openvidu-browser/.npmignore +++ /dev/null @@ -1 +0,0 @@ -docs/ diff --git a/openvidu-browser/.prettierrc b/openvidu-browser/.prettierrc deleted file mode 100644 index bc72fe80d6..0000000000 --- a/openvidu-browser/.prettierrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "singleQuote": true, - "printWidth": 140, - "trailingComma": "none", - "semi": true, - "bracketSpacing": true, - "useTabs": false, - "jsxSingleQuote": true, - "tabWidth": 4 -} diff --git a/openvidu-browser/LICENSE b/openvidu-browser/LICENSE deleted file mode 100644 index 261eeb9e9f..0000000000 --- a/openvidu-browser/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/openvidu-browser/config/replace_for_ts44.sh b/openvidu-browser/config/replace_for_ts44.sh deleted file mode 100755 index 87bab50664..0000000000 --- a/openvidu-browser/config/replace_for_ts44.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -set -e -SEARCH_STRING_1="(type: K," -REPLACE_STRING_1="(type: K | string," -SEARCH_STRING_2='\[key: `signal:\${string}`\]: SignalEvent;' -sed -i "s~${SEARCH_STRING_1}~${REPLACE_STRING_1}~g" ts4.4/lib/OpenVidu/Session.d.ts -sed -i "/${SEARCH_STRING_2}/d" ts4.4/lib/OpenViduInternal/Events/EventMap/SessionEventMap.d.ts \ No newline at end of file diff --git a/openvidu-browser/config/tsconfig.json b/openvidu-browser/config/tsconfig.json deleted file mode 100644 index e7f7ecae8a..0000000000 --- a/openvidu-browser/config/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "include": ["../src"], - "exclude": ["../config", "../docs", "../lib", "../node_modules", "../ts4.4"], - "typedocOptions": { - "name": "OpenVidu Browser", - "entryPoints": ["../src/index.ts"], - "out": "../docs", - "theme": "default", - "readme": "none", - "includeVersion": true, - "validation": { - "notExported": true, - "invalidLink": true - }, - "excludeExternals": true, - "excludePrivate": true, - "excludeProtected": true, - "excludeInternal": true - } -} \ No newline at end of file diff --git a/openvidu-browser/config/tslint.json b/openvidu-browser/config/tslint.json deleted file mode 100644 index c2137e2c7d..0000000000 --- a/openvidu-browser/config/tslint.json +++ /dev/null @@ -1,154 +0,0 @@ -{ - "extends": "tslint:recommended", - "rules": { - "array-type": [ - true, - "array" - ], - "ban-types": { - "options": [ - [ - "Object", - "Avoid using the `Object` type. Did you mean `object`?" - ], - [ - "Function", - "Avoid using the `Function` type. Prefer a specific function type, like `() => void`, or use `ts.AnyFunction`." - ], - [ - "Boolean", - "Avoid using the `Boolean` type. Did you mean `boolean`?" - ], - [ - "Number", - "Avoid using the `Number` type. Did you mean `number`?" - ], - [ - "String", - "Avoid using the `String` type. Did you mean `string`?" - ] - ] - }, - "class-name": true, - "comment-format": [ - true, - "check-space" - ], - "curly": [ - true, - "ignore-same-line" - ], - "indent": [ - true, - "spaces", - 2 - ], - "interface-name": [ - true, - "never-prefix" - ], - "interface-over-type-literal": true, - "jsdoc-format": true, - "no-inferrable-types": true, - "no-internal-module": true, - "no-null-keyword": false, - "no-switch-case-fall-through": true, - "no-trailing-whitespace": [ - true, - "ignore-template-strings" - ], - "no-var-keyword": true, - "object-literal-shorthand": true, - "one-line": [ - true, - "check-open-brace", - "check-whitespace" - ], - "prefer-const": true, - "quotemark": [ - true, - "single", - "avoid-escape", - "avoid-template" - ], - "semicolon": [ - true, - "always", - "ignore-bound-class-methods" - ], - "space-within-parens": true, - "triple-equals": true, - "typedef-whitespace": [ - true, - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - }, - { - "call-signature": "onespace", - "index-signature": "onespace", - "parameter": "onespace", - "property-declaration": "onespace", - "variable-declaration": "onespace" - } - ], - "whitespace": [ - true, - "check-branch", - "check-decl", - "check-operator", - "check-module", - "check-separator", - "check-type" - ], - "no-implicit-dependencies": [ - true, - "dev" - ], - "object-literal-key-quotes": [ - true, - "consistent-as-needed" - ], - "variable-name": [ - true, - "ban-keywords", - "check-format", - "allow-leading-underscore" - ], - "arrow-parens": false, - "arrow-return-shorthand": false, - "forin": false, - "member-access": false, - "no-conditional-assignment": false, - "no-console": false, - "no-debugger": false, - "no-empty-interface": false, - "no-eval": false, - "no-object-literal-type-assertion": false, - "no-shadowed-variable": false, - "no-submodule-imports": false, - "no-var-requires": false, - "ordered-imports": false, - "prefer-conditional-expression": false, - "radix": false, - "trailing-comma": false, - "align": false, - "eofline": false, - "max-line-length": false, - "no-consecutive-blank-lines": false, - "space-before-function-paren": false, - "ban-comma-operator": false, - "max-classes-per-file": false, - "member-ordering": false, - "no-angle-bracket-type-assertion": false, - "no-bitwise": false, - "no-namespace": false, - "no-reference": false, - "object-literal-sort-keys": false, - "one-variable-per-declaration": false, - "unified-signatures": false - } -} \ No newline at end of file diff --git a/openvidu-browser/generate-docs.sh b/openvidu-browser/generate-docs.sh deleted file mode 100755 index 4b75d815d2..0000000000 --- a/openvidu-browser/generate-docs.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -if [[ -z "$BASEHREF_VERSION" ]]; then - echo "Example of use: \"BASEHREF_VERSION=2.12.0 ${0}\"" 1>&2 - exit 1 -fi - -# Replace version from "stable" to the specified one in all TypeDoc links -grep -rl '/en/stable/' src | xargs sed -i -e 's|/en/stable/|/en/'${BASEHREF_VERSION}'/|g' - -# Generate TypeDoc -./node_modules/typedoc/bin/typedoc --tsconfig ./config/tsconfig.json - -# Return links to "stable" version -grep -rl '/en/'${BASEHREF_VERSION}'/' src | xargs sed -i -e 's|/en/'${BASEHREF_VERSION}'/|/en/stable/|g' - -# Clean previous docs from openvidu.io-docs repo and copy new ones -rm -rf ../../openvidu.io-docs/docs/api/openvidu-browser/* -cp -R ./docs/. ../../openvidu.io-docs/docs/api/openvidu-browser \ No newline at end of file diff --git a/openvidu-browser/package-lock.json b/openvidu-browser/package-lock.json deleted file mode 100644 index 604c87f964..0000000000 --- a/openvidu-browser/package-lock.json +++ /dev/null @@ -1,2511 +0,0 @@ -{ - "name": "openvidu-browser", - "version": "2.30.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "openvidu-browser", - "version": "2.30.0", - "license": "Apache-2.0", - "dependencies": { - "events": "3.3.0", - "freeice": "2.2.2", - "hark": "1.2.3", - "inherits": "2.0.4", - "jsnlog": "2.30.0", - "mime": "3.0.0", - "platform": "1.3.6", - "semver": "7.6.2", - "uuid": "9.0.1", - "wolfy87-eventemitter": "5.2.9" - }, - "devDependencies": { - "@types/node": "18.11.9", - "@types/platform": "1.3.4", - "browserify": "17.0.0", - "terser": "5.15.1", - "tsify": "5.0.4", - "tslint": "6.1.3", - "typedoc": "0.23.21", - "typescript": "4.9.3" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.24.2", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", - "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", - "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.5", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", - "dev": true - }, - "node_modules/@types/platform": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@types/platform/-/platform-1.3.4.tgz", - "integrity": "sha512-U0o4K+GNiK0PNxoDwd8xRnvLVe4kzei6opn3/FCjAriqaP+rfrDdSl1kP/hLL6Y3/Y3hhGnBwD4dCkkAqs1W/Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "dev": true, - "dependencies": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "dev": true, - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "node_modules/assert": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz", - "integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==", - "dev": true, - "dependencies": { - "object.assign": "^4.1.4", - "util": "^0.10.4" - } - }, - "node_modules/assert/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true - }, - "node_modules/assert/node_modules/util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "dev": true, - "dependencies": { - "inherits": "2.0.3" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true - }, - "node_modules/browser-pack": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", - "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", - "dev": true, - "dependencies": { - "combine-source-map": "~0.8.0", - "defined": "^1.0.0", - "JSONStream": "^1.0.3", - "safe-buffer": "^5.1.1", - "through2": "^2.0.0", - "umd": "^3.0.0" - }, - "bin": { - "browser-pack": "bin/cmd.js" - } - }, - "node_modules/browser-resolve": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", - "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", - "dev": true, - "dependencies": { - "resolve": "^1.17.0" - } - }, - "node_modules/browserify": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-17.0.0.tgz", - "integrity": "sha512-SaHqzhku9v/j6XsQMRxPyBrSP3gnwmE27gLJYZgMT2GeK3J0+0toN+MnuNYDfHwVGQfLiMZ7KSNSIXHemy905w==", - "dev": true, - "dependencies": { - "assert": "^1.4.0", - "browser-pack": "^6.0.1", - "browser-resolve": "^2.0.0", - "browserify-zlib": "~0.2.0", - "buffer": "~5.2.1", - "cached-path-relative": "^1.0.0", - "concat-stream": "^1.6.0", - "console-browserify": "^1.1.0", - "constants-browserify": "~1.0.0", - "crypto-browserify": "^3.0.0", - "defined": "^1.0.0", - "deps-sort": "^2.0.1", - "domain-browser": "^1.2.0", - "duplexer2": "~0.1.2", - "events": "^3.0.0", - "glob": "^7.1.0", - "has": "^1.0.0", - "htmlescape": "^1.1.0", - "https-browserify": "^1.0.0", - "inherits": "~2.0.1", - "insert-module-globals": "^7.2.1", - "JSONStream": "^1.0.3", - "labeled-stream-splicer": "^2.0.0", - "mkdirp-classic": "^0.5.2", - "module-deps": "^6.2.3", - "os-browserify": "~0.3.0", - "parents": "^1.0.1", - "path-browserify": "^1.0.0", - "process": "~0.11.0", - "punycode": "^1.3.2", - "querystring-es3": "~0.2.0", - "read-only-stream": "^2.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.1.4", - "shasum-object": "^1.0.0", - "shell-quote": "^1.6.1", - "stream-browserify": "^3.0.0", - "stream-http": "^3.0.0", - "string_decoder": "^1.1.1", - "subarg": "^1.0.0", - "syntax-error": "^1.1.1", - "through2": "^2.0.0", - "timers-browserify": "^1.0.1", - "tty-browserify": "0.0.1", - "url": "~0.11.0", - "util": "~0.12.0", - "vm-browserify": "^1.0.0", - "xtend": "^4.0.0" - }, - "bin": { - "browserify": "bin/cmd.js" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dev": true, - "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "node_modules/browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "dev": true, - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", - "dev": true, - "dependencies": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "node_modules/browserify-sign": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", - "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", - "dev": true, - "dependencies": { - "bn.js": "^5.2.1", - "browserify-rsa": "^4.1.0", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.5", - "hash-base": "~3.0", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.7", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "dev": true, - "dependencies": { - "pako": "~1.0.5" - } - }, - "node_modules/buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", - "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", - "dev": true, - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "dev": true - }, - "node_modules/builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", - "dev": true - }, - "node_modules/cached-path-relative": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.1.0.tgz", - "integrity": "sha512-WF0LihfemtesFcJgO7xfOoOcnWzY/QHR4qeDqV44jPU3HTI54+LnfXK3SA27AVVGCdZFgjjFFaqUA9Jx7dMJZA==", - "dev": true - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/combine-source-map": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", - "integrity": "sha512-UlxQ9Vw0b/Bt/KYwCFqdEwsQ1eL8d1gibiFb7lxQJFdvTgc2hIZi6ugsg+kyhzhPV+QEpUiEIwInIAIrgoEkrg==", - "dev": true, - "dependencies": { - "convert-source-map": "~1.1.0", - "inline-source-map": "~0.6.0", - "lodash.memoize": "~3.0.3", - "source-map": "~0.5.3" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", - "dev": true - }, - "node_modules/constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==", - "dev": true - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dev": true, - "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "node_modules/crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dev": true, - "dependencies": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - }, - "engines": { - "node": "*" - } - }, - "node_modules/dash-ast": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", - "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==", - "dev": true - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deps-sort": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", - "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==", - "dev": true, - "dependencies": { - "JSONStream": "^1.0.3", - "shasum-object": "^1.0.0", - "subarg": "^1.0.0", - "through2": "^2.0.0" - }, - "bin": { - "deps-sort": "bin/cmd.js" - } - }, - "node_modules/des.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", - "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/detective": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", - "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", - "dev": true, - "dependencies": { - "acorn-node": "^1.8.2", - "defined": "^1.0.0", - "minimist": "^1.2.6" - }, - "bin": { - "detective": "bin/detective.js" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dev": true, - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "node_modules/domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", - "dev": true, - "engines": { - "node": ">=0.4", - "npm": ">=1.2" - } - }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.2" - } - }, - "node_modules/elliptic": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.5.tgz", - "integrity": "sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==", - "dev": true, - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "dev": true - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/freeice": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/freeice/-/freeice-2.2.2.tgz", - "integrity": "sha512-XNoIxDHufqPIBSLpp4IrFPnoc+hv/0RwdOGhIoggIDC2ZKf5r6OoixbeoFJSmZOAq2aYiEUArhuQ8zVVrM5C4w==", - "dependencies": { - "normalice": "^1.0.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-assigned-identifiers": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", - "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==", - "dev": true - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hark": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/hark/-/hark-1.2.3.tgz", - "integrity": "sha512-u68vz9SCa38ESiFJSDjqK8XbXqWzyot7Cj6Y2b6jk2NJ+II3MY2dIrLMg/kjtIAun4Y1DHF/20hfx4rq1G5GMg==", - "dependencies": { - "wildemitter": "^1.2.0" - } - }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dev": true, - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/htmlescape": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", - "integrity": "sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", - "dev": true - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/inline-source-map": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.3.tgz", - "integrity": "sha512-1aVsPEsJWMJq/pdMU61CDlm1URcW702MTB4w9/zUjMus6H/Py8o7g68Pr9D4I6QluWGt/KdmswuRhaA05xVR1w==", - "dev": true, - "dependencies": { - "source-map": "~0.5.3" - } - }, - "node_modules/insert-module-globals": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.1.tgz", - "integrity": "sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg==", - "dev": true, - "dependencies": { - "acorn-node": "^1.5.2", - "combine-source-map": "^0.8.0", - "concat-stream": "^1.6.1", - "is-buffer": "^1.1.0", - "JSONStream": "^1.0.3", - "path-is-absolute": "^1.0.1", - "process": "~0.11.0", - "through2": "^2.0.0", - "undeclared-identifiers": "^1.1.2", - "xtend": "^4.0.0" - }, - "bin": { - "insert-module-globals": "bin/cmd.js" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", - "dev": true - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsnlog": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/jsnlog/-/jsnlog-2.30.0.tgz", - "integrity": "sha512-o3ROQVkhek+dkc7/9TXlB4TNtxUpYsRLOBJHZYk3Vy0B5zRBmfv9tyr56PrjcgEXuy06ARgfLTANY0+ImhzzGA==" - }, - "node_modules/jsonc-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", - "dev": true - }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ] - }, - "node_modules/JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/labeled-stream-splicer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", - "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "stream-splicer": "^2.0.0" - } - }, - "node_modules/lodash.memoize": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", - "integrity": "sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A==", - "dev": true - }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true - }, - "node_modules/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "dev": true, - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true - }, - "node_modules/module-deps": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.3.tgz", - "integrity": "sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==", - "dev": true, - "dependencies": { - "browser-resolve": "^2.0.0", - "cached-path-relative": "^1.0.2", - "concat-stream": "~1.6.0", - "defined": "^1.0.0", - "detective": "^5.2.0", - "duplexer2": "^0.1.2", - "inherits": "^2.0.1", - "JSONStream": "^1.0.3", - "parents": "^1.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.4.0", - "stream-combiner2": "^1.1.1", - "subarg": "^1.0.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" - }, - "bin": { - "module-deps": "bin/cmd.js" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/normalice": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/normalice/-/normalice-1.0.1.tgz", - "integrity": "sha512-wF2/tv9q/K8S+RqCgll5yC6z/zcXNr+rEHfGIw8A6D58vjfJo+kp749MI6cAHv72LE7nwv92Qi6tZhIeMOOJpg==" - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", - "dev": true - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true - }, - "node_modules/parents": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", - "integrity": "sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg==", - "dev": true, - "dependencies": { - "path-platform": "~0.11.15" - } - }, - "node_modules/parse-asn1": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", - "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", - "dev": true, - "dependencies": { - "asn1.js": "^4.10.1", - "browserify-aes": "^1.2.0", - "evp_bytestokey": "^1.0.3", - "hash-base": "~3.0", - "pbkdf2": "^3.1.2", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "dev": true - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-platform": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", - "integrity": "sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "dev": true, - "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true - }, - "node_modules/platform": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", - "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==" - }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dev": true, - "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", - "dev": true - }, - "node_modules/qs": { - "version": "6.12.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz", - "integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", - "dev": true, - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "node_modules/read-only-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", - "integrity": "sha512-3ALe0bjBVZtkdWKIcThYpQCLbBMd/+Tbh2CDSrAIDO3UsZ4Xs+tnyjv2MjCOMMgBG+AsUOeuP1cgtY1INISc8w==", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.2" - } - }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/readable-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, - "node_modules/shasum-object": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.0.tgz", - "integrity": "sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==", - "dev": true, - "dependencies": { - "fast-safe-stringify": "^2.0.7" - } - }, - "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/shiki": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.11.1.tgz", - "integrity": "sha512-EugY9VASFuDqOexOgXR18ZV+TbFrQHeCpEYaXamO+SZlsnT/2LxuLBX25GGtIrwaEVFXUAbUQ601SWE2rMwWHA==", - "dev": true, - "dependencies": { - "jsonc-parser": "^3.0.0", - "vscode-oniguruma": "^1.6.1", - "vscode-textmate": "^6.0.0" - } - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stream-browserify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "dev": true, - "dependencies": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - } - }, - "node_modules/stream-browserify/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/stream-combiner2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", - "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==", - "dev": true, - "dependencies": { - "duplexer2": "~0.1.0", - "readable-stream": "^2.0.2" - } - }, - "node_modules/stream-http": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", - "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", - "dev": true, - "dependencies": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "xtend": "^4.0.2" - } - }, - "node_modules/stream-http/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/stream-splicer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", - "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.2" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", - "dev": true, - "dependencies": { - "is-utf8": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/subarg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", - "integrity": "sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==", - "dev": true, - "dependencies": { - "minimist": "^1.1.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/syntax-error": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", - "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", - "dev": true, - "dependencies": { - "acorn-node": "^1.2.0" - } - }, - "node_modules/terser": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", - "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser/node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/timers-browserify": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", - "integrity": "sha512-PIxwAupJZiYU4JmVZYwXp9FKsHMXb5h0ZEFyuXTAn8WLHOlcij+FEcbrvDsom1o5dr1YggEtFbECvGCW2sT53Q==", - "dev": true, - "dependencies": { - "process": "~0.11.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/tsconfig": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-5.0.3.tgz", - "integrity": "sha512-Cq65A3kVp6BbsUgg9DRHafaGmbMb9EhAc7fjWvudNWKjkbWrt43FnrtZt6awshH1R0ocfF2Z0uxock3lVqEgOg==", - "dev": true, - "dependencies": { - "any-promise": "^1.3.0", - "parse-json": "^2.2.0", - "strip-bom": "^2.0.0", - "strip-json-comments": "^2.0.0" - } - }, - "node_modules/tsify": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/tsify/-/tsify-5.0.4.tgz", - "integrity": "sha512-XAZtQ5OMPsJFclkZ9xMZWkSNyMhMxEPsz3D2zu79yoKorH9j/DT4xCloJeXk5+cDhosEibu4bseMVjyPOAyLJA==", - "dev": true, - "dependencies": { - "convert-source-map": "^1.1.0", - "fs.realpath": "^1.0.0", - "object-assign": "^4.1.0", - "semver": "^6.1.0", - "through2": "^2.0.0", - "tsconfig": "^5.0.3" - }, - "engines": { - "node": ">=0.12" - }, - "peerDependencies": { - "browserify": ">= 10.x", - "typescript": ">= 2.8" - } - }, - "node_modules/tsify/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tslint": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", - "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", - "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.3", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.13.0", - "tsutils": "^2.29.0" - }, - "bin": { - "tslint": "bin/tslint" - }, - "engines": { - "node": ">=4.8.0" - }, - "peerDependencies": { - "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" - } - }, - "node_modules/tslint/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "peerDependencies": { - "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" - } - }, - "node_modules/tty-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", - "dev": true - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true - }, - "node_modules/typedoc": { - "version": "0.23.21", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.21.tgz", - "integrity": "sha512-VNE9Jv7BgclvyH9moi2mluneSviD43dCE9pY8RWkO88/DrEgJZk9KpUk7WO468c9WWs/+aG6dOnoH7ccjnErhg==", - "dev": true, - "dependencies": { - "lunr": "^2.3.9", - "marked": "^4.0.19", - "minimatch": "^5.1.0", - "shiki": "^0.11.1" - }, - "bin": { - "typedoc": "bin/typedoc" - }, - "engines": { - "node": ">= 14.14" - }, - "peerDependencies": { - "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x" - } - }, - "node_modules/typedoc/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/typedoc/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/typescript": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", - "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/umd": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", - "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==", - "dev": true, - "bin": { - "umd": "bin/cli.js" - } - }, - "node_modules/undeclared-identifiers": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", - "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", - "dev": true, - "dependencies": { - "acorn-node": "^1.3.0", - "dash-ast": "^1.0.0", - "get-assigned-identifiers": "^1.2.0", - "simple-concat": "^1.0.0", - "xtend": "^4.0.1" - }, - "bin": { - "undeclared-identifiers": "bin.js" - } - }, - "node_modules/url": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz", - "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==", - "dev": true, - "dependencies": { - "punycode": "^1.4.1", - "qs": "^6.11.2" - } - }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", - "dev": true - }, - "node_modules/vscode-oniguruma": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", - "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", - "dev": true - }, - "node_modules/vscode-textmate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-6.0.0.tgz", - "integrity": "sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==", - "dev": true - }, - "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wildemitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/wildemitter/-/wildemitter-1.2.1.tgz", - "integrity": "sha512-UMmSUoIQSir+XbBpTxOTS53uJ8s/lVhADCkEbhfRjUGFDPme/XGOb0sBWLx5sTz7Wx/2+TlAw1eK9O5lw5PiEw==" - }, - "node_modules/wolfy87-eventemitter": { - "version": "5.2.9", - "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.2.9.tgz", - "integrity": "sha512-P+6vtWyuDw+MB01X7UeF8TaHBvbCovf4HPEMF/SV7BdDc1SMTiBy13SRD71lQh4ExFTG1d/WNzDGDCyOKSMblw==" - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - } - } -} diff --git a/openvidu-browser/package.json b/openvidu-browser/package.json deleted file mode 100644 index 2a9d46f057..0000000000 --- a/openvidu-browser/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "author": "OpenVidu", - "dependencies": { - "events": "3.3.0", - "freeice": "2.2.2", - "hark": "1.2.3", - "inherits": "2.0.4", - "jsnlog": "2.30.0", - "mime": "3.0.0", - "platform": "1.3.6", - "semver": "7.6.2", - "uuid": "9.0.1", - "wolfy87-eventemitter": "5.2.9" - }, - "description": "OpenVidu Browser", - "devDependencies": { - "@types/node": "18.11.9", - "@types/platform": "1.3.4", - "browserify": "17.0.0", - "terser": "5.15.1", - "tsify": "5.0.4", - "tslint": "6.1.3", - "typedoc": "0.23.21", - "typescript": "4.9.3" - }, - "license": "Apache-2.0", - "main": "lib/index.js", - "name": "openvidu-browser", - "repository": { - "type": "git", - "url": "git://github.com/OpenVidu/openvidu" - }, - "scripts": { - "browserify": "VERSION=${VERSION:-dev}; mkdir -p static/js/ && cd src && ../node_modules/browserify/bin/cmd.js Main.ts -p [ tsify ] --exclude kurento-browser-extensions --debug -o ../static/js/openvidu-browser-$VERSION.js -v", - "browserify-prod": "VERSION=${VERSION:-dev}; mkdir -p static/js/ && cd src && ../node_modules/browserify/bin/cmd.js --debug Main.ts -p [ tsify ] --exclude kurento-browser-extensions | ../node_modules/terser/bin/terser --source-map content=inline --output ../static/js/openvidu-browser-$VERSION.min.js", - "build": "cd src/OpenVidu && ./../../node_modules/typescript/bin/tsc && cd ../.. && ./node_modules/typescript/bin/tsc --declaration src/index.ts --outDir ./lib --sourceMap --target es5 --lib dom,es5,es2015.promise,scripthost && rm -rf ./ts4.4 && mkdir -p ./ts4.4/lib && cp -r ./lib ./ts4.4 && find ./ts4.4/lib -type f ! -iname '*.d.ts' -delete && ./config/replace_for_ts44.sh", - "docs": "./generate-docs.sh" - }, - "types": "lib/index.d.ts", - "typesVersions": { - "<4.4": { - "*": [ - "ts4.4/*" - ] - } - }, - "version": "2.30.0" -} diff --git a/openvidu-browser/src/Main.ts b/openvidu-browser/src/Main.ts deleted file mode 100644 index dfc88ff454..0000000000 --- a/openvidu-browser/src/Main.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { OpenVidu } from './OpenVidu/OpenVidu'; -import { JL } from 'jsnlog'; - -if (typeof globalThis !== 'undefined') { - globalThis['OpenVidu'] = OpenVidu; -} - -// Disable jsnlog when library is loaded -JL.setOptions({ enabled: false }); diff --git a/openvidu-browser/src/OpenVidu/Connection.ts b/openvidu-browser/src/OpenVidu/Connection.ts deleted file mode 100644 index 39af818237..0000000000 --- a/openvidu-browser/src/OpenVidu/Connection.ts +++ /dev/null @@ -1,217 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Session } from './Session'; -import { Stream } from './Stream'; -import { LocalConnectionOptions } from '../OpenViduInternal/Interfaces/Private/LocalConnectionOptions'; -import { RemoteConnectionOptions } from '../OpenViduInternal/Interfaces/Private/RemoteConnectionOptions'; -import { InboundStreamOptions } from '../OpenViduInternal/Interfaces/Private/InboundStreamOptions'; -import { StreamOptionsServer } from '../OpenViduInternal/Interfaces/Private/StreamOptionsServer'; -import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; -import { ExceptionEvent, ExceptionEventName } from '../OpenViduInternal/Events/ExceptionEvent'; - -/** - * @hidden - */ -const logger: OpenViduLogger = OpenViduLogger.getInstance(); - -/** - * Represents each one of the user's connection to the session (the local one and other user's connections). - * Therefore each {@link Session} and {@link Stream} object has an attribute of type Connection - */ -export class Connection { - /** - * Unique identifier of the connection - */ - connectionId: string; - - /** - * Time when this connection was created in OpenVidu Server (UTC milliseconds) - */ - creationTime: number; - - /** - * Data associated to this connection (and therefore to certain user). This is an important field: - * it allows you to broadcast all the information you want for each user (a username, for example) - */ - data: string; - - /** - * Role of the connection. - * - `SUBSCRIBER`: can subscribe to published Streams of other users by calling {@link Session.subscribe} - * - `PUBLISHER`: SUBSCRIBER permissions + can publish their own Streams by calling {@link Session.publish} - * - `MODERATOR`: SUBSCRIBER + PUBLISHER permissions + can force the unpublishing or disconnection over a third-party Stream or Connection by call {@link Session.forceUnpublish} and {@link Session.forceDisconnect} - * - * **Only defined for the local connection. In remote connections will be `undefined`** - */ - role: string; - - /** - * Whether the streams published by this Connection will be recorded or not. This only affects [INDIVIDUAL recording](/en/stable/advanced-features/recording/#individual-recording-selection) PRO - * - * **Only defined for the local connection. In remote connections will be `undefined`** - */ - record: boolean; - - /** - * @hidden - */ - stream?: Stream; - - /** - * @hidden - */ - localOptions: LocalConnectionOptions | undefined; - - /** - * @hidden - */ - remoteOptions: RemoteConnectionOptions | undefined; - - /** - * @hidden - */ - disposed = false; - - /** - * @hidden - */ - rpcSessionId: string; - - /** - * @hidden - */ - constructor(private session: Session, connectionOptions: LocalConnectionOptions | RemoteConnectionOptions) { - let msg = "'Connection' created "; - if (!!(connectionOptions).role) { - // Connection is local - this.localOptions = connectionOptions; - this.connectionId = this.localOptions.id; - this.creationTime = this.localOptions.createdAt; - this.data = this.localOptions.metadata; - this.rpcSessionId = this.localOptions.sessionId; - this.role = this.localOptions.role; - this.record = this.localOptions.record; - msg += '(local)'; - } else { - // Connection is remote - this.remoteOptions = connectionOptions; - this.connectionId = this.remoteOptions.id; - this.creationTime = this.remoteOptions.createdAt; - if (this.remoteOptions.metadata) { - this.data = this.remoteOptions.metadata; - } - if (this.remoteOptions.streams) { - this.initRemoteStreams(this.remoteOptions.streams); - } - msg += "(remote) with 'connectionId' [" + this.remoteOptions.id + ']'; - } - logger.info(msg); - } - - /* Hidden methods */ - - /** - * @hidden - */ - sendIceCandidate(candidate: RTCIceCandidate): void { - - if (!this.disposed) { - logger.debug((!!this.stream!.outboundStreamOpts ? 'Local' : 'Remote') + 'candidate for' + this.connectionId, candidate); - - this.session.openvidu.sendRequest( - 'onIceCandidate', - { - endpointName: this.connectionId, - candidate: candidate.candidate, - sdpMid: candidate.sdpMid, - sdpMLineIndex: candidate.sdpMLineIndex - }, - (error, response) => { - if (error) { - logger.error('Error sending ICE candidate: ' + JSON.stringify(error)); - this.session.emitEvent('exception', [ - new ExceptionEvent( - this.session, - ExceptionEventName.ICE_CANDIDATE_ERROR, - this.session, - 'There was an unexpected error on the server-side processing an ICE candidate generated and sent by the client-side', - error - ) - ]); - } - } - ); - } else { - logger.warn(`Connection ${this.connectionId} disposed when trying to send an ICE candidate. ICE candidate not sent`); - } - } - - /** - * @hidden - */ - initRemoteStreams(options: StreamOptionsServer[]): void { - // This is ready for supporting multiple streams per Connection object. Right now the loop will always run just once - // this.stream should also be replaced by a collection of streams to support multiple streams per Connection - options.forEach((opts) => { - const streamOptions: InboundStreamOptions = { - id: opts.id, - createdAt: opts.createdAt, - connection: this, - hasAudio: opts.hasAudio, - hasVideo: opts.hasVideo, - audioActive: opts.audioActive, - videoActive: opts.videoActive, - typeOfVideo: opts.typeOfVideo, - frameRate: opts.frameRate, - videoDimensions: !!opts.videoDimensions ? JSON.parse(opts.videoDimensions) : undefined, - filter: !!opts.filter ? opts.filter : undefined - }; - const stream = new Stream(this.session, streamOptions); - - this.addStream(stream); - }); - - logger.info( - "Remote 'Connection' with 'connectionId' [" + this.connectionId + '] is now configured for receiving Streams with options: ', - this.stream!.inboundStreamOpts - ); - } - - /** - * @hidden - */ - addStream(stream: Stream): void { - stream.connection = this; - this.stream = stream; - } - - /** - * @hidden - */ - removeStream(): void { - delete this.stream; - } - - /** - * @hidden - */ - dispose(): void { - this.disposed = true; - this.removeStream(); - } -} diff --git a/openvidu-browser/src/OpenVidu/EventDispatcher.ts b/openvidu-browser/src/OpenVidu/EventDispatcher.ts deleted file mode 100644 index dde7135b56..0000000000 --- a/openvidu-browser/src/OpenVidu/EventDispatcher.ts +++ /dev/null @@ -1,112 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Event } from '../OpenViduInternal/Events/Event'; -import { EventMap } from '../OpenViduInternal/Events/EventMap/EventMap'; -import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; - -import EventEmitter = require('wolfy87-eventemitter'); - -/** - * @hidden - */ -const logger: OpenViduLogger = OpenViduLogger.getInstance(); - -export abstract class EventDispatcher { - /** - * @hidden - */ - userHandlerArrowHandler: WeakMap<(event: Event) => void, (event: Event) => void> = new WeakMap(); - /** - * @hidden - */ - ee = new EventEmitter(); - - /** - * Adds function `handler` to handle event `type` - * - * @returns The EventDispatcher object - */ - abstract on(type: K, handler: (event: EventMap[K]) => void): this; - - /** - * Adds function `handler` to handle event `type` just once. The handler will be automatically removed after first execution - * - * @returns The object that dispatched the event - */ - abstract once(type: K, handler: (event: EventMap[K]) => void): this; - - /** - * Removes a `handler` from event `type`. If no handler is provided, all handlers will be removed from the event - * - * @returns The object that dispatched the event - */ - abstract off(type: K, handler?: (event: EventMap[K]) => void): this; - - /** - * @hidden - */ - onAux(type: string, message: string, handler: (event: Event) => void): EventDispatcher { - const arrowHandler = (event) => { - if (event) { - logger.debug(message, event); - } else { - logger.debug(message); - } - handler(event); - }; - this.userHandlerArrowHandler.set(handler, arrowHandler); - this.ee.on(type, arrowHandler); - return this; - } - - /** - * @hidden - */ - onceAux(type: string, message: string, handler: (event: Event) => void): EventDispatcher { - const arrowHandler = (event) => { - if (event) { - logger.debug(message, event); - } else { - logger.debug(message); - } - handler(event); - // Remove handler from map after first and only execution - this.userHandlerArrowHandler.delete(handler); - }; - this.userHandlerArrowHandler.set(handler, arrowHandler); - this.ee.once(type, arrowHandler); - return this; - } - - /** - * @hidden - */ - offAux(type: string, handler?: (event: Event) => void): EventDispatcher { - if (!handler) { - this.ee.removeAllListeners(type); - } else { - // Must remove internal arrow function handler paired with user handler - const arrowHandler = this.userHandlerArrowHandler.get(handler); - if (!!arrowHandler) { - this.ee.off(type, arrowHandler); - } - this.userHandlerArrowHandler.delete(handler); - } - return this; - } -} diff --git a/openvidu-browser/src/OpenVidu/Filter.ts b/openvidu-browser/src/OpenVidu/Filter.ts deleted file mode 100644 index 5e3397334d..0000000000 --- a/openvidu-browser/src/OpenVidu/Filter.ts +++ /dev/null @@ -1,285 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Stream } from './Stream'; -import { FilterEvent } from '../OpenViduInternal/Events/FilterEvent'; -import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPropertyChangedEvent'; -import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError'; -import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; - -/** - * @hidden - */ -const logger: OpenViduLogger = OpenViduLogger.getInstance(); - -/** - * **WARNING**: experimental option. This interface may change in the near future - * - * Video/audio filter applied to a Stream. See {@link Stream.applyFilter} - */ -export class Filter { - /** - * Type of filter applied. This is the name of the remote class identifying the filter to apply in Kurento Media Server. - * For example: `"FaceOverlayFilter"`, `"GStreamerFilter"`. - * - * You can get this property in `*.kmd.json` files defining the Kurento filters. For example, for GStreamerFilter that's - * [here](https://github.com/Kurento/kms-filters/blob/53a452fac71d61795952e3d2202156c6b00f6d65/src/server/interface/filters.GStreamerFilter.kmd.json#L4) - */ - type: string; - - /** - * Parameters used to initialize the filter. - * These correspond to the constructor parameters used in the filter in Kurento Media Server (except for `mediaPipeline` parameter, which is never needed). - * - * For example: for `filter.type = "GStreamerFilter"` could be `filter.options = {"command": "videobalance saturation=0.0"}` - * - * You can get this property in `*.kmd.json` files defining the Kurento filters. For example, for GStreamerFilter that's - * [here](https://github.com/Kurento/kms-filters/blob/53a452fac71d61795952e3d2202156c6b00f6d65/src/server/interface/filters.GStreamerFilter.kmd.json#L13-L31) - */ - options: Object; - - /** - * Value passed the last time {@link Filter.execMethod} was called. If `undefined` this method has not been called yet. - * - * You can use this value to know the current status of any applied filter - */ - lastExecMethod?: { - method: string; - params: Object; - }; - - /** - * @hidden - */ - handlers: Map void> = new Map(); - - /** - * @hidden - */ - stream: Stream; - private logger: OpenViduLogger; - - /** - * @hidden - */ - constructor(type: string, options: Object) { - this.type = type; - this.options = options; - } - - /** - * Executes a filter method. Available methods are specific for each filter - * - * @param method Name of the method - * @param params Parameters of the method - */ - execMethod(method: string, params: Object): Promise { - return new Promise((resolve, reject) => { - logger.info('Executing filter method to stream ' + this.stream.streamId); - - let finalParams; - - const successExecMethod = (triggerEvent) => { - logger.info('Filter method successfully executed on Stream ' + this.stream.streamId); - const oldValue = (Object).assign({}, this.stream.filter); - this.stream.filter!.lastExecMethod = { method, params: finalParams }; - if (triggerEvent) { - this.stream.session.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent( - this.stream.session, - this.stream, - 'filter', - this.stream.filter!, - oldValue, - 'execFilterMethod' - ) - ]); - this.stream.streamManager.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent( - this.stream.streamManager, - this.stream, - 'filter', - this.stream.filter!, - oldValue, - 'execFilterMethod' - ) - ]); - } - return resolve(); - }; - - if (this.type.startsWith('VB:')) { - if (typeof params === 'string') { - try { - params = JSON.parse(params); - } catch (error) { - return reject(new OpenViduError(OpenViduErrorName.VIRTUAL_BACKGROUND_ERROR, 'Wrong params syntax: ' + error)); - } - } - - finalParams = params; - - if (method === 'update') { - if (!this.stream.virtualBackgroundSinkElements?.VB) { - return reject( - new OpenViduError(OpenViduErrorName.VIRTUAL_BACKGROUND_ERROR, 'There is no Virtual Background filter applied') - ); - } else { - this.stream.virtualBackgroundSinkElements.VB.updateValues(params) - .then(() => successExecMethod(false)) - .catch((error) => { - if (error.name === OpenViduErrorName.VIRTUAL_BACKGROUND_ERROR) { - return reject(new OpenViduError(error.name, error.message)); - } else { - return reject( - new OpenViduError( - OpenViduErrorName.VIRTUAL_BACKGROUND_ERROR, - 'Error updating values on Virtual Background filter: ' + error - ) - ); - } - }); - } - } else { - return reject( - new OpenViduError(OpenViduErrorName.VIRTUAL_BACKGROUND_ERROR, `Unknown Virtual Background method "${method}"`) - ); - } - } else { - let stringParams; - if (typeof params !== 'string') { - try { - stringParams = JSON.stringify(params); - } catch (error) { - const errorMsg = "'params' property must be a JSON formatted object"; - logger.error(errorMsg); - return reject(errorMsg); - } - } else { - stringParams = params; - } - - finalParams = stringParams; - - this.stream.session.openvidu.sendRequest( - 'execFilterMethod', - { streamId: this.stream.streamId, method, params: stringParams }, - (error, response) => { - if (error) { - logger.error('Error executing filter method for Stream ' + this.stream.streamId, error); - if (error.code === 401) { - return reject( - new OpenViduError( - OpenViduErrorName.OPENVIDU_PERMISSION_DENIED, - "You don't have permissions to execute a filter method" - ) - ); - } else { - return reject(error); - } - } else { - return successExecMethod(true); - } - } - ); - } - }); - } - - /** - * Subscribe to certain filter event. Available events are specific for each filter - * - * @param eventType Event to which subscribe to. - * @param handler Function to execute upon event dispatched. It receives as parameter a {@link FilterEvent} object - * - * @returns A Promise (to which you can optionally subscribe to) that is resolved if the event listener was successfully attached to the filter and rejected with an Error object if not - */ - addEventListener(eventType: string, handler: (event: FilterEvent) => void): Promise { - return new Promise((resolve, reject) => { - logger.info('Adding filter event listener to event ' + eventType + ' to stream ' + this.stream.streamId); - this.stream.session.openvidu.sendRequest( - 'addFilterEventListener', - { streamId: this.stream.streamId, eventType }, - (error, response) => { - if (error) { - logger.error( - 'Error adding filter event listener to event ' + eventType + 'for Stream ' + this.stream.streamId, - error - ); - if (error.code === 401) { - return reject( - new OpenViduError( - OpenViduErrorName.OPENVIDU_PERMISSION_DENIED, - "You don't have permissions to add a filter event listener" - ) - ); - } else { - return reject(error); - } - } else { - this.handlers.set(eventType, handler); - logger.info( - 'Filter event listener to event ' + eventType + ' successfully applied on Stream ' + this.stream.streamId - ); - return resolve(); - } - } - ); - }); - } - - /** - * Removes certain filter event listener previously set. - * - * @param eventType Event to unsubscribe from. - * - * @returns A Promise (to which you can optionally subscribe to) that is resolved if the event listener was successfully removed from the filter and rejected with an Error object in other case - */ - removeEventListener(eventType: string): Promise { - return new Promise((resolve, reject) => { - logger.info('Removing filter event listener to event ' + eventType + ' to stream ' + this.stream.streamId); - this.stream.session.openvidu.sendRequest( - 'removeFilterEventListener', - { streamId: this.stream.streamId, eventType }, - (error, response) => { - if (error) { - logger.error( - 'Error removing filter event listener to event ' + eventType + 'for Stream ' + this.stream.streamId, - error - ); - if (error.code === 401) { - return reject( - new OpenViduError( - OpenViduErrorName.OPENVIDU_PERMISSION_DENIED, - "You don't have permissions to add a filter event listener" - ) - ); - } else { - return reject(error); - } - } else { - this.handlers.delete(eventType); - logger.info( - 'Filter event listener to event ' + eventType + ' successfully removed on Stream ' + this.stream.streamId - ); - return resolve(); - } - } - ); - }); - } -} diff --git a/openvidu-browser/src/OpenVidu/LocalRecorder.ts b/openvidu-browser/src/OpenVidu/LocalRecorder.ts deleted file mode 100644 index a66af73239..0000000000 --- a/openvidu-browser/src/OpenVidu/LocalRecorder.ts +++ /dev/null @@ -1,416 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Stream } from './Stream'; -import { LocalRecorderState } from '../OpenViduInternal/Enums/LocalRecorderState'; -import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; -import { PlatformUtils } from '../OpenViduInternal/Utils/Platform'; -import Mime = require('mime/lite'); - -/** - * @hidden - */ -const logger: OpenViduLogger = OpenViduLogger.getInstance(); - -/** - * @hidden - */ -let platform: PlatformUtils; - -/** - * Easy recording of {@link Stream} objects straightaway from the browser. Initialized with {@link OpenVidu.initLocalRecorder} method - */ -export class LocalRecorder { - state: LocalRecorderState; - - private connectionId: string; - private mediaRecorder: MediaRecorder; - private chunks: any[] = []; - private blob?: Blob; - private id: string; - private videoPreviewSrc: string; - private videoPreview: HTMLVideoElement; - - /** - * @hidden - */ - constructor(private stream: Stream) { - platform = PlatformUtils.getInstance(); - this.connectionId = !!this.stream.connection ? this.stream.connection.connectionId : 'default-connection'; - this.id = this.stream.streamId + '_' + this.connectionId + '_localrecord'; - this.state = LocalRecorderState.READY; - } - - /** - * Starts the recording of the Stream. {@link state} property must be `READY`. After method succeeds is set to `RECORDING` - * - * @param options The [MediaRecorder.options](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/MediaRecorder#parameters) to be used to record this Stream. - * For example: - * - * ```javascript - * var OV = new OpenVidu(); - * var publisher = await OV.initPublisherAsync(); - * var localRecorder = OV.initLocalRecorder(publisher.stream); - * var options = { - * mimeType: 'video/webm;codecs=vp8', - * audioBitsPerSecond:128000, - * videoBitsPerSecond:2500000 - * }; - * localRecorder.record(options); - * ``` - * - * If not specified, the default options preferred by the platform will be used. - * - * @returns A Promise (to which you can optionally subscribe to) that is resolved if the recording successfully started and rejected with an Error object if not - */ - record(options?: any): Promise { - return new Promise((resolve, reject) => { - try { - if (typeof options === 'string' || options instanceof String) { - return reject( - `When calling LocalRecorder.record(options) parameter 'options' cannot be a string. Must be an object like { mimeType: "${options}" }` - ); - } - if (typeof MediaRecorder === 'undefined') { - logger.error( - 'MediaRecorder not supported on your device. See compatibility in https://caniuse.com/#search=MediaRecorder' - ); - throw Error( - 'MediaRecorder not supported on your device. See compatibility in https://caniuse.com/#search=MediaRecorder' - ); - } - if (this.state !== LocalRecorderState.READY) { - throw Error( - "'LocalRecord.record()' needs 'LocalRecord.state' to be 'READY' (current value: '" + - this.state + - "'). Call 'LocalRecorder.clean()' or init a new LocalRecorder before" - ); - } - logger.log("Starting local recording of stream '" + this.stream.streamId + "' of connection '" + this.connectionId + "'"); - - if (!options) { - options = { mimeType: 'video/webm' }; - } else if (!options.mimeType) { - options.mimeType = 'video/webm'; - } - - this.mediaRecorder = new MediaRecorder(this.stream.getMediaStream(), options); - this.mediaRecorder.start(); - } catch (err) { - return reject(err); - } - - this.mediaRecorder.ondataavailable = (e) => { - if (e.data.size > 0) { - this.chunks.push(e.data); - } - }; - - this.mediaRecorder.onerror = (e) => { - logger.error('MediaRecorder error: ', e); - }; - - this.mediaRecorder.onstart = () => { - logger.log('MediaRecorder started (state=' + this.mediaRecorder.state + ')'); - }; - - this.mediaRecorder.onstop = () => { - this.onStopDefault(); - }; - - this.mediaRecorder.onpause = () => { - logger.log('MediaRecorder paused (state=' + this.mediaRecorder.state + ')'); - }; - - this.mediaRecorder.onresume = () => { - logger.log('MediaRecorder resumed (state=' + this.mediaRecorder.state + ')'); - }; - - this.state = LocalRecorderState.RECORDING; - return resolve(); - }); - } - - /** - * Ends the recording of the Stream. {@link state} property must be `RECORDING` or `PAUSED`. After method succeeds is set to `FINISHED` - * @returns A Promise (to which you can optionally subscribe to) that is resolved if the recording successfully stopped and rejected with an Error object if not - */ - stop(): Promise { - return new Promise((resolve, reject) => { - try { - if (this.state === LocalRecorderState.READY || this.state === LocalRecorderState.FINISHED) { - throw Error( - "'LocalRecord.stop()' needs 'LocalRecord.state' to be 'RECORDING' or 'PAUSED' (current value: '" + - this.state + - "'). Call 'LocalRecorder.start()' before" - ); - } - this.mediaRecorder.onstop = () => { - this.onStopDefault(); - return resolve(); - }; - this.mediaRecorder.stop(); - } catch (e) { - return reject(e); - } - }); - } - - /** - * Pauses the recording of the Stream. {@link state} property must be `RECORDING`. After method succeeds is set to `PAUSED` - * @returns A Promise (to which you can optionally subscribe to) that is resolved if the recording was successfully paused and rejected with an Error object if not - */ - pause(): Promise { - return new Promise((resolve, reject) => { - try { - if (this.state !== LocalRecorderState.RECORDING) { - return reject( - Error( - "'LocalRecord.pause()' needs 'LocalRecord.state' to be 'RECORDING' (current value: '" + - this.state + - "'). Call 'LocalRecorder.start()' or 'LocalRecorder.resume()' before" - ) - ); - } - this.mediaRecorder.pause(); - this.state = LocalRecorderState.PAUSED; - return resolve(); - } catch (error) { - return reject(error); - } - }); - } - - /** - * Resumes the recording of the Stream. {@link state} property must be `PAUSED`. After method succeeds is set to `RECORDING` - * @returns A Promise (to which you can optionally subscribe to) that is resolved if the recording was successfully resumed and rejected with an Error object if not - */ - resume(): Promise { - return new Promise((resolve, reject) => { - try { - if (this.state !== LocalRecorderState.PAUSED) { - throw Error( - "'LocalRecord.resume()' needs 'LocalRecord.state' to be 'PAUSED' (current value: '" + - this.state + - "'). Call 'LocalRecorder.pause()' before" - ); - } - this.mediaRecorder.resume(); - this.state = LocalRecorderState.RECORDING; - return resolve(); - } catch (error) { - return reject(error); - } - }); - } - - /** - * Previews the recording, appending a new HTMLVideoElement to element with id `parentId`. {@link state} property must be `FINISHED` - */ - preview(parentElement): HTMLVideoElement { - if (this.state !== LocalRecorderState.FINISHED) { - throw Error( - "'LocalRecord.preview()' needs 'LocalRecord.state' to be 'FINISHED' (current value: '" + - this.state + - "'). Call 'LocalRecorder.stop()' before" - ); - } - - this.videoPreview = document.createElement('video'); - - this.videoPreview.id = this.id; - this.videoPreview.autoplay = true; - - if (platform.isSafariBrowser()) { - this.videoPreview.playsInline = true; - } - - if (typeof parentElement === 'string') { - const parentElementDom = document.getElementById(parentElement); - if (parentElementDom) { - this.videoPreview = parentElementDom.appendChild(this.videoPreview); - } - } else { - this.videoPreview = parentElement.appendChild(this.videoPreview); - } - - this.videoPreview.src = this.videoPreviewSrc; - - return this.videoPreview; - } - - /** - * Gracefully stops and cleans the current recording (WARNING: it is completely dismissed). Sets {@link state} to `READY` so the recording can start again - */ - clean(): void { - const f = () => { - delete this.blob; - this.chunks = []; - this.state = LocalRecorderState.READY; - }; - if (this.state === LocalRecorderState.RECORDING || this.state === LocalRecorderState.PAUSED) { - this.stop() - .then(() => f()) - .catch(() => f()); - } else { - f(); - } - } - - /** - * Downloads the recorded video through the browser. {@link state} property must be `FINISHED` - */ - download(): void { - if (this.state !== LocalRecorderState.FINISHED) { - throw Error( - "'LocalRecord.download()' needs 'LocalRecord.state' to be 'FINISHED' (current value: '" + - this.state + - "'). Call 'LocalRecorder.stop()' before" - ); - } else { - const a: HTMLAnchorElement = document.createElement('a'); - a.style.display = 'none'; - document.body.appendChild(a); - - const url = globalThis.URL.createObjectURL(this.blob); - a.href = url; - a.download = this.id + '.' + Mime.getExtension(this.blob!.type); - a.click(); - globalThis.URL.revokeObjectURL(url); - - document.body.removeChild(a); - } - } - - /** - * Gets the raw Blob file. Methods preview, download, uploadAsBinary and uploadAsMultipartfile use this same file to perform their specific actions. {@link state} property must be `FINISHED` - */ - getBlob(): Blob { - if (this.state !== LocalRecorderState.FINISHED) { - throw Error("Call 'LocalRecord.stop()' before getting Blob file"); - } else { - return this.blob!; - } - } - - /** - * Uploads the recorded video as a binary file performing an HTTP/POST operation to URL `endpoint`. {@link state} property must be `FINISHED`. Optional HTTP headers can be passed as second parameter. For example: - * ``` - * var headers = { - * "Cookie": "$Version=1; Skin=new;", - * "Authorization":"Basic QWxhZGpbjpuIHNlctZQ==" - * } - * ``` - * @returns A Promise (to which you can optionally subscribe to) that is resolved with the `http.responseText` from server if the operation was successful and rejected with the failed `http.status` if not - */ - uploadAsBinary(endpoint: string, headers?: any): Promise { - return new Promise((resolve, reject) => { - if (this.state !== LocalRecorderState.FINISHED) { - return reject( - Error( - "'LocalRecord.uploadAsBinary()' needs 'LocalRecord.state' to be 'FINISHED' (current value: '" + - this.state + - "'). Call 'LocalRecorder.stop()' before" - ) - ); - } else { - const http = new XMLHttpRequest(); - http.open('POST', endpoint, true); - - if (typeof headers === 'object') { - for (const key of Object.keys(headers)) { - http.setRequestHeader(key, headers[key]); - } - } - - http.onreadystatechange = () => { - if (http.readyState === 4) { - if (http.status.toString().charAt(0) === '2') { - // Success response from server (HTTP status standard: 2XX is success) - return resolve(http.responseText); - } else { - return reject(http.status); - } - } - }; - http.send(this.blob); - } - }); - } - - /** - * Uploads the recorded video as a multipart file performing an HTTP/POST operation to URL `endpoint`. {@link state} property must be `FINISHED`. Optional HTTP headers can be passed as second parameter. For example: - * ``` - * var headers = { - * "Cookie": "$Version=1; Skin=new;", - * "Authorization":"Basic QWxhZGpbjpuIHNlctZQ==" - * } - * ``` - * @returns A Promise (to which you can optionally subscribe to) that is resolved with the `http.responseText` from server if the operation was successful and rejected with the failed `http.status` if not: - */ - uploadAsMultipartfile(endpoint: string, headers?: any): Promise { - return new Promise((resolve, reject) => { - if (this.state !== LocalRecorderState.FINISHED) { - return reject( - Error( - "'LocalRecord.uploadAsMultipartfile()' needs 'LocalRecord.state' to be 'FINISHED' (current value: '" + - this.state + - "'). Call 'LocalRecorder.stop()' before" - ) - ); - } else { - const http = new XMLHttpRequest(); - http.open('POST', endpoint, true); - - if (typeof headers === 'object') { - for (const key of Object.keys(headers)) { - http.setRequestHeader(key, headers[key]); - } - } - - const sendable = new FormData(); - sendable.append('file', this.blob!, this.id + '.' + Mime.getExtension(this.blob!.type)); - - http.onreadystatechange = () => { - if (http.readyState === 4) { - if (http.status.toString().charAt(0) === '2') { - // Success response from server (HTTP status standard: 2XX is success) - return resolve(http.responseText); - } else { - return reject(http.status); - } - } - }; - - http.send(sendable); - } - }); - } - - /* Private methods */ - - private onStopDefault(): void { - logger.log('MediaRecorder stopped (state=' + this.mediaRecorder.state + ')'); - - this.blob = new Blob(this.chunks, { type: this.mediaRecorder.mimeType }); - this.chunks = []; - - this.videoPreviewSrc = globalThis.URL.createObjectURL(this.blob); - - this.state = LocalRecorderState.FINISHED; - } -} diff --git a/openvidu-browser/src/OpenVidu/OpenVidu.ts b/openvidu-browser/src/OpenVidu/OpenVidu.ts deleted file mode 100644 index fa7f61916f..0000000000 --- a/openvidu-browser/src/OpenVidu/OpenVidu.ts +++ /dev/null @@ -1,1301 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { LocalRecorder } from './LocalRecorder'; -import { Publisher } from './Publisher'; -import { Session } from './Session'; -import { Stream } from './Stream'; -import { SessionDisconnectedEvent } from '../OpenViduInternal/Events/SessionDisconnectedEvent'; -import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPropertyChangedEvent'; -import { Device } from '../OpenViduInternal/Interfaces/Public/Device'; -import { OpenViduAdvancedConfiguration } from '../OpenViduInternal/Interfaces/Public/OpenViduAdvancedConfiguration'; -import { PublisherProperties } from '../OpenViduInternal/Interfaces/Public/PublisherProperties'; -import { CustomMediaStreamConstraints } from '../OpenViduInternal/Interfaces/Private/CustomMediaStreamConstraints'; -import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError'; -import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode'; -import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; -import { PlatformUtils } from '../OpenViduInternal/Utils/Platform'; -import { StreamPropertyChangedEventReason, ChangedPropertyType } from '../OpenViduInternal/Events/Types/Types'; - -import * as screenSharingAuto from '../OpenViduInternal/ScreenSharing/Screen-Capturing-Auto'; -import * as screenSharing from '../OpenViduInternal/ScreenSharing/Screen-Capturing'; -import { OpenViduLoggerConfiguration } from '../OpenViduInternal/Logger/OpenViduLoggerConfiguration'; -/** - * @hidden - */ -import EventEmitter = require('wolfy87-eventemitter'); -/** - * @hidden - */ -import RpcBuilder = require('../OpenViduInternal/KurentoUtils/kurento-jsonrpc'); - -/** - * @hidden - */ -const packageJson = require('../../package.json'); -/** - * @hidden - */ -declare var cordova: any; -/** - * @hidden - */ -const logger: OpenViduLogger = OpenViduLogger.getInstance(); - -/** - * @hidden - */ -let platform: PlatformUtils; - -/** - * Entrypoint of OpenVidu Browser library. - * Use it to initialize objects of type {@link Session}, {@link Publisher} and {@link LocalRecorder} - */ -export class OpenVidu { - private jsonRpcClient: any; - private masterNodeHasCrashed = false; - - /** - * @hidden - */ - session: Session; - /** - * @hidden - */ - publishers: Publisher[] = []; - /** - * @hidden - */ - wsUri: string; - /** - * @hidden - */ - httpUri: string; - /** - * @hidden - */ - secret = ''; - /** - * @hidden - */ - recorder = false; - /** - * @hidden - */ - stt = false; - /** - * @hidden - */ - iceServers: RTCIceServer[]; - /** - * @hidden - */ - role: string; - /** - * @hidden - */ - finalUserId: string; - /** - * @hidden - */ - mediaServer: string; - /** - * @hidden - */ - videoSimulcast: boolean; - /** - * @hidden - */ - life: number = -1; - /** - * @hidden - */ - advancedConfiguration: OpenViduAdvancedConfiguration = {}; - /** - * @hidden - */ - webrtcStatsInterval: number = -1; - /** - * @hidden - */ - sendBrowserLogs: OpenViduLoggerConfiguration = OpenViduLoggerConfiguration.disabled; - /** - * @hidden - */ - isAtLeastPro: boolean = false; - /** - * @hidden - */ - isEnterprise: boolean = false; - /** - * @hidden - */ - libraryVersion: string; - /** - * @hidden - */ - ee = new EventEmitter(); - - constructor() { - platform = PlatformUtils.getInstance(); - this.libraryVersion = packageJson.version; - logger.info('OpenVidu initialized'); - logger.info('Platform detected: ' + platform.getDescription()); - logger.info('openvidu-browser version: ' + this.libraryVersion); - - if (platform.isMobileDevice() || platform.isReactNative()) { - // Listen to orientationchange only on mobile devices - this.onOrientationChanged(() => { - this.publishers.forEach((publisher) => { - if (publisher.stream.isLocalStreamPublished && !!publisher.stream && !!publisher.stream.hasVideo) { - this.sendNewVideoDimensionsIfRequired(publisher, 'deviceRotated', 75, 10); - } - }); - }); - } - } - - /** - * Returns new session - */ - initSession(): Session { - this.session = new Session(this); - return this.session; - } - - initPublisher(targetElement: string | HTMLElement | undefined): Publisher; - initPublisher(targetElement: string | HTMLElement | undefined, properties: PublisherProperties): Publisher; - initPublisher(targetElement: string | HTMLElement | undefined, completionHandler: (error: Error | undefined) => void): Publisher; - initPublisher( - targetElement: string | HTMLElement | undefined, - properties: PublisherProperties, - completionHandler: (error: Error | undefined) => void - ): Publisher; - - /** - * Returns a new publisher - * - * #### Events dispatched - * - * The {@link Publisher} object will dispatch an `accessDialogOpened` event, only if the pop-up shown by the browser to request permissions for the camera is opened. You can use this event to alert the user about granting permissions - * for your website. An `accessDialogClosed` event will also be dispatched after user clicks on "Allow" or "Block" in the pop-up. - * - * The {@link Publisher} object will dispatch an `accessAllowed` or `accessDenied` event once it has been granted access to the requested input devices or not. - * - * The {@link Publisher} object will dispatch a `videoElementCreated` event once a HTML video element has been added to DOM (only if you - * [let OpenVidu take care of the video players](/en/stable/cheatsheet/manage-videos/#let-openvidu-take-care-of-the-video-players)). See {@link VideoElementEvent} to learn more. - * - * The {@link Publisher} object will dispatch a `streamPlaying` event once the local streams starts playing. See {@link StreamManagerEvent} to learn more. - * - * @param targetElement HTML DOM element (or its `id` attribute) in which the video element of the Publisher will be inserted (see {@link PublisherProperties.insertMode}). If *null* or *undefined* no default video will be created for this Publisher. - * You can always call method {@link Publisher.addVideoElement} or {@link Publisher.createVideoElement} to manage the video elements on your own (see [Manage video players](/en/stable/cheatsheet/manage-videos) section) - * @param completionHandler `error` parameter is null if `initPublisher` succeeds, and is defined if it fails. - * `completionHandler` function is called before the Publisher dispatches an `accessAllowed` or an `accessDenied` event - */ - initPublisher(targetElement: string | HTMLElement | undefined, param2?, param3?): Publisher { - let properties: PublisherProperties; - - if (!!param2 && typeof param2 !== 'function') { - // Matches 'initPublisher(targetElement, properties)' or 'initPublisher(targetElement, properties, completionHandler)' - - properties = param2; - - properties = { - audioSource: typeof properties.audioSource !== 'undefined' ? properties.audioSource : undefined, - frameRate: - typeof MediaStreamTrack !== 'undefined' && properties.videoSource instanceof MediaStreamTrack - ? undefined - : typeof properties.frameRate !== 'undefined' - ? properties.frameRate - : undefined, - insertMode: - typeof properties.insertMode !== 'undefined' - ? typeof properties.insertMode === 'string' - ? VideoInsertMode[properties.insertMode] - : properties.insertMode - : VideoInsertMode.APPEND, - mirror: typeof properties.mirror !== 'undefined' ? properties.mirror : true, - publishAudio: typeof properties.publishAudio !== 'undefined' ? properties.publishAudio : true, - publishVideo: typeof properties.publishVideo !== 'undefined' ? properties.publishVideo : true, - resolution: - typeof MediaStreamTrack !== 'undefined' && properties.videoSource instanceof MediaStreamTrack - ? undefined - : typeof properties.resolution !== 'undefined' - ? properties.resolution - : '640x480', - videoSource: typeof properties.videoSource !== 'undefined' ? properties.videoSource : undefined, - videoSimulcast: properties.videoSimulcast, - filter: properties.filter - }; - } else { - // Matches 'initPublisher(targetElement)' or 'initPublisher(targetElement, completionHandler)' - - properties = { - insertMode: VideoInsertMode.APPEND, - mirror: true, - publishAudio: true, - publishVideo: true, - resolution: '640x480' - }; - } - - const publisher: Publisher = new Publisher(targetElement, properties, this); - - let completionHandler: (error: Error | undefined) => void; - if (!!param2 && typeof param2 === 'function') { - completionHandler = param2; - } else if (!!param3) { - completionHandler = param3; - } - - publisher - .initialize() - .then(() => { - if (completionHandler !== undefined) { - completionHandler(undefined); - } - publisher.emitEvent('accessAllowed', []); - }) - .catch((error) => { - if (completionHandler !== undefined) { - completionHandler(error); - } - publisher.emitEvent('accessDenied', [error]); - }); - - this.publishers.push(publisher); - return publisher; - } - - /** - * Promisified version of {@link OpenVidu.initPublisher} - * - * > WARNING: events `accessDialogOpened` and `accessDialogClosed` will not be dispatched if using this method instead of {@link OpenVidu.initPublisher} - */ - initPublisherAsync(targetElement: string | HTMLElement | undefined): Promise; - initPublisherAsync(targetElement: string | HTMLElement | undefined, properties: PublisherProperties): Promise; - - initPublisherAsync(targetElement: string | HTMLElement | undefined, properties?: PublisherProperties): Promise { - return new Promise((resolve, reject) => { - let publisher: Publisher; - - const callback = (error: Error) => { - if (!!error) { - return reject(error); - } else { - return resolve(publisher); - } - }; - - if (!!properties) { - publisher = this.initPublisher(targetElement, properties, callback); - } else { - publisher = this.initPublisher(targetElement, callback); - } - }); - } - - /** - * Returns a new local recorder for recording streams straight away from the browser - * @param stream Stream to record - */ - initLocalRecorder(stream: Stream): LocalRecorder { - return new LocalRecorder(stream); - } - - /** - * Checks if the browser supports OpenVidu - * @returns 1 if the browser supports OpenVidu, 0 otherwise - */ - checkSystemRequirements(): boolean { - // Specific iOS platform support (iPhone, iPad) - if (platform.isIPhoneOrIPad()) { - return ( - platform.isIOSWithSafari() || - platform.isChromeMobileBrowser() || - platform.isFirefoxMobileBrowser() || - platform.isOperaMobileBrowser() || - platform.isEdgeMobileBrowser() || - platform.isIonicIos() // Ionic apps for iOS - ); - } - - // General platform support for web clients (Desktop, Mobile) - return ( - platform.isChromeBrowser() || - platform.isChromeMobileBrowser() || - platform.isFirefoxBrowser() || - platform.isFirefoxMobileBrowser() || - platform.isOperaBrowser() || - platform.isOperaMobileBrowser() || - platform.isEdgeBrowser() || - platform.isEdgeMobileBrowser() || - platform.isSamsungBrowser() || - platform.isSafariBrowser() || - platform.isAndroidBrowser() || // Android WebView & Ionic apps for Android - platform.isElectron() || - platform.isNodeJs() || - // TODO: remove when updating platform detection library - platform.isMotorolaEdgeDevice() - ); - } - - /** - * Checks if the browser supports screen-sharing. Desktop Chrome, Firefox and Opera support screen-sharing - * @returns 1 if the browser supports screen-sharing, 0 otherwise - */ - checkScreenSharingCapabilities(): boolean { - return platform.canScreenShare(); - } - - /** - * Collects information about the media input devices available on the system. You can pass property `deviceId` of a {@link Device} object as value of `audioSource` or `videoSource` properties in {@link initPublisher} method - */ - getDevices(): Promise { - return new Promise((resolve, reject) => { - navigator.mediaDevices - .enumerateDevices() - .then((deviceInfos) => { - const devices: Device[] = []; - - // Ionic Android devices - if (platform.isIonicAndroid() && typeof cordova != 'undefined' && cordova?.plugins?.EnumerateDevicesPlugin) { - cordova.plugins.EnumerateDevicesPlugin.getEnumerateDevices().then((pluginDevices: Device[]) => { - let pluginAudioDevices: Device[] = []; - let videoDevices: Device[] = []; - let audioDevices: Device[] = []; - pluginAudioDevices = pluginDevices.filter((device: Device) => device.kind === 'audioinput'); - videoDevices = deviceInfos.filter((device: MediaDeviceInfo) => device.kind === 'videoinput') as any; - audioDevices = deviceInfos.filter((device: MediaDeviceInfo) => device.kind === 'audioinput') as any; - videoDevices.forEach((deviceInfo, index) => { - if (!deviceInfo.label) { - let label = ''; - if (index === 0) { - label = 'Front Camera'; - } else if (index === 1) { - label = 'Back Camera'; - } else { - label = 'Unknown Camera'; - } - devices.push({ - kind: deviceInfo.kind, - deviceId: deviceInfo.deviceId, - label: label - }); - } else { - devices.push({ - kind: deviceInfo.kind, - deviceId: deviceInfo.deviceId, - label: deviceInfo.label - }); - } - }); - audioDevices.forEach((deviceInfo, index) => { - if (!deviceInfo.label) { - let label = ''; - switch (index) { - case 0: // Default Microphone - label = 'Default'; - break; - case 1: // Microphone + Speakerphone - const defaultMatch = pluginAudioDevices.filter((d) => d.label.includes('Built'))[0]; - label = defaultMatch ? defaultMatch.label : 'Built-in Microphone'; - break; - case 2: // Headset Microphone - const wiredMatch = pluginAudioDevices.filter((d) => d.label.includes('Wired'))[0]; - if (wiredMatch) { - label = wiredMatch.label; - } else { - label = 'Headset earpiece'; - } - break; - case 3: - const wirelessMatch = pluginAudioDevices.filter((d) => d.label.includes('Bluetooth'))[0]; - label = wirelessMatch ? wirelessMatch.label : 'Wireless'; - break; - default: - label = 'Unknown Microphone'; - break; - } - devices.push({ - kind: deviceInfo.kind, - deviceId: deviceInfo.deviceId, - label: label - }); - } else { - devices.push({ - kind: deviceInfo.kind, - deviceId: deviceInfo.deviceId, - label: deviceInfo.label - }); - } - }); - return resolve(devices); - }); - } else { - // Rest of platforms - deviceInfos.forEach((deviceInfo) => { - if (deviceInfo.kind === 'audioinput' || deviceInfo.kind === 'videoinput') { - devices.push({ - kind: deviceInfo.kind, - deviceId: deviceInfo.deviceId, - label: deviceInfo.label - }); - } - }); - return resolve(devices); - } - }) - .catch((error) => { - logger.error('Error getting devices', error); - return reject(error); - }); - }); - } - - /** - * Get a MediaStream object that you can customize before calling {@link initPublisher} (pass _MediaStreamTrack_ property of the _MediaStream_ value resolved by the Promise as `audioSource` or `videoSource` properties in {@link initPublisher}) - * - * Parameter `options` is the same as in {@link initPublisher} second parameter (of type {@link PublisherProperties}), but only the following properties will be applied: `audioSource`, `videoSource`, `frameRate`, `resolution` - * - * To customize the Publisher's video, the API for HTMLCanvasElement is very useful. For example, to get a black-and-white video at 10 fps and HD resolution with no sound: - * ``` - * var OV = new OpenVidu(); - * var FRAME_RATE = 10; - * - * OV.getUserMedia({ - * audioSource: false, - * videoSource: undefined, - * resolution: '1280x720', - * frameRate: FRAME_RATE - * }) - * .then(mediaStream => { - * - * var videoTrack = mediaStream.getVideoTracks()[0]; - * var video = document.createElement('video'); - * video.srcObject = new MediaStream([videoTrack]); - * - * var canvas = document.createElement('canvas'); - * var ctx = canvas.getContext('2d'); - * ctx.filter = 'grayscale(100%)'; - * - * video.addEventListener('play', () => { - * var loop = () => { - * if (!video.paused && !video.ended) { - * ctx.drawImage(video, 0, 0, 300, 170); - * setTimeout(loop, 1000/ FRAME_RATE); // Drawing at 10 fps - * } - * }; - * loop(); - * }); - * video.play(); - * - * var grayVideoTrack = canvas.captureStream(FRAME_RATE).getVideoTracks()[0]; - * var publisher = this.OV.initPublisher( - * myHtmlTarget, - * { - * audioSource: false, - * videoSource: grayVideoTrack - * }); - * }); - * ``` - */ - async getUserMedia(options: PublisherProperties): Promise { - const askForAudioStreamOnly = async (previousMediaStream: MediaStream, constraints: MediaStreamConstraints) => { - const definedAudioConstraint = constraints.audio === undefined ? true : constraints.audio; - const constraintsAux: MediaStreamConstraints = { audio: definedAudioConstraint, video: false }; - try { - const audioOnlyStream = await navigator.mediaDevices.getUserMedia(constraintsAux); - previousMediaStream.addTrack(audioOnlyStream.getAudioTracks()[0]); - return previousMediaStream; - } catch (error) { - previousMediaStream.getAudioTracks().forEach((track) => { - track.stop(); - }); - previousMediaStream.getVideoTracks().forEach((track) => { - track.stop(); - }); - throw this.generateAudioDeviceError(error, constraintsAux); - } - }; - - try { - const myConstraints = await this.generateMediaConstraints(options); - if ( - (!!myConstraints.videoTrack && !!myConstraints.audioTrack) || - (!!myConstraints.audioTrack && myConstraints.constraints?.video === false) || - (!!myConstraints.videoTrack && myConstraints.constraints?.audio === false) - ) { - // No need to call getUserMedia at all. Both tracks provided, or only AUDIO track provided or only VIDEO track provided - return this.addAlreadyProvidedTracks(myConstraints, new MediaStream()); - } else { - // getUserMedia must be called. AUDIO or VIDEO are requesting a new track - - // Delete already provided constraints for audio or video - if (!!myConstraints.videoTrack) { - delete myConstraints.constraints!.video; - } - if (!!myConstraints.audioTrack) { - delete myConstraints.constraints!.audio; - } - - let mustAskForAudioTrackLater = false; - if (typeof options.videoSource === 'string') { - // Video is deviceId or screen sharing - if ( - options.videoSource === 'screen' || - options.videoSource === 'window' || - (platform.isElectron() && options.videoSource.startsWith('screen:')) - ) { - // Video is screen sharing - mustAskForAudioTrackLater = - !myConstraints.audioTrack && options.audioSource !== null && options.audioSource !== false; - if (navigator.mediaDevices['getDisplayMedia'] && !platform.isElectron()) { - // getDisplayMedia supported - try { - const mediaStream = await navigator.mediaDevices['getDisplayMedia']({ video: true, audio: options.audioSource === 'screen' }); - this.addAlreadyProvidedTracks(myConstraints, mediaStream); - if (mustAskForAudioTrackLater) { - return await askForAudioStreamOnly(mediaStream, myConstraints.constraints); - } else { - return mediaStream; - } - } catch (error) { - let errorName: OpenViduErrorName = OpenViduErrorName.SCREEN_CAPTURE_DENIED; - const errorMessage = error.toString(); - throw new OpenViduError(errorName, errorMessage); - } - } else { - // getDisplayMedia NOT supported. Can perform getUserMedia below with already calculated constraints - } - } else { - // Video is deviceId. Can perform getUserMedia below with already calculated constraints - } - } - // Use already calculated constraints - const constraintsAux = mustAskForAudioTrackLater - ? { video: myConstraints.constraints!.video } - : myConstraints.constraints; - try { - const mediaStream = await navigator.mediaDevices.getUserMedia(constraintsAux); - this.addAlreadyProvidedTracks(myConstraints, mediaStream); - if (mustAskForAudioTrackLater) { - return await askForAudioStreamOnly(mediaStream, myConstraints.constraints); - } else { - return mediaStream; - } - } catch (error) { - let errorName: OpenViduErrorName; - const errorMessage = error.toString(); - if (!(options.videoSource === 'screen')) { - errorName = OpenViduErrorName.DEVICE_ACCESS_DENIED; - } else { - errorName = OpenViduErrorName.SCREEN_CAPTURE_DENIED; - } - throw new OpenViduError(errorName, errorMessage); - } - } - } catch (error) { - throw error; - } - } - - /* tslint:disable:no-empty */ - /** - * Disable all logging except error level - */ - enableProdMode(): void { - logger.enableProdMode(); - } - /* tslint:enable:no-empty */ - - /** - * Set OpenVidu advanced configuration options. `configuration` is an object of type {@link OpenViduAdvancedConfiguration}. Call this method to override previous values at any moment. - */ - setAdvancedConfiguration(configuration: OpenViduAdvancedConfiguration): void { - this.advancedConfiguration = configuration; - } - - /* Hidden methods */ - - /** - * @hidden - */ - onOrientationChanged(handler): void { - (globalThis as any).addEventListener('orientationchange', handler); - } - - /** - * @hidden - */ - sendNewVideoDimensionsIfRequired(publisher: Publisher, reason: StreamPropertyChangedEventReason, WAIT_INTERVAL: number, MAX_ATTEMPTS: number) { - let attempts = 0; - const oldWidth = publisher?.stream?.videoDimensions?.width || 0; - const oldHeight = publisher?.stream?.videoDimensions?.height || 0; - - const repeatUntilChangeOrMaxAttempts: NodeJS.Timeout = setInterval(() => { - attempts++; - if (attempts > MAX_ATTEMPTS) { - clearTimeout(repeatUntilChangeOrMaxAttempts); - } - publisher.getVideoDimensions().then((newDimensions) => { - if (newDimensions.width !== oldWidth || newDimensions.height !== oldHeight) { - clearTimeout(repeatUntilChangeOrMaxAttempts); - this.sendVideoDimensionsChangedEvent(publisher, reason, oldWidth, oldHeight, newDimensions.width, newDimensions.height); - } - }); - }, WAIT_INTERVAL); - } - - /** - * @hidden - */ - sendVideoDimensionsChangedEvent( - publisher: Publisher, - reason: StreamPropertyChangedEventReason, - oldWidth: number, - oldHeight: number, - newWidth: number, - newHeight: number - ) { - publisher.stream.videoDimensions = { - width: newWidth || 0, - height: newHeight || 0 - }; - this.sendRequest( - 'streamPropertyChanged', - { - streamId: publisher.stream.streamId, - property: 'videoDimensions', - newValue: JSON.stringify(publisher.stream.videoDimensions), - reason - }, - (error, response) => { - if (error) { - logger.error("Error sending 'streamPropertyChanged' event", error); - } else { - this.session.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent( - this.session, - publisher.stream, - 'videoDimensions', - publisher.stream.videoDimensions, - { width: oldWidth, height: oldHeight }, - reason - ) - ]); - publisher.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent( - publisher, - publisher.stream, - 'videoDimensions', - publisher.stream.videoDimensions, - { width: oldWidth, height: oldHeight }, - reason - ) - ]); - this.session.sendVideoData(publisher); - } - } - ); - } - - /** - * @hidden - */ - sendTrackChangedEvent(publisher: Publisher, oldLabel: string, newLabel: string, propertyType: ChangedPropertyType) { - const oldValue = { label: oldLabel }; - const newValue = { label: newLabel }; - const reason = 'trackReplaced'; - - if (publisher.stream.isLocalStreamPublished) { - this.sendRequest( - 'streamPropertyChanged', - { - streamId: publisher.stream.streamId, - property: propertyType, - newValue: newValue, - reason - }, - (error, response) => { - if (error) { - logger.error("Error sending 'streamPropertyChanged' event", error); - } else { - this.session.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent(this.session, publisher.stream, propertyType, newValue, oldValue, reason) - ]); - publisher.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent(publisher, publisher.stream, propertyType, newValue, oldValue, reason) - ]); - } - } - ); - } else { - this.session.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent(this.session, publisher.stream, propertyType, newValue, oldValue, reason) - ]); - publisher.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent(publisher, publisher.stream, propertyType, newValue, oldValue, reason) - ]); - } - } - - /** - * @hidden - */ - generateMediaConstraints(publisherProperties: PublisherProperties): Promise { - return new Promise((resolve, reject) => { - const myConstraints: CustomMediaStreamConstraints = { - audioTrack: undefined, - videoTrack: undefined, - constraints: { - audio: undefined, - video: undefined - } - }; - const audioSource = publisherProperties.audioSource; - const videoSource = publisherProperties.videoSource; - - // CASE 1: null/false - if (audioSource === null || audioSource === false) { - // No audio track - myConstraints.constraints!.audio = false; - } - if (videoSource === null || videoSource === false) { - // No video track - myConstraints.constraints!.video = false; - } - if (myConstraints.constraints!.audio === false && myConstraints.constraints!.video === false) { - // ERROR! audioSource and videoSource cannot be both false at the same time - return reject( - new OpenViduError( - OpenViduErrorName.NO_INPUT_SOURCE_SET, - "Properties 'audioSource' and 'videoSource' cannot be set to false or null at the same time" - ) - ); - } - - // CASE 2: MediaStreamTracks - if (typeof MediaStreamTrack !== 'undefined' && audioSource instanceof MediaStreamTrack) { - // Already provided audio track - myConstraints.audioTrack = audioSource; - } - if (typeof MediaStreamTrack !== 'undefined' && videoSource instanceof MediaStreamTrack) { - // Already provided video track - myConstraints.videoTrack = videoSource; - } - - // CASE 3: Default tracks - if (audioSource === undefined) { - myConstraints.constraints!.audio = true; - } - if (videoSource === undefined) { - myConstraints.constraints!.video = { - width: { - ideal: 640 - }, - height: { - ideal: 480 - } - }; - } - - // CASE 3.5: give values to resolution and frameRate if video not null/false - if (videoSource !== null && videoSource !== false) { - if (!!publisherProperties.resolution) { - const widthAndHeight = publisherProperties.resolution.toLowerCase().split('x'); - const idealWidth = Number(widthAndHeight[0]); - const idealHeight = Number(widthAndHeight[1]); - myConstraints.constraints!.video = { - width: { - ideal: idealWidth - }, - height: { - ideal: idealHeight - } - }; - } - if (!!publisherProperties.frameRate) { - (myConstraints.constraints!.video).frameRate = { ideal: publisherProperties.frameRate }; - } - } - - // CASE 4: deviceId or screen sharing - this.configureDeviceIdOrScreensharing(myConstraints, publisherProperties, resolve, reject); - - return resolve(myConstraints); - }); - } - - /** - * @hidden - */ - startWs(onConnectSucces: (error: Error) => void): void { - const config = { - heartbeat: 5000, - ws: { - uri: this.wsUri + '?sessionId=' + this.session.sessionId, - onconnected: onConnectSucces, - ondisconnect: this.disconnectCallback.bind(this), - onreconnecting: this.reconnectingCallback.bind(this), - onreconnected: this.reconnectedCallback.bind(this), - ismasternodecrashed: this.isMasterNodeCrashed.bind(this) - }, - rpc: { - requestTimeout: 10000, - heartbeatRequestTimeout: 5000, - participantJoined: this.session.onParticipantJoined.bind(this.session), - participantPublished: this.session.onParticipantPublished.bind(this.session), - participantUnpublished: this.session.onParticipantUnpublished.bind(this.session), - participantLeft: this.session.onParticipantLeft.bind(this.session), - participantEvicted: this.session.onParticipantEvicted.bind(this.session), - recordingStarted: this.session.onRecordingStarted.bind(this.session), - recordingStopped: this.session.onRecordingStopped.bind(this.session), - broadcastStarted: this.session.onBroadcastStarted.bind(this.session), - broadcastStopped: this.session.onBroadcastStopped.bind(this.session), - sendMessage: this.session.onNewMessage.bind(this.session), - streamPropertyChanged: this.session.onStreamPropertyChanged.bind(this.session), - connectionPropertyChanged: this.session.onConnectionPropertyChanged.bind(this.session), - networkQualityLevelChanged: this.session.onNetworkQualityLevelChangedChanged.bind(this.session), - filterEventDispatched: this.session.onFilterEventDispatched.bind(this.session), - iceCandidate: this.session.recvIceCandidate.bind(this.session), - mediaError: this.session.onMediaError.bind(this.session), - masterNodeCrashedNotification: this.onMasterNodeCrashedNotification.bind(this), - forciblyReconnectSubscriber: this.session.onForciblyReconnectSubscriber.bind(this.session), - speechToTextMessage: this.session.onSpeechToTextMessage.bind(this.session), - speechToTextDisconnected: this.session.onSpeechToTextDisconnected.bind(this.session) - } - }; - this.jsonRpcClient = new RpcBuilder.clients.JsonRpcClient(config); - } - - /** - * @hidden - */ - onMasterNodeCrashedNotification(response): void { - console.error('Master Node has crashed'); - this.masterNodeHasCrashed = true; - this.session.onLostConnection('nodeCrashed'); - this.jsonRpcClient.close(4103, 'Master Node has crashed'); - } - - /** - * @hidden - */ - getWsReadyState(): number { - return this.jsonRpcClient.getReadyState(); - } - - /** - * @hidden - */ - closeWs(): void { - this.jsonRpcClient.close(4102, 'Connection closed by client'); - } - - /** - * @hidden - */ - sendRequest(method: string, params: any, callback?): void { - if (params && params instanceof Function) { - callback = params; - params = {}; - } - logger.debug('Sending request: {method:"' + method + '", params: ' + JSON.stringify(params) + '}'); - this.jsonRpcClient?.send(method, params, callback); - } - - /** - * @hidden - */ - getWsUri(): string { - return this.wsUri; - } - - /** - * @hidden - */ - getSecret(): string { - return this.secret; - } - - /** - * @hidden - */ - getRecorder(): boolean { - return this.recorder; - } - - /** - * @hidden - */ - getStt(): boolean { - return this.stt; - } - - /** - * @hidden - */ - generateAudioDeviceError(error, constraints: MediaStreamConstraints): OpenViduError { - if (error.name === 'Error') { - // Safari OverConstrainedError has as name property 'Error' instead of 'OverConstrainedError' - error.name = error.constructor.name; - } - let errorName, errorMessage: string; - switch (error.name.toLowerCase()) { - case 'notfounderror': - errorName = OpenViduErrorName.INPUT_AUDIO_DEVICE_NOT_FOUND; - errorMessage = error.toString(); - return new OpenViduError(errorName, errorMessage); - case 'notallowederror': - errorName = OpenViduErrorName.DEVICE_ACCESS_DENIED; - errorMessage = error.toString(); - return new OpenViduError(errorName, errorMessage); - case 'overconstrainederror': - if (error.constraint.toLowerCase() === 'deviceid') { - errorName = OpenViduErrorName.INPUT_AUDIO_DEVICE_NOT_FOUND; - errorMessage = - "Audio input device with deviceId '" + - ((constraints.audio).deviceId!!).exact + - "' not found"; - } else { - errorName = OpenViduErrorName.PUBLISHER_PROPERTIES_ERROR; - errorMessage = "Audio input device doesn't support the value passed for constraint '" + error.constraint + "'"; - } - return new OpenViduError(errorName, errorMessage); - case 'notreadableerror': - errorName = OpenViduErrorName.DEVICE_ALREADY_IN_USE; - errorMessage = error.toString(); - return new OpenViduError(errorName, errorMessage); - default: - return new OpenViduError(OpenViduErrorName.INPUT_AUDIO_DEVICE_GENERIC_ERROR, error.toString()); - } - } - - /** - * @hidden - */ - addAlreadyProvidedTracks(myConstraints: CustomMediaStreamConstraints, mediaStream: MediaStream, stream?: Stream): MediaStream { - if (!!myConstraints.videoTrack) { - mediaStream.addTrack(myConstraints.videoTrack); - if (!!stream) { - if (!!myConstraints.constraints.video) { - stream.lastVideoTrackConstraints = myConstraints.constraints.video; - } else { - stream.lastVideoTrackConstraints = myConstraints.videoTrack.getConstraints(); - } - } - } - if (!!myConstraints.audioTrack) { - mediaStream.addTrack(myConstraints.audioTrack); - } - return mediaStream; - } - - /** - * @hidden - */ - protected configureDeviceIdOrScreensharing( - myConstraints: CustomMediaStreamConstraints, - publisherProperties: PublisherProperties, - resolve, - reject - ) { - const audioSource = publisherProperties.audioSource; - const videoSource = publisherProperties.videoSource; - if (typeof audioSource === 'string' && audioSource !== 'screen') { - myConstraints.constraints!.audio = { deviceId: { exact: audioSource } }; - } - - if (typeof videoSource === 'string') { - if (!this.isScreenShare(videoSource)) { - this.setVideoSource(myConstraints, videoSource); - if (audioSource === 'screen') { - logger.warn('Parameter "audioSource" is set to "screen", which means rquesting audio from screen sharing source. But "videoSource" is not set to "screen". No audio source will be requested'); - myConstraints.constraints!.audio = false; - } - } else { - // Screen sharing - - if (!this.checkScreenSharingCapabilities()) { - const error = new OpenViduError( - OpenViduErrorName.SCREEN_SHARING_NOT_SUPPORTED, - 'You can only screen share in desktop Chrome, Firefox, Opera, Safari (>=13.0), Edge (>= 80) or Electron. Detected client: ' + - platform.getName() + - ' ' + - platform.getVersion() - ); - logger.error(error); - return reject(error); - } else { - if (platform.isElectron()) { - const prefix = 'screen:'; - const videoSourceString: string = videoSource; - const electronScreenId = videoSourceString.substr(videoSourceString.indexOf(prefix) + prefix.length); - (myConstraints.constraints!.video) = { - mandatory: { - chromeMediaSource: 'desktop', - chromeMediaSourceId: electronScreenId - } - }; - return resolve(myConstraints); - } else { - if ( - !!this.advancedConfiguration.screenShareChromeExtension && - !(platform.isFirefoxBrowser() || platform.isFirefoxMobileBrowser()) && - !navigator.mediaDevices['getDisplayMedia'] - ) { - // Custom screen sharing extension for Chrome (and Opera) and no support for MediaDevices.getDisplayMedia() - - screenSharing.getScreenConstraints((error, screenConstraints) => { - if ( - !!error || - (!!screenConstraints.mandatory && screenConstraints.mandatory.chromeMediaSource === 'screen') - ) { - if (error === 'permission-denied' || error === 'PermissionDeniedError') { - const error = new OpenViduError( - OpenViduErrorName.SCREEN_CAPTURE_DENIED, - 'You must allow access to one window of your desktop' - ); - logger.error(error); - return reject(error); - } else { - const extensionId = this.advancedConfiguration - .screenShareChromeExtension!.split('/') - .pop()!! - .trim(); - screenSharing.getChromeExtensionStatus(extensionId, (status) => { - if (status === 'installed-disabled') { - const error = new OpenViduError( - OpenViduErrorName.SCREEN_EXTENSION_DISABLED, - 'You must enable the screen extension' - ); - logger.error(error); - return reject(error); - } - if (status === 'not-installed') { - const error = new OpenViduError( - OpenViduErrorName.SCREEN_EXTENSION_NOT_INSTALLED, - this.advancedConfiguration.screenShareChromeExtension - ); - logger.error(error); - return reject(error); - } - }); - return; - } - } else { - myConstraints.constraints!.video = screenConstraints; - return resolve(myConstraints); - } - }); - return; - } else { - if (navigator.mediaDevices['getDisplayMedia']) { - // getDisplayMedia support (Chrome >= 72, Firefox >= 66, Safari >= 13) - return resolve(myConstraints); - } else { - // Default screen sharing extension for Chrome/Opera, or is Firefox < 66 - const firefoxString = - platform.isFirefoxBrowser() || platform.isFirefoxMobileBrowser() - ? publisherProperties.videoSource - : undefined; - - screenSharingAuto.getScreenId(firefoxString, (error, sourceId, screenConstraints) => { - if (!!error) { - if (error === 'not-installed') { - const extensionUrl = !!this.advancedConfiguration.screenShareChromeExtension - ? this.advancedConfiguration.screenShareChromeExtension - : 'https://chrome.google.com/webstore/detail/openvidu-screensharing/lfcgfepafnobdloecchnfaclibenjold'; - const err = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_NOT_INSTALLED, extensionUrl); - logger.error(err); - return reject(err); - } else if (error === 'installed-disabled') { - const err = new OpenViduError( - OpenViduErrorName.SCREEN_EXTENSION_DISABLED, - 'You must enable the screen extension' - ); - logger.error(err); - return reject(err); - } else if (error === 'permission-denied') { - const err = new OpenViduError( - OpenViduErrorName.SCREEN_CAPTURE_DENIED, - 'You must allow access to one window of your desktop' - ); - logger.error(err); - return reject(err); - } else { - const err = new OpenViduError( - OpenViduErrorName.GENERIC_ERROR, - 'Unknown error when accessing screen share' - ); - logger.error(err); - logger.error(error); - return reject(err); - } - } else { - myConstraints.constraints!.video = screenConstraints.video; - return resolve(myConstraints); - } - }); - return; - } - } - } - } - } - } - } - - /** - * @hidden - */ - protected setVideoSource(myConstraints: CustomMediaStreamConstraints, videoSource: string) { - if (!myConstraints.constraints!.video) { - myConstraints.constraints!.video = {}; - } - (myConstraints.constraints!.video)['deviceId'] = { exact: videoSource }; - } - - /* Private methods */ - - private disconnectCallback(): void { - logger.warn('Websocket connection lost'); - if (this.isRoomAvailable()) { - this.session.onLostConnection('networkDisconnect'); - } else { - alert('Connection error. Please reload page.'); - } - } - - private reconnectingCallback(): void { - logger.warn('Websocket connection lost (reconnecting)'); - if (!this.isRoomAvailable()) { - alert('Connection error. Please reload page.'); - } else { - this.session.emitEvent('reconnecting', []); - } - } - - private reconnectWebsocketThroughRpcConnectMethod(rpcSessionId) { - // This RPC method allows checking: - // Single Master: if success, connection recovered - // if error, no Master Node crashed and life will be -1. onLostConnection with reason networkDisconnect will be triggered - // Multi Master: if success, connection recovered - // if error and Master Node crashed notification was already received, nothing must be done - // if error and Master Node NOT crashed, sessionStatus method must be sent: - // if life is equal, networkDisconnect - // if life is greater, nodeCrashed - this.sendRequest('connect', { sessionId: rpcSessionId, reconnect: true }, (error, response) => { - if (!!error) { - if (this.isMasterNodeCrashed()) { - logger.warn('Master Node has crashed!'); - } else { - logger.error(error); - - const notifyLostConnection = (reason, errorMsg) => { - logger.warn(errorMsg); - this.session.onLostConnection(reason); - this.jsonRpcClient.close(4101, 'Reconnection fault: ' + errorMsg); - }; - - const rpcSessionStatus = () => { - if (this.life === -1) { - // Single Master - notifyLostConnection( - 'networkDisconnect', - 'WS successfully reconnected but the user was already evicted due to timeout' - ); - } else { - // Multi Master - // This RPC method is only required to find out the reason of the disconnection: - // whether the client lost its network connection or a Master Node crashed - this.sendRequest('sessionStatus', { sessionId: this.session.sessionId }, (error, response) => { - if (error != null) { - console.error('Error checking session status', error); - } else { - if (this.life === response.life) { - // If the life stored in the client matches the life stored in the server, it means that the client lost its network connection - notifyLostConnection( - 'networkDisconnect', - 'WS successfully reconnected but the user was already evicted due to timeout' - ); - } else { - // If the life stored in the client is below the life stored in the server, it means that the Master Node has crashed - notifyLostConnection( - 'nodeCrashed', - 'WS successfully reconnected to OpenVidu Server but your Master Node crashed' - ); - } - } - }); - } - }; - - if (error.code === 40007 && error.message === 'reconnection error') { - // Kurento error: invalid RPC sessionId. This means that the kurento-jsonrpc-server of openvidu-server where kurento-jsonrpc-client - // is trying to reconnect does not know about this sessionId. This can mean two things: - // 1) openvidu-browser managed to reconnect after a while, but openvidu-server already evicted the user for not receiving ping. - // 2) openvidu-server process is a different one because of a node crash. - // Send a "sessionStatus" method to check the reason - console.error('Invalid RPC sessionId. Client network disconnection or Master Node crash'); - rpcSessionStatus(); - } else { - rpcSessionStatus(); - } - } - } else { - this.jsonRpcClient.resetPing(); - this.session.onRecoveredConnection(); - } - }); - } - - private reconnectedCallback(): void { - logger.warn('Websocket reconnected'); - if (this.isRoomAvailable()) { - if (!!this.session.connection) { - this.reconnectWebsocketThroughRpcConnectMethod(this.session.connection.rpcSessionId); - } else { - logger.warn('There was no previous connection when running reconnection callback'); - // Make Session object dispatch 'sessionDisconnected' event - const sessionDisconnectEvent = new SessionDisconnectedEvent(this.session, 'networkDisconnect'); - this.session.ee.emitEvent('sessionDisconnected', [sessionDisconnectEvent]); - sessionDisconnectEvent.callDefaultBehavior(); - } - } else { - alert('Connection error. Please reload page.'); - } - } - - private isMasterNodeCrashed() { - return this.masterNodeHasCrashed; - } - - private isRoomAvailable(): boolean { - if (this.session !== undefined && this.session instanceof Session) { - return true; - } else { - logger.warn('Session instance not found'); - return false; - } - } - - private isScreenShare(videoSource: string) { - return videoSource === 'screen' || videoSource === 'window' || (platform.isElectron() && videoSource.startsWith('screen:')); - } -} diff --git a/openvidu-browser/src/OpenVidu/Publisher.ts b/openvidu-browser/src/OpenVidu/Publisher.ts deleted file mode 100644 index 4b67490437..0000000000 --- a/openvidu-browser/src/OpenVidu/Publisher.ts +++ /dev/null @@ -1,875 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { OpenVidu } from './OpenVidu'; -import { Session } from './Session'; -import { Stream } from './Stream'; -import { StreamManager } from './StreamManager'; -import { PublisherProperties } from '../OpenViduInternal/Interfaces/Public/PublisherProperties'; -import { PublisherEventMap } from '../OpenViduInternal/Events/EventMap/PublisherEventMap'; -import { StreamEvent } from '../OpenViduInternal/Events/StreamEvent'; -import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPropertyChangedEvent'; -import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError'; -import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode'; -import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; -import { PlatformUtils } from '../OpenViduInternal/Utils/Platform'; -import { TypeOfVideo } from '../OpenViduInternal/Enums/TypeOfVideo'; -import { StreamEventReason } from '../OpenViduInternal/Events/Types/Types'; - -/** - * @hidden - */ -const logger: OpenViduLogger = OpenViduLogger.getInstance(); - -/** - * @hidden - */ -let platform: PlatformUtils; - -/** - * Packs local media streams. Participants can publish it to a session. Initialized with {@link OpenVidu.initPublisher} method. - * - * See available event listeners at {@link PublisherEventMap}. - */ -export class Publisher extends StreamManager { - /** - * Whether the Publisher has been granted access to the requested input devices or not - */ - accessAllowed = false; - - /** - * Whether you have called {@link Publisher.subscribeToRemote} with value `true` or `false` (*false* by default) - */ - isSubscribedToRemote = false; - - /** - * The {@link Session} to which the Publisher belongs - */ - session: Session; // Initialized by Session.publish(Publisher) - - private accessDenied = false; - protected properties: PublisherProperties; - private permissionDialogTimeout: NodeJS.Timer; - - /** - * @hidden - */ - openvidu: OpenVidu; - /** - * @hidden - */ - videoReference: HTMLVideoElement; - /** - * @hidden - */ - screenShareResizeInterval: NodeJS.Timer; - - /** - * @hidden - */ - constructor(targEl: string | HTMLElement | undefined, properties: PublisherProperties, openvidu: OpenVidu) { - super( - new Stream(!!openvidu.session ? openvidu.session : new Session(openvidu), { - publisherProperties: properties, - mediaConstraints: {} - }), - targEl - ); - platform = PlatformUtils.getInstance(); - this.properties = properties; - this.openvidu = openvidu; - - this.stream.ee.on('local-stream-destroyed', (reason: StreamEventReason) => { - this.stream.isLocalStreamPublished = false; - const streamEvent = new StreamEvent(true, this, 'streamDestroyed', this.stream, reason); - this.emitEvent('streamDestroyed', [streamEvent]); - streamEvent.callDefaultBehavior(); - }); - } - - /** - * Publish or unpublish the audio stream (if available). Calling this method twice in a row passing same `enabled` value will have no effect - * - * #### Events dispatched - * - * > _Only if `Session.publish(Publisher)` has been called for this Publisher_ - * - * The {@link Session} object of the local participant will dispatch a `streamPropertyChanged` event with `changedProperty` set to `"audioActive"` and `reason` set to `"publishAudio"` - * The {@link Publisher} object of the local participant will also dispatch the exact same event - * - * The {@link Session} object of every other participant connected to the session will dispatch a `streamPropertyChanged` event with `changedProperty` set to `"audioActive"` and `reason` set to `"publishAudio"` - * The respective {@link Subscriber} object of every other participant receiving this Publisher's stream will also dispatch the exact same event - * - * See {@link StreamPropertyChangedEvent} to learn more. - * - * @param enabled `true` to publish the audio stream, `false` to unpublish it - */ - publishAudio(enabled: boolean): void { - if (this.stream.audioActive !== enabled) { - const affectedMediaStream: MediaStream = this.stream.displayMyRemote() - ? this.stream.localMediaStreamWhenSubscribedToRemote! - : this.stream.getMediaStream(); - affectedMediaStream.getAudioTracks().forEach((track) => { - track.enabled = enabled; - }); - if (!!this.session && !!this.stream.streamId) { - this.session.openvidu.sendRequest( - 'streamPropertyChanged', - { - streamId: this.stream.streamId, - property: 'audioActive', - newValue: enabled, - reason: 'publishAudio' - }, - (error, response) => { - if (error) { - logger.error("Error sending 'streamPropertyChanged' event", error); - } else { - this.session.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent(this.session, this.stream, 'audioActive', enabled, !enabled, 'publishAudio') - ]); - this.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent(this, this.stream, 'audioActive', enabled, !enabled, 'publishAudio') - ]); - this.session.sendVideoData(this.stream.streamManager); - } - } - ); - } - this.stream.audioActive = enabled; - logger.info("'Publisher' has " + (enabled ? 'published' : 'unpublished') + ' its audio stream'); - } - } - - /** - * Publish or unpublish the video stream (if available). Calling this method twice in a row passing same `enabled` value will have no effect - * - * #### Events dispatched - * - * > _Only if `Session.publish(Publisher)` has been called for this Publisher_ - * - * The {@link Session} object of the local participant will dispatch a `streamPropertyChanged` event with `changedProperty` set to `"videoActive"` and `reason` set to `"publishVideo"` - * The {@link Publisher} object of the local participant will also dispatch the exact same event - * - * The {@link Session} object of every other participant connected to the session will dispatch a `streamPropertyChanged` event with `changedProperty` set to `"videoActive"` and `reason` set to `"publishVideo"` - * The respective {@link Subscriber} object of every other participant receiving this Publisher's stream will also dispatch the exact same event - * - * See {@link StreamPropertyChangedEvent} to learn more. - * - * @param enabled `true` to publish the video stream, `false` to unpublish it - * @param resource - * - * If parameter **`enabled`** is `false`, this optional parameter is of type boolean. It can be set to `true` to forcibly free the hardware resource associated to the video track, or can be set to `false` to keep the access to the hardware resource. - * Not freeing the resource makes the operation much more efficient, but depending on the platform two side-effects can be introduced: the video device may not be accessible by other applications and the access light of - * webcams may remain on. This is platform-dependent: some browsers will not present the side-effects even when not freeing the resource. - * - * If parameter **`enabled`** is `true`, this optional parameter is of type [MediaStreamTrack](https://developer.mozilla.org/docs/Web/API/MediaStreamTrack). It can be set to force the restoration of the video track with a custom track. This may be - * useful if the Publisher was unpublished freeing the hardware resource, and openvidu-browser is not able to successfully re-create the video track as it was before unpublishing. In this way previous track settings will be ignored and this MediaStreamTrack - * will be used instead. - */ - publishVideo(enabled: T, resource?: T extends false ? boolean : MediaStreamTrack): Promise { - return new Promise(async (resolve, reject) => { - if (this.stream.videoActive !== enabled) { - const affectedMediaStream: MediaStream = this.stream.displayMyRemote() - ? this.stream.localMediaStreamWhenSubscribedToRemote! - : this.stream.getMediaStream(); - let mustRestartMediaStream = false; - affectedMediaStream.getVideoTracks().forEach((track) => { - track.enabled = enabled; - if (!enabled && resource === true) { - track.stop(); - } else if (enabled && track.readyState === 'ended') { - // Resource was freed - mustRestartMediaStream = true; - } - }); - - // There is a Virtual Background filter applied that must be removed in case the hardware must be freed - if (!enabled && resource === true && !!this.stream.filter && this.stream.filter.type.startsWith('VB:')) { - this.stream.lastVBFilter = this.stream.filter; // Save the filter to be re-applied in case of unmute - await this.stream.removeFilterAux(true); - } - - if (mustRestartMediaStream) { - const oldVideoTrack = affectedMediaStream.getVideoTracks()[0]; - affectedMediaStream.removeTrack(oldVideoTrack); - - const replaceVideoTrack = async (tr: MediaStreamTrack) => { - affectedMediaStream.addTrack(tr); - if (this.stream.isLocalStreamPublished) { - await this.replaceTrackInRtcRtpSender(tr); - } - if (!!this.stream.lastVBFilter) { - setTimeout(async () => { - let options = this.stream.lastVBFilter!.options; - const lastExecMethod = this.stream.lastVBFilter!.lastExecMethod; - if (!!lastExecMethod && lastExecMethod.method === 'update') { - options = Object.assign({}, options, lastExecMethod.params); - } - await this.stream.applyFilter(this.stream.lastVBFilter!.type, options); - delete this.stream.lastVBFilter; - }, 1); - } - }; - - if (!!resource && resource instanceof MediaStreamTrack) { - await replaceVideoTrack(resource); - } else { - try { - const mediaStream = await navigator.mediaDevices.getUserMedia({ - audio: false, - video: this.stream.lastVideoTrackConstraints - }); - await replaceVideoTrack(mediaStream.getVideoTracks()[0]); - } catch (error) { - return reject(error); - } - } - } - - if (!!this.session && !!this.stream.streamId) { - this.session.openvidu.sendRequest( - 'streamPropertyChanged', - { - streamId: this.stream.streamId, - property: 'videoActive', - newValue: enabled, - reason: 'publishVideo' - }, - (error, response) => { - if (error) { - logger.error("Error sending 'streamPropertyChanged' event", error); - } else { - this.session.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent( - this.session, - this.stream, - 'videoActive', - enabled, - !enabled, - 'publishVideo' - ) - ]); - this.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent(this, this.stream, 'videoActive', enabled, !enabled, 'publishVideo') - ]); - this.session.sendVideoData(this.stream.streamManager); - } - } - ); - } - this.stream.videoActive = enabled; - logger.info("'Publisher' has " + (enabled ? 'published' : 'unpublished') + ' its video stream'); - return resolve(); - } - }); - } - - /** - * Call this method before {@link Session.publish} if you prefer to subscribe to your Publisher's remote stream instead of using the local stream, as any other user would do. - */ - subscribeToRemote(value?: boolean): void { - value = value !== undefined ? value : true; - this.isSubscribedToRemote = value; - this.stream.subscribeToMyRemote(value); - } - - /** - * See {@link EventDispatcher.on} - */ - on(type: K, handler: (event: PublisherEventMap[K]) => void): this { - super.on(type, handler); - - if (type === 'streamCreated') { - if (!!this.stream && this.stream.isLocalStreamPublished) { - this.emitEvent('streamCreated', [new StreamEvent(false, this, 'streamCreated', this.stream, '')]); - } else { - this.stream.ee.on('stream-created-by-publisher', () => { - this.emitEvent('streamCreated', [new StreamEvent(false, this, 'streamCreated', this.stream, '')]); - }); - } - } - if (type === 'accessAllowed') { - if (this.accessAllowed) { - this.emitEvent('accessAllowed', []); - } - } - if (type === 'accessDenied') { - if (this.accessDenied) { - this.emitEvent('accessDenied', []); - } - } - return this; - } - - /** - * See {@link EventDispatcher.once} - */ - once(type: K, handler: (event: PublisherEventMap[K]) => void): this { - super.once(type, handler); - - if (type === 'streamCreated') { - if (!!this.stream && this.stream.isLocalStreamPublished) { - this.emitEvent('streamCreated', [new StreamEvent(false, this, 'streamCreated', this.stream, '')]); - } else { - this.stream.ee.once('stream-created-by-publisher', () => { - this.emitEvent('streamCreated', [new StreamEvent(false, this, 'streamCreated', this.stream, '')]); - }); - } - } - if (type === 'accessAllowed') { - if (this.accessAllowed) { - this.emitEvent('accessAllowed', []); - } - } - if (type === 'accessDenied') { - if (this.accessDenied) { - this.emitEvent('accessDenied', []); - } - } - return this; - } - - /** - * See {@link EventDispatcher.off} - */ - off(type: K, handler?: (event: PublisherEventMap[K]) => void): this { - super.off(type, handler); - return this; - } - - /** - * Replaces the current video or audio track with a different one. This allows you to replace an ongoing track with a different one - * without having to renegotiate the whole WebRTC connection (that is, initializing a new Publisher, unpublishing the previous one - * and publishing the new one). - * - * You can get this new MediaStreamTrack by using the native Web API or simply with {@link OpenVidu.getUserMedia} method. - * - * **WARNING: this method has been proven to work in the majority of cases, but there may be some combinations of published/replaced tracks that may be incompatible - * between them and break the connection in OpenVidu Server. A complete renegotiation may be the only solution in this case. - * Visit [RTCRtpSender.replaceTrack](https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpSender/replaceTrack) documentation for further details.** - * - * @param track The [MediaStreamTrack](https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack) object to replace the current one. - * If it is an audio track, the current audio track will be the replaced one. If it is a video track, the current video track will be the replaced one. - * - * @returns A Promise (to which you can optionally subscribe to) that is resolved if the track was successfully replaced and rejected with an Error object in other case - */ - async replaceTrack(track: MediaStreamTrack): Promise { - return this.replaceTrackAux(track, true); - } - - /* Hidden methods */ - - /** - * @hidden - */ - initialize(): Promise { - return new Promise(async (resolve, reject) => { - let constraints: MediaStreamConstraints = {}; - let constraintsAux: MediaStreamConstraints = {}; - const timeForDialogEvent = 2000; - let startTime; - - const errorCallback = (openViduError: OpenViduError) => { - this.accessDenied = true; - this.accessAllowed = false; - logger.error(`Publisher initialization failed. ${openViduError.name}: ${openViduError.message}`); - return reject(openViduError); - }; - - const successCallback = (mediaStream: MediaStream) => { - this.accessAllowed = true; - this.accessDenied = false; - - if (typeof MediaStreamTrack !== 'undefined' && this.properties.audioSource instanceof MediaStreamTrack) { - mediaStream.removeTrack(mediaStream.getAudioTracks()[0]); - mediaStream.addTrack(this.properties.audioSource); - } - - if (typeof MediaStreamTrack !== 'undefined' && this.properties.videoSource instanceof MediaStreamTrack) { - mediaStream.removeTrack(mediaStream.getVideoTracks()[0]); - mediaStream.addTrack(this.properties.videoSource); - } - - // Apply PublisherProperties.publishAudio and PublisherProperties.publishVideo - if (!!mediaStream.getAudioTracks()[0]) { - const enabled = - this.stream.audioActive !== undefined && this.stream.audioActive !== null - ? this.stream.audioActive - : !!this.stream.outboundStreamOpts.publisherProperties.publishAudio; - mediaStream.getAudioTracks()[0].enabled = enabled; - } - if (!!mediaStream.getVideoTracks()[0]) { - const enabled = - this.stream.videoActive !== undefined && this.stream.videoActive !== null - ? this.stream.videoActive - : !!this.stream.outboundStreamOpts.publisherProperties.publishVideo; - mediaStream.getVideoTracks()[0].enabled = enabled; - } - - // Set Content Hint on all MediaStreamTracks - for (const track of mediaStream.getAudioTracks()) { - if (!track.contentHint?.length) { - // contentHint for audio: "", "speech", "speech-recognition", "music". - // https://w3c.github.io/mst-content-hint/#audio-content-hints - track.contentHint = ''; - logger.info(`Audio track Content Hint set: '${track.contentHint}'`); - } - } - for (const track of mediaStream.getVideoTracks()) { - if (!track.contentHint?.length) { - // contentHint for video: "", "motion", "detail", "text". - // https://w3c.github.io/mst-content-hint/#video-content-hints - switch (this.stream.typeOfVideo) { - case TypeOfVideo.SCREEN: - track.contentHint = 'detail'; - break; - case TypeOfVideo.CUSTOM: - logger.warn('CUSTOM type video track was provided without Content Hint!'); - track.contentHint = 'motion'; - break; - case TypeOfVideo.CAMERA: - case TypeOfVideo.IPCAM: - default: - track.contentHint = 'motion'; - break; - } - logger.info(`Video track Content Hint set: '${track.contentHint}'`); - } - } - - this.initializeVideoReference(mediaStream); - - if (!this.stream.displayMyRemote()) { - // When we are subscribed to our remote we don't still set the MediaStream object in the video elements to - // avoid early 'streamPlaying' event - this.stream.updateMediaStreamInVideos(); - } - delete this.firstVideoElement; - - if (this.stream.isSendVideo()) { - // Has video track - this.getVideoDimensions().then((dimensions) => { - this.stream.videoDimensions = { - width: dimensions.width, - height: dimensions.height - }; - - if (this.stream.isSendScreen()) { - - if(this.stream.isSendAudio() && mediaStream.getAudioTracks().length === 0){ - // If sending audio is enabled and there are no audio tracks in the mediaStream, disable audio for screen sharing. - this.stream.audioActive = false; - this.stream.hasAudio = false; - this.stream.outboundStreamOpts.publisherProperties.publishAudio = false; - this.stream.outboundStreamOpts.publisherProperties.audioSource = false; - } - - // Set interval to listen for screen resize events - this.screenShareResizeInterval = setInterval(() => { - const settings: MediaTrackSettings = mediaStream.getVideoTracks()[0].getSettings(); - const newWidth = settings.width; - const newHeight = settings.height; - const widthChanged = newWidth != null && newWidth !== this.stream.videoDimensions.width; - const heightChanged = newHeight != null && newHeight !== this.stream.videoDimensions.height; - if (this.stream.isLocalStreamPublished && (widthChanged || heightChanged)) { - this.openvidu.sendVideoDimensionsChangedEvent( - this, - 'screenResized', - this.stream.videoDimensions.width, - this.stream.videoDimensions.height, - newWidth || 0, - newHeight || 0 - ); - } - }, 650); - } - - this.stream.isLocalStreamReadyToPublish = true; - this.stream.ee.emitEvent('stream-ready-to-publish', []); - }); - } else { - // Only audio track (no videoDimensions) - this.stream.isLocalStreamReadyToPublish = true; - this.stream.ee.emitEvent('stream-ready-to-publish', []); - } - - return resolve(); - }; - - const getMediaSuccess = async (mediaStream: MediaStream, definedAudioConstraint) => { - this.clearPermissionDialogTimer(startTime, timeForDialogEvent); - if (this.stream.isSendScreen() && this.properties.audioSource !== 'screen' && this.stream.isSendAudio()) { - // When getting desktop as user media audio constraint must be false. Now we can ask for it if required - constraintsAux.audio = definedAudioConstraint; - constraintsAux.video = false; - startTime = Date.now(); - this.setPermissionDialogTimer(timeForDialogEvent); - - try { - const audioOnlyStream = await navigator.mediaDevices.getUserMedia(constraintsAux); - this.clearPermissionDialogTimer(startTime, timeForDialogEvent); - mediaStream.addTrack(audioOnlyStream.getAudioTracks()[0]); - successCallback(mediaStream); - } catch (error) { - this.clearPermissionDialogTimer(startTime, timeForDialogEvent); - mediaStream.getAudioTracks().forEach((track) => { - track.stop(); - }); - mediaStream.getVideoTracks().forEach((track) => { - track.stop(); - }); - errorCallback(this.openvidu.generateAudioDeviceError(error, constraints)); - return; - } - } else { - successCallback(mediaStream); - } - }; - - const getMediaError = async (error) => { - logger.error(`getMediaError: ${error.toString()}`); - this.clearPermissionDialogTimer(startTime, timeForDialogEvent); - if (error.name === 'Error') { - // Safari OverConstrainedError has as name property 'Error' instead of 'OverConstrainedError' - error.name = error.constructor.name; - } - let errorName, errorMessage; - switch (error.name.toLowerCase()) { - case 'notfounderror': - try { - const mediaStream = await navigator.mediaDevices.getUserMedia({ - audio: false, - video: constraints.video - }); - mediaStream.getVideoTracks().forEach((track) => { - track.stop(); - }); - errorName = OpenViduErrorName.INPUT_AUDIO_DEVICE_NOT_FOUND; - errorMessage = error.toString(); - errorCallback(new OpenViduError(errorName, errorMessage)); - } catch (error) { - errorName = OpenViduErrorName.INPUT_VIDEO_DEVICE_NOT_FOUND; - errorMessage = error.toString(); - errorCallback(new OpenViduError(errorName, errorMessage)); - } - - break; - case 'notallowederror': - errorName = this.stream.isSendScreen() - ? OpenViduErrorName.SCREEN_CAPTURE_DENIED - : OpenViduErrorName.DEVICE_ACCESS_DENIED; - errorMessage = error.toString(); - errorCallback(new OpenViduError(errorName, errorMessage)); - break; - case 'overconstrainederror': - try { - const mediaStream = await navigator.mediaDevices.getUserMedia({ - audio: false, - video: constraints.video - }); - mediaStream.getVideoTracks().forEach((track) => { - track.stop(); - }); - if (error.constraint.toLowerCase() === 'deviceid') { - errorName = OpenViduErrorName.INPUT_AUDIO_DEVICE_NOT_FOUND; - errorMessage = - "Audio input device with deviceId '" + - ((constraints.audio).deviceId!!).exact + - "' not found"; - } else { - errorName = OpenViduErrorName.PUBLISHER_PROPERTIES_ERROR; - errorMessage = - "Audio input device doesn't support the value passed for constraint '" + error.constraint + "'"; - } - errorCallback(new OpenViduError(errorName, errorMessage)); - } catch (error) { - if (error.constraint.toLowerCase() === 'deviceid') { - errorName = OpenViduErrorName.INPUT_VIDEO_DEVICE_NOT_FOUND; - errorMessage = - "Video input device with deviceId '" + - ((constraints.video).deviceId!!).exact + - "' not found"; - } else { - errorName = OpenViduErrorName.PUBLISHER_PROPERTIES_ERROR; - errorMessage = - "Video input device doesn't support the value passed for constraint '" + error.constraint + "'"; - } - errorCallback(new OpenViduError(errorName, errorMessage)); - } - - break; - case 'aborterror': - case 'notreadableerror': - errorName = OpenViduErrorName.DEVICE_ALREADY_IN_USE; - errorMessage = error.toString(); - errorCallback(new OpenViduError(errorName, errorMessage)); - break; - default: - errorName = OpenViduErrorName.GENERIC_ERROR; - errorMessage = error.toString(); - errorCallback(new OpenViduError(errorName, errorMessage)); - break; - } - }; - - try { - const myConstraints = await this.openvidu.generateMediaConstraints(this.properties); - if ( - (!!myConstraints.videoTrack && !!myConstraints.audioTrack) || - (!!myConstraints.audioTrack && myConstraints.constraints?.video === false) || - (!!myConstraints.videoTrack && myConstraints.constraints?.audio === false) - ) { - // No need to call getUserMedia at all. MediaStreamTracks already provided - successCallback(this.openvidu.addAlreadyProvidedTracks(myConstraints, new MediaStream(), this.stream)); - } else { - constraints = myConstraints.constraints; - - const outboundStreamOptions = { - mediaConstraints: constraints, - publisherProperties: this.properties - }; - this.stream.setOutboundStreamOptions(outboundStreamOptions); - - const definedAudioConstraint = constraints.audio === undefined ? true : constraints.audio; - constraintsAux.audio = this.stream.isSendScreen() ? false : definedAudioConstraint; - constraintsAux.video = constraints.video; - startTime = Date.now(); - this.setPermissionDialogTimer(timeForDialogEvent); - - try { - if (this.stream.isSendScreen() && navigator.mediaDevices['getDisplayMedia'] && !platform.isElectron()) { - const mediaStream = await navigator.mediaDevices['getDisplayMedia']({ video: true, audio: this.properties.audioSource === 'screen' }); - this.openvidu.addAlreadyProvidedTracks(myConstraints, mediaStream); - await getMediaSuccess(mediaStream, definedAudioConstraint); - } else { - this.stream.lastVideoTrackConstraints = constraintsAux.video; - const mediaStream = await navigator.mediaDevices.getUserMedia(constraintsAux); - this.openvidu.addAlreadyProvidedTracks(myConstraints, mediaStream, this.stream); - await getMediaSuccess(mediaStream, definedAudioConstraint); - } - } catch (error) { - await getMediaError(error); - } - } - } catch (error) { - errorCallback(error); - } - }); - } - - /** - * @hidden - */ - async replaceTrackAux(track: MediaStreamTrack, updateLastConstraints: boolean): Promise { - // Set field "enabled" of the new track to the previous value - const trackOriginalEnabledValue: boolean = track.enabled; - if (track.kind === 'video') { - track.enabled = this.stream.videoActive; - } else if (track.kind === 'audio') { - track.enabled = this.stream.audioActive; - } - try { - if (this.stream.isLocalStreamPublished) { - // Only if the Publisher has been published is necessary to call native Web API RTCRtpSender.replaceTrack - // If it has not been published yet, replacing it on the MediaStream object is enough - this.replaceTrackInMediaStream(track, updateLastConstraints); - return await this.replaceTrackInRtcRtpSender(track); - } else { - // Publisher not published. Simply replace the track on the local MediaStream - return this.replaceTrackInMediaStream(track, updateLastConstraints); - } - } catch (error) { - track.enabled = trackOriginalEnabledValue; - throw error; - } - } - - /** - * @hidden - * - * To obtain the videoDimensions we wait for the video reference to have enough metadata - * and then try to use MediaStreamTrack.getSettingsMethod(). If not available, then we - * use the HTMLVideoElement properties videoWidth and videoHeight - */ - getVideoDimensions(): Promise<{ width: number; height: number }> { - return new Promise((resolve, reject) => { - // Ionic iOS and Safari iOS supposedly require the video element to actually exist inside the DOM - const requiresDomInsertion: boolean = (platform.isIonicIos() || platform.isIOSWithSafari()) && (this.videoReference.readyState < 1); - - let loadedmetadataListener; - const resolveDimensions = () => { - let width: number; - let height: number; - if (typeof this.stream.getMediaStream().getVideoTracks()[0].getSettings === 'function') { - const settings = this.stream.getMediaStream().getVideoTracks()[0].getSettings(); - width = settings.width || this.videoReference.videoWidth; - height = settings.height || this.videoReference.videoHeight; - } else { - logger.warn('MediaStreamTrack does not have getSettings method on ' + platform.getDescription()); - width = this.videoReference.videoWidth; - height = this.videoReference.videoHeight; - } - - if (loadedmetadataListener != null) { - this.videoReference.removeEventListener('loadedmetadata', loadedmetadataListener); - } - if (requiresDomInsertion) { - document.body.removeChild(this.videoReference); - } - - return resolve({ width, height }); - }; - - if (this.videoReference.readyState >= 1) { - // The video already has metadata available - // No need of loadedmetadata event - resolveDimensions(); - } else { - // The video does not have metadata available yet - // Must listen to loadedmetadata event - loadedmetadataListener = () => { - if (!this.videoReference.videoWidth) { - let interval = setInterval(() => { - if (!!this.videoReference.videoWidth) { - clearInterval(interval); - resolveDimensions(); - } - }, 40); - } else { - resolveDimensions(); - } - }; - this.videoReference.addEventListener('loadedmetadata', loadedmetadataListener); - if (requiresDomInsertion) { - document.body.appendChild(this.videoReference); - } - } - }); - } - - /** - * @hidden - */ - reestablishStreamPlayingEvent() { - if (this.ee.getListeners('streamPlaying').length > 0) { - this.addPlayEventToFirstVideo(); - } - } - - /** - * @hidden - */ - initializeVideoReference(mediaStream: MediaStream) { - this.videoReference = document.createElement('video'); - this.videoReference.style.display = 'none'; - this.videoReference.muted = true; - this.videoReference.autoplay = true; - this.videoReference.controls = false; - if ( - platform.isSafariBrowser() || - (platform.isIPhoneOrIPad() && - (platform.isChromeMobileBrowser() || - platform.isEdgeMobileBrowser() || - platform.isOperaMobileBrowser() || - platform.isFirefoxMobileBrowser())) - ) { - this.videoReference.playsInline = true; - } - this.stream.setMediaStream(mediaStream); - if (!!this.firstVideoElement) { - this.createVideoElement(this.firstVideoElement.targetElement, this.properties.insertMode); - } - this.videoReference.srcObject = this.stream.getMediaStream(); - } - - /** - * @hidden - */ - replaceTrackInMediaStream(track: MediaStreamTrack, updateLastConstraints: boolean): void { - const mediaStream: MediaStream = this.stream.displayMyRemote() - ? this.stream.localMediaStreamWhenSubscribedToRemote! - : this.stream.getMediaStream(); - let removedTrack: MediaStreamTrack; - if (track.kind === 'video') { - removedTrack = mediaStream.getVideoTracks()[0]; - if (updateLastConstraints) { - this.stream.lastVideoTrackConstraints = track.getConstraints(); - } - } else { - removedTrack = mediaStream.getAudioTracks()[0]; - } - removedTrack.enabled = false; - removedTrack.stop(); - mediaStream.removeTrack(removedTrack); - mediaStream.addTrack(track); - const trackInfo = { - oldLabel: removedTrack?.label || '', - newLabel: track?.label || '' - }; - if (track.kind === 'video' && updateLastConstraints) { - this.openvidu.sendNewVideoDimensionsIfRequired(this, 'trackReplaced', 50, 30); - this.openvidu.sendTrackChangedEvent(this, trackInfo.oldLabel, trackInfo.newLabel, 'videoTrack'); - if (this.stream.isLocalStreamPublished) { - this.session.sendVideoData(this.stream.streamManager, 5, true, 5); - } - } else if (track.kind === 'audio' && updateLastConstraints) { - this.openvidu.sendTrackChangedEvent(this, trackInfo.oldLabel, trackInfo.newLabel, 'audioTrack'); - } - if (track.kind === 'audio') { - this.stream.disableHarkSpeakingEvent(false); - this.stream.disableHarkStoppedSpeakingEvent(false); - this.stream.disableHarkVolumeChangeEvent(false); - this.stream.initHarkEvents(); - } - } - - /* Private methods */ - - private setPermissionDialogTimer(waitTime: number): void { - this.permissionDialogTimeout = setTimeout(() => { - this.emitEvent('accessDialogOpened', []); - }, waitTime); - } - - private clearPermissionDialogTimer(startTime: number, waitTime: number): void { - clearTimeout(this.permissionDialogTimeout); - if (Date.now() - startTime > waitTime) { - // Permission dialog was shown and now is closed - this.emitEvent('accessDialogClosed', []); - } - } - - private async replaceTrackInRtcRtpSender(track: MediaStreamTrack): Promise { - const senders: RTCRtpSender[] = this.stream.getRTCPeerConnection().getSenders(); - let sender: RTCRtpSender | undefined; - if (track.kind === 'video') { - sender = senders.find((s) => !!s.track && s.track.kind === 'video'); - if (!sender) { - throw new Error("There's no replaceable track for that kind of MediaStreamTrack in this Publisher object"); - } - } else if (track.kind === 'audio') { - sender = senders.find((s) => !!s.track && s.track.kind === 'audio'); - if (!sender) { - throw new Error("There's no replaceable track for that kind of MediaStreamTrack in this Publisher object"); - } - } else { - throw new Error('Unknown track kind ' + track.kind); - } - await (sender as RTCRtpSender).replaceTrack(track); - } -} diff --git a/openvidu-browser/src/OpenVidu/Session.ts b/openvidu-browser/src/OpenVidu/Session.ts deleted file mode 100644 index db40b98694..0000000000 --- a/openvidu-browser/src/OpenVidu/Session.ts +++ /dev/null @@ -1,1804 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Connection } from './Connection'; -import { Filter } from './Filter'; -import { OpenVidu } from './OpenVidu'; -import { Publisher } from './Publisher'; -import { Stream } from './Stream'; -import { StreamManager } from './StreamManager'; -import { Subscriber } from './Subscriber'; -import { Capabilities } from '../OpenViduInternal/Interfaces/Public/Capabilities'; -import { EventDispatcher } from './EventDispatcher'; -import { SignalOptions } from '../OpenViduInternal/Interfaces/Public/SignalOptions'; -import { SubscriberProperties } from '../OpenViduInternal/Interfaces/Public/SubscriberProperties'; -import { RemoteConnectionOptions } from '../OpenViduInternal/Interfaces/Private/RemoteConnectionOptions'; -import { LocalConnectionOptions } from '../OpenViduInternal/Interfaces/Private/LocalConnectionOptions'; -import { SessionOptions } from '../OpenViduInternal/Interfaces/Private/SessionOptions'; -import { SessionEventMap } from '../OpenViduInternal/Events/EventMap/SessionEventMap'; -import { ConnectionEvent } from '../OpenViduInternal/Events/ConnectionEvent'; -import { FilterEvent } from '../OpenViduInternal/Events/FilterEvent'; -import { RecordingEvent } from '../OpenViduInternal/Events/RecordingEvent'; -import { SessionDisconnectedEvent } from '../OpenViduInternal/Events/SessionDisconnectedEvent'; -import { SignalEvent } from '../OpenViduInternal/Events/SignalEvent'; -import { SpeechToTextEvent } from '../OpenViduInternal/Events/SpeechToTextEvent'; -import { StreamEvent } from '../OpenViduInternal/Events/StreamEvent'; -import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPropertyChangedEvent'; -import { ConnectionPropertyChangedEvent } from '../OpenViduInternal/Events/ConnectionPropertyChangedEvent'; -import { NetworkQualityLevelChangedEvent } from '../OpenViduInternal/Events/NetworkQualityLevelChangedEvent'; -import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError'; -import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode'; -import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; -import { PlatformUtils } from '../OpenViduInternal/Utils/Platform'; -import { StreamPropertyChangedEventReason, ChangedPropertyType, RecordingEventReason, ConnectionEventReason, StreamEventReason } from '../OpenViduInternal/Events/Types/Types'; -/** - * @hidden - */ -import semverMajor = require('semver/functions/major'); -/** - * @hidden - */ -import semverMinor = require('semver/functions/minor'); -import { ExceptionEvent, ExceptionEventName } from '../OpenViduInternal/Events/ExceptionEvent'; - -/** - * @hidden - */ -const logger: OpenViduLogger = OpenViduLogger.getInstance(); - -/** - * @hidden - */ -let platform: PlatformUtils; - -/** - * Represents a video call. It can also be seen as a videoconference room where multiple users can connect. - * Participants who publish their videos to a session can be seen by the rest of users connected to that specific session. - * Initialized with {@link OpenVidu.initSession} method. - * - * See available event listeners at {@link SessionEventMap}. - */ -export class Session extends EventDispatcher { - /** - * Local connection to the Session. This object is defined only after {@link Session.connect} has been successfully executed, and can be retrieved subscribing to `connectionCreated` event - */ - connection: Connection; - - /** - * Unique identifier of the Session - */ - sessionId: string; - - /** - * Collection of all StreamManagers of this Session ({@link Publisher} and {@link Subscriber}) - */ - streamManagers: StreamManager[] = []; - - /** - * Object defining the methods that the client is able to call. These are defined by the {@link Connection.role}. - * This object is only defined after {@link Session.connect} has been successfully resolved - */ - capabilities: Capabilities; - - // This map is only used to avoid race condition between 'joinRoom' response and 'onParticipantPublished' notification - /** - * @hidden - */ - remoteStreamsCreated: Map = new Map(); - - /** - * @hidden - */ - remoteConnections: Map = new Map(); - /** - * @hidden - */ - openvidu: OpenVidu; - /** - * @hidden - */ - options: SessionOptions; - /** - * @hidden - */ - token: string; - /** - * @hidden - */ - private videoDataInterval: NodeJS.Timeout; - /** - * @hidden - */ - private videoDataTimeout: NodeJS.Timeout; - - /** - * @hidden - */ - constructor(openvidu: OpenVidu) { - super(); - platform = PlatformUtils.getInstance(); - this.openvidu = openvidu; - } - - connect(token: string): Promise; - connect(token: string, metadata: any): Promise; - - /** - * Connects to the session using `token`. Parameter `metadata` allows you to pass extra data to share with other users when - * they receive `streamCreated` event. The structure of `metadata` string is up to you (maybe some standardized format - * as JSON or XML is a good idea). - * - * This metadata is not considered secure, as it is generated in the client side. To pass secure data, add it as a parameter in the - * token generation operation (through the API REST, openvidu-java-client or openvidu-node-client). - * - * Only after the returned Promise is successfully resolved {@link Session.connection} object will be available and properly defined. - * - * #### Events dispatched - * - * The {@link Session} object of the local participant will first dispatch one or more `connectionCreated` events upon successful termination of this method: - * - First one for your own local Connection object, so you can retrieve {@link Session.connection} property. - * - Then one for each remote Connection previously connected to the Session, if any. Any other remote user connecting to the Session after you have - * successfully connected will also dispatch a `connectionCreated` event when they do so. - * - * The {@link Session} object of the local participant will also dispatch a `streamCreated` event for each remote active {@link Publisher} that was already streaming - * when connecting, just after dispatching all remote `connectionCreated` events. - * - * The {@link Session} object of every other participant connected to the session will dispatch a `connectionCreated` event. - * - * See {@link ConnectionEvent} and {@link StreamEvent} to learn more. - * - * @returns A Promise to which you must subscribe that is resolved if the the connection to the Session was successful and rejected with an Error object if not - * - */ - connect(token: string, metadata?: any): Promise { - return new Promise((resolve, reject) => { - this.processToken(token); - - if (this.openvidu.checkSystemRequirements()) { - // Early configuration to deactivate automatic subscription to streams - this.options = { - sessionId: this.sessionId, - participantId: token, - metadata: !!metadata ? this.stringClientMetadata(metadata) : '' - }; - this.connectAux(token) - .then(() => resolve()) - .catch((error) => reject(error)); - } else { - return reject( - new OpenViduError( - OpenViduErrorName.BROWSER_NOT_SUPPORTED, - 'Browser ' + - platform.getName() + - ' (version ' + - platform.getVersion() + - ') for ' + - platform.getFamily() + - ' is not supported in OpenVidu' - ) - ); - } - }); - } - - /** - * Leaves the session, destroying all streams and deleting the user as a participant. - * - * #### Events dispatched - * - * The {@link Session} object of the local participant will dispatch a `sessionDisconnected` event. - * This event will automatically unsubscribe the leaving participant from every Subscriber object of the session (this includes closing the RTCPeerConnection and disposing all MediaStreamTracks) - * and also deletes any HTML video element associated to each Subscriber (only those [created by OpenVidu Browser](/en/stable/cheatsheet/manage-videos/#let-openvidu-take-care-of-the-video-players)). - * For every video removed, each Subscriber object will dispatch a `videoElementDestroyed` event. - * Call `event.preventDefault()` upon event `sessionDisconnected` to avoid this behavior and take care of disposing and cleaning all the Subscriber objects yourself. - * See {@link SessionDisconnectedEvent} and {@link VideoElementEvent} to learn more. - * - * The {@link Publisher} object of the local participant will dispatch a `streamDestroyed` event if there is a {@link Publisher} object publishing to the session. - * This event will automatically stop all media tracks and delete any HTML video element associated to it (only those [created by OpenVidu Browser](/en/stable/cheatsheet/manage-videos/#let-openvidu-take-care-of-the-video-players)). - * For every video removed, the Publisher object will dispatch a `videoElementDestroyed` event. - * Call `event.preventDefault()` upon event `streamDestroyed` if you want to clean the Publisher object on your own or re-publish it in a different Session (to do so it is a mandatory requirement to call `Session.unpublish()` - * or/and `Session.disconnect()` in the previous session). See {@link StreamEvent} and {@link VideoElementEvent} to learn more. - * - * The {@link Session} object of every other participant connected to the session will dispatch a `streamDestroyed` event if the disconnected participant was publishing. - * This event will automatically unsubscribe the Subscriber object from the session (this includes closing the RTCPeerConnection and disposing all MediaStreamTracks) - * and also deletes any HTML video element associated to that Subscriber (only those [created by OpenVidu Browser](/en/stable/cheatsheet/manage-videos/#let-openvidu-take-care-of-the-video-players)). - * For every video removed, the Subscriber object will dispatch a `videoElementDestroyed` event. - * Call `event.preventDefault()` upon event `streamDestroyed` to avoid this default behavior and take care of disposing and cleaning the Subscriber object yourself. - * See {@link StreamEvent} and {@link VideoElementEvent} to learn more. - * - * The {@link Session} object of every other participant connected to the session will dispatch a `connectionDestroyed` event in any case. See {@link ConnectionEvent} to learn more. - */ - disconnect(): void { - this.leave(false, 'disconnect'); - } - - subscribe(stream: Stream, targetElement: string | HTMLElement | undefined): Subscriber; - subscribe(stream: Stream, targetElement: string | HTMLElement | undefined, properties: SubscriberProperties): Subscriber; - subscribe( - stream: Stream, - targetElement: string | HTMLElement | undefined, - completionHandler: (error: Error | undefined) => void - ): Subscriber; - subscribe( - stream: Stream, - targetElement: string | HTMLElement | undefined, - properties: SubscriberProperties, - completionHandler: (error: Error | undefined) => void - ): Subscriber; - - /** - * Subscribes to a `stream`, adding a new HTML video element to DOM with `subscriberProperties` settings. This method is usually called in the callback of `streamCreated` event. - * - * #### Events dispatched - * - * The {@link Subscriber} object will dispatch a `videoElementCreated` event once the HTML video element has been added to DOM (only if you - * [let OpenVidu take care of the video players](/en/stable/cheatsheet/manage-videos/#let-openvidu-take-care-of-the-video-players)). See {@link VideoElementEvent} to learn more. - * - * The {@link Subscriber} object will dispatch a `streamPlaying` event once the remote stream starts playing. See {@link StreamManagerEvent} to learn more. - * - * @param stream Stream object to subscribe to - * @param targetElement HTML DOM element (or its `id` attribute) in which the video element of the Subscriber will be inserted (see {@link SubscriberProperties.insertMode}). If *null* or *undefined* no default video will be created for this Subscriber. - * You can always call method {@link Subscriber.addVideoElement} or {@link Subscriber.createVideoElement} to manage the video elements on your own (see [Manage video players](/en/stable/cheatsheet/manage-videos) section) - * @param completionHandler `error` parameter is null if `subscribe` succeeds, and is defined if it fails. - */ - subscribe( - stream: Stream, - targetElement: string | HTMLElement | undefined, - param3?: ((error: Error | undefined) => void) | SubscriberProperties, - param4?: (error: Error | undefined) => void - ): Subscriber { - let properties: SubscriberProperties = {}; - if (!!param3 && typeof param3 !== 'function') { - properties = { - insertMode: - typeof param3.insertMode !== 'undefined' - ? typeof param3.insertMode === 'string' - ? VideoInsertMode[param3.insertMode] - : properties.insertMode - : VideoInsertMode.APPEND, - subscribeToAudio: typeof param3.subscribeToAudio !== 'undefined' ? param3.subscribeToAudio : true, - subscribeToVideo: typeof param3.subscribeToVideo !== 'undefined' ? param3.subscribeToVideo : true - }; - } else { - properties = { - insertMode: VideoInsertMode.APPEND, - subscribeToAudio: true, - subscribeToVideo: true - }; - } - - let completionHandler: ((error: Error | undefined) => void) | undefined = undefined; - if (!!param3 && typeof param3 === 'function') { - completionHandler = param3; - } else if (!!param4) { - completionHandler = param4; - } - - if (!this.sessionConnected()) { - if (completionHandler !== undefined) { - completionHandler(this.notConnectedError()); - } - throw this.notConnectedError(); - } - - logger.info('Subscribing to ' + stream.connection.connectionId); - - stream - .subscribe() - .then(() => { - logger.info('Subscribed correctly to ' + stream.connection.connectionId); - if (completionHandler !== undefined) { - completionHandler(undefined); - } - }) - .catch((error) => { - if (completionHandler !== undefined) { - completionHandler(error); - } - }); - const subscriber = new Subscriber(stream, targetElement, properties); - if (!!subscriber.targetElement) { - stream.streamManager.createVideoElement(subscriber.targetElement, properties.insertMode); - } - return subscriber; - } - - /** - * Promisified version of {@link Session.subscribe} - */ - subscribeAsync(stream: Stream, targetElement: string | HTMLElement): Promise; - subscribeAsync(stream: Stream, targetElement: string | HTMLElement, properties: SubscriberProperties): Promise; - - subscribeAsync(stream: Stream, targetElement: string | HTMLElement, properties?: SubscriberProperties): Promise { - return new Promise((resolve, reject) => { - if (!this.sessionConnected()) { - return reject(this.notConnectedError()); - } - - let subscriber: Subscriber; - - const callback = (error: Error) => { - if (!!error) { - return reject(error); - } else { - return resolve(subscriber); - } - }; - - if (!!properties) { - subscriber = this.subscribe(stream, targetElement, properties, callback); - } else { - subscriber = this.subscribe(stream, targetElement, callback); - } - }); - } - - /** - * Unsubscribes from `subscriber`, automatically removing its associated HTML video elements. - * - * #### Events dispatched - * - * The {@link Subscriber} object will dispatch a `videoElementDestroyed` event for each video associated to it that was removed from DOM. - * Only videos [created by OpenVidu Browser](/en/stable/cheatsheet/manage-videos/#let-openvidu-take-care-of-the-video-players)) will be automatically removed - * - * See {@link VideoElementEvent} to learn more - */ - unsubscribe(subscriber: Subscriber): Promise { - return new Promise((resolve, reject) => { - if (!this.sessionConnected()) { - return reject(this.notConnectedError()); - } else { - const connectionId = subscriber.stream.connection.connectionId; - - logger.info('Unsubscribing from ' + connectionId); - - this.openvidu.sendRequest( - 'unsubscribeFromVideo', - { sender: subscriber.stream.connection.connectionId }, - (error, response) => { - if (error) { - logger.error('Error unsubscribing from ' + connectionId); - return reject(error); - } else { - logger.info('Unsubscribed correctly from ' + connectionId); - subscriber.stream.streamManager.removeAllVideos(); - subscriber.stream.disposeWebRtcPeer(); - subscriber.stream.disposeMediaStream(); - return resolve(); - } - } - ); - } - }); - } - - /** - * Publishes to the Session the Publisher object - * - * #### Events dispatched - * - * The local {@link Publisher} object will dispatch a `streamCreated` event upon successful termination of this method. See {@link StreamEvent} to learn more. - * - * The local {@link Publisher} object will dispatch a `streamPlaying` once the media stream starts playing. See {@link StreamManagerEvent} to learn more. - * - * The {@link Session} object of every other participant connected to the session will dispatch a `streamCreated` event so they can subscribe to it. See {@link StreamEvent} to learn more. - * - * @returns A Promise (to which you can optionally subscribe to) that is resolved only after the publisher was successfully published and rejected with an Error object if not - */ - publish(publisher: Publisher): Promise { - return new Promise((resolve, reject) => { - if (!this.sessionConnected()) { - return reject(this.notConnectedError()); - } - - publisher.session = this; - publisher.stream.session = this; - - if (!publisher.stream.publishedOnce) { - // 'Session.unpublish(Publisher)' has NOT been called - this.connection.addStream(publisher.stream); - publisher.stream - .publish() - .then(() => { - this.sendVideoData(publisher, 8, true, 5); - return resolve(); - }) - .catch((error) => reject(error)); - } else { - // 'Session.unpublish(Publisher)' has been called. Must initialize again Publisher - publisher - .initialize() - .then(() => { - this.connection.addStream(publisher.stream); - publisher.reestablishStreamPlayingEvent(); - publisher.stream - .publish() - .then(() => { - this.sendVideoData(publisher, 8, true, 5); - return resolve(); - }) - .catch((error) => reject(error)); - }) - .catch((error) => reject(error)); - } - }); - } - - /** - * Unpublishes from the Session the Publisher object. - * - * #### Events dispatched - * - * The {@link Publisher} object of the local participant will dispatch a `streamDestroyed` event. - * This event will automatically stop all media tracks and delete any HTML video element associated to this Publisher - * (only those videos [created by OpenVidu Browser](/en/stable/cheatsheet/manage-videos/#let-openvidu-take-care-of-the-video-players)). - * For every video removed, the Publisher object will dispatch a `videoElementDestroyed` event. - * Call `event.preventDefault()` upon event `streamDestroyed` if you want to clean the Publisher object on your own or re-publish it in a different Session. - * - * The {@link Session} object of every other participant connected to the session will dispatch a `streamDestroyed` event. - * This event will automatically unsubscribe the Subscriber object from the session (this includes closing the RTCPeerConnection and disposing all MediaStreamTracks) and - * delete any HTML video element associated to it (only those [created by OpenVidu Browser](/en/stable/cheatsheet/manage-videos/#let-openvidu-take-care-of-the-video-players)). - * For every video removed, the Subscriber object will dispatch a `videoElementDestroyed` event. - * Call `event.preventDefault()` upon event `streamDestroyed` to avoid this default behavior and take care of disposing and cleaning the Subscriber object on your own. - * - * See {@link StreamEvent} and {@link VideoElementEvent} to learn more. - */ - unpublish(publisher: Publisher): Promise { - return new Promise((resolve, reject) => { - if (!this.sessionConnected()) { - throw this.notConnectedError(); - } - - const stream = publisher.stream; - - if (!stream.connection) { - return reject(new Error('The associated Connection object of this Publisher is null')); - } else if (stream.connection !== this.connection) { - return reject( - new Error( - 'The associated Connection object of this Publisher is not your local Connection. ' + - "Only moderators can force unpublish on remote Streams via 'forceUnpublish' method" - ) - ); - } else { - logger.info('Unpublishing local media (' + stream.connection.connectionId + ')'); - - this.openvidu.sendRequest('unpublishVideo', (error, response) => { - if (error) { - return reject(error); - } else { - logger.info('Media unpublished correctly'); - - stream.disposeWebRtcPeer(); - - if (stream.connection.stream == stream) { - // The Connection.stream may have changed if Session.publish was called with other Publisher - delete stream.connection.stream; - } - - const streamEvent = new StreamEvent(true, publisher, 'streamDestroyed', publisher.stream, 'unpublish'); - publisher.emitEvent('streamDestroyed', [streamEvent]); - streamEvent.callDefaultBehavior(); - - return resolve(); - } - }); - } - }); - } - - /** - * Forces some user to leave the session - * - * #### Events dispatched - * - * The behavior is the same as when some user calls {@link Session.disconnect}, but `reason` property in all events will be `"forceDisconnectByUser"`. - * - * The {@link Session} object of every participant will dispatch a `streamDestroyed` event if the evicted user was publishing a stream, with property `reason` set to `"forceDisconnectByUser"`. - * The {@link Session} object of every participant except the evicted one will dispatch a `connectionDestroyed` event for the evicted user, with property `reason` set to `"forceDisconnectByUser"`. - * - * If any, the {@link Publisher} object of the evicted participant will also dispatch a `streamDestroyed` event with property `reason` set to `"forceDisconnectByUser"`. - * The {@link Session} object of the evicted participant will dispatch a `sessionDisconnected` event with property `reason` set to `"forceDisconnectByUser"`. - * - * See {@link StreamEvent}, {@link ConnectionEvent} and {@link SessionDisconnectedEvent} to learn more. - * - * @returns A Promise (to which you can optionally subscribe to) that is resolved only after the participant has been successfully evicted from the session and rejected with an Error object if not - */ - forceDisconnect(connection: Connection): Promise { - return new Promise((resolve, reject) => { - if (!this.sessionConnected()) { - return reject(this.notConnectedError()); - } - - logger.info('Forcing disconnect for connection ' + connection.connectionId); - this.openvidu.sendRequest('forceDisconnect', { connectionId: connection.connectionId }, (error, response) => { - if (error) { - logger.error('Error forcing disconnect for Connection ' + connection.connectionId, error); - if (error.code === 401) { - return reject( - new OpenViduError( - OpenViduErrorName.OPENVIDU_PERMISSION_DENIED, - "You don't have permissions to force a disconnection" - ) - ); - } else { - return reject(error); - } - } else { - logger.info('Forcing disconnect correctly for Connection ' + connection.connectionId); - return resolve(); - } - }); - }); - } - - /** - * Forces some user to unpublish a Stream - * - * #### Events dispatched - * - * The behavior is the same as when some user calls {@link Session.unpublish}, but `reason` property in all events will be `"forceUnpublishByUser"` - * - * The {@link Session} object of every participant will dispatch a `streamDestroyed` event with property `reason` set to `"forceDisconnectByUser"` - * - * The {@link Publisher} object of the affected participant will also dispatch a `streamDestroyed` event with property `reason` set to `"forceDisconnectByUser"` - * - * See {@link StreamEvent} to learn more. - * - * @returns A Promise (to which you can optionally subscribe to) that is resolved only after the remote Stream has been successfully unpublished from the session and rejected with an Error object if not - */ - forceUnpublish(stream: Stream): Promise { - return new Promise((resolve, reject) => { - if (!this.sessionConnected()) { - return reject(this.notConnectedError()); - } - - logger.info('Forcing unpublish for stream ' + stream.streamId); - this.openvidu.sendRequest('forceUnpublish', { streamId: stream.streamId }, (error, response) => { - if (error) { - logger.error('Error forcing unpublish for Stream ' + stream.streamId, error); - if (error.code === 401) { - return reject( - new OpenViduError( - OpenViduErrorName.OPENVIDU_PERMISSION_DENIED, - "You don't have permissions to force an unpublishing" - ) - ); - } else { - return reject(error); - } - } else { - logger.info('Forcing unpublish correctly for Stream ' + stream.streamId); - return resolve(); - } - }); - }); - } - - /** - * Sends one signal. `signal` object has the following optional properties: - * ```json - * {data:string, to:Connection[], type:string} - * ``` - * All users subscribed to that signal (`session.on('signal:type', ...)` or `session.on('signal', ...)` for all signals) and whose Connection objects are in `to` array will receive it. Their local - * Session objects will dispatch a `signal` or `signal:type` event. See {@link SignalEvent} to learn more. - * - * @returns A Promise (to which you can optionally subscribe to) that is resolved if the message successfully reached openvidu-server and rejected with an Error object if not. _This doesn't - * mean that openvidu-server could resend the message to all the listed receivers._ - */ - signal(signal: SignalOptions): Promise { - return new Promise((resolve, reject) => { - if (!this.sessionConnected()) { - return reject(this.notConnectedError()); - } - - const signalMessage = {}; - - if (signal.to && signal.to.length > 0) { - const connectionIds: string[] = []; - signal.to.forEach((connection) => { - if (!!connection.connectionId) { - connectionIds.push(connection.connectionId); - } - }); - signalMessage['to'] = connectionIds; - } else { - signalMessage['to'] = []; - } - - signalMessage['data'] = signal.data ? signal.data : ''; - - let typeAux: string = signal.type ? signal.type : 'signal'; - if (!!typeAux) { - if (typeAux.substring(0, 7) !== 'signal:') { - typeAux = 'signal:' + typeAux; - } - } - signalMessage['type'] = typeAux; - - this.openvidu.sendRequest( - 'sendMessage', - { - message: JSON.stringify(signalMessage) - }, - (error, response) => { - if (!!error) { - return reject(error); - } else { - return resolve(); - } - } - ); - }); - } - - /** - * Subscribe to the Speech-To-Text events for this {@link Stream}. The Session object will emit {@link SpeechToTextEvent} for the Stream - * when speech is detected in its audio track. - * - * @param stream - The Stream for which you want to start receiving {@link SpeechToTextEvent}. - * @param lang - The language of the Stream's audio track. It must be a valid [BCP-47](https://tools.ietf.org/html/bcp47) language tag like "en-US" or "es-ES". - * - * @returns A Promise (to which you can optionally subscribe to) that is resolved if the speech-to-text subscription - * was successful and rejected with an Error object if not. - */ - subscribeToSpeechToText(stream: Stream, lang: string): Promise { - return new Promise((resolve, reject) => { - this.openvidu.sendRequest( - 'subscribeToSpeechToText', - { - connectionId: stream.connection.connectionId, - lang - }, - (error, response) => { - if (!!error) { - return reject(error); - } else { - return resolve(); - } - } - ); - }); - } - - /** - * Unsubscribe from the Speech-To-Text events for this {@link Stream}. - * - * @returns A Promise (to which you can optionally subscribe to) that is resolved if the speech-to-text subscription - * was successful and rejected with an Error object if not. - */ - unsubscribeFromSpeechToText(stream: Stream): Promise { - return new Promise((resolve, reject) => { - this.openvidu.sendRequest( - 'unsubscribeFromSpeechToText', - { - connectionId: stream.connection.connectionId - }, - (error, response) => { - if (!!error) { - return reject(error); - } else { - return resolve(); - } - } - ); - }); - } - - /** - * See {@link EventDispatcher.on} - */ - on(type: K, handler: (event: SessionEventMap[K]) => void): this { - super.onAux(type, "Event '" + type + "' triggered by 'Session'", handler); - - if (type === 'publisherStartSpeaking') { - // If there are already available remote streams with audio, enable hark 'speaking' event in all of them - this.remoteConnections.forEach((remoteConnection) => { - if (!!remoteConnection.stream?.hasAudio) { - remoteConnection.stream.enableHarkSpeakingEvent(); - } - }); - if (!!this.connection?.stream?.hasAudio) { - // If connected to the Session and publishing with audio, also enable hark 'speaking' event for the Publisher - this.connection.stream.enableHarkSpeakingEvent(); - } - } - if (type === 'publisherStopSpeaking') { - // If there are already available remote streams with audio, enable hark 'stopped_speaking' event in all of them - this.remoteConnections.forEach((remoteConnection) => { - if (!!remoteConnection.stream?.hasAudio) { - remoteConnection.stream.enableHarkStoppedSpeakingEvent(); - } - }); - if (!!this.connection?.stream?.hasAudio) { - // If connected to the Session and publishing with audio, also enable hark 'stopped_speaking' event for the Publisher - this.connection.stream.enableHarkStoppedSpeakingEvent(); - } - } - - return this; - } - - /** - * See {@link EventDispatcher.once} - */ - once(type: K, handler: (event: SessionEventMap[K]) => void): this { - super.onceAux(type, "Event '" + type + "' triggered once by 'Session'", handler); - - if (type === 'publisherStartSpeaking') { - // If there are already available remote streams with audio, enable hark 'speaking' event (once) in all of them once - this.remoteConnections.forEach((remoteConnection) => { - if (!!remoteConnection.stream?.hasAudio) { - remoteConnection.stream.enableOnceHarkSpeakingEvent(); - } - }); - if (!!this.connection?.stream?.hasAudio) { - // If connected to the Session and publishing with audio, also enable hark 'speaking' event (once) for the Publisher - this.connection.stream.enableOnceHarkSpeakingEvent(); - } - } - if (type === 'publisherStopSpeaking') { - // If there are already available remote streams with audio, enable hark 'stopped_speaking' event (once) in all of them once - this.remoteConnections.forEach((remoteConnection) => { - if (!!remoteConnection.stream?.hasAudio) { - remoteConnection.stream.enableOnceHarkStoppedSpeakingEvent(); - } - }); - if (!!this.connection?.stream?.hasAudio) { - // If connected to the Session and publishing with audio, also enable hark 'stopped_speaking' event (once) for the Publisher - this.connection.stream.enableOnceHarkStoppedSpeakingEvent(); - } - } - - return this; - } - - /** - * See {@link EventDispatcher.off} - */ - off(type: K, handler?: (event: SessionEventMap[K]) => void): this { - super.offAux(type, handler); - - if (type === 'publisherStartSpeaking') { - // Check if Session object still has some listener for the event - if (!this.anySpeechEventListenerEnabled('publisherStartSpeaking', false)) { - this.remoteConnections.forEach((remoteConnection) => { - if (!!remoteConnection.stream?.streamManager) { - // Check if Subscriber object still has some listener for the event - if (!this.anySpeechEventListenerEnabled('publisherStartSpeaking', false, remoteConnection.stream.streamManager)) { - remoteConnection.stream.disableHarkSpeakingEvent(false); - } - } - }); - if (!!this.connection?.stream?.streamManager) { - // Check if Publisher object still has some listener for the event - if (!this.anySpeechEventListenerEnabled('publisherStartSpeaking', false, this.connection.stream.streamManager)) { - this.connection.stream.disableHarkSpeakingEvent(false); - } - } - } - } - if (type === 'publisherStopSpeaking') { - // Check if Session object still has some listener for the event - if (!this.anySpeechEventListenerEnabled('publisherStopSpeaking', false)) { - this.remoteConnections.forEach((remoteConnection) => { - if (!!remoteConnection.stream?.streamManager) { - // Check if Subscriber object still has some listener for the event - if (!this.anySpeechEventListenerEnabled('publisherStopSpeaking', false, remoteConnection.stream.streamManager)) { - remoteConnection.stream.disableHarkStoppedSpeakingEvent(false); - } - } - }); - if (!!this.connection?.stream?.streamManager) { - // Check if Publisher object still has some listener for the event - if (!this.anySpeechEventListenerEnabled('publisherStopSpeaking', false, this.connection.stream.streamManager)) { - this.connection.stream.disableHarkStoppedSpeakingEvent(false); - } - } - } - } - return this; - } - - /* Hidden methods */ - - /** - * @hidden - */ - onParticipantJoined(event: RemoteConnectionOptions): void { - // Connection shouldn't exist - this.getConnection(event.id, '') - .then((connection) => { - logger.warn('Connection ' + connection.connectionId + ' already exists in connections list'); - }) - .catch((openViduError) => { - const connection = new Connection(this, event); - this.remoteConnections.set(event.id, connection); - this.ee.emitEvent('connectionCreated', [new ConnectionEvent(false, this, 'connectionCreated', connection, '')]); - }); - } - - /** - * @hidden - */ - onParticipantLeft(event: { connectionId: string; reason: ConnectionEventReason }): void { - this.getRemoteConnection(event.connectionId, 'onParticipantLeft') - .then((connection) => { - if (!!connection.stream) { - const stream = connection.stream; - - const streamEvent = new StreamEvent(true, this, 'streamDestroyed', stream, event.reason); - this.ee.emitEvent('streamDestroyed', [streamEvent]); - streamEvent.callDefaultBehavior(); - - this.remoteStreamsCreated.delete(stream.streamId); - } - connection.dispose(); - this.remoteConnections.delete(connection.connectionId); - this.ee.emitEvent('connectionDestroyed', [ - new ConnectionEvent(false, this, 'connectionDestroyed', connection, event.reason) - ]); - }) - .catch((openViduError) => { - logger.error(openViduError); - }); - } - - /** - * @hidden - */ - onParticipantPublished(event: RemoteConnectionOptions): void { - const afterConnectionFound = (connection) => { - this.remoteConnections.set(connection.connectionId, connection); - - if (!this.remoteStreamsCreated.get(connection.stream.streamId)) { - // Avoid race condition between stream.subscribe() in "onParticipantPublished" and in "joinRoom" rpc callback - // This condition is false if openvidu-server sends "participantPublished" event to a subscriber participant that has - // already subscribed to certain stream in the callback of "joinRoom" method - - this.ee.emitEvent('streamCreated', [new StreamEvent(false, this, 'streamCreated', connection.stream, '')]); - } - - this.remoteStreamsCreated.set(connection.stream.streamId, true); - }; - - // Get the existing Connection created on 'onParticipantJoined' for - // existing participants or create a new one for new participants - let connection: Connection; - this.getRemoteConnection(event.id, 'onParticipantPublished') - - .then((con) => { - // Update existing Connection - connection = con; - event.metadata = con.data; - connection.remoteOptions = event; - connection.initRemoteStreams(event.streams); - afterConnectionFound(connection); - }) - .catch((openViduError) => { - // Create new Connection - connection = new Connection(this, event); - afterConnectionFound(connection); - }); - } - - /** - * @hidden - */ - onParticipantUnpublished(event: { connectionId: string; reason: StreamEventReason }): void { - if (event.connectionId === this.connection.connectionId) { - // Your stream has been forcedly unpublished from the session - this.stopPublisherStream(event.reason); - } else { - this.getRemoteConnection(event.connectionId, 'onParticipantUnpublished') - - .then((connection) => { - const streamEvent = new StreamEvent(true, this, 'streamDestroyed', connection.stream!, event.reason); - this.ee.emitEvent('streamDestroyed', [streamEvent]); - streamEvent.callDefaultBehavior(); - - // Deleting the remote stream if it exists - if (connection.stream != null) { - const streamId: string = connection.stream!.streamId; - this.remoteStreamsCreated.delete(streamId); - connection.removeStream(); - } - }) - .catch((openViduError) => { - logger.error(openViduError); - }); - } - } - - /** - * @hidden - */ - onParticipantEvicted(event: { connectionId: string; reason: ConnectionEventReason }): void { - if (event.connectionId === this.connection.connectionId) { - // You have been evicted from the session - if (!!this.sessionId && !this.connection.disposed) { - this.leave(true, event.reason); - } - } - } - - /** - * @hidden - */ - onNewMessage(event: { type?: string; data?: string; from?: string }): void { - logger.info('New signal: ' + JSON.stringify(event)); - - const strippedType = !!event.type ? event.type.replace(/^(signal:)/, '') : undefined; - - if (!!event.from) { - // Signal sent by other client - this.getConnection( - event.from, - "Connection '" + - event.from + - "' unknown when 'onNewMessage'. Existing remote connections: " + - JSON.stringify(this.remoteConnections.keys()) + - '. Existing local connection: ' + - this.connection.connectionId - ) - - .then((connection) => { - this.ee.emitEvent('signal', [new SignalEvent(this, strippedType, event.data, connection)]); - if (!!event.type && event.type !== 'signal') { - this.ee.emitEvent(event.type, [new SignalEvent(this, strippedType, event.data, connection)]); - } - }) - .catch((openViduError) => { - logger.error(openViduError); - }); - } else { - // Signal sent by server - this.ee.emitEvent('signal', [new SignalEvent(this, strippedType, event.data, undefined)]); - if (!!event.type && event.type !== 'signal') { - this.ee.emitEvent(event.type, [new SignalEvent(this, strippedType, event.data, undefined)]); - } - } - } - - /** - * @hidden - */ - onStreamPropertyChanged(event: { connectionId: string; streamId: string; property: ChangedPropertyType; newValue: any; reason: StreamPropertyChangedEventReason }): void { - const callback = (connection: Connection) => { - if (!!connection.stream && connection.stream.streamId === event.streamId) { - const stream = connection.stream; - let oldValue; - switch (event.property) { - case 'audioActive': - oldValue = stream.audioActive; - event.newValue = event.newValue === 'true'; - stream.audioActive = event.newValue; - break; - case 'videoActive': - oldValue = stream.videoActive; - event.newValue = event.newValue === 'true'; - stream.videoActive = event.newValue; - const videoTrack = stream?.getMediaStream()?.getVideoTracks()?.[0]; - if(videoTrack && !videoTrack.enabled && stream.videoActive){ - videoTrack.enabled = true; - } - break; - case 'videoTrack': - event.newValue = JSON.parse(event.newValue); - break; - case 'audioTrack': - event.newValue = JSON.parse(event.newValue); - break; - case 'videoDimensions': - oldValue = stream.videoDimensions; - event.newValue = JSON.parse(JSON.parse(event.newValue)); - stream.videoDimensions = event.newValue; - break; - case 'filter': - oldValue = stream.filter; - event.newValue = Object.keys(event.newValue).length > 0 ? event.newValue : undefined; - if (event.newValue !== undefined) { - stream.filter = new Filter(event.newValue.type, event.newValue.options); - stream.filter.stream = stream; - if (event.newValue.lastExecMethod) { - stream.filter.lastExecMethod = event.newValue.lastExecMethod; - } - } else { - delete stream.filter; - } - event.newValue = stream.filter; - break; - } - this.ee.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent(this, stream, event.property, event.newValue, oldValue, event.reason) - ]); - if (!!stream.streamManager) { - stream.streamManager.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent(stream.streamManager, stream, event.property, event.newValue, oldValue, event.reason) - ]); - } - } else { - logger.error( - "No stream with streamId '" + - event.streamId + - "' found for connection '" + - event.connectionId + - "' on 'streamPropertyChanged' event" - ); - } - }; - - if (event.connectionId === this.connection.connectionId) { - // Your stream has been forcedly changed (filter feature) - callback(this.connection); - } else { - this.getRemoteConnection(event.connectionId, 'onStreamPropertyChanged') - .then((connection) => { - callback(connection); - }) - .catch((openViduError) => { - logger.error(openViduError); - }); - } - } - - /** - * @hidden - */ - onConnectionPropertyChanged(event: { property: string; newValue: any }): void { - let oldValue; - switch (event.property) { - case 'role': - oldValue = this.connection.role.slice(); - this.connection.role = event.newValue; - this.connection.localOptions!.role = event.newValue; - break; - case 'record': - oldValue = this.connection.record; - event.newValue = event.newValue === 'true'; - this.connection.record = event.newValue; - this.connection.localOptions!.record = event.newValue; - break; - } - this.ee.emitEvent('connectionPropertyChanged', [ - new ConnectionPropertyChangedEvent(this, this.connection, event.property, event.newValue, oldValue) - ]); - } - - /** - * @hidden - */ - onNetworkQualityLevelChangedChanged(event: { connectionId: string; newValue: number; oldValue: number }): void { - if (event.connectionId === this.connection.connectionId) { - this.ee.emitEvent('networkQualityLevelChanged', [ - new NetworkQualityLevelChangedEvent(this, event.newValue, event.oldValue, this.connection) - ]); - } else { - this.getConnection(event.connectionId, 'Connection not found for connectionId ' + event.connectionId) - .then((connection: Connection) => { - this.ee.emitEvent('networkQualityLevelChanged', [ - new NetworkQualityLevelChangedEvent(this, event.newValue, event.oldValue, connection) - ]); - }) - .catch((openViduError) => { - logger.error(openViduError); - }); - } - } - - /** - * @hidden - */ - recvIceCandidate(event: { - senderConnectionId: string; - endpointName: string; - sdpMLineIndex: number; - sdpMid: string; - candidate: string; - }): void { - // The event contains fields that can be used to obtain a proper candidate, - // using the RTCIceCandidate constructor: - // https://w3c.github.io/webrtc-pc/#dom-rtcicecandidate-constructor - const candidateInit: RTCIceCandidateInit = { - candidate: event.candidate, - sdpMLineIndex: event.sdpMLineIndex, - sdpMid: event.sdpMid - }; - const iceCandidate = new RTCIceCandidate(candidateInit); - - this.getConnection( - event.senderConnectionId, - 'Connection not found for connectionId ' + - event.senderConnectionId + - ' owning endpoint ' + - event.endpointName + - '. Ice candidate will be ignored: ' + - iceCandidate - ) - .then((connection) => { - const stream: Stream = connection.stream!; - stream - .getWebRtcPeer() - .addIceCandidate(iceCandidate) - .catch((error) => { - logger.error( - 'Error adding candidate for ' + stream!.streamId + ' stream of endpoint ' + event.endpointName + ': ' + error - ); - }); - }) - .catch((openViduError) => { - logger.error(openViduError); - }); - } - - /** - * @hidden - */ - onSessionClosed(msg): void { - logger.info('Session closed: ' + JSON.stringify(msg)); - const s = msg.sessionId; - if (s !== undefined) { - this.ee.emitEvent('session-closed', [ - { - session: s - } - ]); - } else { - logger.warn('Session undefined on session closed', msg); - } - } - - /** - * @hidden - */ - onLostConnection(reason: ConnectionEventReason): void { - logger.warn('Lost connection in Session ' + this.sessionId); - if (!!this.sessionId && !!this.connection && !this.connection.disposed) { - this.leave(true, reason); - } - } - - /** - * @hidden - */ - onRecoveredConnection(): void { - logger.info('Recovered connection in Session ' + this.sessionId); - this.reconnectBrokenStreams(); - this.ee.emitEvent('reconnected', []); - } - - /** - * @hidden - */ - onMediaError(event: { error: string }): void { - logger.error('Media error: ' + JSON.stringify(event)); - const err = event.error; - if (err) { - this.ee.emitEvent('error-media', [{ error: err }]); - } else { - logger.warn('Received undefined media error:', event); - } - } - - /** - * @hidden - */ - onRecordingStarted(event: { id: string; name: string }): void { - this.ee.emitEvent('recordingStarted', [new RecordingEvent(this, 'recordingStarted', event.id, event.name)]); - } - - /** - * @hidden - */ - onRecordingStopped(event: { id: string; name: string; reason: RecordingEventReason }): void { - this.ee.emitEvent('recordingStopped', [new RecordingEvent(this, 'recordingStopped', event.id, event.name, event.reason)]); - } - - /** - * @hidden - */ - onBroadcastStarted(): void { - this.ee.emitEvent('broadcastStarted', []); - } - - /** - * @hidden - */ - onBroadcastStopped(): void { - this.ee.emitEvent('broadcastStopped', []); - } - - /** - * @hidden - */ - onFilterEventDispatched(event: { connectionId: string; streamId: string; filterType: string; eventType: string; data: string }): void { - const connectionId: string = event.connectionId; - this.getConnection(connectionId, 'No connection found for connectionId ' + connectionId).then((connection) => { - logger.info(`Filter event of type "${event.eventType}" dispatched`); - const stream: Stream = connection.stream!; - if (!stream || !stream.filter) { - return logger.error( - `Filter event of type "${event.eventType}" dispatched for stream ${stream.streamId} but there is no ${!stream ? 'stream' : 'filter' - } defined` - ); - } - const eventHandler = stream.filter.handlers.get(event.eventType); - if (!eventHandler || typeof eventHandler !== 'function') { - const actualHandlers: string[] = Array.from(stream.filter.handlers.keys()); - return logger.error( - `Filter event of type "${event.eventType}" not handled or not a function! Active filter events: ${actualHandlers.join( - ',' - )}` - ); - } else { - eventHandler.call(this, new FilterEvent(stream.filter, event.eventType, event.data)); - } - }); - } - - /** - * @hidden - */ - onForciblyReconnectSubscriber(event: { connectionId: string; streamId: string; sdpOffer: string }): Promise { - return new Promise((resolve, reject) => { - this.getRemoteConnection(event.connectionId, 'onForciblyReconnectSubscriber') - .then((connection) => { - if (!!connection.stream && connection.stream.streamId === event.streamId) { - const stream = connection.stream; - - if (stream.setupReconnectionEventEmitter(resolve, reject)) { - // Ongoing reconnection - // Wait for the event emitter to be free (with success or error) and call the method again - if (stream.reconnectionEventEmitter!['onForciblyReconnectSubscriberLastEvent'] != null) { - // Two or more onForciblyReconnectSubscriber events were received while a reconnection process - // of the subscriber was already taking place. Always use the last one to retry the re-subscription - // process, as that SDP offer will be the only one available at the server side. Ignore previous ones - stream.reconnectionEventEmitter!['onForciblyReconnectSubscriberLastEvent'] = event; - return reject('Ongoing forced subscriber reconnection'); - } else { - // One onForciblyReconnectSubscriber even has been received while a reconnection process - // of the subscriber was already taking place. Set up a listener to wait for it to retry the - // forced reconnection process - stream.reconnectionEventEmitter!['onForciblyReconnectSubscriberLastEvent'] = event; - const callback = () => { - const eventAux = stream.reconnectionEventEmitter!['onForciblyReconnectSubscriberLastEvent']; - delete stream.reconnectionEventEmitter!['onForciblyReconnectSubscriberLastEvent']; - this.onForciblyReconnectSubscriber(eventAux); - }; - stream.reconnectionEventEmitter!.once('success', () => { - callback(); - }); - stream.reconnectionEventEmitter!.once('error', () => { - callback(); - }); - } - return; - } - - stream - .completeWebRtcPeerReceive(true, true, event.sdpOffer) - .then(() => stream.finalResolveForSubscription(true, resolve)) - .catch((error) => - stream.finalRejectForSubscription( - true, - `Error while forcibly reconnecting remote stream ${event.streamId}: ${error.toString()}`, - reject - ) - ); - } else { - const errMsg = - "No stream with streamId '" + - event.streamId + - "' found for connection '" + - event.connectionId + - "' on 'streamPropertyChanged' event"; - logger.error(errMsg); - return reject(errMsg); - } - }) - .catch((openViduError) => { - logger.error(openViduError); - return reject(openViduError); - }); - }); - } - - /** - * @hidden - */ - reconnectBrokenStreams(): void { - logger.info('Re-establishing media connections...'); - let someReconnection = false; - // Re-establish Publisher stream - if (!!this.connection.stream && this.connection.stream.streamIceConnectionStateBroken()) { - logger.warn('Re-establishing Publisher ' + this.connection.stream.streamId); - this.connection.stream.initWebRtcPeerSend(true); - someReconnection = true; - } - // Re-establish Subscriber streams - this.remoteConnections.forEach((remoteConnection) => { - if (!!remoteConnection.stream && remoteConnection.stream.streamIceConnectionStateBroken()) { - logger.warn('Re-establishing Subscriber ' + remoteConnection.stream.streamId); - remoteConnection.stream.initWebRtcPeerReceive(true); - someReconnection = true; - } - }); - if (!someReconnection) { - logger.info('There were no media streams in need of a reconnection'); - } - } - - /** - * @hidden - */ - async onSpeechToTextMessage(event: { - timestamp?: Date; - streamId: string; - connectionId: string; - sessionId: string; - text: string; - reason: string; - raw: string; - lang: string; - }): Promise { - const connection = await this.getConnection(event.connectionId, 'No connection found for connectionId ' + event.connectionId); - const ev = new SpeechToTextEvent(this, connection, event.text, (event.reason).toLowerCase(), event.raw, event.lang); - this.ee.emitEvent('speechToTextMessage', [ev]); - } - - /** - * @hidden - */ - async onSpeechToTextDisconnected(event: { message: string }): Promise { - this.emitEvent('exception', [new ExceptionEvent(this, ExceptionEventName.SPEECH_TO_TEXT_DISCONNECTED, this, event.message)]); - } - - /** - * @hidden - */ - emitEvent(type: string, eventArray: any[]): void { - this.ee.emitEvent(type, eventArray); - } - - /** - * @hidden - */ - leave(forced: boolean, reason: ConnectionEventReason): void { - forced = !!forced; - logger.info('Leaving Session (forced=' + forced + ')'); - this.stopVideoDataIntervals(); - - if (!!this.connection) { - if (!this.connection.disposed && !forced) { - this.openvidu.sendRequest('leaveRoom', (error, response) => { - if (error) { - logger.error(`leaveRoom error: ${JSON.stringify(error)}`); - } - this.openvidu.closeWs(); - }); - } else { - this.openvidu.closeWs(); - } - - this.stopPublisherStream(reason); - - if (!this.connection.disposed) { - // Make Session object dispatch 'sessionDisconnected' event (if it is not already disposed) - const sessionDisconnectEvent = new SessionDisconnectedEvent(this, reason); - this.ee.emitEvent('sessionDisconnected', [sessionDisconnectEvent]); - sessionDisconnectEvent.callDefaultBehavior(); - } - } else { - logger.warn('You were not connected to the session ' + this.sessionId); - } - logger.flush(); - } - - /** - * @hidden - */ - initializeParams(token: string) { - const joinParams = { - token: !!token ? token : '', - session: this.sessionId, - platform: !!platform.getDescription() ? platform.getDescription() : 'unknown', - sdkVersion: this.openvidu.libraryVersion, - metadata: !!this.options.metadata ? this.options.metadata : '', - secret: this.openvidu.getSecret(), - recorder: this.openvidu.getRecorder(), - stt: this.openvidu.getStt() - }; - return joinParams; - } - - /** - * @hidden - */ - sendVideoData(streamManager: StreamManager, intervalSeconds: number = 1, doInterval: boolean = false, maxLoops: number = 1) { - if ( - platform.isChromeBrowser() || - platform.isChromeMobileBrowser() || - platform.isOperaBrowser() || - platform.isOperaMobileBrowser() || - platform.isEdgeBrowser() || - platform.isEdgeMobileBrowser() || - platform.isElectron() || - (platform.isSafariBrowser() && !platform.isIonicIos()) || - platform.isAndroidBrowser() || - platform.isSamsungBrowser() || - platform.isIonicAndroid() || - platform.isIOSWithSafari() - ) { - const obtainAndSendVideo = async () => { - const pc = streamManager.stream.getRTCPeerConnection(); - if (pc.connectionState === 'connected') { - const statsMap = await pc.getStats(); - const arr: any[] = []; - statsMap.forEach((stats) => { - if ('frameWidth' in stats && 'frameHeight' in stats && arr.length === 0) { - arr.push(stats); - } - }); - if (arr.length > 0) { - this.openvidu.sendRequest( - 'videoData', - { - height: arr[0].frameHeight, - width: arr[0].frameWidth, - videoActive: streamManager.stream.videoActive != null ? streamManager.stream.videoActive : false, - audioActive: streamManager.stream.audioActive != null ? streamManager.stream.audioActive : false - }, - (error, response) => { - if (error) { - logger.error("Error sending 'videoData' event", error); - } - } - ); - } - } - }; - if (doInterval) { - let loops = 1; - this.videoDataInterval = setInterval(() => { - if (loops < maxLoops) { - loops++; - obtainAndSendVideo(); - } else { - clearInterval(this.videoDataInterval); - } - }, intervalSeconds * 1000); - } else { - this.videoDataTimeout = setTimeout(obtainAndSendVideo, intervalSeconds * 1000); - } - } else if (platform.isFirefoxBrowser() || platform.isFirefoxMobileBrowser() || platform.isIonicIos() || platform.isReactNative()) { - // Basic version for Firefox and Ionic iOS. They do not support stats - this.openvidu.sendRequest( - 'videoData', - { - height: streamManager.stream.videoDimensions?.height || 0, - width: streamManager.stream.videoDimensions?.width || 0, - videoActive: streamManager.stream.videoActive != null ? streamManager.stream.videoActive : false, - audioActive: streamManager.stream.audioActive != null ? streamManager.stream.audioActive : false - }, - (error, response) => { - if (error) { - logger.error("Error sending 'videoData' event", error); - } - } - ); - } else { - logger.error( - 'Browser ' + - platform.getName() + - ' (version ' + - platform.getVersion() + - ') for ' + - platform.getFamily() + - ' is not supported in OpenVidu for Network Quality' - ); - } - } - - /** - * @hidden - */ - sessionConnected() { - return this.connection != null; - } - - /** - * @hidden - */ - notConnectedError(): OpenViduError { - return new OpenViduError( - OpenViduErrorName.OPENVIDU_NOT_CONNECTED, - "There is no connection to the session. Method 'Session.connect' must be successfully completed first" - ); - } - - /** - * @hidden - */ - anySpeechEventListenerEnabled(event: string, onlyOnce: boolean, streamManager?: StreamManager): boolean { - let handlersInSession = this.ee.getListeners(event); - if (onlyOnce) { - handlersInSession = handlersInSession.filter((h) => (h as any).once); - } - let listenersInSession = handlersInSession.length; - if (listenersInSession > 0) return true; - let listenersInStreamManager = 0; - if (!!streamManager) { - let handlersInStreamManager = streamManager.ee.getListeners(event); - if (onlyOnce) { - handlersInStreamManager = handlersInStreamManager.filter((h) => (h as any).once); - } - listenersInStreamManager = handlersInStreamManager.length; - } - return listenersInStreamManager > 0; - } - - /** - * @hidden - */ - getTokenParams(token: string) { - const match = token.match(/^(wss?)\:\/\/(([^:\/?#]*)(?:\:([0-9]+))?)([\/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/); - if (!!match) { - const url = { - protocol: match[1], - host: match[2], - hostname: match[3], - port: match[4], - pathname: match[5], - search: match[6], - hash: match[7] - }; - - const params = token.split('?'); - const queryParams = decodeURI(params[1]) - .split('&') - .map((param) => param.split('=')) - .reduce((values, [key, value]) => { - values[key] = value; - return values; - }, {}); - - return { - sessionId: queryParams['sessionId'], - secret: queryParams['secret'], - recorder: queryParams['recorder'], - stt: queryParams['stt'], - webrtcStatsInterval: queryParams['webrtcStatsInterval'], - sendBrowserLogs: queryParams['sendBrowserLogs'], - edition: queryParams['edition'], - wsUri: url.protocol + '://' + url.host + '/openvidu', - httpUri: 'https://' + url.host - }; - } else { - throw new Error(`Token not valid: "${token}"`); - } - } - - /* Private methods */ - - private connectAux(token: string): Promise { - return new Promise((resolve, reject) => { - this.openvidu.startWs((error) => { - if (!!error) { - return reject(error); - } else { - const joinParams = this.initializeParams(token); - - this.openvidu.sendRequest('joinRoom', joinParams, (error, response: LocalConnectionOptions) => { - if (!!error) { - return reject(error); - } else { - // Process join room response - this.processJoinRoomResponse(response, token); - - // Initialize local Connection object with values returned by openvidu-server - this.connection = new Connection(this, response); - - // Initialize remote Connections with value returned by openvidu-server - const events = { - connections: new Array(), - streams: new Array() - }; - const existingParticipants: RemoteConnectionOptions[] = response.value; - existingParticipants.forEach((remoteConnectionOptions: RemoteConnectionOptions) => { - const connection = new Connection(this, remoteConnectionOptions); - this.remoteConnections.set(connection.connectionId, connection); - events.connections.push(connection); - if (!!connection.stream) { - this.remoteStreamsCreated.set(connection.stream.streamId, true); - events.streams.push(connection.stream); - } - }); - - // Own 'connectionCreated' event - this.ee.emitEvent('connectionCreated', [ - new ConnectionEvent(false, this, 'connectionCreated', this.connection, '') - ]); - - // One 'connectionCreated' event for each existing connection in the session - events.connections.forEach((connection) => { - this.ee.emitEvent('connectionCreated', [ - new ConnectionEvent(false, this, 'connectionCreated', connection, '') - ]); - }); - - // One 'streamCreated' event for each active stream in the session - events.streams.forEach((stream) => { - this.ee.emitEvent('streamCreated', [new StreamEvent(false, this, 'streamCreated', stream, '')]); - }); - - if (!!response.recordingId && !!response.recordingName) { - this.ee.emitEvent('recordingStarted', [ - new RecordingEvent(this, 'recordingStarted', response.recordingId, response.recordingName) - ]); - } - - return resolve(); - } - }); - } - }); - }); - } - - private stopPublisherStream(reason: StreamEventReason) { - if (!!this.connection.stream) { - // Dispose Publisher's local stream - this.connection.stream.disposeWebRtcPeer(); - if (this.connection.stream.isLocalStreamPublished) { - // Make Publisher object dispatch 'streamDestroyed' event if the Stream was published - this.connection.stream.ee.emitEvent('local-stream-destroyed', [reason]); - } - } - } - - private stopVideoDataIntervals(): void { - clearInterval(this.videoDataInterval); - clearTimeout(this.videoDataTimeout); - } - - private stringClientMetadata(metadata: any): string { - if (typeof metadata !== 'string') { - return JSON.stringify(metadata); - } else { - return metadata; - } - } - - protected getConnection(connectionId: string, errorMessage: string): Promise { - return new Promise((resolve, reject) => { - const connection = this.remoteConnections.get(connectionId); - if (!!connection) { - // Resolve remote connection - return resolve(connection); - } else { - if (this.connection.connectionId === connectionId) { - // Resolve local connection - return resolve(this.connection); - } else { - // Connection not found. Reject with OpenViduError - return reject(new OpenViduError(OpenViduErrorName.GENERIC_ERROR, errorMessage)); - } - } - }); - } - - private getRemoteConnection(connectionId: string, operation: string): Promise { - return new Promise((resolve, reject) => { - const connection = this.remoteConnections.get(connectionId); - if (!!connection) { - // Resolve remote connection - return resolve(connection); - } else { - // Remote connection not found. Reject with OpenViduError - const errorMessage = - 'Remote connection ' + - connectionId + - " unknown when '" + - operation + - "'. " + - 'Existing remote connections: ' + - JSON.stringify(this.remoteConnections.keys()); - return reject(new OpenViduError(OpenViduErrorName.GENERIC_ERROR, errorMessage)); - } - }); - } - - private processToken(token: string): void { - const tokenParams = this.getTokenParams(token); - this.sessionId = tokenParams.sessionId; - - if (!!tokenParams.secret) { - this.openvidu.secret = tokenParams.secret; - } - if (!!tokenParams.recorder) { - this.openvidu.recorder = true; - } - if (!!tokenParams.stt) { - this.openvidu.stt = true; - } - if (!!tokenParams.webrtcStatsInterval) { - this.openvidu.webrtcStatsInterval = tokenParams.webrtcStatsInterval; - } - if (!!tokenParams.sendBrowserLogs) { - this.openvidu.sendBrowserLogs = tokenParams.sendBrowserLogs; - } - this.openvidu.isAtLeastPro = tokenParams.edition === 'pro' || tokenParams.edition === 'enterprise'; - this.openvidu.isEnterprise = tokenParams.edition === 'enterprise'; - - this.openvidu.wsUri = tokenParams.wsUri; - this.openvidu.httpUri = tokenParams.httpUri; - } - - private processJoinRoomResponse(opts: LocalConnectionOptions, token: string) { - this.sessionId = opts.session; - if (opts.customIceServers != null && opts.customIceServers.length > 0) { - this.openvidu.iceServers = []; - for (const iceServer of opts.customIceServers) { - let rtcIceServer: RTCIceServer = { - urls: [iceServer.url] - }; - logger.log('STUN/TURN server IP: ' + iceServer.url); - if (iceServer.username != null && iceServer.credential != null) { - rtcIceServer.username = iceServer.username; - rtcIceServer.credential = iceServer.credential; - logger.log('TURN credentials [' + iceServer.username + ':' + iceServer.credential + ']'); - } - this.openvidu.iceServers.push(rtcIceServer); - } - } - this.openvidu.role = opts.role; - this.openvidu.finalUserId = opts.finalUserId; - this.openvidu.mediaServer = opts.mediaServer; - this.openvidu.videoSimulcast = opts.videoSimulcast; - this.capabilities = { - subscribe: true, - publish: this.openvidu.role !== 'SUBSCRIBER', - forceUnpublish: this.openvidu.role === 'MODERATOR', - forceDisconnect: this.openvidu.role === 'MODERATOR' - }; - logger.info('openvidu-server version: ' + opts.version); - if (opts.life != null) { - this.openvidu.life = opts.life; - } - const minorDifference: number = semverMinor(opts.version) - semverMinor(this.openvidu.libraryVersion); - if (semverMajor(opts.version) !== semverMajor(this.openvidu.libraryVersion) || !(minorDifference == 0 || minorDifference == 1)) { - logger.error( - `openvidu-browser (${this.openvidu.libraryVersion}) and openvidu-server (${opts.version}) versions are incompatible. ` + - 'Errors are likely to occur. openvidu-browser SDK is only compatible with the same version or the immediately following minor version of an OpenVidu deployment' - ); - } else if (minorDifference == 1) { - logger.warn( - `openvidu-browser version ${this.openvidu.libraryVersion} does not match openvidu-server version ${opts.version}. ` + - `These versions are still compatible with each other, but openvidu-browser version must be updated as soon as possible to ${semverMajor( - opts.version - )}.${semverMinor(opts.version)}.x. ` + - `This client using openvidu-browser ${this.openvidu.libraryVersion} will become incompatible with the next release of openvidu-server` - ); - } - - // Configure JSNLogs - OpenViduLogger.configureJSNLog(this.openvidu, token); - - // Store token - this.token = token; - } -} diff --git a/openvidu-browser/src/OpenVidu/Stream.ts b/openvidu-browser/src/OpenVidu/Stream.ts deleted file mode 100644 index cb228f50a0..0000000000 --- a/openvidu-browser/src/OpenVidu/Stream.ts +++ /dev/null @@ -1,1877 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Connection } from './Connection'; -import { Filter } from './Filter'; -import { Publisher } from './Publisher'; -import { Session } from './Session'; -import { StreamManager } from './StreamManager'; -import { Subscriber } from './Subscriber'; -import { InboundStreamOptions } from '../OpenViduInternal/Interfaces/Private/InboundStreamOptions'; -import { OutboundStreamOptions } from '../OpenViduInternal/Interfaces/Private/OutboundStreamOptions'; -import { - WebRtcPeer, - WebRtcPeerSendonly, - WebRtcPeerRecvonly, - WebRtcPeerSendrecv, - WebRtcPeerConfiguration -} from '../OpenViduInternal/WebRtcPeer/WebRtcPeer'; -import { WebRtcStats } from '../OpenViduInternal/WebRtcStats/WebRtcStats'; -import { ExceptionEvent, ExceptionEventName } from '../OpenViduInternal/Events/ExceptionEvent'; -import { PublisherSpeakingEvent } from '../OpenViduInternal/Events/PublisherSpeakingEvent'; -import { StreamManagerEvent } from '../OpenViduInternal/Events/StreamManagerEvent'; -import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPropertyChangedEvent'; -import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError'; -import { TypeOfVideo } from '../OpenViduInternal/Enums/TypeOfVideo'; -import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; -import { PlatformUtils } from '../OpenViduInternal/Utils/Platform'; - -import { v4 as uuidv4 } from 'uuid'; - -/** - * @hidden - */ -import hark = require('hark'); -/** - * @hidden - */ -import EventEmitter = require('wolfy87-eventemitter'); -/** - * @hidden - */ -const logger: OpenViduLogger = OpenViduLogger.getInstance(); - -/** - * @hidden - */ -let platform: PlatformUtils; - -/** - * Represents each one of the media streams available in OpenVidu Server for certain session. - * Each {@link Publisher} and {@link Subscriber} has an attribute of type Stream, as they give access - * to one of them (sending and receiving it, respectively) - */ -export class Stream { - /** - * The Connection object that is publishing the stream - */ - connection: Connection; - - /** - * Frame rate of the video in frames per second. This property is only defined if the {@link Publisher} of - * the stream was initialized passing a _frameRate_ property on {@link OpenVidu.initPublisher} method - */ - frameRate?: number; - - /** - * Whether the stream has a video track or not - */ - hasVideo: boolean; - - /** - * Whether the stream has an audio track or not - */ - hasAudio: boolean; - - /** - * Whether the stream has the video track muted or unmuted. If {@link hasVideo} is false, this property is undefined. - * - * This property may change if the Publisher publishing the stream calls {@link Publisher.publishVideo}. Whenever this happens a {@link StreamPropertyChangedEvent} will be dispatched - * by the Session object as well as by the affected Subscriber/Publisher object - */ - videoActive: boolean; - - /** - * Whether the stream has the audio track muted or unmuted. If {@link hasAudio} is false, this property is undefined - * - * This property may change if the Publisher publishing the stream calls {@link Publisher.publishAudio}. Whenever this happens a {@link StreamPropertyChangedEvent} will be dispatched - * by the Session object as well as by the affected Subscriber/Publisher object - */ - audioActive: boolean; - - /** - * Unique identifier of the stream. If the stream belongs to a... - * - Subscriber object: property `streamId` is always defined - * - Publisher object: property `streamId` is only defined after successful execution of {@link Session.publish} - */ - streamId: string; - - /** - * Time when this stream was created in OpenVidu Server (UTC milliseconds). Depending on the owner of this stream: - * - Subscriber object: property `creationTime` is always defined - * - Publisher object: property `creationTime` is only defined after successful execution of {@link Session.publish} - */ - creationTime: number; - - /** - * Can be: - * - `"CAMERA"`: when the video source comes from a webcam. - * - `"SCREEN"`: when the video source comes from screen-sharing. - * - `"CUSTOM"`: when {@link PublisherProperties.videoSource} has been initialized in the Publisher side with a custom MediaStreamTrack when calling {@link OpenVidu.initPublisher}). - * - `"IPCAM"`: when the video source comes from an IP camera participant instead of a regular participant (see [IP cameras](/en/stable/advanced-features/ip-cameras/)). - * - * If {@link hasVideo} is false, this property is undefined - */ - typeOfVideo?: keyof typeof TypeOfVideo; // TODO: Change this type to enum TypeOfVideo on the next breaking-change release - - /** - * StreamManager object ({@link Publisher} or {@link Subscriber}) in charge of displaying this stream in the DOM - */ - streamManager: StreamManager; - - /** - * Width and height in pixels of the encoded video stream. If {@link hasVideo} is false, this property is undefined - * - * This property may change if the Publisher that is publishing: - * - If it is a mobile device, whenever the user rotates the device. - * - If it is screen-sharing, whenever the user changes the size of the captured window. - * - * Whenever this happens a {@link StreamPropertyChangedEvent} will be dispatched by the Session object as well as by the affected Subscriber/Publisher object - */ - videoDimensions: { width: number; height: number }; - - /** - * **WARNING**: experimental option. This interface may change in the near future - * - * Filter applied to the Stream. You can apply filters by calling {@link Stream.applyFilter}, execute methods of the applied filter with - * {@link Filter.execMethod} and remove it with {@link Stream.removeFilter}. Be aware that the client calling this methods must have the - * necessary permissions: the token owned by the client must have been initialized with the appropriated `allowedFilters` array. - */ - filter?: Filter; - - protected webRtcPeer: WebRtcPeer; - protected mediaStream?: MediaStream; - private webRtcStats: WebRtcStats; - - private isSubscribeToRemote = false; - - private virtualBackgroundSourceElements?: { videoClone: HTMLVideoElement; mediaStreamClone: MediaStream }; - /** - * @hidden - */ - virtualBackgroundSinkElements?: { VB: any; video: HTMLVideoElement }; - - /** - * @hidden - */ - isLocalStreamReadyToPublish = false; - /** - * @hidden - */ - isLocalStreamPublished = false; - /** - * @hidden - */ - publishedOnce = false; - /** - * @hidden - */ - session: Session; - /** - * @hidden - */ - inboundStreamOpts: InboundStreamOptions; - /** - * @hidden - */ - outboundStreamOpts: OutboundStreamOptions; - /** - * @hidden - */ - speechEvent: any; - /** - * @hidden - */ - harkSpeakingEnabled = false; - /** - * @hidden - */ - harkSpeakingEnabledOnce = false; - /** - * @hidden - */ - harkStoppedSpeakingEnabled = false; - /** - * @hidden - */ - harkStoppedSpeakingEnabledOnce = false; - /** - * @hidden - */ - harkVolumeChangeEnabled = false; - /** - * @hidden - */ - harkVolumeChangeEnabledOnce = false; - /** - * @hidden - */ - harkOptions; - /** - * @hidden - */ - localMediaStreamWhenSubscribedToRemote?: MediaStream; - /** - * @hidden - */ - ee = new EventEmitter(); - /** - * @hidden - */ - reconnectionEventEmitter: EventEmitter | undefined; - /** - * @hidden - */ - lastVideoTrackConstraints: MediaTrackConstraints | boolean | undefined; - /** - * @hidden - */ - lastVBFilter?: Filter; - - /** - * @hidden - */ - constructor(session: Session, options: InboundStreamOptions | OutboundStreamOptions | {}) { - platform = PlatformUtils.getInstance(); - this.session = session; - - if (options.hasOwnProperty('id')) { - // InboundStreamOptions: stream belongs to a Subscriber - this.inboundStreamOpts = options; - this.streamId = this.inboundStreamOpts.id; - this.creationTime = this.inboundStreamOpts.createdAt; - this.hasAudio = this.inboundStreamOpts.hasAudio; - this.hasVideo = this.inboundStreamOpts.hasVideo; - if (this.hasAudio) { - this.audioActive = this.inboundStreamOpts.audioActive; - } - if (this.hasVideo) { - this.videoActive = this.inboundStreamOpts.videoActive; - this.typeOfVideo = !this.inboundStreamOpts.typeOfVideo ? undefined : this.inboundStreamOpts.typeOfVideo; - this.frameRate = this.inboundStreamOpts.frameRate === -1 ? undefined : this.inboundStreamOpts.frameRate; - this.videoDimensions = this.inboundStreamOpts.videoDimensions; - } - if (!!this.inboundStreamOpts.filter && Object.keys(this.inboundStreamOpts.filter).length > 0) { - if ( - !!this.inboundStreamOpts.filter.lastExecMethod && - Object.keys(this.inboundStreamOpts.filter.lastExecMethod).length === 0 - ) { - delete this.inboundStreamOpts.filter.lastExecMethod; - } - this.filter = this.inboundStreamOpts.filter; - } - } else { - // OutboundStreamOptions: stream belongs to a Publisher - this.outboundStreamOpts = options; - - this.hasAudio = this.isSendAudio(); - this.hasVideo = this.isSendVideo(); - - if (this.hasAudio) { - this.audioActive = !!this.outboundStreamOpts.publisherProperties.publishAudio; - } - if (this.hasVideo) { - this.videoActive = !!this.outboundStreamOpts.publisherProperties.publishVideo; - this.frameRate = this.outboundStreamOpts.publisherProperties.frameRate; - if ( - typeof MediaStreamTrack !== 'undefined' && - this.outboundStreamOpts.publisherProperties.videoSource instanceof MediaStreamTrack - ) { - this.typeOfVideo = TypeOfVideo.CUSTOM; - } else { - this.typeOfVideo = this.isSendScreen() ? TypeOfVideo.SCREEN : TypeOfVideo.CAMERA; - } - } - if (!!this.outboundStreamOpts.publisherProperties.filter) { - this.filter = this.outboundStreamOpts.publisherProperties.filter; - } - } - - this.ee.on('mediastream-updated', () => { - this.streamManager.updateMediaStream(this.mediaStream!); - logger.debug('Video srcObject [' + this.mediaStream?.id + '] updated in stream [' + this.streamId + ']'); - }); - } - - /** - * Recreates the media connection with the server. This entails the disposal of the previous RTCPeerConnection and the re-negotiation - * of a new one, that will apply the same properties. - * - * This method can be useful in those situations were there the media connection breaks and OpenVidu is not able to recover on its own - * for any kind of unanticipated reason (see [Automatic reconnection](/en/stable/advanced-features/automatic-reconnection/)). - * - * @returns A Promise (to which you can optionally subscribe to) that is resolved if the reconnection operation was successful and rejected with an Error object if not - */ - public reconnect(): Promise { - return this.reconnectStream('API'); - } - - /** - * Applies an audio/video filter to the stream. - * - * @param type Type of filter applied. See {@link Filter.type} - * @param options Parameters used to initialize the filter. See {@link Filter.options} - * - * @returns A Promise (to which you can optionally subscribe to) that is resolved to the applied filter if success and rejected with an Error object if not - */ - applyFilter(type: string, options: Object): Promise { - return new Promise(async (resolve, reject) => { - if (!!this.filter) { - return reject( - new OpenViduError(OpenViduErrorName.GENERIC_ERROR, 'There is already a filter applied to Stream ' + this.streamId) - ); - } - - const resolveApplyFilter = (error, triggerEvent) => { - if (error) { - logger.error('Error applying filter for Stream ' + this.streamId, error); - if (error.code === 401) { - return reject( - new OpenViduError(OpenViduErrorName.OPENVIDU_PERMISSION_DENIED, "You don't have permissions to apply a filter") - ); - } else { - return reject(error); - } - } else { - logger.info('Filter successfully applied on Stream ' + this.streamId); - const oldValue: Filter = this.filter!; - this.filter = new Filter(type, options); - this.filter.stream = this; - if (triggerEvent) { - this.session.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent(this.session, this, 'filter', this.filter, oldValue, 'applyFilter') - ]); - this.streamManager.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent(this.streamManager, this, 'filter', this.filter, oldValue, 'applyFilter') - ]); - } - return resolve(this.filter); - } - }; - - if (type.startsWith('VB:')) { - // Client filters - - if (!this.hasVideo) { - return reject( - new OpenViduError( - OpenViduErrorName.VIRTUAL_BACKGROUND_ERROR, - 'The Virtual Background filter requires a video track to be applied' - ) - ); - } - if (!this.mediaStream || this.streamManager.videos.length === 0) { - return reject( - new OpenViduError( - OpenViduErrorName.VIRTUAL_BACKGROUND_ERROR, - 'The StreamManager requires some video element to be attached to it in order to apply a Virtual Background filter' - ) - ); - } - - let openviduToken: string; - if (!!this.session.token) { - openviduToken = this.session.token; - } else { - openviduToken = options['token']; - } - if (!openviduToken) { - return reject( - new OpenViduError( - OpenViduErrorName.VIRTUAL_BACKGROUND_ERROR, - 'Virtual Background requires the client to be connected to a Session or to have a "token" property available in "options" parameter with a valid OpenVidu token' - ) - ); - } - - const tokenParams = this.session.getTokenParams(openviduToken); - if (tokenParams.edition !== 'pro' && tokenParams.edition !== 'enterprise') { - return reject( - new OpenViduError( - OpenViduErrorName.VIRTUAL_BACKGROUND_ERROR, - 'OpenVidu Virtual Background API is available from OpenVidu Pro edition onwards' - ) - ); - } - - openviduToken = encodeURIComponent(btoa(openviduToken)); - - logger.info('Applying Virtual Background to stream ' + this.streamId); - - const afterScriptLoaded = async () => { - try { - const id = this.streamId + '_' + uuidv4(); - const mediaStreamClone = this.mediaStream!.clone(); - const videoClone = this.streamManager.videos[0].video.cloneNode(false) as HTMLVideoElement; - // @ts-ignore - videoClone.id = VirtualBackground.VirtualBackground.SOURCE_VIDEO_PREFIX + id; - videoClone.srcObject = mediaStreamClone; - videoClone.muted = true; - this.virtualBackgroundSourceElements = { videoClone, mediaStreamClone }; - - // @ts-ignore - VirtualBackground.VirtualBackground.hideHtmlElement(videoClone, false); - // @ts-ignore - VirtualBackground.VirtualBackground.appendHtmlElementToHiddenContainer(videoClone, id); - - await videoClone.play(); - - // @ts-ignore - const VB = new VirtualBackground.VirtualBackground({ - id, - openviduServerUrl: new URL(tokenParams.httpUri), - openviduToken, - inputVideo: videoClone, - inputResolution: '160x96', - outputFramerate: 24 - }); - - let filteredVideo: HTMLVideoElement; - switch (type) { - case 'VB:blur': { - filteredVideo = await VB.backgroundBlur(options); - break; - } - case 'VB:image': { - filteredVideo = await VB.backgroundImage(options); - break; - } - default: - throw new Error('Unknown Virtual Background filter: ' + type); - } - - this.virtualBackgroundSinkElements = { VB, video: filteredVideo }; - - videoClone.style.display = 'none'; - - if (this.streamManager.remote) { - this.streamManager.replaceTrackInMediaStream( - (this.virtualBackgroundSinkElements.video.srcObject as MediaStream).getVideoTracks()[0], - false - ); - } else { - (this.streamManager as Publisher).replaceTrackAux( - (this.virtualBackgroundSinkElements.video.srcObject as MediaStream).getVideoTracks()[0], - false - ); - } - - resolveApplyFilter(undefined, false); - } catch (error) { - if (error.name === OpenViduErrorName.VIRTUAL_BACKGROUND_ERROR) { - resolveApplyFilter(new OpenViduError(OpenViduErrorName.VIRTUAL_BACKGROUND_ERROR, error.message), false); - } else { - resolveApplyFilter(error, false); - } - } - }; - - // @ts-ignore - if (typeof VirtualBackground === 'undefined') { - let script: HTMLScriptElement = document.createElement('script'); - script.type = 'text/javascript'; - script.src = tokenParams.httpUri + '/openvidu/virtual-background/openvidu-virtual-background.js?token=' + openviduToken; - script.onload = async () => { - try { - await afterScriptLoaded(); - resolve(new Filter(type, options)); - } catch (error) { - reject(error); - } - }; - document.body.appendChild(script); - } else { - afterScriptLoaded() - .then(() => resolve(new Filter(type, options))) - .catch((error) => reject(error)); - } - } else { - // Server filters - - if (!this.session.sessionConnected()) { - return reject(this.session.notConnectedError()); - } - - logger.info('Applying server filter to stream ' + this.streamId); - options = options != null ? options : {}; - let optionsString = options; - if (typeof optionsString !== 'string') { - optionsString = JSON.stringify(optionsString); - } - this.session.openvidu.sendRequest( - 'applyFilter', - { streamId: this.streamId, type, options: optionsString }, - (error, response) => { - resolveApplyFilter(error, true); - } - ); - } - }); - } - - /** - * Removes an audio/video filter previously applied. - * - * @returns A Promise (to which you can optionally subscribe to) that is resolved if the previously applied filter has been successfully removed and rejected with an Error object in other case - */ - async removeFilter(): Promise { - return await this.removeFilterAux(false); - } - - /** - * Returns the internal RTCPeerConnection object associated to this stream (https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection) - * - * @returns Native RTCPeerConnection Web API object - */ - getRTCPeerConnection(): RTCPeerConnection { - return this.webRtcPeer.pc; - } - - /** - * Returns the internal MediaStream object associated to this stream (https://developer.mozilla.org/en-US/docs/Web/API/MediaStream) - * - * @returns Native MediaStream Web API object - */ - getMediaStream(): MediaStream { - return this.mediaStream!; - } - - /* Hidden methods */ - - /** - * @hidden - */ - removeFilterAux(isDisposing: boolean): Promise { - return new Promise(async (resolve, reject) => { - const resolveRemoveFilter = (error, triggerEvent) => { - if (error) { - delete this.filter; - logger.error('Error removing filter for Stream ' + this.streamId, error); - if (error.code === 401) { - return reject( - new OpenViduError(OpenViduErrorName.OPENVIDU_PERMISSION_DENIED, "You don't have permissions to remove a filter") - ); - } else { - return reject(error); - } - } else { - logger.info('Filter successfully removed from Stream ' + this.streamId); - const oldValue = this.filter!; - delete this.filter; - if (triggerEvent) { - this.session.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent(this.session, this, 'filter', this.filter!, oldValue, 'applyFilter') - ]); - this.streamManager.emitEvent('streamPropertyChanged', [ - new StreamPropertyChangedEvent(this.streamManager, this, 'filter', this.filter!, oldValue, 'applyFilter') - ]); - } - return resolve(); - } - }; - - if (!!this.filter) { - // There is a filter applied - - if (this.filter?.type.startsWith('VB:')) { - // Client filters - - try { - const mediaStreamClone = this.virtualBackgroundSourceElements!.mediaStreamClone; - if (!isDisposing) { - if (this.streamManager.remote) { - this.streamManager.replaceTrackInMediaStream(mediaStreamClone.getVideoTracks()[0], false); - } else { - await (this.streamManager as Publisher).replaceTrackAux(mediaStreamClone.getVideoTracks()[0], false); - } - } else { - mediaStreamClone.getTracks().forEach((track) => track.stop()); - } - - this.virtualBackgroundSinkElements!.VB.cleanUp(); - - delete this.virtualBackgroundSinkElements; - delete this.virtualBackgroundSourceElements; - - return resolveRemoveFilter(undefined, false); - } catch (error) { - return resolveRemoveFilter(error, false); - } - } else { - // Server filters - - if (!this.session.sessionConnected()) { - return reject(this.session.notConnectedError()); - } - - logger.info('Removing filter of stream ' + this.streamId); - this.session.openvidu.sendRequest('removeFilter', { streamId: this.streamId }, (error, response) => { - return resolveRemoveFilter(error, true); - }); - } - } else { - // There is no filter applied - return reject(new OpenViduError(OpenViduErrorName.GENERIC_ERROR, 'Stream ' + this.streamId + ' has no filter applied')); - } - }); - } - - /** - * @hidden - */ - setMediaStream(mediaStream: MediaStream): void { - this.mediaStream = mediaStream; - } - - /** - * @hidden - */ - updateMediaStreamInVideos() { - this.ee.emitEvent('mediastream-updated', []); - } - - /** - * @hidden - */ - getWebRtcPeer(): WebRtcPeer { - return this.webRtcPeer; - } - - /** - * @hidden - */ - subscribeToMyRemote(value: boolean): void { - this.isSubscribeToRemote = value; - } - - /** - * @hidden - */ - setOutboundStreamOptions(outboundStreamOpts: OutboundStreamOptions): void { - this.outboundStreamOpts = outboundStreamOpts; - } - - /** - * @hidden - */ - subscribe(): Promise { - return new Promise((resolve, reject) => { - this.initWebRtcPeerReceive(false) - .then(() => resolve()) - .catch((error) => reject(error)); - }); - } - - /** - * @hidden - */ - publish(): Promise { - return new Promise((resolve, reject) => { - if (this.isLocalStreamReadyToPublish) { - this.initWebRtcPeerSend(false) - .then(() => resolve()) - .catch((error) => reject(error)); - } else { - this.ee.once('stream-ready-to-publish', () => { - this.publish() - .then(() => resolve()) - .catch((error) => reject(error)); - }); - } - }); - } - - /** - * @hidden - */ - disposeWebRtcPeer(): void { - let webrtcId; - if (!!this.webRtcPeer) { - this.webRtcPeer.dispose(); - webrtcId = this.webRtcPeer.getId(); - } - this.stopWebRtcStats(); - logger.info( - (!!this.outboundStreamOpts ? 'Outbound ' : 'Inbound ') + - 'RTCPeerConnection with id [' + - webrtcId + - "] from 'Stream' with id [" + - this.streamId + - '] is now closed' - ); - } - - /** - * @hidden - */ - async disposeMediaStream(): Promise { - if (!!this.filter && this.filter.type.startsWith('VB:')) { - try { - await this.removeFilterAux(true); - console.debug(`Success removing Virtual Background filter for stream ${this.streamId}`); - } catch (error) { - console.error(`Error removing Virtual Background filter for stream ${this.streamId}`, error); - } - } - if (this.mediaStream) { - this.mediaStream.getAudioTracks().forEach((track) => { - track.stop(); - }); - this.mediaStream.getVideoTracks().forEach((track) => { - track.stop(); - }); - delete this.mediaStream; - } - // If subscribeToRemote local MediaStream must be stopped - if (this.localMediaStreamWhenSubscribedToRemote) { - this.localMediaStreamWhenSubscribedToRemote.getAudioTracks().forEach((track) => { - track.stop(); - }); - this.localMediaStreamWhenSubscribedToRemote.getVideoTracks().forEach((track) => { - track.stop(); - }); - delete this.localMediaStreamWhenSubscribedToRemote; - } - if (!!this.speechEvent) { - if (!!this.speechEvent.stop) { - this.speechEvent.stop(); - } - delete this.speechEvent; - } - logger.info( - (!!this.outboundStreamOpts ? 'Local ' : 'Remote ') + "MediaStream from 'Stream' with id [" + this.streamId + '] is now disposed' - ); - } - - /** - * @hidden - */ - displayMyRemote(): boolean { - return this.isSubscribeToRemote; - } - - /** - * @hidden - */ - isSendAudio(): boolean { - return ( - !!this.outboundStreamOpts && - this.outboundStreamOpts.publisherProperties.audioSource !== null && - this.outboundStreamOpts.publisherProperties.audioSource !== false - ); - } - - /** - * @hidden - */ - isSendVideo(): boolean { - return ( - !!this.outboundStreamOpts && - this.outboundStreamOpts.publisherProperties.videoSource !== null && - this.outboundStreamOpts.publisherProperties.videoSource !== false - ); - } - - /** - * @hidden - */ - isSendScreen(): boolean { - let screen = false - if (typeof MediaStreamTrack !== 'undefined' && - this.outboundStreamOpts.publisherProperties.videoSource instanceof MediaStreamTrack) { - let trackSettings: any = this.outboundStreamOpts.publisherProperties.videoSource.getSettings(); - if (trackSettings.displaySurface) { - screen = ["monitor", "window", "browser"].includes(trackSettings.displaySurface); - } - } - if (!screen && platform.isElectron()) { - screen = - typeof this.outboundStreamOpts.publisherProperties.videoSource === 'string' && - this.outboundStreamOpts.publisherProperties.videoSource.startsWith('screen:'); - } - if (!screen) { - screen = this.outboundStreamOpts.publisherProperties.videoSource === 'screen'; - } - return !!this.outboundStreamOpts && screen; - } - - /** - * @hidden - */ - enableHarkSpeakingEvent(): void { - this.setHarkListenerIfNotExists(); - if (!this.harkSpeakingEnabled && !!this.speechEvent) { - this.harkSpeakingEnabled = true; - this.speechEvent.on('speaking', () => { - this.session.emitEvent('publisherStartSpeaking', [ - new PublisherSpeakingEvent(this.session, 'publisherStartSpeaking', this.connection, this.streamId) - ]); - this.streamManager.emitEvent('publisherStartSpeaking', [ - new PublisherSpeakingEvent(this.streamManager, 'publisherStartSpeaking', this.connection, this.streamId) - ]); - this.harkSpeakingEnabledOnce = false; // Disable 'once' version if 'on' version was triggered - }); - } - } - - /** - * @hidden - */ - enableOnceHarkSpeakingEvent(): void { - this.setHarkListenerIfNotExists(); - if (!this.harkSpeakingEnabledOnce && !!this.speechEvent) { - this.harkSpeakingEnabledOnce = true; - this.speechEvent.once('speaking', () => { - if (this.harkSpeakingEnabledOnce) { - // If the listener has been disabled in the meantime (for example by the 'on' version) do not trigger the event - this.session.emitEvent('publisherStartSpeaking', [ - new PublisherSpeakingEvent(this.session, 'publisherStartSpeaking', this.connection, this.streamId) - ]); - this.streamManager.emitEvent('publisherStartSpeaking', [ - new PublisherSpeakingEvent(this.streamManager, 'publisherStartSpeaking', this.connection, this.streamId) - ]); - } - this.disableHarkSpeakingEvent(true); - }); - } - } - - /** - * @hidden - */ - disableHarkSpeakingEvent(disabledByOnce: boolean): void { - if (!!this.speechEvent) { - this.harkSpeakingEnabledOnce = false; - if (disabledByOnce) { - if (this.harkSpeakingEnabled) { - // The 'on' version of this same event is enabled too. Do not remove the hark listener - return; - } - } else { - this.harkSpeakingEnabled = false; - } - // Shutting down the hark event - if ( - this.harkVolumeChangeEnabled || - this.harkVolumeChangeEnabledOnce || - this.harkStoppedSpeakingEnabled || - this.harkStoppedSpeakingEnabledOnce - ) { - // Some other hark event is enabled. Cannot stop the hark process, just remove the specific listener - this.speechEvent.off('speaking'); - } else { - // No other hark event is enabled. We can get entirely rid of it - this.speechEvent.stop(); - delete this.speechEvent; - } - } - } - - /** - * @hidden - */ - enableHarkStoppedSpeakingEvent(): void { - this.setHarkListenerIfNotExists(); - if (!this.harkStoppedSpeakingEnabled && !!this.speechEvent) { - this.harkStoppedSpeakingEnabled = true; - this.speechEvent.on('stopped_speaking', () => { - this.session.emitEvent('publisherStopSpeaking', [ - new PublisherSpeakingEvent(this.session, 'publisherStopSpeaking', this.connection, this.streamId) - ]); - this.streamManager.emitEvent('publisherStopSpeaking', [ - new PublisherSpeakingEvent(this.streamManager, 'publisherStopSpeaking', this.connection, this.streamId) - ]); - this.harkStoppedSpeakingEnabledOnce = false; // Disable 'once' version if 'on' version was triggered - }); - } - } - - /** - * @hidden - */ - enableOnceHarkStoppedSpeakingEvent(): void { - this.setHarkListenerIfNotExists(); - if (!this.harkStoppedSpeakingEnabledOnce && !!this.speechEvent) { - this.harkStoppedSpeakingEnabledOnce = true; - this.speechEvent.once('stopped_speaking', () => { - if (this.harkStoppedSpeakingEnabledOnce) { - // If the listener has been disabled in the meantime (for example by the 'on' version) do not trigger the event - this.session.emitEvent('publisherStopSpeaking', [ - new PublisherSpeakingEvent(this.session, 'publisherStopSpeaking', this.connection, this.streamId) - ]); - this.streamManager.emitEvent('publisherStopSpeaking', [ - new PublisherSpeakingEvent(this.streamManager, 'publisherStopSpeaking', this.connection, this.streamId) - ]); - } - this.disableHarkStoppedSpeakingEvent(true); - }); - } - } - - /** - * @hidden - */ - disableHarkStoppedSpeakingEvent(disabledByOnce: boolean): void { - if (!!this.speechEvent) { - this.harkStoppedSpeakingEnabledOnce = false; - if (disabledByOnce) { - if (this.harkStoppedSpeakingEnabled) { - // We are cancelling the 'once' listener for this event, but the 'on' version - // of this same event is enabled too. Do not remove the hark listener - return; - } - } else { - this.harkStoppedSpeakingEnabled = false; - } - // Shutting down the hark event - if ( - this.harkVolumeChangeEnabled || - this.harkVolumeChangeEnabledOnce || - this.harkSpeakingEnabled || - this.harkSpeakingEnabledOnce - ) { - // Some other hark event is enabled. Cannot stop the hark process, just remove the specific listener - this.speechEvent.off('stopped_speaking'); - } else { - // No other hark event is enabled. We can get entirely rid of it - this.speechEvent.stop(); - delete this.speechEvent; - } - } - } - - /** - * @hidden - */ - enableHarkVolumeChangeEvent(force: boolean): void { - if (this.setHarkListenerIfNotExists()) { - if (!this.harkVolumeChangeEnabled || force) { - this.harkVolumeChangeEnabled = true; - this.speechEvent.on('volume_change', (harkEvent) => { - const oldValue = this.speechEvent.oldVolumeValue; - const value = { newValue: harkEvent, oldValue }; - this.speechEvent.oldVolumeValue = harkEvent; - this.streamManager.emitEvent('streamAudioVolumeChange', [ - new StreamManagerEvent(this.streamManager, 'streamAudioVolumeChange', value) - ]); - }); - } - } else { - // This way whenever the MediaStream object is available, the event listener will be automatically added - this.harkVolumeChangeEnabled = true; - } - } - - /** - * @hidden - */ - enableOnceHarkVolumeChangeEvent(force: boolean): void { - if (this.setHarkListenerIfNotExists()) { - if (!this.harkVolumeChangeEnabledOnce || force) { - this.harkVolumeChangeEnabledOnce = true; - this.speechEvent.once('volume_change', (harkEvent) => { - const oldValue = this.speechEvent.oldVolumeValue; - const value = { newValue: harkEvent, oldValue }; - this.speechEvent.oldVolumeValue = harkEvent; - this.disableHarkVolumeChangeEvent(true); - this.streamManager.emitEvent('streamAudioVolumeChange', [ - new StreamManagerEvent(this.streamManager, 'streamAudioVolumeChange', value) - ]); - }); - } - } else { - // This way whenever the MediaStream object is available, the event listener will be automatically added - this.harkVolumeChangeEnabledOnce = true; - } - } - - /** - * @hidden - */ - disableHarkVolumeChangeEvent(disabledByOnce: boolean): void { - if (!!this.speechEvent) { - this.harkVolumeChangeEnabledOnce = false; - if (disabledByOnce) { - if (this.harkVolumeChangeEnabled) { - // We are cancelling the 'once' listener for this event, but the 'on' version - // of this same event is enabled too. Do not remove the hark listener - return; - } - } else { - this.harkVolumeChangeEnabled = false; - } - // Shutting down the hark event - if ( - this.harkSpeakingEnabled || - this.harkSpeakingEnabledOnce || - this.harkStoppedSpeakingEnabled || - this.harkStoppedSpeakingEnabledOnce - ) { - // Some other hark event is enabled. Cannot stop the hark process, just remove the specific listener - this.speechEvent.off('volume_change'); - } else { - // No other hark event is enabled. We can get entirely rid of it - this.speechEvent.stop(); - delete this.speechEvent; - } - } - } - - /** - * @hidden - */ - isLocal(): boolean { - // inbound options undefined and outbound options defined - return !this.inboundStreamOpts && !!this.outboundStreamOpts; - } - - /** - * @hidden - */ - getSelectedIceCandidate(): Promise { - return new Promise((resolve, reject) => { - this.webRtcStats - .getSelectedIceCandidateInfo() - .then((report) => resolve(report)) - .catch((error) => reject(error)); - }); - } - - /** - * @hidden - */ - getRemoteIceCandidateList(): RTCIceCandidate[] { - return this.webRtcPeer.remoteCandidatesQueue; - } - - /** - * @hidden - */ - getLocalIceCandidateList(): RTCIceCandidate[] { - return this.webRtcPeer.localCandidatesQueue; - } - - /** - * @hidden - */ - streamIceConnectionStateBroken() { - if (!this.getWebRtcPeer() || !this.getRTCPeerConnection()) { - return false; - } - if (!!this.session.openvidu.advancedConfiguration.forceMediaReconnectionAfterNetworkDrop) { - logger.warn( - `OpenVidu Browser advanced configuration option "forceMediaReconnectionAfterNetworkDrop" is enabled. Stream ${this.streamId - } (${this.isLocal() ? 'Publisher' : 'Subscriber'}) will force a reconnection` - ); - return true; - } else { - const iceConnectionState: RTCIceConnectionState = this.getRTCPeerConnection().iceConnectionState; - return iceConnectionState !== 'connected' && iceConnectionState !== 'completed'; - } - } - - /* Private methods */ - - private setHarkListenerIfNotExists(): boolean { - if (!!this.mediaStream) { - if (!this.speechEvent) { - const harkOptions = !!this.harkOptions - ? this.harkOptions - : this.session.openvidu.advancedConfiguration.publisherSpeakingEventsOptions || {}; - harkOptions.interval = typeof harkOptions.interval === 'number' ? harkOptions.interval : 100; - harkOptions.threshold = typeof harkOptions.threshold === 'number' ? harkOptions.threshold : -50; - this.speechEvent = hark(this.mediaStream, harkOptions); - } - return true; - } - return false; - } - - /** - * @hidden - */ - setupReconnectionEventEmitter(resolve: (value: void | PromiseLike) => void, reject: (reason?: any) => void): boolean { - if (this.reconnectionEventEmitter == undefined) { - // There is no ongoing reconnection - this.reconnectionEventEmitter = new EventEmitter(); - return false; - } else { - // Ongoing reconnection - console.warn( - `Trying to reconnect stream ${this.streamId} (${this.isLocal() ? 'Publisher' : 'Subscriber' - }) but an ongoing reconnection process is active. Waiting for response...` - ); - this.reconnectionEventEmitter.once('success', () => resolve()); - this.reconnectionEventEmitter.once('error', (error) => reject(error)); - return true; - } - } - - /** - * @hidden - */ - initWebRtcPeerSend(reconnect: boolean): Promise { - return new Promise((resolve, reject) => { - if (reconnect) { - if (this.setupReconnectionEventEmitter(resolve, reject)) { - // Ongoing reconnection - return; - } - } else { - // MediaStream will already have hark events for reconnected streams - this.initHarkEvents(); // Init hark events for the local stream - } - - const finalResolve = () => { - if (reconnect) { - this.reconnectionEventEmitter?.emitEvent('success'); - delete this.reconnectionEventEmitter; - } - return resolve(); - }; - - const finalReject = (error) => { - if (reconnect) { - this.reconnectionEventEmitter?.emitEvent('error', [error]); - delete this.reconnectionEventEmitter; - } - return reject(error); - }; - - const successOfferCallback = (sdpOfferParam) => { - logger.debug('Sending SDP offer to publish as ' + this.streamId, sdpOfferParam); - - const method = reconnect ? 'reconnectStream' : 'publishVideo'; - let params; - if (reconnect) { - params = { - stream: this.streamId, - sdpString: sdpOfferParam - }; - } else { - let typeOfVideo; - if (this.isSendVideo()) { - typeOfVideo = - typeof MediaStreamTrack !== 'undefined' && - this.outboundStreamOpts.publisherProperties.videoSource instanceof MediaStreamTrack - ? TypeOfVideo.CUSTOM - : this.isSendScreen() - ? TypeOfVideo.SCREEN - : TypeOfVideo.CAMERA; - } - params = { - doLoopback: this.displayMyRemote() || false, - hasAudio: this.isSendAudio(), - hasVideo: this.isSendVideo(), - audioActive: this.audioActive, - videoActive: this.videoActive, - typeOfVideo, - frameRate: !!this.frameRate ? this.frameRate : -1, - videoDimensions: JSON.stringify(this.videoDimensions), - filter: this.outboundStreamOpts.publisherProperties.filter, - sdpOffer: sdpOfferParam - }; - } - - this.session.openvidu.sendRequest(method, params, (error, response) => { - if (error) { - if (error.code === 401) { - finalReject( - new OpenViduError(OpenViduErrorName.OPENVIDU_PERMISSION_DENIED, "You don't have permissions to publish") - ); - } else { - finalReject('Error on publishVideo: ' + JSON.stringify(error)); - } - } else { - this.webRtcPeer - .processRemoteAnswer(response.sdpAnswer) - .then(() => { - this.streamId = response.id; - this.creationTime = response.createdAt; - this.isLocalStreamPublished = true; - this.publishedOnce = true; - if (this.displayMyRemote()) { - this.localMediaStreamWhenSubscribedToRemote = this.mediaStream; - this.remotePeerSuccessfullyEstablished(reconnect); - } - if (reconnect) { - this.ee.emitEvent('stream-reconnected-by-publisher', []); - } else { - this.ee.emitEvent('stream-created-by-publisher', []); - } - this.initWebRtcStats(); - logger.info( - "'Publisher' (" + - this.streamId + - ') successfully ' + - (reconnect ? 'reconnected' : 'published') + - ' to session' - ); - - finalResolve(); - }) - .catch((error) => { - finalReject(error); - }); - } - }); - }; - - const config: WebRtcPeerConfiguration = { - mediaConstraints: { - audio: this.hasAudio, - video: this.hasVideo - }, - simulcast: this.outboundStreamOpts.publisherProperties.videoSimulcast ?? this.session.openvidu.videoSimulcast, - onIceCandidate: this.connection.sendIceCandidate.bind(this.connection), - onIceConnectionStateException: this.onIceConnectionStateExceptionHandler.bind(this), - iceServers: this.getIceServersConf(), - rtcConfiguration: this.session.openvidu.advancedConfiguration.rtcConfiguration, - mediaStream: this.mediaStream, - mediaServer: this.session.openvidu.mediaServer, - typeOfVideo: this.typeOfVideo ? TypeOfVideo[this.typeOfVideo] : undefined - }; - - if (this.session.openvidu.mediaServer !== 'mediasoup') { - // Simulcast is only supported by mediasoup - config.simulcast = false; - } - - if (reconnect) { - this.disposeWebRtcPeer(); - } - if (this.displayMyRemote()) { - this.webRtcPeer = new WebRtcPeerSendrecv(config); - } else { - this.webRtcPeer = new WebRtcPeerSendonly(config); - } - this.webRtcPeer.addIceConnectionStateChangeListener('publisher of ' + this.connection.connectionId); - this.webRtcPeer - .createOffer() - .then((sdpOffer) => { - this.webRtcPeer - .processLocalOffer(sdpOffer) - .then(() => { - successOfferCallback(sdpOffer.sdp); - }) - .catch((error) => { - finalReject(new Error('(publish) SDP process local offer error: ' + JSON.stringify(error))); - }); - }) - .catch((error) => { - finalReject(new Error('(publish) SDP create offer error: ' + JSON.stringify(error))); - }); - }); - } - - /** - * @hidden - */ - finalResolveForSubscription(reconnect: boolean, resolve: (value: void | PromiseLike) => void) { - logger.info("'Subscriber' (" + this.streamId + ') successfully ' + (reconnect ? 'reconnected' : 'subscribed')); - this.remotePeerSuccessfullyEstablished(reconnect); - this.initWebRtcStats(); - if (reconnect) { - this.reconnectionEventEmitter?.emitEvent('success'); - delete this.reconnectionEventEmitter; - } - return resolve(); - } - - /** - * @hidden - */ - finalRejectForSubscription(reconnect: boolean, error: any, reject: (reason?: any) => void) { - logger.error( - "Error for 'Subscriber' (" + - this.streamId + - ') while trying to ' + - (reconnect ? 'reconnect' : 'subscribe') + - ': ' + - error.toString() - ); - if (reconnect) { - this.reconnectionEventEmitter?.emitEvent('error', [error]); - delete this.reconnectionEventEmitter; - } - return reject(error); - } - - /** - * @hidden - */ - initWebRtcPeerReceive(reconnect: boolean): Promise { - return new Promise((resolve, reject) => { - if (reconnect) { - if (this.setupReconnectionEventEmitter(resolve, reject)) { - // Ongoing reconnection - return; - } - } - - if (this.session.openvidu.mediaServer === 'mediasoup') { - // Server initiates negotiation - - this.initWebRtcPeerReceiveFromServer(reconnect) - .then(() => this.finalResolveForSubscription(reconnect, resolve)) - .catch((error) => this.finalRejectForSubscription(reconnect, error, reject)); - } else { - // Client initiates negotiation - - this.initWebRtcPeerReceiveFromClient(reconnect) - .then(() => this.finalResolveForSubscription(reconnect, resolve)) - .catch((error) => this.finalRejectForSubscription(reconnect, error, reject)); - } - }); - } - - /** - * @hidden - */ - initWebRtcPeerReceiveFromClient(reconnect: boolean): Promise { - return new Promise((resolve, reject) => { - this.completeWebRtcPeerReceive(reconnect, false) - .then((response) => { - this.webRtcPeer - .processRemoteAnswer(response.sdpAnswer) - .then(() => resolve()) - .catch((error) => reject(error)); - }) - .catch((error) => reject(error)); - }); - } - - /** - * @hidden - */ - initWebRtcPeerReceiveFromServer(reconnect: boolean): Promise { - return new Promise((resolve, reject) => { - // Server initiates negotiation - this.session.openvidu.sendRequest('prepareReceiveVideoFrom', { sender: this.streamId, reconnect }, (error, response) => { - if (error) { - return reject(new Error('Error on prepareReceiveVideoFrom: ' + JSON.stringify(error))); - } else { - this.completeWebRtcPeerReceive(reconnect, false, response.sdpOffer) - .then(() => resolve()) - .catch((error) => reject(error)); - } - }); - }); - } - - /** - * @hidden - */ - completeWebRtcPeerReceive(reconnect: boolean, forciblyReconnect: boolean, sdpOfferByServer?: string): Promise { - return new Promise((resolve, reject) => { - logger.debug("'Session.subscribe(Stream)' called"); - - const sendSdpToServer = (sdpString: string) => { - logger.debug(`Sending local SDP ${!!sdpOfferByServer ? 'answer' : 'offer'} to subscribe to ${this.streamId}`, sdpString); - - const method = reconnect ? 'reconnectStream' : 'receiveVideoFrom'; - const params = {}; - params[reconnect ? 'stream' : 'sender'] = this.streamId; - if (!!sdpOfferByServer) { - params[reconnect ? 'sdpString' : 'sdpAnswer'] = sdpString; - } else { - params['sdpOffer'] = sdpString; - } - if (reconnect) { - params['forciblyReconnect'] = forciblyReconnect; - } - - this.session.openvidu.sendRequest(method, params, (error, response) => { - if (error) { - return reject(new Error('Error on ' + method + ' : ' + JSON.stringify(error))); - } else { - return resolve(response); - } - }); - }; - - const config: WebRtcPeerConfiguration = { - mediaConstraints: { - audio: this.hasAudio, - video: this.hasVideo - }, - simulcast: false, - onIceCandidate: this.connection.sendIceCandidate.bind(this.connection), - onIceConnectionStateException: this.onIceConnectionStateExceptionHandler.bind(this), - iceServers: this.getIceServersConf(), - rtcConfiguration: this.session.openvidu.advancedConfiguration.rtcConfiguration, - mediaServer: this.session.openvidu.mediaServer, - typeOfVideo: this.typeOfVideo ? TypeOfVideo[this.typeOfVideo] : undefined - }; - - if (reconnect) { - this.disposeWebRtcPeer(); - } - - this.webRtcPeer = new WebRtcPeerRecvonly(config); - this.webRtcPeer.addIceConnectionStateChangeListener(this.streamId); - - if (!!sdpOfferByServer) { - this.webRtcPeer - .processRemoteOffer(sdpOfferByServer) - .then(() => { - this.webRtcPeer - .createAnswer() - .then((sdpAnswer) => { - this.webRtcPeer - .processLocalAnswer(sdpAnswer) - .then(() => { - sendSdpToServer(sdpAnswer.sdp!); - }) - .catch((error) => { - return reject(new Error('(subscribe) SDP process local answer error: ' + JSON.stringify(error))); - }); - }) - .catch((error) => { - return reject(new Error('(subscribe) SDP create answer error: ' + JSON.stringify(error))); - }); - }) - .catch((error) => { - return reject(new Error('(subscribe) SDP process remote offer error: ' + JSON.stringify(error))); - }); - } else { - this.webRtcPeer - .createOffer() - .then((sdpOffer) => { - this.webRtcPeer - .processLocalOffer(sdpOffer) - .then(() => { - sendSdpToServer(sdpOffer.sdp!); - }) - .catch((error) => { - return reject(new Error('(subscribe) SDP process local offer error: ' + JSON.stringify(error))); - }); - }) - .catch((error) => { - return reject(new Error('(subscribe) SDP create offer error: ' + JSON.stringify(error))); - }); - } - }); - } - - /** - * @hidden - */ - remotePeerSuccessfullyEstablished(reconnect: boolean): void { - if (reconnect && this.mediaStream != null) { - // Now we can destroy the existing MediaStream - this.disposeMediaStream(); - } - - this.mediaStream = new MediaStream(); - let receiver: RTCRtpReceiver; - for (receiver of this.webRtcPeer.pc.getReceivers()) { - if (!!receiver.track) { - this.mediaStream.addTrack(receiver.track); - } - } - logger.debug('Peer remote stream', this.mediaStream); - - if (!!this.mediaStream) { - if (this.streamManager instanceof Subscriber) { - // Apply SubscriberProperties.subscribeToAudio and SubscriberProperties.subscribeToVideo - if (!!this.mediaStream.getAudioTracks()[0]) { - const enabled = reconnect ? this.audioActive : !!(this.streamManager as Subscriber).properties.subscribeToAudio; - this.mediaStream.getAudioTracks()[0].enabled = enabled; - } - if (!!this.mediaStream.getVideoTracks()[0]) { - const enabled = reconnect ? this.videoActive : !!this.videoActive && !!(this.streamManager as Subscriber).properties.subscribeToVideo; - this.mediaStream.getVideoTracks()[0].enabled = enabled; - } - } - - this.updateMediaStreamInVideos(); - this.initHarkEvents(); // Init hark events for the remote stream - } - } - - /** - * @hidden - */ - initHarkEvents(): void { - if (!!this.mediaStream!.getAudioTracks()[0]) { - // Hark events can only be set if audio track is available - if (this.session.anySpeechEventListenerEnabled('publisherStartSpeaking', true, this.streamManager)) { - this.enableOnceHarkSpeakingEvent(); - } - if (this.session.anySpeechEventListenerEnabled('publisherStartSpeaking', false, this.streamManager)) { - this.enableHarkSpeakingEvent(); - } - if (this.session.anySpeechEventListenerEnabled('publisherStopSpeaking', true, this.streamManager)) { - this.enableOnceHarkStoppedSpeakingEvent(); - } - if (this.session.anySpeechEventListenerEnabled('publisherStopSpeaking', false, this.streamManager)) { - this.enableHarkStoppedSpeakingEvent(); - } - if (this.harkVolumeChangeEnabledOnce) { - this.enableOnceHarkVolumeChangeEvent(true); - } - if (this.harkVolumeChangeEnabled) { - this.enableHarkVolumeChangeEvent(true); - } - } - } - - private onIceConnectionStateExceptionHandler(exceptionName: ExceptionEventName, message: string, data?: any): void { - switch (exceptionName) { - case ExceptionEventName.ICE_CONNECTION_FAILED: - this.onIceConnectionFailed(); - break; - case ExceptionEventName.ICE_CONNECTION_DISCONNECTED: - this.onIceConnectionDisconnected(); - break; - } - this.session.emitEvent('exception', [new ExceptionEvent(this.session, exceptionName, this, message, data)]); - } - - private onIceConnectionFailed() { - // Immediately reconnect, as this is a terminal error - logger.log( - `[ICE_CONNECTION_FAILED] Handling ICE_CONNECTION_FAILED event. Reconnecting stream ${this.streamId} (${this.isLocal() ? 'Publisher' : 'Subscriber' - })` - ); - this.reconnectStreamAndLogResultingIceConnectionState(ExceptionEventName.ICE_CONNECTION_FAILED); - } - - private onIceConnectionDisconnected() { - // Wait to see if the ICE connection is able to reconnect - logger.log( - `[ICE_CONNECTION_DISCONNECTED] Handling ICE_CONNECTION_DISCONNECTED event. Waiting for ICE to be restored and reconnect stream ${this.streamId - } (${this.isLocal() ? 'Publisher' : 'Subscriber'}) if not possible` - ); - const timeout = this.session.openvidu.advancedConfiguration.iceConnectionDisconnectedExceptionTimeout || 4000; - this.awaitWebRtcPeerConnectionState(timeout).then((state) => { - switch (state) { - case 'failed': - // Do nothing, as an ICE_CONNECTION_FAILED event will have already raised - logger.warn( - `[ICE_CONNECTION_DISCONNECTED] ICE connection of stream ${this.streamId} (${this.isLocal() ? 'Publisher' : 'Subscriber' - }) is now failed after ICE_CONNECTION_DISCONNECTED` - ); - break; - case 'connected': - case 'completed': - logger.log( - `[ICE_CONNECTION_DISCONNECTED] ICE connection of stream ${this.streamId} (${this.isLocal() ? 'Publisher' : 'Subscriber' - }) automatically restored after ICE_CONNECTION_DISCONNECTED. Current ICE connection state: ${state}` - ); - break; - case 'closed': - case 'checking': - case 'new': - case 'disconnected': - // Rest of states - logger.warn( - `[ICE_CONNECTION_DISCONNECTED] ICE connection of stream ${this.streamId} (${this.isLocal() ? 'Publisher' : 'Subscriber' - }) couldn't be restored after ICE_CONNECTION_DISCONNECTED event. Current ICE connection state after ${timeout} ms: ${state}` - ); - this.reconnectStreamAndLogResultingIceConnectionState(ExceptionEventName.ICE_CONNECTION_DISCONNECTED); - break; - } - }); - } - - private async reconnectStreamAndLogResultingIceConnectionState(event: string) { - try { - const finalIceStateAfterReconnection = await this.reconnectStreamAndReturnIceConnectionState(event); - switch (finalIceStateAfterReconnection) { - case 'connected': - case 'completed': - logger.log( - `[${event}] Stream ${this.streamId} (${this.isLocal() ? 'Publisher' : 'Subscriber' - }) successfully reconnected after ${event}. Current ICE connection state: ${finalIceStateAfterReconnection}` - ); - break; - default: - logger.error( - `[${event}] Stream ${this.streamId} (${this.isLocal() ? 'Publisher' : 'Subscriber' - }) failed to reconnect after ${event}. Current ICE connection state: ${finalIceStateAfterReconnection}` - ); - break; - } - } catch (error) { - logger.error( - `[${event}] Error reconnecting stream ${this.streamId} (${this.isLocal() ? 'Publisher' : 'Subscriber' - }) after ${event}: ${error}` - ); - } - } - - private async reconnectStreamAndReturnIceConnectionState(event: string): Promise { - logger.log(`[${event}] Reconnecting stream ${this.streamId} (${this.isLocal() ? 'Publisher' : 'Subscriber'}) after event ${event}`); - try { - await this.reconnectStream(event); - const timeout = this.session.openvidu.advancedConfiguration.iceConnectionDisconnectedExceptionTimeout || 4000; - return this.awaitWebRtcPeerConnectionState(timeout); - } catch (error) { - logger.warn( - `[${event}] Error reconnecting stream ${this.streamId} (${this.isLocal() ? 'Publisher' : 'Subscriber'}). Reason: ${error}` - ); - return this.awaitWebRtcPeerConnectionState(1); - } - } - - private async awaitWebRtcPeerConnectionState(timeout: number): Promise { - let state = this.getRTCPeerConnection().iceConnectionState; - const interval = 150; - const intervals = Math.ceil(timeout / interval); - for (let i = 0; i < intervals; i++) { - state = this.getRTCPeerConnection().iceConnectionState; - if (state === 'connected' || state === 'completed') { - break; - } - // Sleep - await new Promise((resolve) => setTimeout(resolve, interval)); - } - return state; - } - - private async reconnectStream(event: string) { - const isWsConnected = await this.isWebsocketConnected(event, 3000); - if (isWsConnected) { - // There is connection to openvidu-server. The RTCPeerConnection is the only one broken - logger.log( - `[${event}] Trying to reconnect stream ${this.streamId} (${this.isLocal() ? 'Publisher' : 'Subscriber' - }) and the websocket is opened` - ); - if (this.isLocal()) { - return this.initWebRtcPeerSend(true); - } else { - return this.initWebRtcPeerReceive(true); - } - } else { - // There is no connection to openvidu-server. Nothing can be done. The automatic reconnection - // feature should handle a possible reconnection of RTCPeerConnection in case network comes back - const errorMsg = `[${event}] Trying to reconnect stream ${this.streamId} (${this.isLocal() ? 'Publisher' : 'Subscriber' - }) but the websocket wasn't opened`; - logger.error(errorMsg); - throw Error(errorMsg); - } - } - - private isWebsocketConnected(event: string, msResponseTimeout: number): Promise { - return new Promise((resolve, reject) => { - const wsReadyState = this.session.openvidu.getWsReadyState(); - if (wsReadyState === 1) { - const responseTimeout = setTimeout(() => { - console.warn(`[${event}] Websocket timeout of ${msResponseTimeout}ms`); - return resolve(false); - }, msResponseTimeout); - this.session.openvidu.sendRequest('echo', {}, (error, response) => { - clearTimeout(responseTimeout); - if (!!error) { - console.warn(`[${event}] Websocket 'echo' returned error: ${error}`); - return resolve(false); - } else { - return resolve(true); - } - }); - } else { - console.warn(`[${event}] Websocket readyState is ${wsReadyState}`); - return resolve(false); - } - }); - } - - /** - * @hidden - */ - initWebRtcStats(): void { - this.webRtcStats = new WebRtcStats(this); - this.webRtcStats.initWebRtcStats(); - - //TODO: send common webrtc stats from client to openvidu-server - /*if (this.session.openvidu.webrtcStatsInterval > 0) { - setInterval(() => { - this.gatherStatsForPeer().then(jsonStats => { - const body = { - sessionId: this.session.sessionId, - participantPrivateId: this.connection.rpcSessionId, - stats: jsonStats - } - var xhr = new XMLHttpRequest(); - xhr.open('POST', this.session.openvidu.httpUri + '/elasticsearch/webrtc-stats', true); - xhr.setRequestHeader('Content-Type', 'application/json'); - xhr.send(JSON.stringify(body)); - }) - }, this.session.openvidu.webrtcStatsInterval * 1000); - }*/ - } - - private stopWebRtcStats(): void { - if (!!this.webRtcStats && this.webRtcStats.isEnabled()) { - this.webRtcStats.stopWebRtcStats(); - } - } - - private getIceServersConf(): RTCIceServer[] | undefined { - let returnValue; - if (!!this.session.openvidu.advancedConfiguration.iceServers) { - // Priority 1: OpenViduAdvancedConfiguration.iceServers - returnValue = - this.session.openvidu.advancedConfiguration.iceServers === 'freeice' - ? undefined - : this.session.openvidu.advancedConfiguration.iceServers; - } else if (!!this.session.openvidu.advancedConfiguration.rtcConfiguration?.iceServers) { - // Priority 2: OpenViduAdvancedConfiguration.rtcConfiguration.iceServers - returnValue = this.session.openvidu.advancedConfiguration.rtcConfiguration.iceServers; - } else if (this.session.openvidu.iceServers) { - // Priority 3: default ICE servers sent by openvidu-server - returnValue = this.session.openvidu.iceServers; - } else { - // Priority 4: freeice STUN servers - returnValue = undefined; - } - return returnValue; - } - - private gatherStatsForPeer(): Promise { - return new Promise((resolve, reject) => { - if (this.isLocal()) { - // Publisher stream stats - - this.getRTCPeerConnection() - .getSenders() - .forEach((sender) => - sender.getStats().then((response) => { - response.forEach((report) => { - if (this.isReportWanted(report)) { - const finalReport = {}; - - finalReport['type'] = report.type; - finalReport['timestamp'] = report.timestamp; - finalReport['id'] = report.id; - - // Common to Chrome, Firefox and Safari - if (report.type === 'outbound-rtp') { - finalReport['ssrc'] = report.ssrc; - finalReport['firCount'] = report.firCount; - finalReport['pliCount'] = report.pliCount; - finalReport['nackCount'] = report.nackCount; - finalReport['qpSum'] = report.qpSum; - - // Set media type - if (!!report.kind) { - finalReport['mediaType'] = report.kind; - } else if (!!report.mediaType) { - finalReport['mediaType'] = report.mediaType; - } else { - // Safari does not have 'mediaType' defined for inbound-rtp. Must be inferred from 'id' field - finalReport['mediaType'] = report.id.indexOf('VideoStream') !== -1 ? 'video' : 'audio'; - } - - if (finalReport['mediaType'] === 'video') { - finalReport['framesEncoded'] = report.framesEncoded; - } - - finalReport['packetsSent'] = report.packetsSent; - finalReport['bytesSent'] = report.bytesSent; - } - - // Only for Chrome and Safari - if (report.type === 'candidate-pair' && report.totalRoundTripTime !== undefined) { - // This is the final selected candidate pair - finalReport['availableOutgoingBitrate'] = report.availableOutgoingBitrate; - finalReport['rtt'] = report.currentRoundTripTime; - finalReport['averageRtt'] = report.totalRoundTripTime / report.responsesReceived; - } - - // Only for Firefox >= 66.0 - if (report.type === 'remote-inbound-rtp' || report.type === 'remote-outbound-rtp') { - } - - logger.log(finalReport); - } - }); - }) - ); - } else { - // Subscriber stream stats - - this.getRTCPeerConnection() - .getReceivers() - .forEach((receiver) => - receiver.getStats().then((response) => { - response.forEach((report) => { - if (this.isReportWanted(report)) { - const finalReport = {}; - - finalReport['type'] = report.type; - finalReport['timestamp'] = report.timestamp; - finalReport['id'] = report.id; - - // Common to Chrome, Firefox and Safari - if (report.type === 'inbound-rtp') { - finalReport['ssrc'] = report.ssrc; - finalReport['firCount'] = report.firCount; - finalReport['pliCount'] = report.pliCount; - finalReport['nackCount'] = report.nackCount; - finalReport['qpSum'] = report.qpSum; - - // Set media type - if (!!report.kind) { - finalReport['mediaType'] = report.kind; - } else if (!!report.mediaType) { - finalReport['mediaType'] = report.mediaType; - } else { - // Safari does not have 'mediaType' defined for inbound-rtp. Must be inferred from 'id' field - finalReport['mediaType'] = report.id.indexOf('VideoStream') !== -1 ? 'video' : 'audio'; - } - - if (finalReport['mediaType'] === 'video') { - finalReport['framesDecoded'] = report.framesDecoded; - } - - finalReport['packetsReceived'] = report.packetsReceived; - finalReport['packetsLost'] = report.packetsLost; - finalReport['jitter'] = report.jitter; - finalReport['bytesReceived'] = report.bytesReceived; - } - - // Only for Chrome and Safari - if (report.type === 'candidate-pair' && report.totalRoundTripTime !== undefined) { - // This is the final selected candidate pair - finalReport['availableIncomingBitrate'] = report.availableIncomingBitrate; - finalReport['rtt'] = report.currentRoundTripTime; - finalReport['averageRtt'] = report.totalRoundTripTime / report.responsesReceived; - } - - // Only for Firefox >= 66.0 - if (report.type === 'remote-inbound-rtp' || report.type === 'remote-outbound-rtp') { - } - logger.log(finalReport); - } - }); - }) - ); - } - }); - } - - private isReportWanted(report: any): boolean { - return ( - (report.type === 'inbound-rtp' && !this.isLocal()) || - (report.type === 'outbound-rtp' && this.isLocal()) || - (report.type === 'candidate-pair' && report.nominated && report.bytesSent > 0) - ); - } -} diff --git a/openvidu-browser/src/OpenVidu/StreamManager.ts b/openvidu-browser/src/OpenVidu/StreamManager.ts deleted file mode 100644 index 23251a4eba..0000000000 --- a/openvidu-browser/src/OpenVidu/StreamManager.ts +++ /dev/null @@ -1,621 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Stream } from './Stream'; -import { Subscriber } from './Subscriber'; -import { EventDispatcher } from './EventDispatcher'; -import { StreamManagerVideo } from '../OpenViduInternal/Interfaces/Public/StreamManagerVideo'; -import { StreamManagerEventMap } from '../OpenViduInternal/Events/EventMap/StreamManagerEventMap'; -import { StreamManagerEvent } from '../OpenViduInternal/Events/StreamManagerEvent'; -import { VideoElementEvent } from '../OpenViduInternal/Events/VideoElementEvent'; -import { ExceptionEvent, ExceptionEventName } from '../OpenViduInternal/Events/ExceptionEvent'; -import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode'; -import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; -import { PlatformUtils } from '../OpenViduInternal/Utils/Platform'; - -/** - * @hidden - */ -const logger: OpenViduLogger = OpenViduLogger.getInstance(); - -/** - * @hidden - */ -let platform: PlatformUtils; - -/** - * Interface in charge of displaying the media streams in the HTML DOM. This wraps any {@link Publisher} and {@link Subscriber} object. - * You can insert as many video players fo the same Stream as you want by calling {@link StreamManager.addVideoElement} or - * {@link StreamManager.createVideoElement}. - * The use of StreamManager wrapper is particularly useful when you don't need to differentiate between Publisher or Subscriber streams or just - * want to directly manage your own video elements (even more than one video element per Stream). This scenario is pretty common in - * declarative, MVC frontend frameworks such as Angular, React or Vue.js - * - * See available event listeners at {@link StreamManagerEventMap}. - */ -export abstract class StreamManager extends EventDispatcher { - /** - * The Stream represented in the DOM by the Publisher/Subscriber - */ - stream: Stream; - - /** - * All the videos displaying the Stream of this Publisher/Subscriber - */ - videos: StreamManagerVideo[] = []; - - /** - * Whether the Stream represented in the DOM is local or remote - * - `false` for {@link Publisher} - * - `true` for {@link Subscriber} - */ - remote: boolean; - - /** - * The DOM HTMLElement assigned as target element when creating the video for the Publisher/Subscriber. This property is only defined if: - * - {@link Publisher} has been initialized by calling method {@link OpenVidu.initPublisher} with a valid `targetElement` parameter - * - {@link Subscriber} has been initialized by calling method {@link Session.subscribe} with a valid `targetElement` parameter - */ - targetElement: HTMLElement; - - /** - * `id` attribute of the DOM video element displaying the Publisher/Subscriber's stream. This property is only defined if: - * - {@link Publisher} has been initialized by calling method {@link OpenVidu.initPublisher} with a valid `targetElement` parameter - * - {@link Subscriber} has been initialized by calling method {@link Session.subscribe} with a valid `targetElement` parameter - */ - id: string; - - /** - * @hidden - */ - protected firstVideoElement?: StreamManagerVideo; - /** - * @hidden - */ - protected element: HTMLElement; - /** - * @hidden - */ - protected canPlayListener: EventListener; - /** - * @hidden - */ - private streamPlayingEventExceptionTimeout?: NodeJS.Timeout; - /** - * @hidden - */ - private lazyLaunchVideoElementCreatedEvent = false; - - /** - * @hidden - */ - constructor(stream: Stream, targetElement?: HTMLElement | string) { - super(); - platform = PlatformUtils.getInstance(); - this.stream = stream; - this.stream.streamManager = this; - this.remote = !this.stream.isLocal(); - - if (!!targetElement) { - let targEl; - if (typeof targetElement === 'string') { - targEl = document.getElementById(targetElement); - } else if (targetElement instanceof HTMLElement) { - targEl = targetElement; - } - - if (!!targEl) { - this.firstVideoElement = { - targetElement: targEl, - video: document.createElement('video'), - id: '', - canplayListenerAdded: false - }; - if ( - platform.isSafariBrowser() || - (platform.isIPhoneOrIPad() && - (platform.isChromeMobileBrowser() || - platform.isEdgeMobileBrowser() || - platform.isOperaMobileBrowser() || - platform.isFirefoxMobileBrowser())) - ) { - this.firstVideoElement.video.playsInline = true; - } - this.targetElement = targEl; - this.element = targEl; - } - } - - this.canPlayListener = () => { - this.deactivateStreamPlayingEventExceptionTimeout(); - this.ee.emitEvent('streamPlaying', [new StreamManagerEvent(this, 'streamPlaying', undefined)]); - }; - } - - /** - * See {@link EventDispatcher.on} - */ - on(type: K, handler: (event: StreamManagerEventMap[K]) => void): this { - super.onAux(type, "Event '" + type + "' triggered by '" + (this.remote ? 'Subscriber' : 'Publisher') + "'", handler); - - if (type === 'videoElementCreated') { - if (!!this.stream && this.lazyLaunchVideoElementCreatedEvent) { - this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(this.videos[0].video, this, 'videoElementCreated')]); - this.lazyLaunchVideoElementCreatedEvent = false; - } - } - if (type === 'streamPlaying') { - if ( - this.videos[0] && - this.videos[0].video && - this.videos[0].video.currentTime > 0 && - this.videos[0].video.paused === false && - this.videos[0].video.ended === false && - this.videos[0].video.readyState === 4 - ) { - this.ee.emitEvent('streamPlaying', [new StreamManagerEvent(this, 'streamPlaying', undefined)]); - } - } - if (this.stream.hasAudio) { - if (type === 'publisherStartSpeaking') { - this.stream.enableHarkSpeakingEvent(); - } - if (type === 'publisherStopSpeaking') { - this.stream.enableHarkStoppedSpeakingEvent(); - } - if (type === 'streamAudioVolumeChange') { - this.stream.enableHarkVolumeChangeEvent(false); - } - } - return this; - } - - /** - * See {@link EventDispatcher.once} - */ - once(type: K, handler: (event: StreamManagerEventMap[K]) => void): this { - super.onceAux(type, "Event '" + type + "' triggered once by '" + (this.remote ? 'Subscriber' : 'Publisher') + "'", handler); - - if (type === 'videoElementCreated') { - if (!!this.stream && this.lazyLaunchVideoElementCreatedEvent) { - this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(this.videos[0].video, this, 'videoElementCreated')]); - } - } - if (type === 'streamPlaying') { - if ( - this.videos[0] && - this.videos[0].video && - this.videos[0].video.currentTime > 0 && - this.videos[0].video.paused === false && - this.videos[0].video.ended === false && - this.videos[0].video.readyState === 4 - ) { - this.ee.emitEvent('streamPlaying', [new StreamManagerEvent(this, 'streamPlaying', undefined)]); - } - } - if (this.stream.hasAudio) { - if (type === 'publisherStartSpeaking') { - this.stream.enableOnceHarkSpeakingEvent(); - } - if (type === 'publisherStopSpeaking') { - this.stream.enableOnceHarkStoppedSpeakingEvent(); - } - if (type === 'streamAudioVolumeChange') { - this.stream.enableOnceHarkVolumeChangeEvent(false); - } - } - return this; - } - - /** - * See {@link EventDispatcher.off} - */ - off(type: K, handler?: (event: StreamManagerEventMap[K]) => void): this { - super.offAux(type, handler); - - if (type === 'publisherStartSpeaking') { - // Both StreamManager and Session can have "publisherStartSpeaking" event listeners - const remainingStartSpeakingEventListeners = - this.ee.getListeners(type).length + this.stream.session.ee.getListeners(type).length; - if (remainingStartSpeakingEventListeners === 0) { - this.stream.disableHarkSpeakingEvent(false); - } - } - if (type === 'publisherStopSpeaking') { - // Both StreamManager and Session can have "publisherStopSpeaking" event listeners - const remainingStopSpeakingEventListeners = - this.ee.getListeners(type).length + this.stream.session.ee.getListeners(type).length; - if (remainingStopSpeakingEventListeners === 0) { - this.stream.disableHarkStoppedSpeakingEvent(false); - } - } - if (type === 'streamAudioVolumeChange') { - // Only StreamManager can have "streamAudioVolumeChange" event listeners - const remainingVolumeEventListeners = this.ee.getListeners(type).length; - if (remainingVolumeEventListeners === 0) { - this.stream.disableHarkVolumeChangeEvent(false); - } - } - - return this; - } - - /** - * Makes `video` element parameter display this {@link stream}. This is useful when you are - * [managing the video elements on your own](/en/stable/cheatsheet/manage-videos/#you-take-care-of-the-video-players) - * - * Calling this method with a video already added to other Publisher/Subscriber will cause the video element to be - * disassociated from that previous Publisher/Subscriber and to be associated to this one. - * - * @returns 1 if the video wasn't associated to any other Publisher/Subscriber and has been successfully added to this one. - * 0 if the video was already added to this Publisher/Subscriber. -1 if the video was previously associated to any other - * Publisher/Subscriber and has been successfully disassociated from that one and properly added to this one. - */ - addVideoElement(video: HTMLVideoElement): number { - this.initializeVideoProperties(video); - - if (!this.remote && this.stream.displayMyRemote()) { - if (video.srcObject !== this.stream.getMediaStream()) { - video.srcObject = this.stream.getMediaStream(); - } - } - - // If the video element is already part of this StreamManager do nothing - for (const v of this.videos) { - if (v.video === video) { - return 0; - } - } - - let returnNumber = 1; - - for (const streamManager of this.stream.session.streamManagers) { - if (streamManager.disassociateVideo(video)) { - returnNumber = -1; - break; - } - } - - this.stream.session.streamManagers.forEach((streamManager) => { - streamManager.disassociateVideo(video); - }); - - this.pushNewStreamManagerVideo({ - video, - id: video.id, - canplayListenerAdded: false - }); - - logger.info('New video element associated to ', this); - - return returnNumber; - } - - /** - * Creates a new video element displaying this {@link stream}. This allows you to have multiple video elements displaying the same media stream. - * - * #### Events dispatched - * - * The Publisher/Subscriber object will dispatch a `videoElementCreated` event once the HTML video element has been added to DOM. See {@link VideoElementEvent} - * - * @param targetElement HTML DOM element (or its `id` attribute) in which the video element of the Publisher/Subscriber will be inserted - * @param insertMode How the video element will be inserted accordingly to `targetElemet` - * - * @returns The created HTMLVideoElement - */ - createVideoElement(targetElement?: string | HTMLElement, insertMode?: VideoInsertMode): HTMLVideoElement { - let targEl; - if (typeof targetElement === 'string') { - targEl = document.getElementById(targetElement); - if (!targEl) { - throw new Error("The provided 'targetElement' couldn't be resolved to any HTML element: " + targetElement); - } - } else if (targetElement instanceof HTMLElement) { - targEl = targetElement; - } else { - throw new Error("The provided 'targetElement' couldn't be resolved to any HTML element: " + targetElement); - } - - const video = this.createVideo(); - this.initializeVideoProperties(video); - - let insMode = !!insertMode ? insertMode : VideoInsertMode.APPEND; - switch (insMode) { - case VideoInsertMode.AFTER: - targEl.parentNode!!.insertBefore(video, targEl.nextSibling); - break; - case VideoInsertMode.APPEND: - targEl.appendChild(video); - break; - case VideoInsertMode.BEFORE: - targEl.parentNode!!.insertBefore(video, targEl); - break; - case VideoInsertMode.PREPEND: - targEl.insertBefore(video, targEl.childNodes[0]); - break; - case VideoInsertMode.REPLACE: - targEl.parentNode!!.replaceChild(video, targEl); - break; - default: - insMode = VideoInsertMode.APPEND; - targEl.appendChild(video); - break; - } - - const v: StreamManagerVideo = { - targetElement: targEl, - video, - insertMode: insMode, - id: video.id, - canplayListenerAdded: false - }; - this.pushNewStreamManagerVideo(v); - - this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(v.video, this, 'videoElementCreated')]); - this.lazyLaunchVideoElementCreatedEvent = !!this.firstVideoElement; - - return video; - } - - /** - * Updates the current configuration for the {@link PublisherSpeakingEvent} feature and the [StreamManagerEvent.streamAudioVolumeChange](/en/stable/api/openvidu-browser/classes/StreamManagerEvent.html) feature for this specific - * StreamManager audio stream, overriding the global options set with {@link OpenVidu.setAdvancedConfiguration}. This way you can customize the audio events options - * for each specific StreamManager and change them dynamically. - * - * @param publisherSpeakingEventsOptions New options to be applied to this StreamManager's audio stream. It is an object which includes the following optional properties: - * - `interval`: (number) how frequently the analyser polls the audio stream to check if speaking has started/stopped or audio volume has changed. Default **100** (ms) - * - `threshold`: (number) the volume at which _publisherStartSpeaking_, _publisherStopSpeaking_ events will be fired. Default **-50** (dB) - */ - updatePublisherSpeakingEventsOptions(publisherSpeakingEventsOptions: { interval?: number; threshold?: number }): void { - const currentHarkOptions = !!this.stream.harkOptions - ? this.stream.harkOptions - : this.stream.session.openvidu.advancedConfiguration.publisherSpeakingEventsOptions || {}; - const newInterval = - typeof publisherSpeakingEventsOptions.interval === 'number' - ? publisherSpeakingEventsOptions.interval - : typeof currentHarkOptions.interval === 'number' - ? currentHarkOptions.interval - : 100; - const newThreshold = - typeof publisherSpeakingEventsOptions.threshold === 'number' - ? publisherSpeakingEventsOptions.threshold - : typeof currentHarkOptions.threshold === 'number' - ? currentHarkOptions.threshold - : -50; - this.stream.harkOptions = { - interval: newInterval, - threshold: newThreshold - }; - if (!!this.stream.speechEvent) { - this.stream.speechEvent.setInterval(newInterval); - this.stream.speechEvent.setThreshold(newThreshold); - } - } - - /* Hidden methods */ - - /** - * @hidden - */ - initializeVideoProperties(video: HTMLVideoElement): void { - if (!(!this.remote && this.stream.displayMyRemote())) { - // Avoid setting the MediaStream into the srcObject if remote subscription before publishing - if (video.srcObject !== this.stream.getMediaStream()) { - // If srcObject already set don't do it again - video.srcObject = this.stream.getMediaStream(); - } - } - video.autoplay = true; - video.controls = false; - - if ( - platform.isSafariBrowser() || - (platform.isIPhoneOrIPad() && - (platform.isChromeMobileBrowser() || - platform.isEdgeMobileBrowser() || - platform.isOperaMobileBrowser() || - platform.isFirefoxMobileBrowser())) - ) { - video.playsInline = true; - } - - if (!video.id) { - video.id = (this.remote ? 'remote-' : 'local-') + 'video-' + this.stream.streamId; - // DEPRECATED property: assign once the property id if the user provided a valid targetElement - if (!this.id && !!this.targetElement) { - this.id = video.id; - } - } - - if (this.remote && this.isMirroredVideo(video)) { - // Subscriber video associated to a previously mirrored video element - this.removeMirrorVideo(video); - } else if (!this.remote && !this.stream.displayMyRemote()) { - // Publisher video - video.muted = true; - if (this.isMirroredVideo(video) && !this.stream.outboundStreamOpts.publisherProperties.mirror) { - // If the video was already rotated and now is set to not mirror - this.removeMirrorVideo(video); - } else if (this.stream.outboundStreamOpts.publisherProperties.mirror && !this.stream.isSendScreen()) { - // If the video is now set to mirror and is not screen share - this.mirrorVideo(video); - } - } - } - - /** - * @hidden - */ - removeAllVideos(): void { - for (let i = this.stream.session.streamManagers.length - 1; i >= 0; --i) { - if (this.stream.session.streamManagers[i] === this) { - this.stream.session.streamManagers.splice(i, 1); - } - } - - this.videos.forEach((streamManagerVideo) => { - // Remove oncanplay event listener (only OpenVidu browser listener, not the user ones) - if (!!streamManagerVideo.video && !!streamManagerVideo.video.removeEventListener) { - streamManagerVideo.video.removeEventListener('canplay', this.canPlayListener); - } - streamManagerVideo.canplayListenerAdded = false; - if (!!streamManagerVideo.targetElement) { - // Only remove from DOM videos created by OpenVidu Browser (those generated by passing a valid targetElement in OpenVidu.initPublisher - // and Session.subscribe or those created by StreamManager.createVideoElement). All this videos triggered a videoElementCreated event - streamManagerVideo.video.parentNode!.removeChild(streamManagerVideo.video); - this.ee.emitEvent('videoElementDestroyed', [ - new VideoElementEvent(streamManagerVideo.video, this, 'videoElementDestroyed') - ]); - } - // Remove srcObject from the video - this.removeSrcObject(streamManagerVideo); - // Remove from collection of videos every video managed by OpenVidu Browser - this.videos = this.videos.filter((v) => !v.targetElement); - }); - } - - /** - * @hidden - */ - disassociateVideo(video: HTMLVideoElement): boolean { - let disassociated = false; - for (let i = 0; i < this.videos.length; i++) { - if (this.videos[i].video === video) { - this.videos[i].video.removeEventListener('canplay', this.canPlayListener); - this.videos.splice(i, 1); - disassociated = true; - logger.info('Video element disassociated from ', this); - break; - } - } - return disassociated; - } - - /** - * @hidden - */ - addPlayEventToFirstVideo() { - if (!!this.videos[0] && !!this.videos[0].video && !this.videos[0].canplayListenerAdded) { - this.activateStreamPlayingEventExceptionTimeout(); - this.videos[0].video.addEventListener('canplay', this.canPlayListener); - this.videos[0].canplayListenerAdded = true; - } - } - - /** - * @hidden - */ - updateMediaStream(mediaStream: MediaStream) { - this.videos.forEach((streamManagerVideo) => { - streamManagerVideo.video.srcObject = mediaStream; - if (platform.isIonicIos()) { - // iOS Ionic. LIMITATION: must reinsert the video in the DOM for - // the media stream to be updated - const vParent = streamManagerVideo.video.parentElement; - const newVideo = streamManagerVideo.video; - vParent!!.replaceChild(newVideo, streamManagerVideo.video); - streamManagerVideo.video = newVideo; - } - }); - } - - /** - * @hidden - */ - emitEvent(type: string, eventArray: any[]): void { - this.ee.emitEvent(type, eventArray); - } - - /** - * @hidden - */ - createVideo(): HTMLVideoElement { - return document.createElement('video'); - } - - /** - * @hidden - */ - removeSrcObject(streamManagerVideo: StreamManagerVideo) { - streamManagerVideo.video.srcObject = null; - this.deactivateStreamPlayingEventExceptionTimeout(); - } - - /** - * @hidden - */ - abstract replaceTrackInMediaStream(track: MediaStreamTrack, updateLastConstraints: boolean): void; - - /* Private methods */ - - protected pushNewStreamManagerVideo(streamManagerVideo: StreamManagerVideo) { - this.videos.push(streamManagerVideo); - this.addPlayEventToFirstVideo(); - if (this.stream.session.streamManagers.indexOf(this) === -1) { - this.stream.session.streamManagers.push(this); - } - } - - private mirrorVideo(video: HTMLVideoElement): void { - if (!platform.isIonicIos()) { - video.style.transform = 'rotateY(180deg)'; - video.style.webkitTransform = 'rotateY(180deg)'; - } - } - - private removeMirrorVideo(video: HTMLVideoElement): void { - video.style.transform = 'unset'; - video.style.webkitTransform = 'unset'; - } - - private isMirroredVideo(video: HTMLVideoElement): boolean { - return video.style.transform === 'rotateY(180deg)' || video.style.webkitTransform === 'rotateY(180deg)'; - } - - private activateStreamPlayingEventExceptionTimeout() { - if (!this.remote) { - // ExceptionEvent NO_STREAM_PLAYING_EVENT is only for subscribers - return; - } - if (this.streamPlayingEventExceptionTimeout != null) { - // The timeout is already activated - return; - } - // Trigger ExceptionEvent NO_STREAM_PLAYING_EVENT if after timeout there is no 'canplay' event - const msTimeout = this.stream.session.openvidu.advancedConfiguration.noStreamPlayingEventExceptionTimeout || 4000; - this.streamPlayingEventExceptionTimeout = setTimeout(() => { - const msg = - 'StreamManager of Stream ' + - this.stream.streamId + - ' (' + - (this.remote ? 'Subscriber' : 'Publisher') + - ') did not trigger "streamPlaying" event in ' + - msTimeout + - ' ms'; - logger.warn(msg); - this.stream.session.emitEvent('exception', [ - new ExceptionEvent(this.stream.session, ExceptionEventName.NO_STREAM_PLAYING_EVENT, (this) as Subscriber, msg) - ]); - delete this.streamPlayingEventExceptionTimeout; - }, msTimeout); - } - - private deactivateStreamPlayingEventExceptionTimeout() { - clearTimeout(this.streamPlayingEventExceptionTimeout as any); - delete this.streamPlayingEventExceptionTimeout; - } -} diff --git a/openvidu-browser/src/OpenVidu/Subscriber.ts b/openvidu-browser/src/OpenVidu/Subscriber.ts deleted file mode 100644 index a49c8068e9..0000000000 --- a/openvidu-browser/src/OpenVidu/Subscriber.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Stream } from './Stream'; -import { StreamManager } from './StreamManager'; -import { SubscriberProperties } from '../OpenViduInternal/Interfaces/Public/SubscriberProperties'; -import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; - -/** - * @hidden - */ -const logger: OpenViduLogger = OpenViduLogger.getInstance(); - -/** - * Packs remote media streams. Participants automatically receive them when others publish their streams. Initialized with {@link Session.subscribe} method - * - * See available event listeners at {@link StreamManagerEventMap}. - */ -export class Subscriber extends StreamManager { - /** - * @hidden - */ - properties: SubscriberProperties; - - /** - * @hidden - */ - constructor(stream: Stream, targEl: string | HTMLElement | undefined, properties: SubscriberProperties) { - super(stream, targEl); - this.element = this.targetElement; - this.stream = stream; - this.properties = properties; - } - - /** - * Subscribe or unsubscribe from the audio stream (if available). Calling this method twice in a row passing same value will have no effect - * @param value `true` to subscribe to the audio stream, `false` to unsubscribe from it - */ - subscribeToAudio(value: boolean): Subscriber { - this.stream - .getMediaStream() - .getAudioTracks() - .forEach((track) => { - track.enabled = value; - }); - this.stream.audioActive = value; - logger.info("'Subscriber' has " + (value ? 'subscribed to' : 'unsubscribed from') + ' its audio stream'); - return this; - } - - /** - * Subscribe or unsubscribe from the video stream (if available). Calling this method twice in a row passing same value will have no effect - * @param value `true` to subscribe to the video stream, `false` to unsubscribe from it - */ - subscribeToVideo(value: boolean): Subscriber { - this.stream - .getMediaStream() - .getVideoTracks() - .forEach((track) => { - track.enabled = value; - }); - this.stream.videoActive = value; - logger.info("'Subscriber' has " + (value ? 'subscribed to' : 'unsubscribed from') + ' its video stream'); - return this; - } - - /* Hidden methods */ - - /** - * @hidden - */ - replaceTrackInMediaStream(track: MediaStreamTrack, updateLastConstraints: boolean): void { - const mediaStream: MediaStream = this.stream.getMediaStream(); - let removedTrack: MediaStreamTrack; - if (track.kind === 'video') { - removedTrack = mediaStream.getVideoTracks()[0]; - if (updateLastConstraints) { - this.stream.lastVideoTrackConstraints = track.getConstraints(); - } - } else { - removedTrack = mediaStream.getAudioTracks()[0]; - } - mediaStream.removeTrack(removedTrack); - removedTrack.stop(); - mediaStream.addTrack(track); - } -} diff --git a/openvidu-browser/src/OpenVidu/tsconfig.json b/openvidu-browser/src/OpenVidu/tsconfig.json deleted file mode 100644 index ff476291e2..0000000000 --- a/openvidu-browser/src/OpenVidu/tsconfig.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - //"allowUnusedLabels": true, - "allowUnreachableCode": false, - "buildOnSave": false, - "compileOnSave": true, - "compilerOptions": { - "allowJs": true, - "allowSyntheticDefaultImports": true, - "emitBOM": false, - "forceConsistentCasingInFileNames": true, - "lib": [ - "dom", - "es2015.promise", - "es5", - "scripthost" - ], - "module": "commonjs", - "noFallthroughCasesInSwitch": true, - //"noImplicitAny": true, - "noImplicitReturns": true, - "noImplicitThis": true, - //"noUnusedLocals": true, - //"noUnusedParameters": true, - "outDir": "../../lib", - "preserveConstEnums": true, - "removeComments": true, - "skipDefaultLibCheck": true, - "skipLibCheck": true, - "sourceMap": true, - "strictNullChecks": true, - "suppressExcessPropertyErrors": true, - "suppressImplicitAnyIndexErrors": true, - "target": "es5" - } -} \ No newline at end of file diff --git a/openvidu-browser/src/OpenViduInternal/Enums/LocalRecorderState.ts b/openvidu-browser/src/OpenViduInternal/Enums/LocalRecorderState.ts deleted file mode 100644 index ac815d7a7f..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Enums/LocalRecorderState.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -export enum LocalRecorderState { - READY = 'READY', - RECORDING = 'RECORDING', - PAUSED = 'PAUSED', - FINISHED = 'FINISHED' -} diff --git a/openvidu-browser/src/OpenViduInternal/Enums/OpenViduError.ts b/openvidu-browser/src/OpenViduInternal/Enums/OpenViduError.ts deleted file mode 100644 index a3b08e2c6d..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Enums/OpenViduError.ts +++ /dev/null @@ -1,141 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * Defines property {@link OpenViduError.name} - */ -export enum OpenViduErrorName { - /** - * Browser is not supported by OpenVidu. - * Returned upon unsuccessful {@link Session.connect} - */ - BROWSER_NOT_SUPPORTED = 'BROWSER_NOT_SUPPORTED', - - /** - * The user hasn't granted permissions to the required input device when the browser asked for them. - * Returned upon unsuccessful {@link OpenVidu.initPublisher} or {@link OpenVidu.getUserMedia} - */ - DEVICE_ACCESS_DENIED = 'DEVICE_ACCESS_DENIED', - - /** - * The required input device is probably being used by other process when the browser asked for it. - * This error can also be triggered when the user granted permission to use the devices but a hardware - * error occurred at the OS, browser or web page level, which prevented access to the device. - * Returned upon unsuccessful {@link OpenVidu.initPublisher} or {@link OpenVidu.getUserMedia} - */ - DEVICE_ALREADY_IN_USE = 'DEVICE_ALREADY_IN_USE', - - /** - * The user hasn't granted permissions to capture some desktop screen when the browser asked for them. - * Returned upon unsuccessful {@link OpenVidu.initPublisher} or {@link OpenVidu.getUserMedia} - */ - SCREEN_CAPTURE_DENIED = 'SCREEN_CAPTURE_DENIED', - - /** - * Browser does not support screen sharing. - * Returned upon unsuccessful {@link OpenVidu.initPublisher} or {@link OpenVidu.getUserMedia} - */ - SCREEN_SHARING_NOT_SUPPORTED = 'SCREEN_SHARING_NOT_SUPPORTED', - - /** - * Only for Chrome, there's no screen sharing extension installed - * Returned upon unsuccessful {@link OpenVidu.initPublisher} or {@link OpenVidu.getUserMedia} - */ - SCREEN_EXTENSION_NOT_INSTALLED = 'SCREEN_EXTENSION_NOT_INSTALLED', - - /** - * Only for Chrome, the screen sharing extension is installed but is disabled - * Returned upon unsuccessful {@link OpenVidu.initPublisher} or {@link OpenVidu.getUserMedia} - */ - SCREEN_EXTENSION_DISABLED = 'SCREEN_EXTENSION_DISABLED', - - /** - * No video input device found with the provided deviceId (property {@link PublisherProperties.videoSource}) - * Returned upon unsuccessful {@link OpenVidu.initPublisher} or {@link OpenVidu.getUserMedia} - */ - INPUT_VIDEO_DEVICE_NOT_FOUND = 'INPUT_VIDEO_DEVICE_NOT_FOUND', - - /** - * No audio input device found with the provided deviceId (property {@link PublisherProperties.audioSource}) - * Returned upon unsuccessful {@link OpenVidu.initPublisher} or {@link OpenVidu.getUserMedia} - */ - INPUT_AUDIO_DEVICE_NOT_FOUND = 'INPUT_AUDIO_DEVICE_NOT_FOUND', - - /** - * There was an unknown error when trying to access the specified audio device - * Returned upon unsuccessful {@link OpenVidu.initPublisher} or {@link OpenVidu.getUserMedia} - */ - INPUT_AUDIO_DEVICE_GENERIC_ERROR = 'INPUT_AUDIO_DEVICE_GENERIC_ERROR', - - /** - * Method {@link OpenVidu.initPublisher} or {@link OpenVidu.getUserMedia} has been called with properties `videoSource` and `audioSource` of - * {@link PublisherProperties} parameter both set to *false* or *null* - */ - NO_INPUT_SOURCE_SET = 'NO_INPUT_SOURCE_SET', - - /** - * Some media property of {@link PublisherProperties} such as `frameRate` or `resolution` is not supported - * by the input devices (whenever it is possible they are automatically adjusted to the most similar value). - * Returned upon unsuccessful {@link OpenVidu.initPublisher} or {@link OpenVidu.getUserMedia} - */ - PUBLISHER_PROPERTIES_ERROR = 'PUBLISHER_PROPERTIES_ERROR', - - /** - * The client tried to call a method without the required permissions. This can occur for methods {@link Session.publish}, - * {@link Session.forceUnpublish}, {@link Session.forceDisconnect}, {@link Stream.applyFilter}, {@link Stream.removeFilter} - */ - OPENVIDU_PERMISSION_DENIED = 'OPENVIDU_PERMISSION_DENIED', - - /** - * There is no connection to the Session. This error will be thrown when any method requiring a connection to - * openvidu-server is called before successfully calling method {@link Session.connect} - */ - OPENVIDU_NOT_CONNECTED = 'OPENVIDU_NOT_CONNECTED', - - /** - * Error related to [Virtual Background](/en/stable/advanced-features/virtual-background/) - */ - VIRTUAL_BACKGROUND_ERROR = 'VIRTUAL_BACKGROUND_ERROR', - - /** - * Generic error - */ - GENERIC_ERROR = 'GENERIC_ERROR' -} - -/** - * Simple object to identify runtime errors on the client side - */ -export class OpenViduError { - /** - * Uniquely identifying name of the error - */ - name: OpenViduErrorName; - - /** - * Full description of the error - */ - message: string; - - /** - * @hidden - */ - constructor(name: OpenViduErrorName, message: string) { - this.name = name; - this.message = message; - } -} diff --git a/openvidu-browser/src/OpenViduInternal/Enums/TypeOfVideo.ts b/openvidu-browser/src/OpenViduInternal/Enums/TypeOfVideo.ts deleted file mode 100644 index 863d911b79..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Enums/TypeOfVideo.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -export enum TypeOfVideo { - CAMERA = 'CAMERA', - SCREEN = 'SCREEN', - CUSTOM = 'CUSTOM', - IPCAM = 'IPCAM' -} diff --git a/openvidu-browser/src/OpenViduInternal/Enums/VideoInsertMode.ts b/openvidu-browser/src/OpenViduInternal/Enums/VideoInsertMode.ts deleted file mode 100644 index 0aa16dc293..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Enums/VideoInsertMode.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * How the video will be inserted in the DOM for Publishers and Subscribers. See {@link PublisherProperties.insertMode} and {@link SubscriberProperties.insertMode} - */ -export enum VideoInsertMode { - /** - * Video inserted after the target element (as next sibling) - */ - AFTER = 'AFTER', - /** - * Video inserted as last child of the target element - */ - APPEND = 'APPEND', - /** - * Video inserted before the target element (as previous sibling) - */ - BEFORE = 'BEFORE', - /** - * Video inserted as first child of the target element - */ - PREPEND = 'PREPEND', - /** - * Video replaces target element - */ - REPLACE = 'REPLACE' -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/ConnectionEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/ConnectionEvent.ts deleted file mode 100644 index b32983f1fc..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/ConnectionEvent.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Event } from './Event'; -import { Connection } from '../../OpenVidu/Connection'; -import { Session } from '../../OpenVidu/Session'; -import { ConnectionEventReason } from './Types/Types'; - -/** - * Triggered by: - * - {@link SessionEventMap.connectionCreated} - * - {@link SessionEventMap.connectionDestroyed} - */ -export class ConnectionEvent extends Event { - /** - * Connection object that was created or destroyed - */ - connection: Connection; - - /** - * For `connectionDestroyed` event: - * - "disconnect": the remote user has called `Session.disconnect()` - * - "forceDisconnectByUser": the remote user has been evicted from the Session by other user calling `Session.forceDisconnect()` - * - "forceDisconnectByServer": the remote user has been evicted from the Session by the application - * - "sessionClosedByServer": the Session has been closed by the application - * - "networkDisconnect": the remote user network connection has dropped - * - "nodeCrashed": a node has crashed in the server side - * - * For `connectionCreated` event an empty string - */ - reason: ConnectionEventReason; - - /** - * @hidden - */ - constructor(cancelable: boolean, target: Session, type: string, connection: Connection, reason: ConnectionEventReason) { - super(cancelable, target, type); - this.connection = connection; - this.reason = reason; - } - - /** - * @hidden - */ - // tslint:disable-next-line:no-empty - callDefaultBehavior() { } -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/ConnectionPropertyChangedEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/ConnectionPropertyChangedEvent.ts deleted file mode 100644 index 42d328abb3..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/ConnectionPropertyChangedEvent.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Connection } from '../../OpenVidu/Connection'; -import { Session } from '../../OpenVidu/Session'; -import { Event } from './Event'; - -/** - * **This feature is part of OpenVidu - * PRO - * and - * ENTERPRISE - * editions** - * - * Triggered by {@link SessionEventMap.connectionPropertyChanged} - */ -export class ConnectionPropertyChangedEvent extends Event { - /** - * The Connection whose property has changed - */ - connection: Connection; - - /** - * The property of the stream that changed. This value is either `"role"` or `"record"` - */ - changedProperty: string; - - /** - * New value of the property (after change, current value) - */ - newValue: Object; - - /** - * Previous value of the property (before change) - */ - oldValue: Object; - - /** - * @hidden - */ - constructor(target: Session, connection: Connection, changedProperty: string, newValue: Object, oldValue: Object) { - super(false, target, 'connectionPropertyChanged'); - this.connection = connection; - this.changedProperty = changedProperty; - this.newValue = newValue; - this.oldValue = oldValue; - } - - /** - * @hidden - */ - // tslint:disable-next-line:no-empty - callDefaultBehavior() {} -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/Event.ts b/openvidu-browser/src/OpenViduInternal/Events/Event.ts deleted file mode 100644 index f19b7e38dc..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/Event.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Filter } from '../../OpenVidu/Filter'; -import { StreamManager } from '../../OpenVidu/StreamManager'; -import { Session } from '../../OpenVidu/Session'; - -export abstract class Event { - /** - * Whether the event has a default behavior that may be prevented by calling {@link Event.preventDefault} - */ - cancelable: boolean; - - /** - * The object that dispatched the event - */ - target: Session | StreamManager | Filter; - - /** - * The type of event. This is the same string you pass as first parameter when calling method `on()` of any object implementing {@link EventDispatcher} interface - */ - type: string; - - /** - * @hidden - */ - hasBeenPrevented = false; - - /** - * @hidden - */ - constructor(cancelable: boolean, target: Session | StreamManager | Filter, type: string) { - this.cancelable = cancelable; - this.target = target; - this.type = type; - } - - /** - * Whether the default beahivour of the event has been prevented or not. Call {@link Event.preventDefault} to prevent it - */ - isDefaultPrevented(): boolean { - return this.hasBeenPrevented; - } - - /** - * Prevents the default behavior of the event. The following events have a default behavior: - * - * - `sessionDisconnected`: dispatched by {@link Session} object, automatically unsubscribes the leaving participant from every Subscriber object of the session (this includes closing the RTCPeerConnection and disposing all MediaStreamTracks) - * and also deletes any HTML video element associated to each Subscriber (only those created by OpenVidu Browser, either by passing a valid parameter as `targetElement` in method {@link Session.subscribe} or - * by calling {@link Subscriber.createVideoElement}). For every video removed, each Subscriber object will also dispatch a `videoElementDestroyed` event. - * - * - `streamDestroyed`: - * - If dispatched by a {@link Publisher} (*you* have unpublished): automatically stops all media tracks and deletes any HTML video element associated to it (only those created by OpenVidu Browser, either by passing a valid parameter as `targetElement` - * in method {@link OpenVidu.initPublisher} or by calling {@link Publisher.createVideoElement}). For every video removed, the Publisher object will also dispatch a `videoElementDestroyed` event. - * - If dispatched by {@link Session} (*other user* has unpublished): automatically unsubscribes the proper Subscriber object from the session (this includes closing the RTCPeerConnection and disposing all MediaStreamTracks) - * and also deletes any HTML video element associated to that Subscriber (only those created by OpenVidu Browser, either by passing a valid parameter as `targetElement` in method {@link Session.subscribe} or - * by calling {@link Subscriber.createVideoElement}). For every video removed, the Subscriber object will also dispatch a `videoElementDestroyed` event. - */ - preventDefault() { - // tslint:disable-next-line:no-empty - this.callDefaultBehavior = () => {}; - this.hasBeenPrevented = true; - } - - /** - * @hidden - */ - abstract callDefaultBehavior(); -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/EventMap/EventMap.ts b/openvidu-browser/src/OpenViduInternal/Events/EventMap/EventMap.ts deleted file mode 100644 index 3a74210e5f..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/EventMap/EventMap.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * All OpenVidu Browser events inherit from this interface - */ -export interface EventMap {} diff --git a/openvidu-browser/src/OpenViduInternal/Events/EventMap/PublisherEventMap.ts b/openvidu-browser/src/OpenViduInternal/Events/EventMap/PublisherEventMap.ts deleted file mode 100644 index acae11cccb..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/EventMap/PublisherEventMap.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { StreamEvent } from '../StreamEvent'; -import { StreamManagerEventMap } from './StreamManagerEventMap'; - -/** - * Events dispatched by {@link Publisher} object. Manage event listeners with - * {@link Publisher.on}, {@link Publisher.once} and {@link Publisher.off} methods. - * - * Example: - * - * ```javascript - * publisher.on('accessDenied', () => { - * console.error('Camera access has been denied!'); - * } - * - * publisher.off('accessDenied'); - * ``` - */ -export interface PublisherEventMap extends StreamManagerEventMap { - /** - * Event dispatched when the {@link Publisher} has been published to the session (see {@link Session.publish}). - */ - streamCreated: StreamEvent; - - /** - * Event dispatched when the {@link Publisher} has been unpublished from the session. - */ - streamDestroyed: StreamEvent; - - /** - * Event dispatched when a Publisher tries to access some media input device and has the required permissions to do so. - * - * This happens when calling {@link OpenVidu.initPublisher} or {@link OpenVidu.initPublisherAsync} and the application - * has permissions to use the devices. This usually means the user has accepted the permissions dialog that the - * browser will show when trying to access the camera/microphone/screen. - */ - accessAllowed: never; - - /** - * Event dispatched when a Publisher tries to access some media input device and does NOT have the required permissions to do so. - * - * This happens when calling {@link OpenVidu.initPublisher} or {@link OpenVidu.initPublisherAsync} and the application - * lacks the required permissions to use the devices. This usually means the user has NOT accepted the permissions dialog that the - * browser will show when trying to access the camera/microphone/screen. - */ - accessDenied: never; - - /** - * Event dispatched when the pop-up shown by the browser to request permissions for the input media devices is opened. - * - * You can use this event to alert the user about granting permissions for your website. Note that this event is artificially - * generated based only on time intervals when accessing media devices. A heavily overloaded client device that simply takes more - * than usual to access the media device could produce a false trigger of this event. - */ - accessDialogOpened: never; - - /** - * Event dispatched after the user clicks on "Allow" or "Block" in the pop-up shown by the browser to request permissions - * for the input media devices. - * - * This event can only be triggered after an {@link accessDialogOpened} event has been previously triggered. - */ - accessDialogClosed: never; -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/EventMap/SessionEventMap.ts b/openvidu-browser/src/OpenViduInternal/Events/EventMap/SessionEventMap.ts deleted file mode 100644 index 0e7f76a395..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/EventMap/SessionEventMap.ts +++ /dev/null @@ -1,225 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { EventMap } from './EventMap'; -import { ConnectionEvent } from '../ConnectionEvent'; -import { ConnectionPropertyChangedEvent } from '../ConnectionPropertyChangedEvent'; -import { ExceptionEvent } from '../ExceptionEvent'; -import { NetworkQualityLevelChangedEvent } from '../NetworkQualityLevelChangedEvent'; -import { PublisherSpeakingEvent } from '../PublisherSpeakingEvent'; -import { RecordingEvent } from '../RecordingEvent'; -import { SessionDisconnectedEvent } from '../SessionDisconnectedEvent'; -import { SignalEvent } from '../SignalEvent'; -import { SpeechToTextEvent } from '../SpeechToTextEvent'; -import { StreamEvent } from '../StreamEvent'; -import { StreamPropertyChangedEvent } from '../StreamPropertyChangedEvent'; - -/** - * Events dispatched by {@link Session} object. Manage event listeners with - * {@link Session.on}, {@link Session.once} and {@link Session.off} methods. - * - * Example: - * - * ```javascript - * session.on('connectionCreated', (event) => { - * console.log('Connection ' + event.connection.connectionId + ' created'); - * } - * - * session.off('connectionDestroyed'); - * ``` - */ -export interface SessionEventMap extends EventMap { - /** - * Event dispatched when a new user has connected to the session. - * - * It is fired for both the local user and remote users. - */ - connectionCreated: ConnectionEvent; - - /** - * Event dispatched when a remote user has left the session. - * - * For the local user see {@link sessionDisconnected}. - */ - connectionDestroyed: ConnectionEvent; - - /** - * **This feature is part of OpenVidu - * PRO - * and - * ENTERPRISE - * editions** - * - * Event dispatched when a property of the local {@link Connection} object changes. - * - * It is fired only for the local user. - * - * The properties that may change are {@link Connection.role} and {@link Connection.record}. - * The only way the Connection properties may change is by updating them through: - * - * - [API REST](/en/stable/reference-docs/REST-API/#patch-connection) - * - [openvidu-java-client](/en/stable/reference-docs/openvidu-java-client/#update-a-connection) - * - [openvidu-node-client](/en/stable/reference-docs/openvidu-node-client/#update-a-connection)

- */ - connectionPropertyChanged: ConnectionPropertyChangedEvent; - - /** - * Event dispatched when the local user has left the session. - * - * For remote users see {@link connectionDestroyed}. - */ - sessionDisconnected: SessionDisconnectedEvent; - - /** - * Event dispatched when a user has started publishing media to the session (see {@link Session.publish}). - * - * It is fired for both the local user and remote users. - */ - streamCreated: StreamEvent; - - /** - * Event dispatched when a user stops publishing media to the session. - * - * It is fired for both the local user and remote users. - */ - streamDestroyed: StreamEvent; - - /** - * Event dispatched when a Stream undergoes any change in any of its mutable properties - * (see {@link StreamPropertyChangedEvent.changedProperty}). - * - * It is fired for both remote streams (owned by a {@link Subscriber}) or local streams (owned by a {@link Publisher}). - */ - streamPropertyChanged: StreamPropertyChangedEvent; - - /** - * Event dispatched when a user has started speaking. - * - * It is fired for both the local user and remote users. - * - * Extra information: - * - This event will only be triggered for **streams that have audio tracks** ({@link Stream.hasAudio} must be true). - * - Further configuration can be applied on how the event is dispatched by setting property `publisherSpeakingEventsOptions` in the call of {@link OpenVidu.setAdvancedConfiguration}. - */ - publisherStartSpeaking: PublisherSpeakingEvent; - - /** - * Event dispatched when a user has stopped speaking. - * - * It is fired for both the local user and remote users. - * - * Extra information: - * - This event will only be triggered for **streams that have audio tracks** ({@link Stream.hasAudio} must be true). - * - Further configuration can be applied on how the event is dispatched by setting property `publisherSpeakingEventsOptions` in the call of {@link OpenVidu.setAdvancedConfiguration}. - */ - publisherStopSpeaking: PublisherSpeakingEvent; - - /** - * @hidden - */ - [key: `signal:${string}`]: SignalEvent; - - /** - * Event dispatched when a signal is received (see [Send text messages between users](/en/stable/cheatsheet/send-messages)). - * - * If the listener is added as **`signal:TYPE`**, only signals of type **`TYPE`** will trigger the event. - */ - signal: SignalEvent; - - /** - * Event dispatched when the session has started being recorded. - * - * Property **`OPENVIDU_RECORDING_NOTIFICATION`** of [the OpenVidu deployment configuration](/en/stable/reference-docs/openvidu-config/) - * defines which users should receive this events (by default, only users with role `PUBLISHER` or `MODERATOR`) - */ - recordingStarted: RecordingEvent; - - /** - * Event dispatched when the session has stopped being recorded. - * - * Property **`OPENVIDU_RECORDING_NOTIFICATION`** of [the OpenVidu deployment configuration](/en/stable/reference-docs/openvidu-config/) - * defines which users should receive this events (by default, only users with role `PUBLISHER` or `MODERATOR`) - */ - recordingStopped: RecordingEvent; - - /** - * **This feature is part of OpenVidu - * PRO - * and - * ENTERPRISE - * editions** - * - * Event dispatched when the session has started being broadcasted. See [Broadcast to YouTube/Twitch](/en/stable/advanced-features/broadcast/) - */ - broadcastStarted: never; - - /** - * **This feature is part of OpenVidu - * PRO - * and - * ENTERPRISE - * editions** - * - * Event dispatched when the session has stopped being broadcasted. See [Broadcast to YouTube/Twitch](/en/stable/advanced-features/broadcast/) - */ - broadcastStopped: never; - - /** - * **This feature is part of OpenVidu - * PRO - * and - * ENTERPRISE - * editions** - * - * Event dispatched when the network quality level of a {@link Connection} changes. See [network quality](/en/stable/advanced-features/network-quality/). - */ - networkQualityLevelChanged: NetworkQualityLevelChangedEvent; - - /** - * **This feature is part of OpenVidu - * PRO - * and - * ENTERPRISE - * editions** - * - * Event dispatched when a speech-to-text message has been received for certain Stream. See [Speech To Text](/en/stable/advanced-features/speech-to-text/). - */ - speechToTextMessage: SpeechToTextEvent; - - /** - * Event dispatched when the local user has lost its connection to the session, and starts the automatic reconnection process. - * - * See [Reconnection events](/en/stable/advanced-features/automatic-reconnection/#reconnection-events). - */ - reconnecting: never; - - /** - * Event dispatched when the local user has successfully recovered its connection to the session after losing it. - * - * If the connection was recovered but OpenVidu Server already evicted the user due to timeout, then this event will - * not be dispatched. A {@link sessionDisconnected} event with reason `networkDisconnect` will be triggered instead. - * - * See [Reconnection events](/en/stable/advanced-features/automatic-reconnection/#reconnection-events). - */ - reconnected: never; - - /** - * This event acts as a global handler for asynchronous errors that may be triggered for multiple reasons and from multiple origins. - * To see the different types of exceptions go to {@link ExceptionEventName}. - */ - exception: ExceptionEvent; -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/EventMap/StreamManagerEventMap.ts b/openvidu-browser/src/OpenViduInternal/Events/EventMap/StreamManagerEventMap.ts deleted file mode 100644 index 47b78d0812..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/EventMap/StreamManagerEventMap.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { EventMap } from './EventMap'; -import { PublisherSpeakingEvent } from '../PublisherSpeakingEvent'; -import { StreamManagerEvent } from '../StreamManagerEvent'; -import { StreamPropertyChangedEvent } from '../StreamPropertyChangedEvent'; -import { VideoElementEvent } from '../VideoElementEvent'; - -/** - * Events dispatched by {@link StreamManager} object. Manage event listeners with - * {@link StreamManager.on}, {@link StreamManager.once} and {@link StreamManager.off} methods. - * - * Example: - * - * ```javascript - * streamManager.on('videoElementCreated', (event) => { - * console.log('New video element created:', event.element); - * } - * - * streamManager.off('videoElementCreated'); - * ``` - */ -export interface StreamManagerEventMap extends EventMap { - /** - * Event dispatched when a new HTML video element has been inserted into DOM by OpenVidu Browser library. See - * [Manage video players](/en/stable/cheatsheet/manage-videos) section. - */ - videoElementCreated: VideoElementEvent; - - /** - * Event dispatched when an HTML video element has been removed from DOM by OpenVidu Browser library. See - * [Manage video players](/en/stable/cheatsheet/manage-videos) section. - */ - videoElementDestroyed: VideoElementEvent; - - /** - * Event dispatched when the media stream starts playing (one of its videos has media and has begun to play). - * This event will be dispatched when these 3 conditions are met: - * 1. The StreamManager has no video associated in the DOM. - * 2. It is associated to one video. - * 3. That video starts playing. Internally the expected Web API event is [HTMLMediaElement.canplay](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canplay_event). - */ - streamPlaying: StreamManagerEvent; - - /** - * Event dispatched when the volume of the media stream's audio track changes. Only applies if {@link Stream.hasAudio} is `true`. - * The frequency this event is fired with is defined by property `interval` of - * {@link OpenViduAdvancedConfiguration.publisherSpeakingEventsOptions} (default 100ms) - */ - streamAudioVolumeChange: StreamManagerEvent; - - /** - * Event dispatched when a Stream undergoes any change in any of its mutable properties - * (see {@link StreamPropertyChangedEvent.changedProperty}). - */ - streamPropertyChanged: StreamPropertyChangedEvent; - - /** - * Event dispatched when the user owning the stream has started speaking. - * - * Extra information: - * - This event will only be triggered for **streams that have audio tracks** ({@link Stream.hasAudio} must be true). - * - Further configuration can be applied on how the event is dispatched by setting property `publisherSpeakingEventsOptions` in the call of {@link OpenVidu.setAdvancedConfiguration}. - */ - publisherStartSpeaking: PublisherSpeakingEvent; - - /** - * Event dispatched when the user owning the stream has stopped speaking. - * - * Extra information: - * - This event will only be triggered for **streams that have audio tracks** ({@link Stream.hasAudio} must be true). - * - Further configuration can be applied on how the event is dispatched by setting property `publisherSpeakingEventsOptions` in the call of {@link OpenVidu.setAdvancedConfiguration}. - */ - publisherStopSpeaking: PublisherSpeakingEvent; -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/ExceptionEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/ExceptionEvent.ts deleted file mode 100644 index e807b4524a..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/ExceptionEvent.ts +++ /dev/null @@ -1,136 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Session } from '../../OpenVidu/Session'; -import { Stream } from '../../OpenVidu/Stream'; -import { Subscriber } from '../../OpenVidu/Subscriber'; -import { Event } from './Event'; - -/** - * Defines property {@link ExceptionEvent.name} - */ -export enum ExceptionEventName { - /** - * There was an unexpected error on the server-side processing an ICE candidate generated and sent by the client-side. - * - * {@link ExceptionEvent} objects with this {@link ExceptionEvent.name} will have as {@link ExceptionEvent.origin} property a {@link Session} object. - */ - ICE_CANDIDATE_ERROR = 'ICE_CANDIDATE_ERROR', - - /** - * The [ICE connection state](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceConnectionState) - * of an [RTCPeerConnection](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection) reached `failed` status. - * - * This is a terminal error that won't have any kind of possible recovery. If the client is still connected to OpenVidu Server, - * then an automatic reconnection process of the media stream is immediately performed. If the ICE connection has broken due to - * a total network drop, then no automatic reconnection process will be possible. - * - * {@link ExceptionEvent} objects with this {@link ExceptionEvent.name} will have as {@link ExceptionEvent.origin} property a {@link Stream} object. - */ - ICE_CONNECTION_FAILED = 'ICE_CONNECTION_FAILED', - - /** - * The [ICE connection state](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceConnectionState) - * of an [RTCPeerConnection](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection) reached `disconnected` status. - * - * This is not a terminal error, and it is possible for the ICE connection to be reconnected. If the client is still connected to - * OpenVidu Server and after certain timeout the ICE connection has not reached a success or terminal status, then an automatic - * reconnection process of the media stream is performed. If the ICE connection has broken due to a total network drop, then no - * automatic reconnection process will be possible. - * - * You can customize the timeout for the reconnection attempt with property {@link OpenViduAdvancedConfiguration.iceConnectionDisconnectedExceptionTimeout}, - * which by default is 4000 milliseconds. - * - * {@link ExceptionEvent} objects with this {@link ExceptionEvent.name} will have as {@link ExceptionEvent.origin} property a {@link Stream} object. - */ - ICE_CONNECTION_DISCONNECTED = 'ICE_CONNECTION_DISCONNECTED', - - /** - * A {@link Subscriber} object has not fired event `streamPlaying` after certain timeout. `streamPlaying` event belongs to {@link StreamManagerEvent} - * category. It wraps Web API native event [canplay](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canplay_event). - * - * OpenVidu Browser can take care of the video players (see [here](/en/stable/cheatsheet/manage-videos/#let-openvidu-take-care-of-the-video-players)), - * or you can take care of video players on your own (see [here](/en/stable/cheatsheet/manage-videos/#you-take-care-of-the-video-players)). - * Either way, whenever a {@link Subscriber} object is commanded to attach its {@link Stream} to a video element, it is supposed to fire `streamPlaying` - * event shortly after. If it does not, then we can safely assume that something wrong has happened while playing the remote video and the - * application may be notified through this specific ExceptionEvent. - * - * The timeout can be configured with property {@link OpenViduAdvancedConfiguration.noStreamPlayingEventExceptionTimeout}. By default it is 4000 milliseconds. - * - * This is just an informative exception. It only means that a remote Stream that is supposed to be playing by a video player has not done so - * in a reasonable time. But the lack of the event can be caused by multiple reasons. If a Subscriber is not playing its Stream, the origin - * of the problem could be located at the Publisher side. Or may be caused by a transient network problem. But it also could be a problem with - * autoplay permissions. Bottom line, the cause can be very varied, and depending on the application the lack of the event could even be expected. - * - * {@link ExceptionEvent} objects with this {@link ExceptionEvent.name} will have as {@link ExceptionEvent.origin} property a {@link Subscriber} object. - */ - NO_STREAM_PLAYING_EVENT = 'NO_STREAM_PLAYING_EVENT', - - /** - * There has been a server-side disconnection of the Speech To Text module. From the moment this exception is fired to the moment method - * {@link Session.subscribeToSpeechToText} is called again, the transcription of the audio stream will not be available and no {@link SpeechToTextEvent} - * will be fired. - * - * {@link ExceptionEvent} objects with this {@link ExceptionEvent.name} will have as {@link ExceptionEvent.origin} property a {@link Session} object. - */ - SPEECH_TO_TEXT_DISCONNECTED = 'SPEECH_TO_TEXT_DISCONNECTED', -} - -/** - * Triggered by {@link SessionEventMap.exception} - */ -export class ExceptionEvent extends Event { - /** - * Name of the exception - */ - name: ExceptionEventName; - - /** - * Object affected by the exception. Depending on the {@link ExceptionEvent.name} property: - * - {@link Session}: `ICE_CANDIDATE_ERROR` - * - {@link Stream}: `ICE_CONNECTION_FAILED`, `ICE_CONNECTION_DISCONNECTED` - * - {@link Subscriber}: `NO_STREAM_PLAYING_EVENT` - */ - origin: Session | Stream | Subscriber; - - /** - * Informative description of the exception - */ - message: string; - - /** - * Any extra information associated to the exception - */ - data?: any; - - /** - * @hidden - */ - constructor(session: Session, name: ExceptionEventName, origin: Session | Stream | Subscriber, message: string, data?: any) { - super(false, session, 'exception'); - this.name = name; - this.origin = origin; - this.message = message; - this.data = data; - } - - /** - * @hidden - */ - // tslint:disable-next-line:no-empty - callDefaultBehavior() { } -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/FilterEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/FilterEvent.ts deleted file mode 100644 index 9b62c8ebf3..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/FilterEvent.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Event } from './Event'; -import { Filter } from '../../OpenVidu/Filter'; - -/** - * Defines every event dispatched by audio/video stream filters. You can subscribe to filter events by calling {@link Filter.addEventListener} - */ -export class FilterEvent extends Event { - /** - * Data of the event - */ - data: Object; - - /** - * @hidden - */ - constructor(target: Filter, eventType: string, data: Object) { - super(false, target, eventType); - this.data = data; - } - - /** - * @hidden - */ - // tslint:disable-next-line:no-empty - callDefaultBehavior() {} -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/NetworkQualityLevelChangedEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/NetworkQualityLevelChangedEvent.ts deleted file mode 100644 index 2c797e7c79..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/NetworkQualityLevelChangedEvent.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Event } from './Event'; -import { Session } from '../../OpenVidu/Session'; -import { Connection } from '../../OpenVidu/Connection'; - -/** - * Triggered by {@link SessionEventMap.networkQualityLevelChanged} - */ -export class NetworkQualityLevelChangedEvent extends Event { - /** - * New value of the network quality level - */ - newValue: number; - - /** - * Old value of the network quality level - */ - oldValue: number; - - /** - * Connection for whom the network quality level changed - */ - connection: Connection; - - /** - * @hidden - */ - constructor(target: Session, newValue: number, oldValue: number, connection: Connection) { - super(false, target, 'networkQualityLevelChanged'); - this.newValue = newValue; - this.oldValue = oldValue; - this.connection = connection; - } - - /** - * @hidden - */ - // tslint:disable-next-line:no-empty - callDefaultBehavior() {} -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/PublisherSpeakingEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/PublisherSpeakingEvent.ts deleted file mode 100644 index b6be41fddf..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/PublisherSpeakingEvent.ts +++ /dev/null @@ -1,54 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Event } from './Event'; -import { Connection } from '../../OpenVidu/Connection'; -import { Session } from '../../OpenVidu/Session'; -import { StreamManager } from '../../OpenVidu/StreamManager'; - -/** - * Triggered by: - * - `publisherStartSpeaking` (available for [Session](/en/stable/api/openvidu-browser/interfaces/SessionEventMap.html#publisherStartSpeaking) and [StreamManager](/en/stable/api/openvidu-browser/interfaces/StreamManagerEventMap.html#publisherStartSpeaking) objects) - * - `publisherStopSpeaking` (available for [Session](/en/stable/api/openvidu-browser/interfaces/SessionEventMap.html#publisherStopSpeaking) and [StreamManager](/en/stable/api/openvidu-browser/interfaces/StreamManagerEventMap.html#publisherStopSpeaking) objects) - */ -export class PublisherSpeakingEvent extends Event { - /** - * The client that started or stopped speaking - */ - connection: Connection; - - /** - * The streamId of the Stream affected by the speaking event - */ - streamId: string; - - /** - * @hidden - */ - constructor(target: Session | StreamManager, type: string, connection: Connection, streamId: string) { - super(false, target, type); - this.type = type; - this.connection = connection; - this.streamId = streamId; - } - - /** - * @hidden - */ - // tslint:disable-next-line:no-empty - callDefaultBehavior() {} -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/RecordingEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/RecordingEvent.ts deleted file mode 100644 index 4bd186dc99..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/RecordingEvent.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Event } from './Event'; -import { Session } from '../../OpenVidu/Session'; -import { RecordingEventReason } from './Types/Types'; - -/** - * Triggered by: - * - {@link SessionEventMap.recordingStarted} - * - {@link SessionEventMap.recordingStopped} - */ -export class RecordingEvent extends Event { - /** - * The recording ID generated in openvidu-server - */ - id: string; - - /** - * The recording name you supplied to openvidu-server. For example, to name your recording file MY_RECORDING: - * - With **API REST**: POST to `/api/recordings/start` passing JSON body `{"session":"sessionId","name":"MY_RECORDING"}` - * - With **openvidu-java-client**: `OpenVidu.startRecording(sessionId, "MY_RECORDING")` or `OpenVidu.startRecording(sessionId, new RecordingProperties.Builder().name("MY_RECORDING").build())` - * - With **openvidu-node-client**: `OpenVidu.startRecording(sessionId, "MY_RECORDING")` or `OpenVidu.startRecording(sessionId, {name: "MY_RECORDING"})` - * - * If no name is supplied, this property will be undefined and the recorded file will be named after property {@link id} - */ - name?: string; - - /** - * For 'recordingStopped' event: - * - "recordingStoppedByServer": the recording has been gracefully stopped by the application - * - "sessionClosedByServer": the Session has been closed by the application - * - "automaticStop": see [Automatic stop of recordings](/en/stable/advanced-features/recording/#automatic-stop-of-recordings) - * - "nodeCrashed": a node has crashed in the server side - * - * For 'recordingStarted' empty string - */ - reason?: RecordingEventReason; - - /** - * @hidden - */ - constructor(target: Session, type: string, id: string, name: string, reason?: RecordingEventReason) { - super(false, target, type); - this.id = id; - if (name !== id) { - this.name = name; - } - this.reason = reason; - } - - /** - * @hidden - */ - // tslint:disable-next-line:no-empty - callDefaultBehavior() { } -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/SessionDisconnectedEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/SessionDisconnectedEvent.ts deleted file mode 100644 index 67c5dadbec..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/SessionDisconnectedEvent.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Event } from './Event'; -import { Session } from '../../OpenVidu/Session'; -import { OpenViduLogger } from '../Logger/OpenViduLogger'; -import { ConnectionEventReason } from './Types/Types'; - -/** - * @hidden - */ -const logger: OpenViduLogger = OpenViduLogger.getInstance(); - -/** - * Triggered by {@link SessionEventMap.sessionDisconnected} - */ -export class SessionDisconnectedEvent extends Event { - /** - * - "disconnect": you have called `Session.disconnect()` - * - "forceDisconnectByUser": you have been evicted from the Session by other user calling `Session.forceDisconnect()` - * - "forceDisconnectByServer": you have been evicted from the Session by the application - * - "sessionClosedByServer": the Session has been closed by the application - * - "networkDisconnect": your network connection has dropped. Before a SessionDisconnectedEvent with this reason is triggered, - * Session object will always have previously dispatched a `reconnecting` event. If the reconnection process succeeds, - * Session object will dispatch a `reconnected` event. If it fails, Session object will dispatch a SessionDisconnectedEvent - * with reason "networkDisconnect" - * - "nodeCrashed": a node has crashed in the server side. You can use this reason to ask your application's backend to reconnect - * to a new session to replace the crashed one - */ - reason: ConnectionEventReason; - - /** - * @hidden - */ - constructor(target: Session, reason: ConnectionEventReason) { - super(true, target, 'sessionDisconnected'); - this.reason = reason; - } - - /** - * @hidden - */ - callDefaultBehavior() { - logger.info("Calling default behavior upon '" + this.type + "' event dispatched by 'Session'"); - - const session = this.target; - - // Dispose and delete all remote Connections - session.remoteConnections.forEach((remoteConnection) => { - const connectionId = remoteConnection.connectionId; - if (!!session.remoteConnections.get(connectionId)?.stream) { - session.remoteConnections.get(connectionId)?.stream!.disposeWebRtcPeer(); - session.remoteConnections.get(connectionId)?.stream!.disposeMediaStream(); - if (session.remoteConnections.get(connectionId)?.stream!.streamManager) { - session.remoteConnections.get(connectionId)?.stream!.streamManager.removeAllVideos(); - } - const streamId = session.remoteConnections.get(connectionId)?.stream?.streamId; - if (!!streamId) { - session.remoteStreamsCreated.delete(streamId); - } - session.remoteConnections.get(connectionId)?.dispose(); - } - session.remoteConnections.delete(connectionId); - }); - } -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/SignalEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/SignalEvent.ts deleted file mode 100644 index bc443b9ab4..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/SignalEvent.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Event } from './Event'; -import { Connection } from '../../OpenVidu/Connection'; -import { Session } from '../../OpenVidu/Session'; - -/** - * Triggered by {@link SessionEventMap.signal} - */ -export class SignalEvent extends Event { - /** - * The type of signal. It is string `"signal"` for those signals sent with no {@link SignalOptions.type} property, and `"signal:type"` if was sent with a - * valid {@link SignalOptions.type} property. - * - * The client must be specifically subscribed to `Session.on('signal:type', function(signalEvent) {...})` to trigger that type of signal. - * - * Subscribing to `Session.on('signal', function(signalEvent) {...})` will trigger all signals, no matter their type. - */ - type: string; - - /** - * The message of the signal (can be empty) - */ - data?: string; - - /** - * The client that sent the signal. This property is undefined if the signal - * was directly generated by the application server (not by other client) - */ - from?: Connection; - - /** - * @hidden - */ - constructor(target: Session, type?: string, data?: string, from?: Connection) { - super(false, target, 'signal'); - if (!!type) { - this.type = 'signal:' + type; - } - this.data = data; - this.from = from; - } - - /** - * @hidden - */ - // tslint:disable-next-line:no-empty - callDefaultBehavior() {} -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/SpeechToTextEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/SpeechToTextEvent.ts deleted file mode 100644 index fba138f931..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/SpeechToTextEvent.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Event } from './Event'; -import { Connection } from '../../OpenVidu/Connection'; -import { Session } from '../../OpenVidu/Session'; -import { SpeechToTextEventReason } from './Types/Types'; - -/** - * Triggered by {@link SessionEventMap.speechToTextMessage} - */ -export class SpeechToTextEvent extends Event { - - /** - * The {@link Connection} owning the Stream that produced the speech-to-text event. - * In other words, this is the participant that spoke and produced this transcription event. - */ - connection: Connection; - - /** - * The text of the event. This is the transcription for this specific piece of audio stream - */ - text: string; - - /** - * All speech-to-text events are generated - */ - reason: SpeechToTextEventReason; - - /** - * The original event from the speech to text engine. This can vary depending on the engine - */ - raw: string; - - /** - * [BCP-47](https://tools.ietf.org/html/bcp47) language tag (like "en-US" or "es-ES") of the recognized text. This will be the same as the language provided - * in method {@link Session.subscribeToSpeechToText} method - */ - lang: string; - - /** - * @hidden - */ - constructor(target: Session, connection: Connection, text: string, reason: SpeechToTextEventReason, raw: string, lang: string) { - super(false, target, 'speechToTextMessage'); - this.connection = connection; - this.text = text; - this.reason = reason; - this.raw = raw; - this.lang = lang; - } - - /** - * @hidden - */ - // tslint:disable-next-line:no-empty - callDefaultBehavior() { } -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/StreamEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/StreamEvent.ts deleted file mode 100644 index 7f447f4ba5..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/StreamEvent.ts +++ /dev/null @@ -1,113 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Event } from './Event'; -import { Publisher } from '../../OpenVidu/Publisher'; -import { Session } from '../../OpenVidu/Session'; -import { Stream } from '../../OpenVidu/Stream'; -import { OpenViduLogger } from '../Logger/OpenViduLogger'; -import { StreamEventReason } from './Types/Types'; - -/** - * @hidden - */ -const logger: OpenViduLogger = OpenViduLogger.getInstance(); - -/** - * Triggered by: - * - `streamCreated` (available for [Session](/en/stable/api/openvidu-browser/interfaces/SessionEventMap.html#streamCreated) and [Publisher](/en/stable/api/openvidu-browser/interfaces/PublisherEventMap.html#streamCreated) objects) - * - `streamDestroyed` (available for [Session](/en/stable/api/openvidu-browser/interfaces/SessionEventMap.html#streamDestroyed) and [Publisher](/en/stable/api/openvidu-browser/interfaces/PublisherEventMap.html#streamDestroyed) objects) - */ -export class StreamEvent extends Event { - /** - * Stream object that was created or destroyed - */ - stream: Stream; - - /** - * For 'streamDestroyed' event: - * - "unpublish": method `Session.unpublish()` has been called - * - "disconnect": method `Session.disconnect()` has been called - * - "forceUnpublishByUser": some user has called `Session.forceUnpublish()` over the Stream - * - "forceDisconnectByUser": some user has called `Session.forceDisconnect()` over the Stream - * - "forceUnpublishByServer": the user's stream has been unpublished from the Session by the application - * - "forceDisconnectByServer": the user has been evicted from the Session by the application - * - "sessionClosedByServer": the Session has been closed by the application - * - "networkDisconnect": the user's network connection has dropped - * - "nodeCrashed": a node has crashed in the server side - * - * For 'streamCreated' empty string - */ - reason: StreamEventReason; - - /** - * @hidden - */ - constructor(cancelable: boolean, target: Session | Publisher, type: string, stream: Stream, reason: StreamEventReason) { - super(cancelable, target, type); - this.stream = stream; - this.reason = reason; - } - - /** - * @hidden - */ - callDefaultBehavior() { - if (this.type === 'streamDestroyed') { - if (this.target instanceof Session) { - // Remote Stream - logger.info("Calling default behavior upon '" + this.type + "' event dispatched by 'Session'"); - this.stream.disposeWebRtcPeer(); - } else if (this.target instanceof Publisher) { - // Local Stream - logger.info("Calling default behavior upon '" + this.type + "' event dispatched by 'Publisher'"); - clearInterval((this.target).screenShareResizeInterval); - this.stream.isLocalStreamReadyToPublish = false; - - // Delete Publisher object from OpenVidu publishers array - const openviduPublishers = (this.target).openvidu.publishers; - for (let i = 0; i < openviduPublishers.length; i++) { - if (openviduPublishers[i] === this.target) { - openviduPublishers.splice(i, 1); - break; - } - } - } - - // Dispose the MediaStream local object - this.stream.disposeMediaStream(); - - // Remove from DOM all video elements associated to this Stream, if there's a StreamManager defined - // (method Session.subscribe must have been called) - if (this.stream.streamManager) this.stream.streamManager.removeAllVideos(); - - // Delete stream from Session.remoteStreamsCreated map - this.stream.session.remoteStreamsCreated.delete(this.stream.streamId); - - // Delete StreamOptionsServer from remote Connection - const remoteConnection = this.stream.session.remoteConnections.get(this.stream.connection.connectionId); - if (!!remoteConnection && !!remoteConnection.remoteOptions) { - const streamOptionsServer = remoteConnection.remoteOptions.streams; - for (let i = streamOptionsServer.length - 1; i >= 0; --i) { - if (streamOptionsServer[i].id === this.stream.streamId) { - streamOptionsServer.splice(i, 1); - } - } - } - } - } -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/StreamManagerEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/StreamManagerEvent.ts deleted file mode 100644 index 0892434658..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/StreamManagerEvent.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Event } from './Event'; -import { StreamManager } from '../../OpenVidu/StreamManager'; - -/** - * Triggered by: - * - {@link StreamManagerEventMap.streamPlaying} - * - {@link StreamManagerEventMap.streamAudioVolumeChange} - */ -export class StreamManagerEvent extends Event { - /** - * For `streamAudioVolumeChange` event: - * - `{newValue: number, oldValue: number}`: new and old audio volume values. These values are between -100 (silence) and 0 (loudest possible volume). - * They are not exact and depend on how the browser is managing the audio track, but -100 and 0 can be taken as limit values. - * - * For `streamPlaying` event undefined - */ - value: Object | undefined; - - /** - * @hidden - */ - constructor(target: StreamManager, type: string, value: Object | undefined) { - super(false, target, type); - this.value = value; - } - - /** - * @hidden - */ - // tslint:disable-next-line:no-empty - callDefaultBehavior() {} -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/StreamPropertyChangedEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/StreamPropertyChangedEvent.ts deleted file mode 100644 index dc7dffeb17..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/StreamPropertyChangedEvent.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Event } from './Event'; -import { Session } from '../../OpenVidu/Session'; -import { Stream } from '../../OpenVidu/Stream'; -import { StreamManager } from '../../OpenVidu/StreamManager'; -import { StreamPropertyChangedEventReason, ChangedPropertyType } from './Types/Types'; - -/** - * Triggered by `streamPropertyChanged` (available for [Session](/en/stable/api/openvidu-browser/interfaces/SessionEventMap.html#streamPropertyChanged) and [StreamManager](/en/stable/api/openvidu-browser/interfaces/StreamManagerEventMap.html#streamPropertyChanged) objects) - */ -export class StreamPropertyChangedEvent extends Event { - /** - * The Stream whose property has changed. You can always identify the user publishing the changed stream by consulting property {@link Stream.connection} - */ - stream: Stream; - - /** - * The property of the stream that changed. This value is either `"videoActive"`, `"audioActive"`, `"videoTrack"`, `"audioTrack"`, `"videoDimensions"` or `"filter"` - */ - changedProperty: ChangedPropertyType; - - /** - * Cause of the change on the stream's property: - * - For `videoActive`: `"publishVideo"` - * - For `audioActive`: `"publishAudio"` - * - For `videoTrack`: `"trackReplaced"` - * - For `audioTrack`: `"trackReplaced"` - * - For `videoDimensions`: `"deviceRotated"`, `"screenResized"` or `"trackReplaced"` - * - For `filter`: `"applyFilter"`, `"execFilterMethod"` or `"removeFilter"` - */ - reason: StreamPropertyChangedEventReason; - - /** - * New value of the property (after change, current value) - */ - newValue: Object; - - /** - * Previous value of the property (before change) - */ - oldValue: Object; - - /** - * @hidden - */ - constructor( - target: Session | StreamManager, - stream: Stream, - changedProperty: ChangedPropertyType, - newValue: Object, - oldValue: Object, - reason: StreamPropertyChangedEventReason - ) { - super(false, target, 'streamPropertyChanged'); - this.stream = stream; - this.changedProperty = changedProperty; - this.newValue = newValue; - this.oldValue = oldValue; - this.reason = reason; - } - - /** - * @hidden - */ - // tslint:disable-next-line:no-empty - callDefaultBehavior() { } -} diff --git a/openvidu-browser/src/OpenViduInternal/Events/Types/Types.ts b/openvidu-browser/src/OpenViduInternal/Events/Types/Types.ts deleted file mode 100644 index 30f0314fb3..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/Types/Types.ts +++ /dev/null @@ -1,42 +0,0 @@ -export type ChangedPropertyType = - 'videoActive' | - 'audioActive' | - 'videoTrack' | - 'audioTrack' | - 'videoDimensions' | - 'filter'; - -export type StreamPropertyChangedEventReason = - 'publishVideo' | - 'publishAudio' | - 'trackReplaced' | - 'deviceRotated' | - 'screenResized' | - 'applyFilter' | - 'execFilterMethod' | - 'removeFilter'; - -export type ConnectionEventReason = - 'disconnect' | - 'forceDisconnectByUser' | - 'forceDisconnectByServer' | - 'sessionClosedByServer' | - 'networkDisconnect' | - 'nodeCrashed' | - ''; - -export type StreamEventReason = - ConnectionEventReason | - 'unpublish' | - 'forceUnpublishByUser' | - 'forceUnpublishByServer'; - -export type RecordingEventReason = - 'recordingStoppedByServer' | - 'sessionClosedByServer' | - 'automaticStop' | - 'nodeCrashed'; - -export type SpeechToTextEventReason = - 'recognizing' | - 'recognized'; \ No newline at end of file diff --git a/openvidu-browser/src/OpenViduInternal/Events/VideoElementEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/VideoElementEvent.ts deleted file mode 100644 index 3617cc88c5..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Events/VideoElementEvent.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Event } from './Event'; -import { StreamManager } from '../../OpenVidu/StreamManager'; - -/** - * Triggered by: - * - {@link StreamManagerEventMap.videoElementCreated} - * - {@link StreamManagerEventMap.videoElementDestroyed} - */ -export class VideoElementEvent extends Event { - /** - * Video element that was created or destroyed - */ - element: HTMLVideoElement; - - /** - * @hidden - */ - constructor(element: HTMLVideoElement, target: StreamManager, type: string) { - super(false, target, type); - this.element = element; - } - - /** - * @hidden - */ - // tslint:disable-next-line:no-empty - callDefaultBehavior() {} -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/CustomMediaStreamConstraints.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Private/CustomMediaStreamConstraints.ts deleted file mode 100644 index cddadb1e79..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/CustomMediaStreamConstraints.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -export interface CustomMediaStreamConstraints { - constraints: MediaStreamConstraints; - audioTrack: MediaStreamTrack | undefined; - videoTrack: MediaStreamTrack | undefined; -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/IceServerProperties.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Private/IceServerProperties.ts deleted file mode 100644 index 533e9a3e66..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/IceServerProperties.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -export interface IceServerProperties { - url: string; - username?: string; - credential?: string; -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/InboundStreamOptions.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Private/InboundStreamOptions.ts deleted file mode 100644 index 0a9a724a60..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/InboundStreamOptions.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Connection } from '../../../OpenVidu/Connection'; -import { Filter } from '../../../OpenVidu/Filter'; -import { TypeOfVideo } from '../../Enums/TypeOfVideo'; - -export interface InboundStreamOptions { - id: string; - createdAt: number; - connection: Connection; - hasAudio: boolean; - hasVideo: boolean; - audioActive: boolean; - videoActive: boolean; - typeOfVideo: TypeOfVideo; - frameRate: number; - videoDimensions: { width: number; height: number }; - filter?: Filter; -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/LocalConnectionOptions.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Private/LocalConnectionOptions.ts deleted file mode 100644 index ef5fc3ea7f..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/LocalConnectionOptions.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { RemoteConnectionOptions } from './RemoteConnectionOptions'; -import { IceServerProperties } from './IceServerProperties'; - -export interface LocalConnectionOptions { - id: string; - finalUserId: string; - createdAt: number; - metadata: string; - value: RemoteConnectionOptions[]; - session: string; // OpenVidu Session identifier - sessionId: string; // JSON-RPC session identifier - role: string; - record: boolean; - coturnIp: string; - coturnPort: number; - turnUsername: string; - turnCredential: string; - version: string; - mediaServer: string; - videoSimulcast: boolean; - life: number; - customIceServers?: IceServerProperties[]; - recordingId?: string; // Defined if the session is being recorded and the client must be notified - recordingName?: string; // Defined if the session is being recorded and the client must be notified -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/OutboundStreamOptions.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Private/OutboundStreamOptions.ts deleted file mode 100644 index e954c8b3c6..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/OutboundStreamOptions.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { PublisherProperties } from '../Public/PublisherProperties'; - -export interface OutboundStreamOptions { - publisherProperties: PublisherProperties; - mediaConstraints: MediaStreamConstraints; -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/RemoteConnectionOptions.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Private/RemoteConnectionOptions.ts deleted file mode 100644 index 33f0bb7a5f..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/RemoteConnectionOptions.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { StreamOptionsServer } from './StreamOptionsServer'; - -export interface RemoteConnectionOptions { - id: string; - createdAt: number; - metadata: string; - streams: StreamOptionsServer[]; -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/SessionOptions.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Private/SessionOptions.ts deleted file mode 100644 index efe276bcc7..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/SessionOptions.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -export interface SessionOptions { - sessionId: string; - participantId: string; - metadata: string; -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/SignalOptions.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Private/SignalOptions.ts deleted file mode 100644 index 19737379bd..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/SignalOptions.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Connection } from '../../../OpenVidu/Connection'; - -export interface SignalOptions { - type?: string; - to?: Connection[]; - data?: string; -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/StreamOptionsServer.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Private/StreamOptionsServer.ts deleted file mode 100644 index f88c49542a..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Private/StreamOptionsServer.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Filter } from '../../../OpenVidu/Filter'; -import { TypeOfVideo } from '../../Enums/TypeOfVideo'; - -export interface StreamOptionsServer { - id: string; - createdAt: number; - hasAudio: boolean; - hasVideo: boolean; - audioActive: boolean; - videoActive: boolean; - typeOfVideo: TypeOfVideo; - frameRate: number; - videoDimensions: string; - filter: Filter; -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Public/Capabilities.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Public/Capabilities.ts deleted file mode 100644 index aa91e33760..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Public/Capabilities.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * See {@link Session.capabilities} - */ -export interface Capabilities { - /** - * `true` if the client can call {@link Session.forceDisconnect}, `false` if not - */ - forceDisconnect: boolean; - - /** - * `true` if the client can call {@link Session.forceUnpublish}, `false` if not - */ - forceUnpublish: boolean; - - /** - * `true` if the client can call {@link Session.publish}, `false` if not - */ - publish: boolean; - - /** - * `true` if the client can call {@link Session.subscribe}, `false` if not (true for every user for now) - */ - subscribe: boolean; -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Public/Device.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Public/Device.ts deleted file mode 100644 index 4435d74518..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Public/Device.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * See {@link OpenVidu.getDevices} - */ -export interface Device { - /** - * The kind of device - */ - kind: 'videoinput' | 'audioinput'; - - /** - * Unique ID for the device. Use it on `audioSource` or `videoSource` properties of {@link PublisherProperties} - */ - deviceId: string; - - /** - * Description of the device. An empty string if the user hasn't granted permissions to the site to access the device - */ - label: string; -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Public/OpenViduAdvancedConfiguration.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Public/OpenViduAdvancedConfiguration.ts deleted file mode 100644 index 055bc23eb4..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Public/OpenViduAdvancedConfiguration.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * See {@link OpenVidu.setAdvancedConfiguration} - */ -export interface OpenViduAdvancedConfiguration { - /** - * Array of [RTCIceServer](https://developer.mozilla.org/en-US/docs/Web/API/RTCIceServer) to be used by OpenVidu Browser. By default OpenVidu will generate the required credentials to use the COTURN server hosted along OpenVidu Server. - * You can also set this property to string 'freeice' to force the use of free STUN servers instead (got thanks to [freeice](https://github.com/DamonOehlman/freeice) library). - * - * > **WARNING**: this value has priority over the standard `iceServers` property of {@link rtcConfiguration}. It will override any value in `OpenViduAdvancedConfiguration.rtcConfiguration.iceServers` - */ - iceServers?: RTCIceServer[] | string; - - /** - * Custom configuration for all [RTCPeerConnection](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection#parameters) objects. This object will be passed as is to all RTCPeerConnection constructor (all Publishers and Subscribers). - */ - rtcConfiguration?: RTCConfiguration; - - /** - * URL to a custom screen share extension for Chrome (always based on ours: [openvidu-screen-sharing-chrome-extension](https://github.com/OpenVidu/openvidu-screen-sharing-chrome-extension)) to be used instead of the default one. - * Must be something like this: `https://chrome.google.com/webstore/detail/YOUR_WEBSTORE_EXTENSION_NAME/YOUR_EXTENSION_ID` - */ - screenShareChromeExtension?: string; - - /** - * Custom configuration for the {@link PublisherSpeakingEvent} feature and the [StreamManagerEvent.streamAudioVolumeChange](/en/stable/api/openvidu-browser/classes/StreamManagerEvent.html) feature. It is an object which includes the following optional properties: - * - `interval`: (number) how frequently the analyser polls the audio stream to check if speaking has started/stopped or audio volume has changed. Default **100** (ms) - * - `threshold`: (number) the volume at which _publisherStartSpeaking_ and _publisherStopSpeaking_ events will be fired. Default **-50** (dB) - * - * This sets the global default configuration that will affect all streams, but you can later customize these values for each specific stream by calling {@link StreamManager.updatePublisherSpeakingEventsOptions} - */ - publisherSpeakingEventsOptions?: { - interval?: number; - threshold?: number; - }; - - /** - * Determines the automatic reconnection process policy. Whenever the client's network drops, OpenVidu Browser starts a reconnection process with OpenVidu Server. After network is recovered, OpenVidu Browser automatically - * inspects all of its media streams to see their status. For any of them that are broken, it asks OpenVidu Server for a forced and silent reconnection. - * - * This policy is technically enough to recover any broken media connection after a network drop, but in practice it has been proven that OpenVidu Browser may think a media connection has properly recovered when in fact it has not. - * This is not a common case, but it may occur. This property allows **forcing OpenVidu Browser to reconnect all of its outgoing and incoming media streams** after a network drop regardless of their supposed status. - * - * Default to `false`. - */ - forceMediaReconnectionAfterNetworkDrop?: boolean; - - /** - * The milliseconds that must elapse after triggering {@link ExceptionEvent} of name [`ICE_CONNECTION_DISCONNECTED`](/en/stable/api/openvidu-browser/enums/ExceptionEventName.html#ICE_CONNECTION_DISCONNECTED) to perform an automatic reconnection process of the affected media stream. - * This automatic reconnection process can only take place if the client still has network connection to OpenVidu Server. If the ICE connection has broken because of a total network drop, - * then no reconnection process will be possible at all. - * - * Default to `4000`. - */ - iceConnectionDisconnectedExceptionTimeout?: number; - - /** - * The milliseconds that must elapse for the {@link ExceptionEvent} of name [`NO_STREAM_PLAYING_EVENT`](/en/stable/api/openvidu-browser/enums/ExceptionEventName.html#NO_STREAM_PLAYING_EVENT) to be fired. - * - * Default to `4000`. - */ - noStreamPlayingEventExceptionTimeout?: number; -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Public/PublisherProperties.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Public/PublisherProperties.ts deleted file mode 100644 index e440560cf4..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Public/PublisherProperties.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Filter } from '../../../OpenVidu/Filter'; -import { VideoInsertMode } from '../../Enums/VideoInsertMode'; - -/** - * See {@link OpenVidu.initPublisher} - */ -export interface PublisherProperties { - /** - * Which device should provide the audio source. Can be: - * - Property `deviceId` of a {@link Device} - * - `"screen"` to share the screen audio when {@link videoSource} is set to `"screen"`. If {@link videoSource} is not set to `"screen"` this will result in no audio source and a video-only publisher. - * - A MediaStreamTrack obtained from a MediaStream object with {@link OpenVidu.getUserMedia} - * - `false` or null to have a video-only publisher - * @default _Default microphone_ - */ - audioSource?: string | MediaStreamTrack | boolean; - - /** - * Desired framerate of the video in frames per second. - * Limiting the framerate has always effect on browsers Chrome and Opera. Firefox requires that the input device explicitly supports the desired framerate. - * @default undefined - */ - frameRate?: number; - - /** - * How the video element of the publisher should be inserted in the DOM - * @default VideoInsertMode.APPEND - */ - insertMode?: VideoInsertMode | string; - - /** - * Whether the publisher's video will be mirrored in the page or not. Only affects the local view of the publisher in the browser (remote streams will not be mirrored). If `videoSource` is set to "screen" this property is fixed to `false` - * @default true - */ - mirror?: boolean; - - /** - * Whether to initially publish to the session with the audio unmuted or muted. Only makes sense if property `audioSource` is NOT set to *false* or *null*. You can change the audio state later during the session with {@link Publisher.publishAudio} - * @default true - */ - publishAudio?: boolean; - - /** - * Whether to initially publish to the session with the video enabled or disabled. Only makes sense if property `videoSource` is NOT set to *false* or *null*. You can change the video state later during the session with {@link Publisher.publishVideo} - * @default true - */ - publishVideo?: boolean; - - /** - * Resolution of the video: `"320x240"`, `"640x480"`, `"1280x720"` (low, medium and high quality respectively) - * @default "640x480" - */ - resolution?: string; - - /** - * Which device should provide the video source. Can be: - * - Property `deviceId` of a {@link Device} - * - `"screen"` to screen-share. We provide a default screen-shraring extension for Chrome that can run in any domain, but you can customize it so it has your own icon, your own name, etc. Visit this - * [GitHub repository](https://github.com/OpenVidu/openvidu-screen-sharing-chrome-extension/) to learn how. Once you have uploaded your own extension to Chrome Web Store, - * simply call `OpenVidu.setAdvancedConfiguration({screenShareChromeExtension : "https://chrome.google.com/webstore/detail/YOUR_EXTENSION_NAME/YOUR_EXTENSION_ID"})` before calling `OpenVidu.initPublisher(targetElement, {videoSource: "screen"})`. - * For Firefox (<66) `"screen"` string will ask for permissions to share the entire screen. To ask for a specific window or application, use `"window"` string instead (this only applies to Firefox). - * - A MediaStreamTrack obtained from a MediaStream object with {@link OpenVidu.getUserMedia} - * - `false` or null to have an audio-only publisher - * @default _Default camera_ - */ - videoSource?: string | MediaStreamTrack | boolean; - - /** - * Use Simulcast video on WebRTC Publishers. - * Senders will encode duplicate video streams with different qualities, - * so the media server is able to select the most appropriate quality stream - * for each Subscriber. - * This setting is honored only if OpenVidu Server was configured to use the - * mediasoup media server. Otherwise, Simulcast will be disabled. - */ - videoSimulcast?: boolean; - - /** - * **WARNING**: experimental option. This property may change in the near future - * - * Define a filter to apply in the Publisher's stream - */ - filter?: Filter; -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Public/SignalOptions.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Public/SignalOptions.ts deleted file mode 100644 index eb9169ed95..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Public/SignalOptions.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Connection } from '../../../OpenVidu/Connection'; - -/** - * See {@link Session.signal} - */ -export interface SignalOptions { - /** - * The actual message of the signal. - */ - data?: string; - - /** - * The participants to whom to send the signal. They will only receive it if they are subscribed to - * event `Session.on('signal')`. If empty or undefined, the signal will be send to all participants. - */ - to?: Connection[]; - - /** - * The type of the signal. Participants subscribed to event `Session.on('signal:type')` will - * receive it. Participants subscribed to `Session.on('signal')` will receive all signals. - */ - type?: string; -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Public/StreamManagerVideo.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Public/StreamManagerVideo.ts deleted file mode 100644 index 57898f93aa..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Public/StreamManagerVideo.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { VideoInsertMode } from '../../Enums/VideoInsertMode'; - -export interface StreamManagerVideo { - /** - * DOM video element displaying the StreamManager's stream - */ - video: HTMLVideoElement; - - /** - * `id` attribute of the DOM video element displaying the StreamManager's stream - */ - id: string; - - /** - * The DOM HTMLElement assigned as target element when creating a video for the StreamManager. This property is defined when: - * - {@link OpenVidu.initPublisher} or {@link Session.subscribe} methods have been called passing a valid `targetElement` parameter. - * - {@link StreamManager.createVideoElement} has been called. - * - * This property is undefined when: - * - {@link OpenVidu.initPublisher} or {@link Session.subscribe} methods have been called passing *null* or *undefined* as `targetElement` parameter. - * - {@link StreamManager.addVideoElement} has been called. - */ - targetElement?: HTMLElement; - - /** - * How the DOM video element should be inserted with respect to `targetElement`. This property is defined when: - * - {@link OpenVidu.initPublisher} or {@link Session.subscribe} methods have been called passing a valid `targetElement` parameter. - * - {@link StreamManager.createVideoElement} has been called. - * - * This property is undefined when: - * - {@link OpenVidu.initPublisher} or {@link Session.subscribe} methods have been called passing *null* or *undefined* as `targetElement` parameter. - * - {@link StreamManager.addVideoElement} has been called. - */ - insertMode?: VideoInsertMode; - - /** - * @hidden - */ - canplayListenerAdded: boolean; -} diff --git a/openvidu-browser/src/OpenViduInternal/Interfaces/Public/SubscriberProperties.ts b/openvidu-browser/src/OpenViduInternal/Interfaces/Public/SubscriberProperties.ts deleted file mode 100644 index 85779bf879..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Interfaces/Public/SubscriberProperties.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { VideoInsertMode } from '../../Enums/VideoInsertMode'; - -/** - * See {@link Session.subscribe} - */ -export interface SubscriberProperties { - /** - * How the video element of the subscriber should be inserted in the DOM - * @default VideoInsertMode.APPEND - */ - insertMode?: VideoInsertMode | string; - - /** - * Whether to initially subscribe to the audio track of the stream or not. You can change the audio state later with {@link Subscriber.subscribeToAudio} - * @default true - */ - subscribeToAudio?: boolean; - - /** - * Whether to initially subscribe to the video track of the stream or not. You can change the video state later with {@link Subscriber.subscribeToVideo} - * @default true - */ - subscribeToVideo?: boolean; -} diff --git a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/Mapper.js b/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/Mapper.js deleted file mode 100644 index 83c515d349..0000000000 --- a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/Mapper.js +++ /dev/null @@ -1,52 +0,0 @@ -function Mapper() { - var sources = {}; - - this.forEach = function (callback) { - for (var key in sources) { - var source = sources[key]; - - for (var key2 in source) callback(source[key2]); - } - }; - - this.get = function (id, source) { - var ids = sources[source]; - if (ids == undefined) return undefined; - - return ids[id]; - }; - - this.remove = function (id, source) { - var ids = sources[source]; - if (ids == undefined) return; - - delete ids[id]; - - // Check it's empty - for (var i in ids) { - return false; - } - - delete sources[source]; - }; - - this.set = function (value, id, source) { - if (value == undefined) return this.remove(id, source); - - var ids = sources[source]; - if (ids == undefined) sources[source] = ids = {}; - - ids[id] = value; - }; -} - -Mapper.prototype.pop = function (id, source) { - var value = this.get(id, source); - if (value == undefined) return undefined; - - this.remove(id, source); - - return value; -}; - -module.exports = Mapper; diff --git a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/clients/index.js b/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/clients/index.js deleted file mode 100644 index 46b9e3ab26..0000000000 --- a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/clients/index.js +++ /dev/null @@ -1,20 +0,0 @@ -/* - * (C) Copyright 2014 Kurento (http://kurento.org/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -var JsonRpcClient = require('./jsonrpcclient'); - -exports.JsonRpcClient = JsonRpcClient; diff --git a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/clients/jsonrpcclient.js b/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/clients/jsonrpcclient.js deleted file mode 100644 index ace0dd83b7..0000000000 --- a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/clients/jsonrpcclient.js +++ /dev/null @@ -1,280 +0,0 @@ -/* - * (C) Copyright 2014 Kurento (http://kurento.org/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -var RpcBuilder = require('../'); -var WebSocketWithReconnection = require('./transports/webSocketWithReconnection'); -var OpenViduLogger = require('../../../Logger/OpenViduLogger').OpenViduLogger; - -Date.now = - Date.now || - function () { - return +new Date(); - }; - -var PING_INTERVAL = 5000; - -var RECONNECTING = 'RECONNECTING'; -var CONNECTED = 'CONNECTED'; -var DISCONNECTED = 'DISCONNECTED'; - -var Logger = OpenViduLogger.getInstance(); - -/** - * - * heartbeat: interval in ms for each heartbeat message, - *
- * ws : {
- * 	uri : URI to conntect to,
- * 	onconnected : callback method to invoke when connection is successful,
- * 	ondisconnect : callback method to invoke when the connection is lost (max retries for reconnecting reached),
- * 	onreconnecting : callback method to invoke when the client is reconnecting,
- * 	onreconnected : callback method to invoke when the client successfully reconnects,
- * 	onerror : callback method to invoke when there is an error
- * },
- * rpc : {
- * 	requestTimeout : timeout for a request,
- * 	sessionStatusChanged: callback method for changes in session status,
- * 	mediaRenegotiation: mediaRenegotiation
- * }
- * 
- */ -function JsonRpcClient(configuration) { - var self = this; - - var wsConfig = configuration.ws; - - var notReconnectIfNumLessThan = -1; - - var pingNextNum = 0; - var enabledPings = true; - var pingPongStarted = false; - var pingInterval; - - var status = DISCONNECTED; - - var onreconnecting = wsConfig.onreconnecting; - var onreconnected = wsConfig.onreconnected; - var onconnected = wsConfig.onconnected; - var onerror = wsConfig.onerror; - - configuration.rpc.pull = function (params, request) { - request.reply(null, 'push'); - }; - - wsConfig.onreconnecting = function () { - Logger.debug('--------- ONRECONNECTING -----------'); - if (status === RECONNECTING) { - Logger.error('Websocket already in RECONNECTING state when receiving a new ONRECONNECTING message. Ignoring it'); - return; - } - - stopPing(); - - status = RECONNECTING; - if (onreconnecting) { - onreconnecting(); - } - }; - - wsConfig.onreconnected = function () { - Logger.debug('--------- ONRECONNECTED -----------'); - if (status === CONNECTED) { - Logger.error('Websocket already in CONNECTED state when receiving a new ONRECONNECTED message. Ignoring it'); - return; - } - status = CONNECTED; - - updateNotReconnectIfLessThan(); - - if (onreconnected) { - onreconnected(); - } - }; - - wsConfig.onconnected = function () { - Logger.debug('--------- ONCONNECTED -----------'); - if (status === CONNECTED) { - Logger.error('Websocket already in CONNECTED state when receiving a new ONCONNECTED message. Ignoring it'); - return; - } - status = CONNECTED; - - enabledPings = true; - usePing(); - - if (onconnected) { - onconnected(); - } - }; - - wsConfig.onerror = function (error) { - Logger.debug('--------- ONERROR -----------'); - - status = DISCONNECTED; - - stopPing(); - - if (onerror) { - onerror(error); - } - }; - - var ws = new WebSocketWithReconnection(wsConfig); - - Logger.debug('Connecting websocket to URI: ' + wsConfig.uri); - - var rpcBuilderOptions = { - request_timeout: configuration.rpc.requestTimeout, - ping_request_timeout: configuration.rpc.heartbeatRequestTimeout - }; - - var rpc = new RpcBuilder(RpcBuilder.packers.JsonRPC, rpcBuilderOptions, ws, function (request) { - Logger.debug('Received request: ' + JSON.stringify(request)); - - try { - var func = configuration.rpc[request.method]; - - if (func === undefined) { - Logger.error('Method ' + request.method + ' not registered in client'); - } else { - func(request.params, request); - } - } catch (err) { - Logger.error('Exception processing request: ' + JSON.stringify(request)); - Logger.error(err); - } - }); - - this.send = function (method, params, callback) { - var requestTime = Date.now(); - - rpc.encode(method, params, function (error, result) { - if (error) { - try { - Logger.error( - 'ERROR:' + - error.message + - ' in Request: method:' + - method + - ' params:' + - JSON.stringify(params) + - ' request:' + - error.request - ); - if (error.data) { - Logger.error('ERROR DATA:' + JSON.stringify(error.data)); - } - } catch (e) {} - error.requestTime = requestTime; - } - if (callback) { - if (result != undefined && result.value !== 'pong') { - Logger.debug('Response: ' + JSON.stringify(result)); - } - callback(error, result); - } - }); - }; - - function updateNotReconnectIfLessThan() { - Logger.debug('notReconnectIfNumLessThan = ' + pingNextNum + ' (old=' + notReconnectIfNumLessThan + ')'); - notReconnectIfNumLessThan = pingNextNum; - } - - function sendPing() { - if (enabledPings) { - var params = null; - if (pingNextNum == 0 || pingNextNum == notReconnectIfNumLessThan) { - params = { - interval: configuration.heartbeat || PING_INTERVAL - }; - } - pingNextNum++; - - self.send( - 'ping', - params, - (function (pingNum) { - return function (error, result) { - if (error) { - Logger.debug('Error in ping request #' + pingNum + ' (' + error.message + ')'); - if (pingNum > notReconnectIfNumLessThan) { - enabledPings = false; - updateNotReconnectIfLessThan(); - Logger.debug('Server did not respond to ping message #' + pingNum + '. Reconnecting... '); - ws.reconnectWs(); - } - } - }; - })(pingNextNum) - ); - } else { - Logger.debug('Trying to send ping, but ping is not enabled'); - } - } - - /* - * If configuration.hearbeat has any value, the ping-pong will work with the interval - * of configuration.hearbeat - */ - function usePing() { - if (!pingPongStarted) { - Logger.debug('Starting ping (if configured)'); - pingPongStarted = true; - - if (configuration.heartbeat != undefined) { - pingInterval = setInterval(sendPing, configuration.heartbeat); - sendPing(); - } - } - } - - function stopPing() { - clearInterval(pingInterval); - pingPongStarted = false; - enabledPings = false; - pingNextNum = -1; - rpc.cancel(); - } - - this.close = function (code, reason) { - Logger.debug('Closing with code: ' + code + ' because: ' + reason); - if (pingInterval != undefined) { - Logger.debug('Clearing ping interval'); - clearInterval(pingInterval); - } - pingPongStarted = false; - enabledPings = false; - ws.close(code, reason); - }; - - this.reconnect = function () { - ws.reconnectWs(); - }; - - this.resetPing = function () { - enabledPings = true; - pingNextNum = 0; - usePing(); - }; - - this.getReadyState = function () { - return ws.getReadyState(); - }; -} - -module.exports = JsonRpcClient; diff --git a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/clients/transports/index.js b/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/clients/transports/index.js deleted file mode 100644 index 59c85285f9..0000000000 --- a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/clients/transports/index.js +++ /dev/null @@ -1,20 +0,0 @@ -/* - * (C) Copyright 2014 Kurento (http://kurento.org/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -var WebSocketWithReconnection = require('./webSocketWithReconnection'); - -exports.WebSocketWithReconnection = WebSocketWithReconnection; diff --git a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/clients/transports/webSocketWithReconnection.js b/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/clients/transports/webSocketWithReconnection.js deleted file mode 100644 index 6888dca8a5..0000000000 --- a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/clients/transports/webSocketWithReconnection.js +++ /dev/null @@ -1,161 +0,0 @@ -/* - * (C) Copyright 2013-2015 Kurento (http://kurento.org/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -'use strict'; - -var OpenViduLogger = require('../../../../Logger/OpenViduLogger').OpenViduLogger; -var Logger = OpenViduLogger.getInstance(); - -var MAX_RETRIES = 2000; // Forever... -var RETRY_TIME_MS = 3000; // FIXME: Implement exponential wait times... - -var CONNECTING = 0; -var OPEN = 1; -var CLOSING = 2; -var CLOSED = 3; - -/* -config = { -uri : wsUri, -onconnected : callback method to invoke when connection is successful, -ondisconnect : callback method to invoke when the connection is lost (max retries for reconnecting reached), -onreconnecting : callback method to invoke when the client is reconnecting, -onreconnected : callback method to invoke when the client successfully reconnects, -}; -*/ -function WebSocketWithReconnection(config) { - var closing = false; - var registerMessageHandler; - var wsUri = config.uri; - var reconnecting = false; - - var ws = new WebSocket(wsUri); - - ws.onopen = () => { - Logger.debug('WebSocket connected to ' + wsUri); - if (config.onconnected) { - config.onconnected(); - } - }; - - ws.onerror = (error) => { - Logger.error('Could not connect to ' + wsUri + ' (invoking onerror if defined)', error); - if (config.onerror) { - config.onerror(error); - } - }; - - var reconnectionOnClose = () => { - if (ws.readyState === CLOSED) { - if (closing) { - Logger.debug('Connection closed by user'); - } else { - if (config.ismasternodecrashed()) { - Logger.error('Master Node has crashed. Stopping reconnection process'); - } else { - Logger.debug('Connection closed unexpectedly. Reconnecting...'); - reconnect(MAX_RETRIES, 1); - } - } - } else { - Logger.debug('Close callback from previous websocket. Ignoring it'); - } - }; - - ws.onclose = reconnectionOnClose; - - function reconnect(maxRetries, numRetries) { - Logger.debug('reconnect (attempt #' + numRetries + ', max=' + maxRetries + ')'); - if (numRetries === 1) { - if (reconnecting) { - Logger.warn('Trying to reconnect when already reconnecting... Ignoring this reconnection.'); - return; - } else { - reconnecting = true; - } - if (config.onreconnecting) { - config.onreconnecting(); - } - } - reconnectAux(maxRetries, numRetries); - } - - function addReconnectionQueryParamsIfMissing(uriString) { - var searchParams = new URLSearchParams(new URL(uriString).search); - if (!searchParams.has('reconnect')) { - uriString = Array.from(searchParams).length > 0 ? uriString + '&reconnect=true' : uriString + '?reconnect=true'; - } - return uriString; - } - - function reconnectAux(maxRetries, numRetries) { - Logger.debug('Reconnection attempt #' + numRetries); - ws.close(4104, 'Connection closed for reconnection'); - - wsUri = addReconnectionQueryParamsIfMissing(wsUri); - ws = new WebSocket(wsUri); - - ws.onopen = () => { - Logger.debug('Reconnected to ' + wsUri + ' after ' + numRetries + ' attempts...'); - reconnecting = false; - registerMessageHandler(); - if (config.onreconnected) { - config.onreconnected(); - } - ws.onclose = reconnectionOnClose; - }; - - ws.onerror = (error) => { - Logger.warn('Reconnection error: ', error); - if (numRetries === maxRetries) { - if (config.ondisconnect) { - config.ondisconnect(); - } - } else { - setTimeout(() => { - reconnect(maxRetries, numRetries + 1); - }, RETRY_TIME_MS); - } - }; - } - - this.close = (code, reason) => { - closing = true; - ws.close(code, reason); - }; - - this.reconnectWs = () => { - Logger.debug('reconnectWs'); - reconnect(MAX_RETRIES, 1); - }; - - this.send = (message) => { - ws.send(message); - }; - - this.addEventListener = (type, callback) => { - registerMessageHandler = () => { - ws.addEventListener(type, callback); - }; - registerMessageHandler(); - }; - - this.getReadyState = () => { - return ws.readyState; - }; -} - -module.exports = WebSocketWithReconnection; diff --git a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/index.js b/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/index.js deleted file mode 100644 index fb448400d0..0000000000 --- a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/index.js +++ /dev/null @@ -1,687 +0,0 @@ -/* - * (C) Copyright 2014 Kurento (http://kurento.org/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -var defineProperty_IE8 = false; -if (Object.defineProperty) { - try { - Object.defineProperty({}, 'x', {}); - } catch (e) { - defineProperty_IE8 = true; - } -} - -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind -if (!Function.prototype.bind) { - Function.prototype.bind = function (oThis) { - if (typeof this !== 'function') { - // closest thing possible to the ECMAScript 5 - // internal IsCallable function - throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function () {}, - fBound = function () { - return fToBind.apply(this instanceof fNOP && oThis ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - - return fBound; - }; -} - -var EventEmitter = require('events').EventEmitter; - -var inherits = require('inherits'); - -var packers = require('./packers'); -var Mapper = require('./Mapper'); - -var BASE_TIMEOUT = 5000; - -function unifyResponseMethods(responseMethods) { - if (!responseMethods) return {}; - - for (var key in responseMethods) { - var value = responseMethods[key]; - - if (typeof value == 'string') - responseMethods[key] = { - response: value - }; - } - - return responseMethods; -} - -function unifyTransport(transport) { - if (!transport) return; - - // Transport as a function - if (transport instanceof Function) - return { - send: transport - }; - - // WebSocket & DataChannel - if (transport.send instanceof Function) return transport; - - // Message API (Inter-window & WebWorker) - if (transport.postMessage instanceof Function) { - transport.send = transport.postMessage; - return transport; - } - - // Stream API - if (transport.write instanceof Function) { - transport.send = transport.write; - return transport; - } - - // Transports that only can receive messages, but not send - if (transport.onmessage !== undefined) return; - if (transport.pause instanceof Function) return; - - throw new SyntaxError('Transport is not a function nor a valid object'); -} - -/** - * Representation of a RPC notification - * - * @class - * - * @constructor - * - * @param {String} method -method of the notification - * @param params - parameters of the notification - */ -function RpcNotification(method, params) { - if (defineProperty_IE8) { - this.method = method; - this.params = params; - } else { - Object.defineProperty(this, 'method', { - value: method, - enumerable: true - }); - Object.defineProperty(this, 'params', { - value: params, - enumerable: true - }); - } -} - -/** - * @class - * - * @constructor - * - * @param {object} packer - * - * @param {object} [options] - * - * @param {object} [transport] - * - * @param {Function} [onRequest] - */ -function RpcBuilder(packer, options, transport, onRequest) { - var self = this; - - if (!packer) throw new SyntaxError('Packer is not defined'); - - if (!packer.pack || !packer.unpack) throw new SyntaxError('Packer is invalid'); - - var responseMethods = unifyResponseMethods(packer.responseMethods); - - if (options instanceof Function) { - if (transport != undefined) throw new SyntaxError("There can't be parameters after onRequest"); - - onRequest = options; - transport = undefined; - options = undefined; - } - - if (options && options.send instanceof Function) { - if (transport && !(transport instanceof Function)) throw new SyntaxError('Only a function can be after transport'); - - onRequest = transport; - transport = options; - options = undefined; - } - - if (transport instanceof Function) { - if (onRequest != undefined) throw new SyntaxError("There can't be parameters after onRequest"); - - onRequest = transport; - transport = undefined; - } - - if (transport && transport.send instanceof Function) - if (onRequest && !(onRequest instanceof Function)) throw new SyntaxError('Only a function can be after transport'); - - options = options || {}; - - EventEmitter.call(this); - - if (onRequest) this.on('request', onRequest); - - if (defineProperty_IE8) this.peerID = options.peerID; - else - Object.defineProperty(this, 'peerID', { - value: options.peerID - }); - - var max_retries = options.max_retries || 0; - - function transportMessage(event) { - self.decode(event.data || event); - } - - this.getTransport = function () { - return transport; - }; - this.setTransport = function (value) { - // Remove listener from old transport - if (transport) { - // W3C transports - if (transport.removeEventListener) transport.removeEventListener('message', transportMessage); - // Node.js Streams API - else if (transport.removeListener) transport.removeListener('data', transportMessage); - } - - // Set listener on new transport - if (value) { - // W3C transports - if (value.addEventListener) value.addEventListener('message', transportMessage); - // Node.js Streams API - else if (value.addListener) value.addListener('data', transportMessage); - } - - transport = unifyTransport(value); - }; - - if (!defineProperty_IE8) - Object.defineProperty(this, 'transport', { - get: this.getTransport.bind(this), - set: this.setTransport.bind(this) - }); - - this.setTransport(transport); - - var request_timeout = options.request_timeout || BASE_TIMEOUT; - var ping_request_timeout = options.ping_request_timeout || request_timeout; - var response_timeout = options.response_timeout || BASE_TIMEOUT; - var duplicates_timeout = options.duplicates_timeout || BASE_TIMEOUT; - - var requestID = 0; - - var requests = new Mapper(); - var responses = new Mapper(); - var processedResponses = new Mapper(); - - var message2Key = {}; - - /** - * Store the response to prevent to process duplicate request later - */ - function storeResponse(message, id, dest) { - var response = { - message: message, - /** Timeout to auto-clean old responses */ - timeout: setTimeout(function () { - responses.remove(id, dest); - }, response_timeout) - }; - - responses.set(response, id, dest); - } - - /** - * Store the response to ignore duplicated messages later - */ - function storeProcessedResponse(ack, from) { - var timeout = setTimeout(function () { - processedResponses.remove(ack, from); - }, duplicates_timeout); - - processedResponses.set(timeout, ack, from); - } - - /** - * Representation of a RPC request - * - * @class - * @extends RpcNotification - * - * @constructor - * - * @param {String} method -method of the notification - * @param params - parameters of the notification - * @param {Integer} id - identifier of the request - * @param [from] - source of the notification - */ - function RpcRequest(method, params, id, from, transport) { - RpcNotification.call(this, method, params); - - this.getTransport = function () { - return transport; - }; - this.setTransport = function (value) { - transport = unifyTransport(value); - }; - - if (!defineProperty_IE8) - Object.defineProperty(this, 'transport', { - get: this.getTransport.bind(this), - set: this.setTransport.bind(this) - }); - - var response = responses.get(id, from); - - /** - * @constant {Boolean} duplicated - */ - if (!(transport || self.getTransport())) { - if (defineProperty_IE8) this.duplicated = Boolean(response); - else - Object.defineProperty(this, 'duplicated', { - value: Boolean(response) - }); - } - - var responseMethod = responseMethods[method]; - - this.pack = packer.pack.bind(packer, this, id); - - /** - * Generate a response to this request - * - * @param {Error} [error] - * @param {*} [result] - * - * @returns {string} - */ - this.reply = function (error, result, transport) { - // Fix optional parameters - if (error instanceof Function || (error && error.send instanceof Function)) { - if (result != undefined) throw new SyntaxError("There can't be parameters after callback"); - - transport = error; - result = null; - error = undefined; - } else if (result instanceof Function || (result && result.send instanceof Function)) { - if (transport != undefined) throw new SyntaxError("There can't be parameters after callback"); - - transport = result; - result = null; - } - - transport = unifyTransport(transport); - - // Duplicated request, remove old response timeout - if (response) clearTimeout(response.timeout); - - if (from != undefined) { - if (error) error.dest = from; - - if (result) result.dest = from; - } - - var message; - - // New request or overriden one, create new response with provided data - if (error || result != undefined) { - if (self.peerID != undefined) { - if (error) error.from = self.peerID; - else result.from = self.peerID; - } - - // Protocol indicates that responses has own request methods - if (responseMethod) { - if (responseMethod.error == undefined && error) - message = { - error: error - }; - else { - var method = error ? responseMethod.error : responseMethod.response; - - message = { - method: method, - params: error || result - }; - } - } else - message = { - error: error, - result: result - }; - - message = packer.pack(message, id); - } - - // Duplicate & not-overriden request, re-send old response - else if (response) message = response.message; - // New empty reply, response null value - else - message = packer.pack( - { - result: null - }, - id - ); - - // Store the response to prevent to process a duplicated request later - storeResponse(message, id, from); - - // Return the stored response so it can be directly send back - transport = transport || this.getTransport() || self.getTransport(); - - if (transport) return transport.send(message); - - return message; - }; - } - inherits(RpcRequest, RpcNotification); - - function cancel(message) { - var key = message2Key[message]; - if (!key) return; - - delete message2Key[message]; - - var request = requests.pop(key.id, key.dest); - if (!request) return; - - clearTimeout(request.timeout); - - // Start duplicated responses timeout - storeProcessedResponse(key.id, key.dest); - } - - /** - * Allow to cancel a request and don't wait for a response - * - * If `message` is not given, cancel all the request - */ - this.cancel = function (message) { - if (message) return cancel(message); - - for (var message in message2Key) cancel(message); - }; - - this.close = function () { - // Prevent to receive new messages - var transport = this.getTransport(); - if (transport && transport.close) transport.close(4003, 'Cancel request'); - - // Request & processed responses - this.cancel(); - - processedResponses.forEach(clearTimeout); - - // Responses - responses.forEach(function (response) { - clearTimeout(response.timeout); - }); - }; - - /** - * Generates and encode a JsonRPC 2.0 message - * - * @param {String} method -method of the notification - * @param params - parameters of the notification - * @param [dest] - destination of the notification - * @param {object} [transport] - transport where to send the message - * @param [callback] - function called when a response to this request is - * received. If not defined, a notification will be send instead - * - * @returns {string} A raw JsonRPC 2.0 request or notification string - */ - this.encode = function (method, params, dest, transport, callback) { - // Fix optional parameters - if (params instanceof Function) { - if (dest != undefined) throw new SyntaxError("There can't be parameters after callback"); - - callback = params; - transport = undefined; - dest = undefined; - params = undefined; - } else if (dest instanceof Function) { - if (transport != undefined) throw new SyntaxError("There can't be parameters after callback"); - - callback = dest; - transport = undefined; - dest = undefined; - } else if (transport instanceof Function) { - if (callback != undefined) throw new SyntaxError("There can't be parameters after callback"); - - callback = transport; - transport = undefined; - } - - if (self.peerID != undefined) { - params = params || {}; - - params.from = self.peerID; - } - - if (dest != undefined) { - params = params || {}; - - params.dest = dest; - } - - // Encode message - var message = { - method: method, - params: params - }; - - if (callback) { - var id = requestID++; - var retried = 0; - - message = packer.pack(message, id); - - function dispatchCallback(error, result) { - self.cancel(message); - - callback(error, result); - } - - var request = { - message: message, - callback: dispatchCallback, - responseMethods: responseMethods[method] || {} - }; - - var encode_transport = unifyTransport(transport); - - function sendRequest(transport) { - var rt = method === 'ping' ? ping_request_timeout : request_timeout; - request.timeout = setTimeout(timeout, rt * Math.pow(2, retried++)); - message2Key[message] = { - id: id, - dest: dest - }; - requests.set(request, id, dest); - - transport = transport || encode_transport || self.getTransport(); - if (transport) return transport.send(message); - - return message; - } - - function retry(transport) { - transport = unifyTransport(transport); - - console.warn(retried + ' retry for request message:', message); - - var timeout = processedResponses.pop(id, dest); - clearTimeout(timeout); - - return sendRequest(transport); - } - - function timeout() { - if (retried < max_retries) return retry(transport); - - var error = new Error('Request has timed out'); - error.request = message; - - error.retry = retry; - - dispatchCallback(error); - } - - return sendRequest(transport); - } - - // Return the packed message - message = packer.pack(message); - - transport = transport || this.getTransport(); - if (transport) return transport.send(message); - - return message; - }; - - /** - * Decode and process a JsonRPC 2.0 message - * - * @param {string} message - string with the content of the message - * - * @returns {RpcNotification|RpcRequest|undefined} - the representation of the - * notification or the request. If a response was processed, it will return - * `undefined` to notify that it was processed - * - * @throws {TypeError} - Message is not defined - */ - this.decode = function (message, transport) { - if (!message) throw new TypeError('Message is not defined'); - - try { - message = packer.unpack(message); - } catch (e) { - // Ignore invalid messages - return console.debug(e, message); - } - - var id = message.id; - var ack = message.ack; - var method = message.method; - var params = message.params || {}; - - var from = params.from; - var dest = params.dest; - - // Ignore messages send by us - if (self.peerID != undefined && from == self.peerID) return; - - // Notification - if (id == undefined && ack == undefined) { - var notification = new RpcNotification(method, params); - - if (self.emit('request', notification)) return; - return notification; - } - - function processRequest() { - // If we have a transport and it's a duplicated request, reply inmediatly - transport = unifyTransport(transport) || self.getTransport(); - if (transport) { - var response = responses.get(id, from); - if (response) return transport.send(response.message); - } - - var idAck = id != undefined ? id : ack; - var request = new RpcRequest(method, params, idAck, from, transport); - - if (self.emit('request', request)) return; - return request; - } - - function processResponse(request, error, result) { - request.callback(error, result); - } - - function duplicatedResponse(timeout) { - console.warn('Response already processed', message); - - // Update duplicated responses timeout - clearTimeout(timeout); - storeProcessedResponse(ack, from); - } - - // Request, or response with own method - if (method) { - // Check if it's a response with own method - if (dest == undefined || dest == self.peerID) { - var request = requests.get(ack, from); - if (request) { - var responseMethods = request.responseMethods; - - if (method == responseMethods.error) return processResponse(request, params); - - if (method == responseMethods.response) return processResponse(request, null, params); - - return processRequest(); - } - - var processed = processedResponses.get(ack, from); - if (processed) return duplicatedResponse(processed); - } - - // Request - return processRequest(); - } - - var error = message.error; - var result = message.result; - - // Ignore responses not send to us - if (error && error.dest && error.dest != self.peerID) return; - if (result && result.dest && result.dest != self.peerID) return; - - // Response - var request = requests.get(ack, from); - if (!request) { - var processed = processedResponses.get(ack, from); - if (processed) return duplicatedResponse(processed); - - return console.warn('No callback was defined for this message', message); - } - - // Process response - processResponse(request, error, result); - }; -} -inherits(RpcBuilder, EventEmitter); - -RpcBuilder.RpcNotification = RpcNotification; - -module.exports = RpcBuilder; - -var clients = require('./clients'); -var transports = require('./clients/transports'); - -RpcBuilder.clients = clients; -RpcBuilder.clients.transports = transports; -RpcBuilder.packers = packers; diff --git a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/packers/JsonRPC.js b/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/packers/JsonRPC.js deleted file mode 100644 index b318c6b93a..0000000000 --- a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/packers/JsonRPC.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * JsonRPC 2.0 packer - */ - -/** - * Pack a JsonRPC 2.0 message - * - * @param {Object} message - object to be packaged. It requires to have all the - * fields needed by the JsonRPC 2.0 message that it's going to be generated - * - * @return {String} - the stringified JsonRPC 2.0 message - */ -function pack(message, id) { - var result = { - jsonrpc: '2.0' - }; - - // Request - if (message.method) { - result.method = message.method; - - if (message.params) result.params = message.params; - - // Request is a notification - if (id != undefined) result.id = id; - } - - // Response - else if (id != undefined) { - if (message.error) { - if (message.result !== undefined) throw new TypeError('Both result and error are defined'); - - result.error = message.error; - } else if (message.result !== undefined) result.result = message.result; - else throw new TypeError('No result or error is defined'); - - result.id = id; - } - - return JSON.stringify(result); -} - -/** - * Unpack a JsonRPC 2.0 message - * - * @param {String} message - string with the content of the JsonRPC 2.0 message - * - * @throws {TypeError} - Invalid JsonRPC version - * - * @return {Object} - object filled with the JsonRPC 2.0 message content - */ -function unpack(message) { - var result = message; - - if (typeof message === 'string' || message instanceof String) { - result = JSON.parse(message); - } - - // Check if it's a valid message - - var version = result.jsonrpc; - if (version !== '2.0') throw new TypeError("Invalid JsonRPC version '" + version + "': " + message); - - // Response - if (result.method == undefined) { - if (result.id == undefined) throw new TypeError('Invalid message: ' + message); - - var result_defined = result.result !== undefined; - var error_defined = result.error !== undefined; - - // Check only result or error is defined, not both or none - if (result_defined && error_defined) throw new TypeError('Both result and error are defined: ' + message); - - if (!result_defined && !error_defined) throw new TypeError('No result or error is defined: ' + message); - - result.ack = result.id; - delete result.id; - } - - // Return unpacked message - return result; -} - -exports.pack = pack; -exports.unpack = unpack; diff --git a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/packers/XmlRPC.js b/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/packers/XmlRPC.js deleted file mode 100644 index 0a437e6866..0000000000 --- a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/packers/XmlRPC.js +++ /dev/null @@ -1,10 +0,0 @@ -function pack(message) { - throw new TypeError('Not yet implemented'); -} - -function unpack(message) { - throw new TypeError('Not yet implemented'); -} - -exports.pack = pack; -exports.unpack = unpack; diff --git a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/packers/index.js b/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/packers/index.js deleted file mode 100644 index 34949b95a4..0000000000 --- a/openvidu-browser/src/OpenViduInternal/KurentoUtils/kurento-jsonrpc/packers/index.js +++ /dev/null @@ -1,5 +0,0 @@ -var JsonRPC = require('./JsonRPC'); -var XmlRPC = require('./XmlRPC'); - -exports.JsonRPC = JsonRPC; -exports.XmlRPC = XmlRPC; diff --git a/openvidu-browser/src/OpenViduInternal/Logger/ConsoleLogger.ts b/openvidu-browser/src/OpenViduInternal/Logger/ConsoleLogger.ts deleted file mode 100644 index 58584fdd0f..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Logger/ConsoleLogger.ts +++ /dev/null @@ -1,41 +0,0 @@ -type ConsoleFunction = (...data: any) => void; -export class ConsoleLogger { - /** - * @hidden - */ - logger: Console; - - /** - * @hidden - */ - log: ConsoleFunction; - - /** - * @hidden - */ - info: ConsoleFunction; - - /** - * @hidden - */ - debug: ConsoleFunction; - - /** - * @hidden - */ - warn: ConsoleFunction; - - /** - * @hidden - */ - error: ConsoleFunction; - - constructor(console: Console) { - this.logger = console; - (this.log = console.log), - (this.info = console.info), - (this.debug = console.debug), - (this.warn = console.warn), - (this.error = console.error); - } -} diff --git a/openvidu-browser/src/OpenViduInternal/Logger/OpenViduLogger.ts b/openvidu-browser/src/OpenViduInternal/Logger/OpenViduLogger.ts deleted file mode 100644 index deaad66071..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Logger/OpenViduLogger.ts +++ /dev/null @@ -1,285 +0,0 @@ -import { JL } from 'jsnlog'; -import { OpenVidu } from '../../OpenVidu/OpenVidu'; -import { ConsoleLogger } from './ConsoleLogger'; -import { OpenViduLoggerConfiguration } from './OpenViduLoggerConfiguration'; - -export class OpenViduLogger { - private static instance: OpenViduLogger; - - private JSNLOG_URL: string = '/openvidu/elk/openvidu-browser-logs'; - private MAX_JSNLOG_BATCH_LOG_MESSAGES: number = 100; - private MAX_MSECONDS_BATCH_MESSAGES: number = 5000; - private MAX_LENGTH_STRING_JSON: number = 1000; - - private defaultConsoleLogger: ConsoleLogger = new ConsoleLogger(globalThis.console); - - private currentAppender: any; - - private isProdMode = false; - private isJSNLogSetup = false; - - // This two variables are used to restart JSNLog - // on different sessions and different userIds - private loggingSessionId: string | undefined; - - /** - * @hidden - */ - static configureJSNLog(openVidu: OpenVidu, token: string) { - try { - // If dev mode or... - if ( - globalThis['LOG_JSNLOG_RESULTS'] || - // If instance is created and it is OpenVidu Pro - (this.instance && - openVidu.isAtLeastPro && - // If logs are enabled - this.instance.isOpenViduBrowserLogsDebugActive(openVidu) && - // Only reconfigure it if session or finalUserId has changed - this.instance.canConfigureJSNLog(openVidu, this.instance)) - ) { - // Check if app logs can be sent - // and replace console.log function to send - // logs of the application - if (openVidu.sendBrowserLogs === OpenViduLoggerConfiguration.debug_app) { - this.instance.replaceWindowConsole(); - } - - // isJSNLogSetup will not be true until completed setup - this.instance.isJSNLogSetup = false; - this.instance.info('Configuring JSNLogs.'); - - const finalUserId = openVidu.finalUserId; - const sessionId = openVidu.session.sessionId; - - const beforeSendCallback = (xhr) => { - // If 401 or 403 or 404 modify ready and status so JSNLog don't retry to send logs - // https://github.com/mperdeck/jsnlog.js/blob/v2.30.0/jsnlog.ts#L805-L818 - const parentReadyStateFunction = xhr.onreadystatechange; - xhr.onreadystatechange = () => { - if (this.isInvalidResponse(xhr)) { - Object.defineProperty(xhr, 'readyState', { value: 4 }); - Object.defineProperty(xhr, 'status', { value: 200 }); - // Disable JSNLog too to not send periodically errors - this.instance.disableLogger(); - } - parentReadyStateFunction(); - }; - - // Headers to identify and authenticate logs - xhr.setRequestHeader('Authorization', 'Basic ' + btoa(`${finalUserId}%/%${sessionId}` + ':' + token)); - xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); - // Additional headers for OpenVidu - xhr.setRequestHeader('OV-Final-User-Id', finalUserId); - xhr.setRequestHeader('OV-Session-Id', sessionId); - xhr.setRequestHeader('OV-Token', token); - }; - - // Creation of the appender. - this.instance.currentAppender = JL.createAjaxAppender(`appender-${finalUserId}-${sessionId}`); - this.instance.currentAppender.setOptions({ - beforeSend: beforeSendCallback, - maxBatchSize: 1000, - batchSize: this.instance.MAX_JSNLOG_BATCH_LOG_MESSAGES, - batchTimeout: this.instance.MAX_MSECONDS_BATCH_MESSAGES - }); - - // Avoid circular dependencies - const logSerializer = (obj): string => { - const getCircularReplacer = () => { - const seen = new WeakSet(); - return (key, value) => { - if (typeof value === 'object' && value != null) { - if (seen.has(value) || (globalThis.HTMLElement && value instanceof HTMLElement)) { - return; - } - seen.add(value); - } - return value; - }; - }; - - // Cut long messages - let stringifyJson = JSON.stringify(obj, getCircularReplacer()); - if (stringifyJson.length > this.instance.MAX_LENGTH_STRING_JSON) { - stringifyJson = `${stringifyJson.substring(0, this.instance.MAX_LENGTH_STRING_JSON)}...`; - } - - if (globalThis['LOG_JSNLOG_RESULTS']) { - console.log(stringifyJson); - } - - return stringifyJson; - }; - - // Initialize JL to send logs - JL.setOptions({ - defaultAjaxUrl: openVidu.httpUri + this.instance.JSNLOG_URL, - serialize: logSerializer, - enabled: true - }); - JL().setOptions({ - appenders: [this.instance.currentAppender] - }); - - this.instance.isJSNLogSetup = true; - this.instance.loggingSessionId = sessionId; - this.instance.info('JSNLog configured.'); - } - } catch (e) { - // Print error - console.error('Error configuring JSNLog: '); - console.error(e); - // Restore defaults values just in case any exception happen- - this.instance.disableLogger(); - } - } - - /** - * @hidden - */ - static getInstance(): OpenViduLogger { - if (!OpenViduLogger.instance) { - OpenViduLogger.instance = new OpenViduLogger(); - } - return OpenViduLogger.instance; - } - - private static isInvalidResponse(xhr: XMLHttpRequest) { - return xhr.status == 401 || xhr.status == 403 || xhr.status == 404 || xhr.status == 0; - } - - private canConfigureJSNLog(openVidu: OpenVidu, logger: OpenViduLogger): boolean { - return openVidu.session.sessionId != logger.loggingSessionId; - } - - private isOpenViduBrowserLogsDebugActive(openVidu: OpenVidu) { - return ( - openVidu.sendBrowserLogs === OpenViduLoggerConfiguration.debug || - openVidu.sendBrowserLogs === OpenViduLoggerConfiguration.debug_app - ); - } - - // Return console functions with jsnlog integration - private getConsoleWithJSNLog() { - return (function (openViduLogger: OpenViduLogger) { - return { - log: function (...args) { - openViduLogger.defaultConsoleLogger.log.apply(openViduLogger.defaultConsoleLogger.logger, arguments); - if (openViduLogger.isJSNLogSetup) { - JL().info(arguments); - } - }, - info: function (...args) { - openViduLogger.defaultConsoleLogger.info.apply(openViduLogger.defaultConsoleLogger.logger, arguments); - if (openViduLogger.isJSNLogSetup) { - JL().info(arguments); - } - }, - debug: function (...args) { - openViduLogger.defaultConsoleLogger.debug.apply(openViduLogger.defaultConsoleLogger.logger, arguments); - }, - warn: function (...args) { - openViduLogger.defaultConsoleLogger.warn.apply(openViduLogger.defaultConsoleLogger.logger, arguments); - if (openViduLogger.isJSNLogSetup) { - JL().warn(arguments); - } - }, - error: function (...args) { - openViduLogger.defaultConsoleLogger.error.apply(openViduLogger.defaultConsoleLogger.logger, arguments); - if (openViduLogger.isJSNLogSetup) { - JL().error(arguments); - } - } - }; - })(this); - } - - private replaceWindowConsole() { - globalThis.console = this.defaultConsoleLogger.logger; - globalThis.console.log = this.getConsoleWithJSNLog().log; - globalThis.console.info = this.getConsoleWithJSNLog().info; - globalThis.console.debug = this.getConsoleWithJSNLog().debug; - globalThis.console.warn = this.getConsoleWithJSNLog().warn; - globalThis.console.error = this.getConsoleWithJSNLog().error; - } - - private disableLogger() { - JL.setOptions({ enabled: false }); - this.isJSNLogSetup = false; - this.loggingSessionId = undefined; - this.currentAppender = undefined; - globalThis.console = this.defaultConsoleLogger.logger; - globalThis.console.log = this.defaultConsoleLogger.log; - globalThis.console.info = this.defaultConsoleLogger.info; - globalThis.console.debug = this.defaultConsoleLogger.debug; - globalThis.console.warn = this.defaultConsoleLogger.warn; - globalThis.console.error = this.defaultConsoleLogger.error; - } - - /** - * @hidden - */ - log(...args: any[]) { - if (!this.isProdMode) { - this.defaultConsoleLogger.log.apply(this.defaultConsoleLogger.logger, arguments); - } - if (this.isJSNLogSetup) { - JL().info(arguments); - } - } - - /** - * @hidden - */ - debug(...args: any[]) { - if (!this.isProdMode) { - this.defaultConsoleLogger.debug.apply(this.defaultConsoleLogger.logger, arguments); - } - } - - /** - * @hidden - */ - info(...args: any[]) { - if (!this.isProdMode) { - this.defaultConsoleLogger.info.apply(this.defaultConsoleLogger.logger, arguments); - } - if (this.isJSNLogSetup) { - JL().info(arguments); - } - } - - /** - * @hidden - */ - warn(...args: any[]) { - this.defaultConsoleLogger.warn.apply(this.defaultConsoleLogger.logger, arguments); - if (this.isJSNLogSetup) { - JL().warn(arguments); - } - } - - /** - * @hidden - */ - error(...args: any[]) { - this.defaultConsoleLogger.error.apply(this.defaultConsoleLogger.logger, arguments); - if (this.isJSNLogSetup) { - JL().error(arguments); - } - } - - /** - * @hidden - */ - flush() { - if (this.isJSNLogSetup && this.currentAppender != null) { - this.currentAppender.sendBatch(); - } - } - - enableProdMode() { - this.isProdMode = true; - } -} diff --git a/openvidu-browser/src/OpenViduInternal/Logger/OpenViduLoggerConfiguration.ts b/openvidu-browser/src/OpenViduInternal/Logger/OpenViduLoggerConfiguration.ts deleted file mode 100644 index ff8d34ac5f..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Logger/OpenViduLoggerConfiguration.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum OpenViduLoggerConfiguration { - disabled = 'disabled', - debug = 'debug', - debug_app = 'debug_app' -} diff --git a/openvidu-browser/src/OpenViduInternal/ScreenSharing/Screen-Capturing-Auto.js b/openvidu-browser/src/OpenViduInternal/ScreenSharing/Screen-Capturing-Auto.js deleted file mode 100644 index 250ca60d4b..0000000000 --- a/openvidu-browser/src/OpenViduInternal/ScreenSharing/Screen-Capturing-Auto.js +++ /dev/null @@ -1,233 +0,0 @@ -// Last time updated on June 08, 2018 - -// Latest file can be found here: https://cdn.webrtc-experiment.com/getScreenId.js - -// Muaz Khan - www.MuazKhan.com -// MIT License - www.WebRTC-Experiment.com/licence -// Documentation - https://github.com/muaz-khan/getScreenId. - -// ______________ -// getScreenId.js - -/* -getScreenId(function (error, sourceId, screen_constraints) { - // error == null || 'permission-denied' || 'not-installed' || 'installed-disabled' || 'not-chrome' - // sourceId == null || 'string' || 'firefox' - - if(microsoftEdge) { - navigator.getDisplayMedia(screen_constraints).then(onSuccess, onFailure); - } - else { - navigator.mediaDevices.getUserMedia(screen_constraints).then(onSuccess)catch(onFailure); - } -}, 'pass second parameter only if you want system audio'); -*/ - -globalThis.getScreenId = function (firefoxString, callback, custom_parameter) { - if (navigator.userAgent.indexOf('Edge') !== -1 && (!!navigator.msSaveOrOpenBlob || !!navigator.msSaveBlob)) { - // microsoft edge => navigator.getDisplayMedia(screen_constraints).then(onSuccess, onFailure); - callback({ - video: true - }); - return; - } - - // for Firefox: - // sourceId == 'firefox' - // screen_constraints = {...} - if (!!navigator.mozGetUserMedia) { - callback(null, 'firefox', { - video: { - mozMediaSource: firefoxString, - mediaSource: firefoxString - } - }); - return; - } - - globalThis.addEventListener('message', onIFrameCallback); - - function onIFrameCallback(event) { - if (!event.data) return; - - if (event.data.chromeMediaSourceId) { - if (event.data.chromeMediaSourceId === 'PermissionDeniedError') { - callback('permission-denied'); - } else { - callback( - null, - event.data.chromeMediaSourceId, - getScreenConstraints(null, event.data.chromeMediaSourceId, event.data.canRequestAudioTrack) - ); - } - - // this event listener is no more needed - globalThis.removeEventListener('message', onIFrameCallback); - } - - if (event.data.chromeExtensionStatus) { - callback(event.data.chromeExtensionStatus, null, getScreenConstraints(event.data.chromeExtensionStatus)); - - // this event listener is no more needed - globalThis.removeEventListener('message', onIFrameCallback); - } - } - - if (!custom_parameter) { - setTimeout(postGetSourceIdMessage, 100); - } else { - setTimeout(function () { - postGetSourceIdMessage(custom_parameter); - }, 100); - } -}; - -function getScreenConstraints(error, sourceId, canRequestAudioTrack) { - var screen_constraints = { - audio: false, - video: { - mandatory: { - chromeMediaSource: error ? 'screen' : 'desktop', - maxWidth: globalThis.screen.width > 1920 ? globalThis.screen.width : 1920, - maxHeight: globalThis.screen.height > 1080 ? globalThis.screen.height : 1080 - }, - optional: [] - } - }; - - if (!!canRequestAudioTrack) { - screen_constraints.audio = { - mandatory: { - chromeMediaSource: error ? 'screen' : 'desktop' - // echoCancellation: true - }, - optional: [] - }; - } - - if (sourceId) { - screen_constraints.video.mandatory.chromeMediaSourceId = sourceId; - - if (screen_constraints.audio && screen_constraints.audio.mandatory) { - screen_constraints.audio.mandatory.chromeMediaSourceId = sourceId; - } - } - - return screen_constraints; -} - -function postGetSourceIdMessage(custom_parameter) { - if (!iframe) { - loadIFrame(function () { - postGetSourceIdMessage(custom_parameter); - }); - return; - } - - if (!iframe.isLoaded) { - setTimeout(function () { - postGetSourceIdMessage(custom_parameter); - }, 100); - return; - } - - if (!custom_parameter) { - iframe.contentWindow.postMessage( - { - captureSourceId: true - }, - '*' - ); - } else if (!!custom_parameter.forEach) { - iframe.contentWindow.postMessage( - { - captureCustomSourceId: custom_parameter - }, - '*' - ); - } else { - iframe.contentWindow.postMessage( - { - captureSourceIdWithAudio: true - }, - '*' - ); - } -} - -var iframe; - -// this function is used in RTCMultiConnection v3 -globalThis.getScreenConstraints = function (callback) { - loadIFrame(function () { - getScreenId(function (error, sourceId, screen_constraints) { - if (!screen_constraints) { - screen_constraints = { - video: true - }; - } - - callback(error, screen_constraints.video); - }); - }); -}; - -function loadIFrame(loadCallback) { - if (iframe) { - loadCallback(); - return; - } - - iframe = document.createElement('iframe'); - iframe.onload = function () { - iframe.isLoaded = true; - loadCallback(); - }; - iframe.src = 'https://openvidu.github.io/openvidu-screen-sharing-chrome-extension/'; - iframe.style.display = 'none'; - (document.body || document.documentElement).appendChild(iframe); -} - -globalThis.getChromeExtensionStatus = function (callback) { - // for Firefox: - if (!!navigator.mozGetUserMedia) { - callback('installed-enabled'); - return; - } - - globalThis.addEventListener('message', onIFrameCallback); - - function onIFrameCallback(event) { - if (!event.data) return; - - if (event.data.chromeExtensionStatus) { - callback(event.data.chromeExtensionStatus); - - // this event listener is no more needed - globalThis.removeEventListener('message', onIFrameCallback); - } - } - - setTimeout(postGetChromeExtensionStatusMessage, 100); -}; - -function postGetChromeExtensionStatusMessage() { - if (!iframe) { - loadIFrame(postGetChromeExtensionStatusMessage); - return; - } - - if (!iframe.isLoaded) { - setTimeout(postGetChromeExtensionStatusMessage, 100); - return; - } - - iframe.contentWindow.postMessage( - { - getChromeExtensionStatus: true - }, - '*' - ); -} - -exports.getScreenId = globalThis.getScreenId; diff --git a/openvidu-browser/src/OpenViduInternal/ScreenSharing/Screen-Capturing.js b/openvidu-browser/src/OpenViduInternal/ScreenSharing/Screen-Capturing.js deleted file mode 100644 index 0eb3cfd378..0000000000 --- a/openvidu-browser/src/OpenViduInternal/ScreenSharing/Screen-Capturing.js +++ /dev/null @@ -1,162 +0,0 @@ -// global variables -var chromeMediaSource = 'screen'; -var sourceId; -var screenCallback; - -if (typeof window !== 'undefined' && typeof navigator !== 'undefined' && typeof navigator.userAgent !== 'undefined') { - var isFirefox = typeof window.InstallTrigger !== 'undefined'; - var isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0; - var isChrome = !!window.chrome && !isOpera; - - window.addEventListener('message', function (event) { - if (event.origin != window.location.origin) { - return; - } - onMessageCallback(event.data); - }); -} - -// and the function that handles received messages -function onMessageCallback(data) { - // "cancel" button is clicked - if (data == 'PermissionDeniedError') { - if (screenCallback) return screenCallback('PermissionDeniedError'); - else throw new Error('PermissionDeniedError'); - } - // extension notified his presence - if (data == 'rtcmulticonnection-extension-loaded') { - chromeMediaSource = 'desktop'; - } - // extension shared temp sourceId - if (data.sourceId && screenCallback) { - screenCallback((sourceId = data.sourceId), data.canRequestAudioTrack === true); - } -} - -// this method can be used to check if chrome extension is installed & enabled. -function isChromeExtensionAvailable(callback) { - if (!callback) return; - if (chromeMediaSource == 'desktop') return callback(true); - - // ask extension if it is available - window.postMessage('are-you-there', '*'); - setTimeout(function () { - if (chromeMediaSource == 'screen') { - callback(false); - } else callback(true); - }, 2000); -} - -// this function can be used to get "source-id" from the extension -function getSourceId(callback) { - if (!callback) throw '"callback" parameter is mandatory.'; - if (sourceId) return callback(sourceId); - screenCallback = callback; - window.postMessage('get-sourceId', '*'); -} - -// this function can be used to get "source-id" from the extension -function getCustomSourceId(arr, callback) { - if (!arr || !arr.forEach) throw '"arr" parameter is mandatory and it must be an array.'; - if (!callback) throw '"callback" parameter is mandatory.'; - - if (sourceId) return callback(sourceId); - - screenCallback = callback; - window.postMessage( - { - 'get-custom-sourceId': arr - }, - '*' - ); -} - -// this function can be used to get "source-id" from the extension -function getSourceIdWithAudio(callback) { - if (!callback) throw '"callback" parameter is mandatory.'; - if (sourceId) return callback(sourceId); - - screenCallback = callback; - window.postMessage('audio-plus-tab', '*'); -} - -function getChromeExtensionStatus(extensionid, callback) { - if (isFirefox) return callback('not-chrome'); - if (arguments.length != 2) { - callback = extensionid; - extensionid = 'lfcgfepafnobdloecchnfaclibenjold'; // default extension-id - } - var image = document.createElement('img'); - image.src = 'chrome-extension://' + extensionid + '/icon.png'; - image.onload = function () { - chromeMediaSource = 'screen'; - window.postMessage('are-you-there', '*'); - setTimeout(function () { - if (chromeMediaSource == 'screen') { - callback('installed-disabled'); - } else callback('installed-enabled'); - }, 2000); - }; - image.onerror = function () { - callback('not-installed'); - }; -} - -function getScreenConstraintsWithAudio(callback) { - getScreenConstraints(callback, true); -} - -// this function explains how to use above methods/objects -function getScreenConstraints(callback, captureSourceIdWithAudio) { - sourceId = ''; - var firefoxScreenConstraints = { - mozMediaSource: 'window', - mediaSource: 'window' - }; - if (isFirefox) return callback(null, firefoxScreenConstraints); - // this statement defines getUserMedia constraints - // that will be used to capture content of screen - var screen_constraints = { - mandatory: { - chromeMediaSource: chromeMediaSource, - maxWidth: screen.width > 1920 ? screen.width : 1920, - maxHeight: screen.height > 1080 ? screen.height : 1080 - }, - optional: [] - }; - // this statement verifies chrome extension availability - // if installed and available then it will invoke extension API - // otherwise it will fallback to command-line based screen capturing API - if (chromeMediaSource == 'desktop' && !sourceId) { - if (captureSourceIdWithAudio) { - getSourceIdWithAudio(function (sourceId, canRequestAudioTrack) { - screen_constraints.mandatory.chromeMediaSourceId = sourceId; - - if (canRequestAudioTrack) { - screen_constraints.canRequestAudioTrack = true; - } - callback(sourceId == 'PermissionDeniedError' ? sourceId : null, screen_constraints); - }); - } else { - getSourceId(function (sourceId) { - screen_constraints.mandatory.chromeMediaSourceId = sourceId; - callback(sourceId == 'PermissionDeniedError' ? sourceId : null, screen_constraints); - }); - } - return; - } - - // this statement sets gets 'sourceId" and sets "chromeMediaSourceId" - if (chromeMediaSource == 'desktop') { - screen_constraints.mandatory.chromeMediaSourceId = sourceId; - } - - // now invoking native getUserMedia API - callback(null, screen_constraints); -} - -exports.getScreenConstraints = getScreenConstraints; -exports.getScreenConstraintsWithAudio = getScreenConstraintsWithAudio; -exports.isChromeExtensionAvailable = isChromeExtensionAvailable; -exports.getChromeExtensionStatus = getChromeExtensionStatus; -exports.getSourceId = getSourceId; diff --git a/openvidu-browser/src/OpenViduInternal/Utils/Platform.ts b/openvidu-browser/src/OpenViduInternal/Utils/Platform.ts deleted file mode 100644 index 7cf6e30131..0000000000 --- a/openvidu-browser/src/OpenViduInternal/Utils/Platform.ts +++ /dev/null @@ -1,233 +0,0 @@ -import platform = require('platform'); - -export class PlatformUtils { - protected static instance: PlatformUtils; - constructor() {} - - static getInstance(): PlatformUtils { - if (!this.instance) { - this.instance = new PlatformUtils(); - } - return PlatformUtils.instance; - } - - public isChromeBrowser(): boolean { - return platform.name === 'Chrome'; - } - - /** - * @hidden - */ - public isSafariBrowser(): boolean { - return platform.name === 'Safari'; - } - - /** - * @hidden - */ - public isChromeMobileBrowser(): boolean { - return platform.name === 'Chrome Mobile'; - } - - /** - * @hidden - */ - public isFirefoxBrowser(): boolean { - return platform.name === 'Firefox'; - } - - /** - * @hidden - */ - public isFirefoxMobileBrowser(): boolean { - return platform.name === 'Firefox Mobile' || platform.name === 'Firefox for iOS'; - } - - /** - * @hidden - */ - public isOperaBrowser(): boolean { - return platform.name === 'Opera'; - } - - /** - * @hidden - */ - public isOperaMobileBrowser(): boolean { - return platform.name === 'Opera Mobile'; - } - - /** - * @hidden - */ - public isEdgeBrowser(): boolean { - const version = platform?.version ? parseFloat(platform.version) : -1; - return platform.name === 'Microsoft Edge' && version >= 80; - } - - /** - * @hidden - */ - public isEdgeMobileBrowser(): boolean { - const version = platform?.version ? parseFloat(platform.version) : -1; - return platform.name === 'Microsoft Edge' && (platform.os?.family === 'Android' || platform.os?.family === 'iOS') && version > 45; - } - - /** - * @hidden - */ - public isAndroidBrowser(): boolean { - return platform.name === 'Android Browser'; - } - - /** - * @hidden - */ - public isElectron(): boolean { - return platform.name === 'Electron'; - } - - /** - * @hidden - */ - public isNodeJs(): boolean { - return platform.name === 'Node.js'; - } - - /** - * @hidden - */ - public isSamsungBrowser(): boolean { - return platform.name === 'Samsung Internet Mobile' || platform.name === 'Samsung Internet'; - } - - // TODO: This method exists to overcome bug https://github.com/bestiejs/platform.js/issues/184 - /** - * @hidden - */ - public isMotorolaEdgeDevice(): boolean { - return platform.product?.toLowerCase().includes('motorola edge') || false; - } - - /** - * @hidden - */ - public isIPhoneOrIPad(): boolean { - const userAgent = !!platform.ua ? platform.ua : navigator.userAgent; - const isTouchable = 'ontouchend' in document; - const isIPad = /\b(\w*Macintosh\w*)\b/.test(userAgent) && isTouchable; - const isIPhone = /\b(\w*iPhone\w*)\b/.test(userAgent) && /\b(\w*Mobile\w*)\b/.test(userAgent) && isTouchable; - return isIPad || isIPhone; - } - - /** - * @hidden - */ - public isIOSWithSafari(): boolean { - const userAgent = !!platform.ua ? platform.ua : navigator.userAgent; - return ( - this.isIPhoneOrIPad() && - /\b(\w*Apple\w*)\b/.test(navigator.vendor) && - /\b(\w*Safari\w*)\b/.test(userAgent) && - !/\b(\w*CriOS\w*)\b/.test(userAgent) && - !/\b(\w*FxiOS\w*)\b/.test(userAgent) - ); - } - - /** - * @hidden - */ - public isIonicIos(): boolean { - return this.isIPhoneOrIPad() && platform.ua!!.indexOf('Safari') === -1; - } - - /** - * @hidden - */ - public isIonicAndroid(): boolean { - return platform.os!!.family === 'Android' && platform.name == 'Android Browser'; - } - - /** - * @hidden - */ - public isMobileDevice(): boolean { - return platform.os!!.family === 'iOS' || platform.os!!.family === 'Android'; - } - - /** - * @hidden - */ - public isReactNative(): boolean { - return false; - } - - /** - * @hidden - */ - public isChromium(): boolean { - return ( - this.isChromeBrowser() || - this.isChromeMobileBrowser() || - this.isOperaBrowser() || - this.isOperaMobileBrowser() || - this.isEdgeBrowser() || - this.isEdgeMobileBrowser() || - this.isSamsungBrowser() || - this.isIonicAndroid() || - this.isIonicIos() || - this.isElectron() || - // TODO: remove when possible - this.isMotorolaEdgeDevice() - ); - } - - - - /** - * @hidden - */ - public canScreenShare(): boolean { - const version = platform?.version ? parseFloat(platform.version) : -1; - // Reject mobile devices - if (this.isMobileDevice()) { - return false; - } - return ( - this.isChromeBrowser() || - this.isFirefoxBrowser() || - this.isOperaBrowser() || - this.isElectron() || - this.isEdgeBrowser() || - (this.isSafariBrowser() && version >= 13) - ); - } - - /** - * @hidden - */ - public getName(): string { - return platform.name || ''; - } - - /** - * @hidden - */ - public getVersion(): string { - return platform.version || ''; - } - - /** - * @hidden - */ - public getFamily(): string { - return platform.os!!.family || ''; - } - - /** - * @hidden - */ - public getDescription(): string { - return platform.description || ''; - } -} diff --git a/openvidu-browser/src/OpenViduInternal/WebRtcPeer/WebRtcPeer.ts b/openvidu-browser/src/OpenViduInternal/WebRtcPeer/WebRtcPeer.ts deleted file mode 100644 index 3df5494888..0000000000 --- a/openvidu-browser/src/OpenViduInternal/WebRtcPeer/WebRtcPeer.ts +++ /dev/null @@ -1,600 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import freeice = require('freeice'); -import { v4 as uuidv4 } from 'uuid'; -import { TypeOfVideo } from '../Enums/TypeOfVideo'; -import { ExceptionEventName } from '../Events/ExceptionEvent'; -import { OpenViduLogger } from '../Logger/OpenViduLogger'; -import { PlatformUtils } from '../Utils/Platform'; - -/** - * @hidden - */ -const logger: OpenViduLogger = OpenViduLogger.getInstance(); -/** - * @hidden - */ -let platform: PlatformUtils; - -export interface WebRtcPeerConfiguration { - mediaConstraints: { - audio: boolean; - video: boolean; - }; - simulcast: boolean; - mediaServer: string; - onIceCandidate: (event: RTCIceCandidate) => void; - onIceConnectionStateException: (exceptionName: ExceptionEventName, message: string, data?: any) => void; - iceServers?: RTCIceServer[]; - rtcConfiguration?: RTCConfiguration; - mediaStream?: MediaStream | null; - mode?: 'sendonly' | 'recvonly' | 'sendrecv'; - id?: string; - typeOfVideo: TypeOfVideo | undefined; -} - -export class WebRtcPeer { - pc: RTCPeerConnection; - remoteCandidatesQueue: RTCIceCandidate[] = []; - localCandidatesQueue: RTCIceCandidate[] = []; - - // Same as WebRtcPeerConfiguration but without optional fields. - protected configuration: Required; - - private iceCandidateList: RTCIceCandidate[] = []; - - constructor(configuration: WebRtcPeerConfiguration) { - platform = PlatformUtils.getInstance(); - - this.configuration = { - ...configuration, - iceServers: !!configuration.iceServers && configuration.iceServers.length > 0 ? configuration.iceServers : freeice(), - rtcConfiguration: configuration.rtcConfiguration !== undefined ? configuration.rtcConfiguration : {}, - mediaStream: configuration.mediaStream !== undefined ? configuration.mediaStream : null, - mode: !!configuration.mode ? configuration.mode : 'sendrecv', - id: !!configuration.id ? configuration.id : this.generateUniqueId() - }; - // prettier-ignore - logger.debug(`[WebRtcPeer] configuration:\n${JSON.stringify(this.configuration, null, 2)}`); - - let rtcConfiguration: RTCConfiguration = this.configuration.rtcConfiguration - ? this.configuration.rtcConfiguration - : { iceServers: this.configuration.iceServers }; - if (!rtcConfiguration.iceServers && this.configuration.iceServers) { - rtcConfiguration.iceServers = this.configuration.iceServers; - } - this.pc = new RTCPeerConnection(rtcConfiguration); - - this.pc.addEventListener('icecandidate', (event: RTCPeerConnectionIceEvent) => { - if (event.candidate !== null) { - // `RTCPeerConnectionIceEvent.candidate` is supposed to be an RTCIceCandidate: - // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnectioniceevent-candidate - // - // But in practice, it is actually an RTCIceCandidateInit that can be used to - // obtain a proper candidate, using the RTCIceCandidate constructor: - // https://w3c.github.io/webrtc-pc/#dom-rtcicecandidate-constructor - const candidateInit: RTCIceCandidateInit = event.candidate as RTCIceCandidateInit; - const iceCandidate = new RTCIceCandidate(candidateInit); - - this.configuration.onIceCandidate(iceCandidate); - if (iceCandidate.candidate !== '') { - this.localCandidatesQueue.push(iceCandidate); - } - } - }); - - this.pc.addEventListener('signalingstatechange', async () => { - if (this.pc.signalingState === 'stable') { - // SDP Offer/Answer finished. Add stored remote candidates. - while (this.iceCandidateList.length > 0) { - let candidate = this.iceCandidateList.shift(); - try { - await this.pc.addIceCandidate(candidate); - } catch (error) { - logger.error('Error when calling RTCPeerConnection#addIceCandidate for RTCPeerConnection ' + this.getId(), error); - } - } - } - }); - } - - getId(): string { - return this.configuration.id; - } - - /** - * This method frees the resources used by WebRtcPeer - */ - dispose() { - logger.debug('Disposing WebRtcPeer'); - if (this.pc) { - if (this.pc.signalingState === 'closed') { - return; - } - this.pc.close(); - this.remoteCandidatesQueue = []; - this.localCandidatesQueue = []; - } - } - - // DEPRECATED LEGACY METHOD: Old WebRTC versions don't implement - // Transceivers, and instead depend on the deprecated - // "offerToReceiveAudio" and "offerToReceiveVideo". - private createOfferLegacy(): Promise { - if (!!this.configuration.mediaStream) { - this.deprecatedPeerConnectionTrackApi(); - } - - const hasAudio = this.configuration.mediaConstraints.audio; - const hasVideo = this.configuration.mediaConstraints.video; - - const options: RTCOfferOptions = { - offerToReceiveAudio: this.configuration.mode !== 'sendonly' && hasAudio, - offerToReceiveVideo: this.configuration.mode !== 'sendonly' && hasVideo - }; - - logger.debug('[createOfferLegacy] RTCPeerConnection.createOffer() options:', JSON.stringify(options)); - - return this.pc.createOffer(options); - } - - /** - * Creates an SDP offer from the local RTCPeerConnection to send to the other peer. - * Only if the negotiation was initiated by this peer. - */ - async createOffer(): Promise { - // TODO: Delete this conditional when all supported browsers are - // modern enough to implement the Transceiver methods. - if (!('addTransceiver' in this.pc)) { - logger.warn( - '[createOffer] Method RTCPeerConnection.addTransceiver() is NOT available; using LEGACY offerToReceive{Audio,Video}' - ); - return this.createOfferLegacy(); - } else { - logger.debug('[createOffer] Method RTCPeerConnection.addTransceiver() is available; using it'); - } - - // Spec doc: https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addtransceiver - - if (this.configuration.mode !== 'recvonly') { - // To send media, assume that all desired media tracks have been - // already added by higher level code to our MediaStream. - - if (!this.configuration.mediaStream) { - throw new Error( - `[WebRtcPeer.createOffer] Direction is '${this.configuration.mode}', but no stream was configured to be sent` - ); - } - - for (const track of this.configuration.mediaStream.getTracks()) { - const tcInit: RTCRtpTransceiverInit = { - direction: this.configuration.mode, - streams: [this.configuration.mediaStream] - }; - - if (track.kind === 'video' && this.configuration.simulcast) { - // Check if the requested size is enough to ask for 3 layers. - const trackSettings = track.getSettings(); - const trackConsts = track.getConstraints(); - - const trackWidth: number = - trackSettings.width ?? (trackConsts.width as ConstrainULongRange).ideal ?? (trackConsts.width as number) ?? 0; - const trackHeight: number = - trackSettings.height ?? (trackConsts.height as ConstrainULongRange).ideal ?? (trackConsts.height as number) ?? 0; - logger.info(`[createOffer] Video track dimensions: ${trackWidth}x${trackHeight}`); - - const trackPixels = trackWidth * trackHeight; - let maxLayers = 0; - if (trackPixels >= 960 * 540) { - maxLayers = 3; - } else if (trackPixels >= 480 * 270) { - maxLayers = 2; - } else { - maxLayers = 1; - } - - tcInit.sendEncodings = []; - for (let l = 0; l < maxLayers; l++) { - const layerDiv = 2 ** (maxLayers - l - 1); - - const encoding: RTCRtpEncodingParameters = { - rid: 'rdiv' + layerDiv.toString(), - - // @ts-ignore -- Property missing from DOM types. - scalabilityMode: 'L1T1' - }; - - if (['detail', 'text'].includes(track.contentHint)) { - // Prioritize best resolution, for maximum picture detail. - encoding.scaleResolutionDownBy = 1.0; - - // @ts-ignore -- Property missing from DOM types. - encoding.maxFramerate = Math.floor(30 / layerDiv); - } else { - encoding.scaleResolutionDownBy = layerDiv; - } - - tcInit.sendEncodings.push(encoding); - } - } - - const tc = this.pc.addTransceiver(track, tcInit); - - if (track.kind === 'video') { - let sendParams = tc.sender.getParameters(); - let needSetParams = false; - - if (!sendParams.degradationPreference?.length) { - // degradationPreference for video: "balanced", "maintain-framerate", "maintain-resolution". - // https://www.w3.org/TR/2018/CR-webrtc-20180927/#dom-rtcdegradationpreference - if (['detail', 'text'].includes(track.contentHint)) { - sendParams.degradationPreference = 'maintain-resolution'; - } else { - sendParams.degradationPreference = 'balanced'; - } - - logger.info(`[createOffer] Video sender Degradation Preference set: ${sendParams.degradationPreference}`); - - // FIXME: Firefox implements degradationPreference on each individual encoding! - // (set it on every element of the sendParams.encodings array) - - needSetParams = true; - } - - // FIXME: Check that the simulcast encodings were applied. - // Firefox doesn't implement `RTCRtpTransceiverInit.sendEncodings` - // so the only way to enable simulcast is with `RTCRtpSender.setParameters()`. - // - // This next block can be deleted when Firefox fixes bug #1396918: - // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 - // - // NOTE: This is done in a way that is compatible with all browsers, to save on - // browser-conditional code. The idea comes from WebRTC Adapter.js: - // * https://github.com/webrtcHacks/adapter/issues/998 - // * https://github.com/webrtcHacks/adapter/blob/v7.7.0/src/js/firefox/firefox_shim.js#L231-L255 - if (this.configuration.simulcast) { - if (sendParams.encodings?.length !== tcInit.sendEncodings!.length) { - sendParams.encodings = tcInit.sendEncodings!; - - needSetParams = true; - } - } - - if (needSetParams) { - logger.debug(`[createOffer] Setting new RTCRtpSendParameters to video sender`); - try { - await tc.sender.setParameters(sendParams); - } catch (error) { - let message = `[WebRtcPeer.createOffer] Cannot set RTCRtpSendParameters to video sender`; - if (error instanceof Error) { - message += `: ${error.message}`; - } - throw new Error(message); - } - } - } - - // DEBUG: Uncomment for details. - // if (track.kind === "video" && this.configuration.simulcast) { - // // Print browser capabilities. - // // prettier-ignore - // logger.debug(`[createOffer] Transceiver send capabilities (static):\n${JSON.stringify(RTCRtpSender.getCapabilities?.("video"), null, 2)}`); - // // prettier-ignore - // logger.debug(`[createOffer] Transceiver recv capabilities (static):\n${JSON.stringify(RTCRtpReceiver.getCapabilities?.("video"), null, 2)}`); - - // // Print requested Transceiver encodings and parameters. - // // prettier-ignore - // logger.debug(`[createOffer] Transceiver send encodings (requested):\n${JSON.stringify(tcInit.sendEncodings, null, 2)}`); - // // prettier-ignore - // logger.debug(`[createOffer] Transceiver send parameters (accepted):\n${JSON.stringify(tc.sender.getParameters(), null, 2)}`); - // } - } - } else { - // To just receive media, create new recvonly transceivers. - for (const kind of ['audio', 'video']) { - // Check if the media kind should be used. - if (!this.configuration.mediaConstraints[kind]) { - continue; - } - - this.configuration.mediaStream = new MediaStream(); - this.pc.addTransceiver(kind, { - direction: this.configuration.mode, - streams: [this.configuration.mediaStream] - }); - } - } - - let sdpOffer: RTCSessionDescriptionInit; - try { - sdpOffer = await this.pc.createOffer(); - } catch (error) { - let message = `[WebRtcPeer.createOffer] Browser failed creating an SDP Offer`; - if (error instanceof Error) { - message += `: ${error.message}`; - } - throw new Error(message); - } - - return sdpOffer; - } - - deprecatedPeerConnectionTrackApi() { - for (const track of this.configuration.mediaStream!.getTracks()) { - this.pc.addTrack(track, this.configuration.mediaStream!); - } - } - - /** - * Creates an SDP answer from the local RTCPeerConnection to send to the other peer - * Only if the negotiation was initiated by the other peer - */ - createAnswer(): Promise { - return new Promise((resolve, reject) => { - // TODO: Delete this conditional when all supported browsers are - // modern enough to implement the Transceiver methods. - if ('getTransceivers' in this.pc) { - logger.debug('[createAnswer] Method RTCPeerConnection.getTransceivers() is available; using it'); - - // Ensure that the PeerConnection already contains one Transceiver - // for each kind of media. - // The Transceivers should have been already created internally by - // the PC itself, when `pc.setRemoteDescription(sdpOffer)` was called. - - for (const kind of ['audio', 'video']) { - // Check if the media kind should be used. - if (!this.configuration.mediaConstraints[kind]) { - continue; - } - - let tc = this.pc.getTransceivers().find((tc) => tc.receiver.track.kind === kind); - - if (tc) { - // Enforce our desired direction. - tc.direction = this.configuration.mode; - } else { - return reject(new Error(`${kind} requested, but no transceiver was created from remote description`)); - } - } - - this.pc - .createAnswer() - .then((sdpAnswer) => resolve(sdpAnswer)) - .catch((error) => reject(error)); - } else { - // TODO: Delete else branch when all supported browsers are - // modern enough to implement the Transceiver methods - - let offerAudio, - offerVideo = true; - if (!!this.configuration.mediaConstraints) { - offerAudio = - typeof this.configuration.mediaConstraints.audio === 'boolean' ? this.configuration.mediaConstraints.audio : true; - offerVideo = - typeof this.configuration.mediaConstraints.video === 'boolean' ? this.configuration.mediaConstraints.video : true; - const constraints: RTCOfferOptions = { - offerToReceiveAudio: offerAudio, - offerToReceiveVideo: offerVideo - }; - (this.pc as RTCPeerConnection).createAnswer(constraints) - .then((sdpAnswer) => resolve(sdpAnswer)) - .catch((error) => reject(error)); - } - } - - // else, there is nothing to do; the legacy createAnswer() options do - // not offer any control over which tracks are included in the answer. - }); - } - - /** - * This peer initiated negotiation. Step 1/4 of SDP offer-answer protocol - */ - processLocalOffer(offer: RTCSessionDescriptionInit): Promise { - return new Promise((resolve, reject) => { - this.pc - .setLocalDescription(offer) - .then(() => { - const localDescription = this.pc.localDescription; - if (!!localDescription) { - logger.debug('Local description set', localDescription.sdp); - return resolve(); - } else { - return reject('Local description is not defined'); - } - }) - .catch((error) => reject(error)); - }); - } - - /** - * Other peer initiated negotiation. Step 2/4 of SDP offer-answer protocol - */ - processRemoteOffer(sdpOffer: string): Promise { - return new Promise((resolve, reject) => { - const offer: RTCSessionDescriptionInit = { - type: 'offer', - sdp: sdpOffer - }; - logger.debug('SDP offer received, setting remote description', offer); - - if (this.pc.signalingState === 'closed') { - return reject('RTCPeerConnection is closed when trying to set remote description'); - } - this.setRemoteDescription(offer) - .then(() => resolve()) - .catch((error) => reject(error)); - }); - } - - /** - * Other peer initiated negotiation. Step 3/4 of SDP offer-answer protocol - */ - processLocalAnswer(answer: RTCSessionDescriptionInit): Promise { - return new Promise((resolve, reject) => { - logger.debug('SDP answer created, setting local description'); - if (this.pc.signalingState === 'closed') { - return reject('RTCPeerConnection is closed when trying to set local description'); - } - this.pc - .setLocalDescription(answer) - .then(() => resolve()) - .catch((error) => reject(error)); - }); - } - - /** - * This peer initiated negotiation. Step 4/4 of SDP offer-answer protocol - */ - processRemoteAnswer(sdpAnswer: string): Promise { - return new Promise((resolve, reject) => { - const answer: RTCSessionDescriptionInit = { - type: 'answer', - sdp: sdpAnswer - }; - logger.debug('SDP answer received, setting remote description'); - - if (this.pc.signalingState === 'closed') { - return reject('RTCPeerConnection is closed when trying to set remote description'); - } - this.setRemoteDescription(answer) - .then(() => { - // DEBUG: Uncomment for details. - // { - // const tc = this.pc.getTransceivers().find((tc) => tc.sender.track?.kind === "video"); - // // prettier-ignore - // logger.debug(`[processRemoteAnswer] Transceiver send parameters (effective):\n${JSON.stringify(tc?.sender.getParameters(), null, 2)}`); - // } - - resolve(); - }) - .catch((error) => reject(error)); - }); - } - - /** - * @hidden - */ - async setRemoteDescription(sdp: RTCSessionDescriptionInit): Promise { - return this.pc.setRemoteDescription(sdp); - } - - /** - * Callback function invoked when an ICE candidate is received - */ - addIceCandidate(iceCandidate: RTCIceCandidate): Promise { - return new Promise((resolve, reject) => { - logger.debug('Remote ICE candidate received', iceCandidate); - this.remoteCandidatesQueue.push(iceCandidate); - switch (this.pc.signalingState) { - case 'closed': - reject(new Error('PeerConnection object is closed')); - break; - case 'stable': - if (!!this.pc.remoteDescription) { - this.pc - .addIceCandidate(iceCandidate) - .then(() => resolve()) - .catch((error) => reject(error)); - } else { - this.iceCandidateList.push(iceCandidate); - resolve(); - } - break; - default: - this.iceCandidateList.push(iceCandidate); - resolve(); - } - }); - } - - addIceConnectionStateChangeListener(otherId: string) { - this.pc.addEventListener('iceconnectionstatechange', () => { - const iceConnectionState: RTCIceConnectionState = this.pc.iceConnectionState; - switch (iceConnectionState) { - case 'disconnected': - // Possible network disconnection - const msg1 = - 'IceConnectionState of RTCPeerConnection ' + - this.configuration.id + - ' (' + - otherId + - ') change to "disconnected". Possible network disconnection'; - logger.warn(msg1); - this.configuration.onIceConnectionStateException(ExceptionEventName.ICE_CONNECTION_DISCONNECTED, msg1); - break; - case 'failed': - const msg2 = 'IceConnectionState of RTCPeerConnection ' + this.configuration.id + ' (' + otherId + ') to "failed"'; - logger.error(msg2); - this.configuration.onIceConnectionStateException(ExceptionEventName.ICE_CONNECTION_FAILED, msg2); - break; - case 'closed': - logger.log( - 'IceConnectionState of RTCPeerConnection ' + this.configuration.id + ' (' + otherId + ') change to "closed"' - ); - break; - case 'new': - logger.log('IceConnectionState of RTCPeerConnection ' + this.configuration.id + ' (' + otherId + ') change to "new"'); - break; - case 'checking': - logger.log( - 'IceConnectionState of RTCPeerConnection ' + this.configuration.id + ' (' + otherId + ') change to "checking"' - ); - break; - case 'connected': - logger.log( - 'IceConnectionState of RTCPeerConnection ' + this.configuration.id + ' (' + otherId + ') change to "connected"' - ); - break; - case 'completed': - logger.log( - 'IceConnectionState of RTCPeerConnection ' + this.configuration.id + ' (' + otherId + ') change to "completed"' - ); - break; - } - }); - } - - /** - * @hidden - */ - generateUniqueId(): string { - return uuidv4(); - } -} - -export class WebRtcPeerRecvonly extends WebRtcPeer { - constructor(configuration: WebRtcPeerConfiguration) { - configuration.mode = 'recvonly'; - super(configuration); - } -} - -export class WebRtcPeerSendonly extends WebRtcPeer { - constructor(configuration: WebRtcPeerConfiguration) { - configuration.mode = 'sendonly'; - super(configuration); - } -} - -export class WebRtcPeerSendrecv extends WebRtcPeer { - constructor(configuration: WebRtcPeerConfiguration) { - configuration.mode = 'sendrecv'; - super(configuration); - } -} diff --git a/openvidu-browser/src/OpenViduInternal/WebRtcStats/WebRtcStats.ts b/openvidu-browser/src/OpenViduInternal/WebRtcStats/WebRtcStats.ts deleted file mode 100644 index 626deb141b..0000000000 --- a/openvidu-browser/src/OpenViduInternal/WebRtcStats/WebRtcStats.ts +++ /dev/null @@ -1,471 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -// tslint:disable:no-string-literal - -import { Stream } from '../../OpenVidu/Stream'; -import { OpenViduLogger } from '../Logger/OpenViduLogger'; -import { PlatformUtils } from '../Utils/Platform'; -/** - * @hidden - */ -const logger: OpenViduLogger = OpenViduLogger.getInstance(); -/** - * @hidden - */ -let platform: PlatformUtils; - -interface WebrtcStatsConfig { - interval: number; - httpEndpoint: string; -} - -interface JSONStatsResponse { - '@timestamp': string; - participant_id: string; - session_id: string; - platform: string; - platform_description: string; - stream: string; - webrtc_stats: IWebrtcStats; -} - -/** - * Common WebRtcSTats for latest Chromium and Firefox versions - */ -interface IWebrtcStats { - inbound?: { - audio: - | { - bytesReceived: number; - packetsReceived: number; - packetsLost: number; - jitter: number; - } - | {}; - video: - | { - bytesReceived: number; - packetsReceived: number; - packetsLost: number; - jitter?: number; // Firefox - jitterBufferDelay?: number; // Chrome - framesDecoded: number; - firCount: number; - nackCount: number; - pliCount: number; - frameHeight?: number; // Chrome - frameWidth?: number; // Chrome - framesDropped?: number; // Chrome - framesReceived?: number; // Chrome - } - | {}; - }; - outbound?: { - audio: - | { - bytesSent: number; - packetsSent: number; - } - | {}; - video: - | { - bytesSent: number; - packetsSent: number; - firCount: number; - framesEncoded: number; - nackCount: number; - pliCount: number; - qpSum: number; - frameHeight?: number; // Chrome - frameWidth?: number; // Chrome - framesSent?: number; // Chrome - } - | {}; - }; - candidatepair?: { - currentRoundTripTime?: number; // Chrome - availableOutgoingBitrate?: number; //Chrome - // availableIncomingBitrate?: number // No support for any browsers (https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidatePairStats/availableIncomingBitrate) - }; -} - -export class WebRtcStats { - private readonly STATS_ITEM_NAME = 'webrtc-stats-config'; - - private webRtcStatsEnabled = false; - private webRtcStatsIntervalId: NodeJS.Timer; - private statsInterval = 1; - private POST_URL: string; - - constructor(private stream: Stream) { - platform = PlatformUtils.getInstance(); - } - - public isEnabled(): boolean { - return this.webRtcStatsEnabled; - } - - public initWebRtcStats(): void { - let webrtcObj; - // When cross-site (aka third-party) cookies are blocked by the browser, - // accessing localStorage in a third-party iframe throws a DOMException. - try { - webrtcObj = localStorage.getItem(this.STATS_ITEM_NAME); - } - catch(e){} - - if (!!webrtcObj) { - this.webRtcStatsEnabled = true; - const webrtcStatsConfig: WebrtcStatsConfig = JSON.parse(webrtcObj); - // webrtc object found in local storage - logger.warn( - 'WebRtc stats enabled for stream ' + this.stream.streamId + ' of connection ' + this.stream.connection.connectionId - ); - logger.warn('localStorage item: ' + JSON.stringify(webrtcStatsConfig)); - - this.POST_URL = webrtcStatsConfig.httpEndpoint; - this.statsInterval = webrtcStatsConfig.interval; // Interval in seconds - - this.webRtcStatsIntervalId = setInterval(async () => { - await this.sendStatsToHttpEndpoint(); - }, this.statsInterval * 1000); - } else { - logger.debug('WebRtc stats not enabled'); - } - } - - // { - // "localCandidate": { - // "id": "RTCIceCandidate_/r4P1y2Q", - // "timestamp": 1616080155617, - // "type": "local-candidate", - // "transportId": "RTCTransport_0_1", - // "isRemote": false, - // "networkType": "wifi", - // "ip": "123.45.67.89", - // "port": 63340, - // "protocol": "udp", - // "candidateType": "srflx", - // "priority": 1686052607, - // "deleted": false, - // "raw": [ - // "candidate:3345412921 1 udp 1686052607 123.45.67.89 63340 typ srflx raddr 192.168.1.31 rport 63340 generation 0 ufrag 0ZtT network-id 1 network-cost 10", - // "candidate:58094482 1 udp 41885695 98.76.54.32 44431 typ relay raddr 123.45.67.89 rport 63340 generation 0 ufrag 0ZtT network-id 1 network-cost 10" - // ] - // }, - // "remoteCandidate": { - // "id": "RTCIceCandidate_1YO18gph", - // "timestamp": 1616080155617, - // "type": "remote-candidate", - // "transportId": "RTCTransport_0_1", - // "isRemote": true, - // "ip": "12.34.56.78", - // "port": 64989, - // "protocol": "udp", - // "candidateType": "srflx", - // "priority": 1679819263, - // "deleted": false, - // "raw": [ - // "candidate:16 1 UDP 1679819263 12.34.56.78 64989 typ srflx raddr 172.19.0.1 rport 64989", - // "candidate:16 1 UDP 1679819263 12.34.56.78 64989 typ srflx raddr 172.19.0.1 rport 64989" - // ] - // } - // } - // Have been tested in: - // - Linux Desktop: - // - Chrome 89.0.4389.90 - // - Opera 74.0.3911.218 - // - Firefox 86 - // - Microsoft Edge 91.0.825.0 - // - Electron 11.3.0 (Chromium 87.0.4280.141) - // - Windows Desktop: - // - Chrome 89.0.4389.90 - // - Opera 74.0.3911.232 - // - Firefox 86.0.1 - // - Microsoft Edge 89.0.774.54 - // - Electron 11.3.0 (Chromium 87.0.4280.141) - // - MacOS Desktop: - // - Chrome 89.0.4389.90 - // - Firefox 87.0 - // - Opera 75.0.3969.93 - // - Microsoft Edge 89.0.774.57 - // - Safari 14.0 (14610.1.28.1.9) - // - Electron 11.3.0 (Chromium 87.0.4280.141) - // - Android: - // - Chrome Mobile 89.0.4389.90 - // - Opera 62.3.3146.57763 - // - Firefox Mobile 86.6.1 - // - Microsoft Edge Mobile 46.02.4.5147 - // - Ionic 5 - // - React Native 0.64 - // - iOS: - // - Safari Mobile - // - ¿Ionic? - // - ¿React Native? - public getSelectedIceCandidateInfo(): Promise { - return new Promise(async (resolve, reject) => { - const statsReport: any = await this.stream.getRTCPeerConnection().getStats(); - let transportStat; - const candidatePairs: Map = new Map(); - const localCandidates: Map = new Map(); - const remoteCandidates: Map = new Map(); - statsReport.forEach((stat: any) => { - if (stat.type === 'transport' && (platform.isChromium() || platform.isSafariBrowser() || platform.isReactNative())) { - transportStat = stat; - } - switch (stat.type) { - case 'candidate-pair': - candidatePairs.set(stat.id, stat); - break; - case 'local-candidate': - localCandidates.set(stat.id, stat); - break; - case 'remote-candidate': - remoteCandidates.set(stat.id, stat); - break; - } - }); - let selectedCandidatePair; - if (transportStat != null) { - const selectedCandidatePairId = transportStat.selectedCandidatePairId; - selectedCandidatePair = candidatePairs.get(selectedCandidatePairId); - } else { - // This is basically Firefox - const length = candidatePairs.size; - const iterator = candidatePairs.values(); - for (let i = 0; i < length; i++) { - const candidatePair = iterator.next().value; - if (candidatePair['selected']) { - selectedCandidatePair = candidatePair; - break; - } - } - } - const localCandidateId = selectedCandidatePair.localCandidateId; - const remoteCandidateId = selectedCandidatePair.remoteCandidateId; - let finalLocalCandidate = localCandidates.get(localCandidateId); - if (!!finalLocalCandidate) { - const candList = this.stream.getLocalIceCandidateList(); - const cand = candList.filter((c: RTCIceCandidate) => { - return ( - !!c.candidate && - (c.candidate.indexOf(finalLocalCandidate.ip) >= 0 || c.candidate.indexOf(finalLocalCandidate.address) >= 0) && - c.candidate.indexOf(finalLocalCandidate.port) >= 0 - ); - }); - finalLocalCandidate.raw = []; - for (let c of cand) { - finalLocalCandidate.raw.push(c.candidate); - } - } else { - finalLocalCandidate = 'ERROR: No active local ICE candidate. Probably ICE-TCP is being used'; - } - - let finalRemoteCandidate = remoteCandidates.get(remoteCandidateId); - if (!!finalRemoteCandidate) { - const candList = this.stream.getRemoteIceCandidateList(); - const cand = candList.filter((c: RTCIceCandidate) => { - return ( - !!c.candidate && - (c.candidate.indexOf(finalRemoteCandidate.ip) >= 0 || c.candidate.indexOf(finalRemoteCandidate.address) >= 0) && - c.candidate.indexOf(finalRemoteCandidate.port) >= 0 - ); - }); - finalRemoteCandidate.raw = []; - for (let c of cand) { - finalRemoteCandidate.raw.push(c.candidate); - } - } else { - finalRemoteCandidate = 'ERROR: No active remote ICE candidate. Probably ICE-TCP is being used'; - } - - return resolve({ - localCandidate: finalLocalCandidate, - remoteCandidate: finalRemoteCandidate - }); - }); - } - - public stopWebRtcStats() { - if (this.webRtcStatsEnabled) { - clearInterval(this.webRtcStatsIntervalId); - logger.warn( - 'WebRtc stats stopped for disposed stream ' + this.stream.streamId + ' of connection ' + this.stream.connection.connectionId - ); - } - } - - private async sendStats(url: string, response: JSONStatsResponse): Promise { - try { - const configuration: RequestInit = { - headers: { - 'Content-type': 'application/json' - }, - body: JSON.stringify(response), - method: 'POST' - }; - await fetch(url, configuration); - } catch (error) { - logger.error(`sendStats error: ${JSON.stringify(error)}`); - } - } - - private async sendStatsToHttpEndpoint(): Promise { - try { - const webrtcStats: IWebrtcStats = await this.getCommonStats(); - const response = this.generateJSONStatsResponse(webrtcStats); - await this.sendStats(this.POST_URL, response); - } catch (error) { - logger.log(error); - } - } - - // Have been tested in: - // - Linux Desktop: - // - Chrome 89.0.4389.90 - // - Opera 74.0.3911.218 - // - Firefox 86 - // - Microsoft Edge 91.0.825.0 - // - Electron 11.3.0 (Chromium 87.0.4280.141) - // - Windows Desktop: - // - Chrome 89.0.4389.90 - // - Opera 74.0.3911.232 - // - Firefox 86.0.1 - // - Microsoft Edge 89.0.774.54 - // - Electron 11.3.0 (Chromium 87.0.4280.141) - // - MacOS Desktop: - // - Chrome 89.0.4389.90 - // - Opera 75.0.3969.93 - // - Firefox 87.0 - // - Microsoft Edge 89.0.774.57 - // - Safari 14.0 (14610.1.28.1.9) - // - Electron 11.3.0 (Chromium 87.0.4280.141) - // - Android: - // - Chrome Mobile 89.0.4389.90 - // - Opera 62.3.3146.57763 - // - Firefox Mobile 86.6.1 - // - Microsoft Edge Mobile 46.02.4.5147 - // - Ionic 5 - // - React Native 0.64 - // - iOS: - // - Safari Mobile - // - ¿Ionic? - // - ¿React Native? - public async getCommonStats(): Promise { - return new Promise(async (resolve, reject) => { - try { - const statsReport: any = await this.stream.getRTCPeerConnection().getStats(); - const response: IWebrtcStats = this.getWebRtcStatsResponseOutline(); - const videoTrackStats = ['framesReceived', 'framesDropped', 'framesSent', 'frameHeight', 'frameWidth']; - const candidatePairStats = ['availableOutgoingBitrate', 'currentRoundTripTime']; - - statsReport.forEach((stat: any) => { - let mediaType = stat.mediaType != null ? stat.mediaType : stat.kind; - const addStat = (direction: string, key: string): void => { - if (stat[key] != null && response[direction] != null) { - if (!mediaType && videoTrackStats.indexOf(key) > -1) { - mediaType = 'video'; - } - if (direction != null && mediaType != null && key != null && response[direction][mediaType] != null) { - response[direction][mediaType][key] = Number(stat[key]); - } else if (direction != null && key != null && candidatePairStats.includes(key)) { - // candidate-pair-stats - response[direction][key] = Number(stat[key]); - } - } - }; - - switch (stat.type) { - case 'outbound-rtp': - addStat('outbound', 'bytesSent'); - addStat('outbound', 'packetsSent'); - addStat('outbound', 'framesEncoded'); - addStat('outbound', 'nackCount'); - addStat('outbound', 'firCount'); - addStat('outbound', 'pliCount'); - addStat('outbound', 'qpSum'); - break; - case 'inbound-rtp': - addStat('inbound', 'bytesReceived'); - addStat('inbound', 'packetsReceived'); - addStat('inbound', 'packetsLost'); - addStat('inbound', 'jitter'); - addStat('inbound', 'framesDecoded'); - addStat('inbound', 'nackCount'); - addStat('inbound', 'firCount'); - addStat('inbound', 'pliCount'); - break; - case 'track': - addStat('inbound', 'jitterBufferDelay'); - addStat('inbound', 'framesReceived'); - addStat('outbound', 'framesDropped'); - addStat('outbound', 'framesSent'); - addStat(this.stream.isLocal() ? 'outbound' : 'inbound', 'frameHeight'); - addStat(this.stream.isLocal() ? 'outbound' : 'inbound', 'frameWidth'); - break; - case 'candidate-pair': - addStat('candidatepair', 'currentRoundTripTime'); - addStat('candidatepair', 'availableOutgoingBitrate'); - break; - } - }); - - // Delete candidatepair from response if null - if (!response?.candidatepair || Object.keys(response.candidatepair).length === 0) { - delete response.candidatepair; - } - - return resolve(response); - } catch (error) { - logger.error('Error getting common stats: ', error); - return reject(error); - } - }); - } - - private generateJSONStatsResponse(stats: IWebrtcStats): JSONStatsResponse { - return { - '@timestamp': new Date().toISOString(), - participant_id: this.stream.connection.data, - session_id: this.stream.session.sessionId, - platform: platform.getName(), - platform_description: platform.getDescription(), - stream: 'webRTC', - webrtc_stats: stats - }; - } - - private getWebRtcStatsResponseOutline(): IWebrtcStats { - if (this.stream.isLocal()) { - return { - outbound: { - audio: {}, - video: {} - }, - candidatepair: {} - }; - } else { - return { - inbound: { - audio: {}, - video: {} - } - }; - } - } -} diff --git a/openvidu-browser/src/index.ts b/openvidu-browser/src/index.ts deleted file mode 100644 index e4fb3588fc..0000000000 --- a/openvidu-browser/src/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { JL } from 'jsnlog'; - -export { OpenVidu } from './OpenVidu/OpenVidu'; -export { Session } from './OpenVidu/Session'; -export { Publisher } from './OpenVidu/Publisher'; -export { Subscriber } from './OpenVidu/Subscriber'; -export { StreamManager } from './OpenVidu/StreamManager'; -export { Stream } from './OpenVidu/Stream'; -export { Connection } from './OpenVidu/Connection'; -export { LocalRecorder } from './OpenVidu/LocalRecorder'; -export { Filter } from './OpenVidu/Filter'; - -export { LocalRecorderState } from './OpenViduInternal/Enums/LocalRecorderState'; -export { OpenViduError, OpenViduErrorName } from './OpenViduInternal/Enums/OpenViduError'; -export { TypeOfVideo } from './OpenViduInternal/Enums/TypeOfVideo'; -export { VideoInsertMode } from './OpenViduInternal/Enums/VideoInsertMode'; - -export { Event } from './OpenViduInternal/Events/Event'; -export { ConnectionEvent } from './OpenViduInternal/Events/ConnectionEvent'; -export { PublisherSpeakingEvent } from './OpenViduInternal/Events/PublisherSpeakingEvent'; -export { RecordingEvent } from './OpenViduInternal/Events/RecordingEvent'; -export { SessionDisconnectedEvent } from './OpenViduInternal/Events/SessionDisconnectedEvent'; -export { SignalEvent } from './OpenViduInternal/Events/SignalEvent'; -export { StreamEvent } from './OpenViduInternal/Events/StreamEvent'; -export { StreamManagerEvent } from './OpenViduInternal/Events/StreamManagerEvent'; -export { VideoElementEvent } from './OpenViduInternal/Events/VideoElementEvent'; -export { StreamPropertyChangedEvent } from './OpenViduInternal/Events/StreamPropertyChangedEvent'; -export { ConnectionPropertyChangedEvent } from './OpenViduInternal/Events/ConnectionPropertyChangedEvent'; -export { FilterEvent } from './OpenViduInternal/Events/FilterEvent'; -export { NetworkQualityLevelChangedEvent } from './OpenViduInternal/Events/NetworkQualityLevelChangedEvent'; -export { SpeechToTextEvent } from './OpenViduInternal/Events/SpeechToTextEvent'; -export { ExceptionEvent, ExceptionEventName } from './OpenViduInternal/Events/ExceptionEvent'; - -export { Capabilities } from './OpenViduInternal/Interfaces/Public/Capabilities'; -export { Device } from './OpenViduInternal/Interfaces/Public/Device'; -export { EventDispatcher } from './OpenVidu/EventDispatcher'; -export { OpenViduAdvancedConfiguration } from './OpenViduInternal/Interfaces/Public/OpenViduAdvancedConfiguration'; -export { PublisherProperties } from './OpenViduInternal/Interfaces/Public/PublisherProperties'; -export { SignalOptions } from './OpenViduInternal/Interfaces/Public/SignalOptions'; -export { StreamManagerVideo } from './OpenViduInternal/Interfaces/Public/StreamManagerVideo'; -export { SubscriberProperties } from './OpenViduInternal/Interfaces/Public/SubscriberProperties'; - -export { EventMap } from './OpenViduInternal/Events/EventMap/EventMap'; -export { SessionEventMap } from './OpenViduInternal/Events/EventMap/SessionEventMap'; -export { StreamManagerEventMap } from './OpenViduInternal/Events/EventMap/StreamManagerEventMap'; -export { PublisherEventMap } from './OpenViduInternal/Events/EventMap/PublisherEventMap'; - -export * from './OpenViduInternal/Events/Types/Types'; - -// Disable jsnlog when library is loaded -JL.setOptions({ enabled: false }); diff --git a/openvidu-browser/tsconfig.json b/openvidu-browser/tsconfig.json deleted file mode 100644 index 6b5bc64b8c..0000000000 --- a/openvidu-browser/tsconfig.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - //"allowUnusedLabels": true, - "allowUnreachableCode": false, - "buildOnSave": false, - "compileOnSave": true, - "compilerOptions": { - "allowJs": true, - "allowSyntheticDefaultImports": true, - "emitBOM": false, - "forceConsistentCasingInFileNames": true, - "lib": [ - "dom", - "es2015.promise", - "es5", - "scripthost" - ], - "module": "commonjs", - "noFallthroughCasesInSwitch": true, - //"noImplicitAny": true, - "noImplicitReturns": true, - "noImplicitThis": true, - //"noUnusedLocals": true, - //"noUnusedParameters": true, - "outDir": "../../lib", - "preserveConstEnums": true, - "removeComments": true, - "rootDir": "./src", - "skipDefaultLibCheck": true, - "skipLibCheck": true, - "sourceMap": true, - "strictNullChecks": true, - "suppressExcessPropertyErrors": true, - "suppressImplicitAnyIndexErrors": true, - "target": "es5" - } -} \ No newline at end of file diff --git a/openvidu-client/.gitignore b/openvidu-client/.gitignore deleted file mode 100644 index b83d22266a..0000000000 --- a/openvidu-client/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target/ diff --git a/openvidu-client/README.md b/openvidu-client/README.md deleted file mode 100644 index bd12a3e9c0..0000000000 --- a/openvidu-client/README.md +++ /dev/null @@ -1,14 +0,0 @@ -[![License badge](https://img.shields.io/badge/license-Apache2-orange.svg)](http://www.apache.org/licenses/LICENSE-2.0) -[![OpenVidu Tests](https://github.com/OpenVidu/openvidu/actions/workflows/openvidu-ce-test.yml/badge.svg)](https://github.com/OpenVidu/openvidu/actions/workflows/openvidu-ce-test.yml) -[![Documentation Status](https://readthedocs.org/projects/openvidu/badge/?version=stable)](https://docs.openvidu.io/en/stable/?badge=stable) -[![Docker badge](https://img.shields.io/docker/pulls/fiware/orion.svg)](https://hub.docker.com/r/openvidu/) -[![Support badge](https://img.shields.io/badge/support-sof-yellowgreen.svg)](https://openvidu.discourse.group/) - -[![][OpenViduLogo]](https://openvidu.io) - -openvidu-client -=== - -Internal Java client used by [openvidu-server](https://github.com/OpenVidu/openvidu/tree/master/openvidu-server). Can be used to implement an Android client. - -[OpenViduLogo]: https://secure.gravatar.com/avatar/5daba1d43042f2e4e85849733c8e5702?s=120 \ No newline at end of file diff --git a/openvidu-client/pom.xml b/openvidu-client/pom.xml deleted file mode 100644 index 35538e6364..0000000000 --- a/openvidu-client/pom.xml +++ /dev/null @@ -1,106 +0,0 @@ - - 4.0.0 - - - io.openvidu - openvidu-parent - 2.0.0 - - - openvidu-client - 1.1.0 - jar - - OpenVidu Client - - OpenVidu client library for the client-side of OpenVidu Server - - https://github.com/OpenVidu/openvidu - - - - Apache 2.0 - http://www.apache.org/licenses/LICENSE-2.0 - repo - - - - - OpenVidu - https://github.com/OpenVidu/openvidu - - - - ${openvidu.scm.url} - scm:git:${openvidu.scm.connection} - scm:git:${openvidu.scm.connection} - develop - - - - - openvidu.io - -openvidu.io Community - OpenVidu - https://openvidu.io - - - - - - org.kurento - kurento-jsonrpc-client - ${version.kurento} - - - org.kurento - kurento-jsonrpc-client-jetty - ${version.kurento} - - - org.junit.jupiter - junit-jupiter-api - ${version.junit} - test - - - org.mockito - mockito-core - ${version.mockito.core} - test - - - - - - default - - - default - true - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - true - - - - org.apache.maven.plugins - maven-failsafe-plugin - - true - - - - - - - - diff --git a/openvidu-client/src/main/java/io/openvidu/client/OpenViduClient.java b/openvidu-client/src/main/java/io/openvidu/client/OpenViduClient.java deleted file mode 100644 index 0e7aaaabb9..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/OpenViduClient.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.openvidu.client; - -import static io.openvidu.client.internal.ProtocolElements.CUSTOMREQUEST_METHOD; -import static io.openvidu.client.internal.ProtocolElements.JOINROOM_METHOD; -import static io.openvidu.client.internal.ProtocolElements.JOINROOM_PEERID_PARAM; -import static io.openvidu.client.internal.ProtocolElements.JOINROOM_PEERSTREAMID_PARAM; -import static io.openvidu.client.internal.ProtocolElements.JOINROOM_PEERSTREAMS_PARAM; -import static io.openvidu.client.internal.ProtocolElements.JOINROOM_ROOM_PARAM; -import static io.openvidu.client.internal.ProtocolElements.JOINROOM_USER_PARAM; -import static io.openvidu.client.internal.ProtocolElements.LEAVEROOM_METHOD; -import static io.openvidu.client.internal.ProtocolElements.ONICECANDIDATE_CANDIDATE_PARAM; -import static io.openvidu.client.internal.ProtocolElements.ONICECANDIDATE_EPNAME_PARAM; -import static io.openvidu.client.internal.ProtocolElements.ONICECANDIDATE_METHOD; -import static io.openvidu.client.internal.ProtocolElements.ONICECANDIDATE_SDPMIDPARAM; -import static io.openvidu.client.internal.ProtocolElements.ONICECANDIDATE_SDPMLINEINDEX_PARAM; -import static io.openvidu.client.internal.ProtocolElements.PUBLISHVIDEO_DOLOOPBACK_PARAM; -import static io.openvidu.client.internal.ProtocolElements.PUBLISHVIDEO_METHOD; -import static io.openvidu.client.internal.ProtocolElements.PUBLISHVIDEO_SDPANSWER_PARAM; -import static io.openvidu.client.internal.ProtocolElements.PUBLISHVIDEO_SDPOFFER_PARAM; -import static io.openvidu.client.internal.ProtocolElements.RECEIVEVIDEO_METHOD; -import static io.openvidu.client.internal.ProtocolElements.RECEIVEVIDEO_SDPANSWER_PARAM; -import static io.openvidu.client.internal.ProtocolElements.RECEIVEVIDEO_SDPOFFER_PARAM; -import static io.openvidu.client.internal.ProtocolElements.RECEIVEVIDEO_SENDER_PARAM; -import static io.openvidu.client.internal.ProtocolElements.SENDMESSAGE_MESSAGE_PARAM; -import static io.openvidu.client.internal.ProtocolElements.SENDMESSAGE_ROOM_METHOD; -import static io.openvidu.client.internal.ProtocolElements.UNPUBLISHVIDEO_METHOD; -import static io.openvidu.client.internal.ProtocolElements.UNSUBSCRIBEFROMVIDEO_METHOD; -import static io.openvidu.client.internal.ProtocolElements.UNSUBSCRIBEFROMVIDEO_SENDER_PARAM; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.kurento.jsonrpc.client.JsonRpcClient; -import org.kurento.jsonrpc.client.JsonRpcClientWebSocket; -import org.kurento.jsonrpc.client.JsonRpcWSConnectionListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import io.openvidu.client.internal.JsonRoomUtils; -import io.openvidu.client.internal.Notification; - -/** - * Java client for the room server. - * - * @author Radu Tom Vlad - */ -public class OpenViduClient { - - private static final Logger log = LoggerFactory.getLogger(OpenViduClient.class); - - private JsonRpcClient client; - private ServerJsonRpcHandler handler; - - public OpenViduClient(String wsUri) { - this(new JsonRpcClientWebSocket(wsUri, new JsonRpcWSConnectionListener() { - - @Override - public void reconnected(boolean sameServer) { - } - - @Override - public void disconnected() { - log.warn("JsonRpcWebsocket connection: Disconnected"); - } - - @Override - public void connectionFailed() { - log.warn("JsonRpcWebsocket connection: Connection failed"); - } - - @Override - public void connected() { - } - - @Override - public void reconnecting() { - log.warn("JsonRpcWebsocket connection: is reconnecting"); - } - }, new SslContextFactory(true))); - } - - public OpenViduClient(JsonRpcClient client) { - this.client = client; - this.handler = new ServerJsonRpcHandler(); - this.client.setServerRequestHandler(this.handler); - } - - public OpenViduClient(JsonRpcClient client, ServerJsonRpcHandler handler) { - this.client = client; - this.handler = handler; - this.client.setServerRequestHandler(this.handler); - } - - public void close() throws IOException { - this.client.close(); - } - - public Map> joinRoom(String roomName, String userName) - throws IOException { - - JsonObject params = new JsonObject(); - params.addProperty(JOINROOM_ROOM_PARAM, roomName); - params.addProperty(JOINROOM_USER_PARAM, userName); - - JsonElement result = client.sendRequest(JOINROOM_METHOD, params); - Map> peers = new HashMap>(); - JsonArray jsonPeers = JsonRoomUtils.getResponseProperty(result, "value", JsonArray.class); - if (jsonPeers.size() > 0) { - Iterator peerIt = jsonPeers.iterator(); - while (peerIt.hasNext()) { - JsonElement peer = peerIt.next(); - String peerId = JsonRoomUtils.getResponseProperty(peer, JOINROOM_PEERID_PARAM, - String.class); - List streams = new ArrayList(); - JsonArray jsonStreams = JsonRoomUtils.getResponseProperty(peer, JOINROOM_PEERSTREAMS_PARAM, - JsonArray.class, true); - if (jsonStreams != null) { - Iterator streamIt = jsonStreams.iterator(); - while (streamIt.hasNext()) { - streams.add(JsonRoomUtils.getResponseProperty(streamIt.next(), - JOINROOM_PEERSTREAMID_PARAM, String.class)); - } - } - peers.put(peerId, streams); - } - } - return peers; - } - - public void leaveRoom() throws IOException { - client.sendRequest(LEAVEROOM_METHOD, new JsonObject()); - } - - public String publishVideo(String sdpOffer, boolean doLoopback) throws IOException { - JsonObject params = new JsonObject(); - params.addProperty(PUBLISHVIDEO_SDPOFFER_PARAM, sdpOffer); - params.addProperty(PUBLISHVIDEO_DOLOOPBACK_PARAM, doLoopback); - JsonElement result = client.sendRequest(PUBLISHVIDEO_METHOD, params); - return JsonRoomUtils.getResponseProperty(result, PUBLISHVIDEO_SDPANSWER_PARAM, String.class); - } - - public void unpublishVideo() throws IOException { - client.sendRequest(UNPUBLISHVIDEO_METHOD, new JsonObject()); - } - - // sender should look like 'username_streamId' - public String receiveVideoFrom(String sender, String sdpOffer) throws IOException { - JsonObject params = new JsonObject(); - params.addProperty(RECEIVEVIDEO_SENDER_PARAM, sender); - params.addProperty(RECEIVEVIDEO_SDPOFFER_PARAM, sdpOffer); - JsonElement result = client.sendRequest(RECEIVEVIDEO_METHOD, params); - return JsonRoomUtils.getResponseProperty(result, RECEIVEVIDEO_SDPANSWER_PARAM, String.class); - } - - // sender should look like 'username_streamId' - public void unsubscribeFromVideo(String sender) throws IOException { - JsonObject params = new JsonObject(); - params.addProperty(UNSUBSCRIBEFROMVIDEO_SENDER_PARAM, sender); - client.sendRequest(UNSUBSCRIBEFROMVIDEO_METHOD, params); - } - - public void onIceCandidate(String endpointName, String candidate, String sdpMid, - int sdpMLineIndex) throws IOException { - JsonObject params = new JsonObject(); - params.addProperty(ONICECANDIDATE_EPNAME_PARAM, endpointName); - params.addProperty(ONICECANDIDATE_CANDIDATE_PARAM, candidate); - params.addProperty(ONICECANDIDATE_SDPMIDPARAM, sdpMid); - params.addProperty(ONICECANDIDATE_SDPMLINEINDEX_PARAM, sdpMLineIndex); - client.sendRequest(ONICECANDIDATE_METHOD, params); - } - - public void sendMessage(String userName, String roomName, String message) throws IOException { - JsonObject params = new JsonObject(); - params.addProperty(SENDMESSAGE_MESSAGE_PARAM, message); - client.sendRequest(SENDMESSAGE_ROOM_METHOD, params); - } - - public JsonElement customRequest(JsonObject customReqParams) throws IOException { - return client.sendRequest(CUSTOMREQUEST_METHOD, customReqParams); - } - - /** - * Polls the notifications list maintained by this client to obtain new events sent by server. - * This method blocks until there is a notification to return. This is a one-time operation for - * the returned element. - * - * @return a server notification object, null when interrupted while waiting - */ - public Notification getServerNotification() { - return this.handler.getNotification(); - } -} diff --git a/openvidu-client/src/main/java/io/openvidu/client/OpenViduException.java b/openvidu-client/src/main/java/io/openvidu/client/OpenViduException.java deleted file mode 100644 index 4c171929a6..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/OpenViduException.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package io.openvidu.client; - -import org.kurento.jsonrpc.JsonRpcErrorException; - -public class OpenViduException extends JsonRpcErrorException { - private static final long serialVersionUID = 1L; - - public static enum Code { - GENERIC_ERROR_CODE(999), WRONG_PATH_CODE(998), WRONG_OPENVIDU_EDITION_ERROR_CODE(997), - SERVICE_NOT_ENABLED_ERROR_CODE(996), - - TRANSPORT_ERROR_CODE(803), TRANSPORT_RESPONSE_ERROR_CODE(802), TRANSPORT_REQUEST_ERROR_CODE(801), - - MEDIA_TYPE_STREAM_INCOMPATIBLE_WITH_RECORDING_PROPERTIES_ERROR_CODE(309), - MEDIA_TYPE_RECORDING_PROPERTIES_ERROR_CODE(308), MEDIA_MUTE_ERROR_CODE(307), - MEDIA_NOT_A_WEB_ENDPOINT_ERROR_CODE(306), MEDIA_RTP_ENDPOINT_ERROR_CODE(305), - MEDIA_WEBRTC_ENDPOINT_ERROR_CODE(304), MEDIA_ENDPOINT_ERROR_CODE(303), MEDIA_SDP_ERROR_CODE(302), - MEDIA_GENERIC_ERROR_CODE(301), - - ROOM_CANNOT_BE_CREATED_ERROR_CODE(204), ROOM_CLOSED_ERROR_CODE(203), ROOM_NOT_FOUND_ERROR_CODE(202), - ROOM_GENERIC_ERROR_CODE(201), - - USER_ALREADY_STREAMING_ERROR_CODE(106), USER_NOT_STREAMING_ERROR_CODE(105), - EXISTING_USER_IN_ROOM_ERROR_CODE(104), USER_CLOSED_ERROR_CODE(103), USER_NOT_FOUND_ERROR_CODE(102), - USER_GENERIC_ERROR_CODE(10), - - USER_UNAUTHORIZED_ERROR_CODE(401), ROLE_NOT_FOUND_ERROR_CODE(402), SESSIONID_CANNOT_BE_CREATED_ERROR_CODE(403), - TOKEN_CANNOT_BE_CREATED_ERROR_CODE(404), EXISTING_FILTER_ALREADY_APPLIED_ERROR_CODE(405), - FILTER_NOT_APPLIED_ERROR_CODE(406), FILTER_EVENT_LISTENER_NOT_FOUND_ERROR_CODE(407), - PUBLISHER_ENDPOINT_NOT_FOUND_ERROR_CODE(408), - - USER_METADATA_FORMAT_INVALID_ERROR_CODE(500), - - SIGNAL_FORMAT_INVALID_ERROR_CODE(600), SIGNAL_TO_INVALID_ERROR_CODE(601), - - BROADCAST_CONCURRENT_ERROR_CODE(711), BROADCAST_START_ERROR_CODE(710), DOCKER_NOT_FOUND(709), RECORDING_PATH_NOT_VALID(708), RECORDING_FILE_EMPTY_ERROR(707), - RECORDING_DELETE_ERROR_CODE(706), RECORDING_LIST_ERROR_CODE(705), RECORDING_STOP_ERROR_CODE(704), - RECORDING_START_ERROR_CODE(703), RECORDING_REPORT_ERROR_CODE(702), RECORDING_COMPLETION_ERROR_CODE(701), - - FORCED_CODEC_NOT_FOUND_IN_SDPOFFER(800), - - MEDIA_NODE_NOT_FOUND(900), MEDIA_NODE_STATUS_WRONG(901), MEDIA_NODE_CONNECTION_ERROR_CODE(902); - - private int value; - - private Code(int value) { - this.value = value; - } - - public int getValue() { - return this.value; - } - } - - private Code code = Code.GENERIC_ERROR_CODE; - - public OpenViduException(Code code, String message) { - super(code.getValue(), message); - this.code = code; - } - - public int getCodeValue() { - return code.getValue(); - } - - @Override - public String toString() { - return super.toString(); - } - -} diff --git a/openvidu-client/src/main/java/io/openvidu/client/ServerJsonRpcHandler.java b/openvidu-client/src/main/java/io/openvidu/client/ServerJsonRpcHandler.java deleted file mode 100644 index 6b6d5bc053..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/ServerJsonRpcHandler.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.openvidu.client; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; - -import org.kurento.jsonrpc.DefaultJsonRpcHandler; -import org.kurento.jsonrpc.Transaction; -import org.kurento.jsonrpc.message.Request; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import io.openvidu.client.internal.IceCandidate; -import io.openvidu.client.internal.IceCandidateInfo; -import io.openvidu.client.internal.JsonRoomUtils; -import io.openvidu.client.internal.MediaErrorInfo; -import io.openvidu.client.internal.Notification; -import io.openvidu.client.internal.ParticipantEvictedInfo; -import io.openvidu.client.internal.ParticipantJoinedInfo; -import io.openvidu.client.internal.ParticipantLeftInfo; -import io.openvidu.client.internal.ParticipantPublishedInfo; -import io.openvidu.client.internal.ParticipantUnpublishedInfo; -import io.openvidu.client.internal.ProtocolElements; -import io.openvidu.client.internal.RoomClosedInfo; -import io.openvidu.client.internal.SendMessageInfo; - -/** - * Service that handles server JSON-RPC events. - * - * @author Radu Tom Vlad - */ -public class ServerJsonRpcHandler extends DefaultJsonRpcHandler { - - private static final Logger log = LoggerFactory.getLogger(ServerJsonRpcHandler.class); - - private BlockingQueue notifications = new ArrayBlockingQueue(100); - - @Override - public void handleRequest(Transaction transaction, Request request) throws Exception { - Notification notif = null; - try { - switch (request.getMethod()) { - case ProtocolElements.ICECANDIDATE_METHOD: - notif = iceCandidate(transaction, request); - break; - case ProtocolElements.MEDIAERROR_METHOD: - notif = mediaError(transaction, request); - break; - case ProtocolElements.PARTICIPANTJOINED_METHOD: - notif = participantJoined(transaction, request); - break; - case ProtocolElements.PARTICIPANTLEFT_METHOD: - notif = participantLeft(transaction, request); - break; - case ProtocolElements.PARTICIPANTEVICTED_METHOD: - notif = participantEvicted(transaction, request); - break; - case ProtocolElements.PARTICIPANTPUBLISHED_METHOD: - notif = participantPublished(transaction, request); - break; - case ProtocolElements.PARTICIPANTUNPUBLISHED_METHOD: - notif = participantUnpublished(transaction, request); - break; - case ProtocolElements.ROOMCLOSED_METHOD: - notif = roomClosed(transaction, request); - break; - case ProtocolElements.PARTICIPANTSENDMESSAGE_METHOD: - notif = participantSendMessage(transaction, request); - break; - default: - throw new Exception("Unrecognized request " + request.getMethod()); - } - } catch (Exception e) { - log.error("Exception processing request {}", request, e); - transaction.sendError(e); - return; - } - if (notif != null) { - try { - notifications.put(notif); - log.debug("Enqueued notification {}", notif); - } catch (InterruptedException e) { - log.warn("Interrupted when enqueuing notification {}", notif, e); - } - } - } - - private Notification participantSendMessage(Transaction transaction, - Request request) { - String data = JsonRoomUtils.getRequestParam(request, - ProtocolElements.PARTICIPANTSENDMESSAGE_DATA_PARAM, String.class); - String from = JsonRoomUtils.getRequestParam(request, - ProtocolElements.PARTICIPANTSENDMESSAGE_FROM_PARAM, String.class); - String type = JsonRoomUtils.getRequestParam(request, - ProtocolElements.PARTICIPANTSENDMESSAGE_TYPE_PARAM, String.class); - SendMessageInfo eventInfo = new SendMessageInfo(data, from, type); - log.debug("Recvd send message event {}", eventInfo); - return eventInfo; - } - - private Notification roomClosed(Transaction transaction, Request request) { - String room = JsonRoomUtils.getRequestParam(request, ProtocolElements.ROOMCLOSED_ROOM_PARAM, - String.class); - RoomClosedInfo eventInfo = new RoomClosedInfo(room); - log.debug("Recvd room closed event {}", eventInfo); - return eventInfo; - } - - private Notification participantUnpublished(Transaction transaction, - Request request) { - String name = JsonRoomUtils.getRequestParam(request, - ProtocolElements.PARTICIPANTUNPUBLISHED_NAME_PARAM, String.class); - ParticipantUnpublishedInfo eventInfo = new ParticipantUnpublishedInfo(name); - log.debug("Recvd participant unpublished event {}", eventInfo); - return eventInfo; - } - - private Notification participantPublished(Transaction transaction, Request request) { - String id = JsonRoomUtils.getRequestParam(request, - ProtocolElements.PARTICIPANTPUBLISHED_USER_PARAM, String.class); - JsonArray jsonStreams = JsonRoomUtils.getRequestParam(request, - ProtocolElements.PARTICIPANTPUBLISHED_STREAMS_PARAM, JsonArray.class); - Iterator streamIt = jsonStreams.iterator(); - List streams = new ArrayList(); - while (streamIt.hasNext()) { - streams.add(JsonRoomUtils.getResponseProperty(streamIt.next(), - ProtocolElements.PARTICIPANTPUBLISHED_STREAMID_PARAM, String.class)); - } - ParticipantPublishedInfo eventInfo = new ParticipantPublishedInfo(id, streams); - log.debug("Recvd published event {}", eventInfo); - return eventInfo; - } - - private Notification participantEvicted(Transaction transaction, Request request) { - ParticipantEvictedInfo eventInfo = new ParticipantEvictedInfo(); - log.debug("Recvd participant evicted event {}", eventInfo); - return eventInfo; - } - - private Notification participantLeft(Transaction transaction, Request request) { - String name = JsonRoomUtils.getRequestParam(request, - ProtocolElements.PARTICIPANTLEFT_NAME_PARAM, String.class); - ParticipantLeftInfo eventInfo = new ParticipantLeftInfo(name); - log.debug("Recvd participant left event {}", eventInfo); - return eventInfo; - } - - private Notification participantJoined(Transaction transaction, Request request) { - String id = JsonRoomUtils.getRequestParam(request, - ProtocolElements.PARTICIPANTJOINED_USER_PARAM, String.class); - ParticipantJoinedInfo eventInfo = new ParticipantJoinedInfo(id); - log.debug("Recvd participant joined event {}", eventInfo); - return eventInfo; - } - - private Notification mediaError(Transaction transaction, Request request) { - String description = JsonRoomUtils.getRequestParam(request, - ProtocolElements.MEDIAERROR_ERROR_PARAM, String.class); - MediaErrorInfo eventInfo = new MediaErrorInfo(description); - log.debug("Recvd media error event {}", eventInfo); - return eventInfo; - } - - private Notification iceCandidate(Transaction transaction, Request request) { - - String candidate = JsonRoomUtils.getRequestParam(request, - ProtocolElements.ICECANDIDATE_CANDIDATE_PARAM, String.class); - String sdpMid = JsonRoomUtils.getRequestParam(request, - ProtocolElements.ICECANDIDATE_SDPMID_PARAM, String.class); - int sdpMLineIndex = JsonRoomUtils.getRequestParam(request, - ProtocolElements.ICECANDIDATE_SDPMLINEINDEX_PARAM, Integer.class); - - IceCandidate iceCandidate = new IceCandidate(candidate, sdpMid, sdpMLineIndex); - - String endpoint = JsonRoomUtils.getRequestParam(request, - ProtocolElements.ICECANDIDATE_EPNAME_PARAM, String.class); - - IceCandidateInfo eventInfo = new IceCandidateInfo(iceCandidate, endpoint); - log.debug("Recvd ICE candidate event {}", eventInfo); - - return eventInfo; - } - - /** - * Blocks until an element is available and then returns it by removing it from the queue. - * - * @return a {@link Notification} from the queue, null when interrupted - * @see BlockingQueue#take() - */ - public Notification getNotification() { - try { - Notification notif = notifications.take(); - log.debug("Dequeued notification {}", notif); - return notif; - } catch (InterruptedException e) { - log.info("Interrupted while polling notifications' queue"); - return null; - } - } -} diff --git a/openvidu-client/src/main/java/io/openvidu/client/internal/IceCandidate.java b/openvidu-client/src/main/java/io/openvidu/client/internal/IceCandidate.java deleted file mode 100644 index 42564b1d3f..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/internal/IceCandidate.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.openvidu.client.internal; - -public class IceCandidate { - - private String candidate; - private String sdpMid; - private int sdpMLineIndex; - - public IceCandidate(String candidate, String sdpMid, int sdpMLineIndex) { - super(); - this.candidate = candidate; - this.sdpMid = sdpMid; - this.sdpMLineIndex = sdpMLineIndex; - } - - public String getCandidate() { - return candidate; - } - - public String getSdpMid() { - return sdpMid; - } - - public int getSdpMLineIndex() { - return sdpMLineIndex; - } - - @Override - public String toString() { - return "IceCandidate [candidate=" + candidate + ", sdpMid=" + sdpMid + ", sdpMLineIndex=" - + sdpMLineIndex + "]"; - } -} diff --git a/openvidu-client/src/main/java/io/openvidu/client/internal/IceCandidateInfo.java b/openvidu-client/src/main/java/io/openvidu/client/internal/IceCandidateInfo.java deleted file mode 100644 index face215b97..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/internal/IceCandidateInfo.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.openvidu.client.internal; - -/** - * @see Notification - * - * @author Radu Tom Vlad - */ -public class IceCandidateInfo extends Notification { - - private IceCandidate iceCandidate; - private String endpointName; - - public IceCandidateInfo(IceCandidate iceCandidate, String endpointName) { - super(ProtocolElements.ICECANDIDATE_METHOD); - this.iceCandidate = iceCandidate; - this.endpointName = endpointName; - } - - public IceCandidate getIceCandidate() { - return iceCandidate; - } - - public void setIceCandidate(IceCandidate iceCandidate) { - this.iceCandidate = iceCandidate; - } - - public String getEndpointName() { - return endpointName; - } - - public void setEndpointName(String endpointName) { - this.endpointName = endpointName; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - if (getMethod() != null) { - builder.append("method=").append(getMethod()).append(", "); - } - if (endpointName != null) { - builder.append("endpointName=").append(endpointName).append(", "); - } - if (iceCandidate != null) { - builder.append("iceCandidate=[sdpMLineIndex= ").append(iceCandidate.getSdpMLineIndex()) - .append(", sdpMid=").append(iceCandidate.getSdpMid()).append(", candidate=") - .append(iceCandidate.getCandidate()).append("]"); - } - builder.append("]"); - return builder.toString(); - } - -} diff --git a/openvidu-client/src/main/java/io/openvidu/client/internal/JsonRoomUtils.java b/openvidu-client/src/main/java/io/openvidu/client/internal/JsonRoomUtils.java deleted file mode 100644 index 552ebc9ec7..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/internal/JsonRoomUtils.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.openvidu.client.internal; - -import org.kurento.jsonrpc.message.Request; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import io.openvidu.client.OpenViduException; -import io.openvidu.client.OpenViduException.Code; - -/** - * JSON tools for extracting info from request or response elements. - * - * @author Radu Tom Vlad - */ -public class JsonRoomUtils { - - public static T getRequestParam(Request request, String paramName, Class type) { - return getRequestParam(request, paramName, type, false); - } - - public static T getRequestParam(Request request, String paramName, Class type, - boolean allowNull) { - JsonObject params = request.getParams(); - if (params == null) { - if (!allowNull) { - throw new OpenViduException(Code.TRANSPORT_REQUEST_ERROR_CODE, - "Invalid request lacking parameter '" + paramName + "'"); - } else { - return null; - } - } - return getConverted(params.get(paramName), paramName, type, allowNull); - } - - public static T getResponseProperty(JsonElement result, String property, Class type) { - return getResponseProperty(result, property, type, false); - } - - public static T getResponseProperty(JsonElement result, String property, Class type, - boolean allowNull) { - if (!(result instanceof JsonObject)) { - throw new OpenViduException(Code.TRANSPORT_RESPONSE_ERROR_CODE, - "Invalid response format. The response '" + result + "' should be a Json object"); - } - return getConverted(result.getAsJsonObject().get(property), property, type, allowNull); - } - - public static JsonArray getResponseArray(JsonElement result) { - if (!result.isJsonArray()) { - throw new OpenViduException(Code.TRANSPORT_RESPONSE_ERROR_CODE, - "Invalid response format. The response '" + result + "' should be a Json array"); - } - return result.getAsJsonArray(); - } - - @SuppressWarnings("unchecked") - private static T getConverted(JsonElement paramValue, String property, Class type, - boolean allowNull) { - if (paramValue == null) { - if (allowNull) { - return null; - } else { - throw new OpenViduException(Code.TRANSPORT_ERROR_CODE, "Invalid method lacking parameter '" - + property + "'"); - } - } - - if (type == String.class) { - if (paramValue.isJsonPrimitive()) { - return (T) paramValue.getAsString(); - } - } - - if (type == Integer.class) { - if (paramValue.isJsonPrimitive()) { - return (T) Integer.valueOf(paramValue.getAsInt()); - } - } - - if (type == JsonArray.class) { - if (paramValue.isJsonArray()) { - return (T) paramValue.getAsJsonArray(); - } - } - - throw new OpenViduException(Code.TRANSPORT_ERROR_CODE, "Param '" + property + "' with value '" - + paramValue + "' is not a " + type.getName()); - } -} diff --git a/openvidu-client/src/main/java/io/openvidu/client/internal/MediaErrorInfo.java b/openvidu-client/src/main/java/io/openvidu/client/internal/MediaErrorInfo.java deleted file mode 100644 index 9993e1b9bd..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/internal/MediaErrorInfo.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.openvidu.client.internal; - -/** - * - * @author Radu Tom Vlad - * - * @see Notification - */ -public class MediaErrorInfo extends Notification { - - private String description; - - public MediaErrorInfo(String description) { - super(ProtocolElements.MEDIAERROR_METHOD); - this.description = description; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - if (getMethod() != null) { - builder.append("method=").append(getMethod()).append(", "); - } - if (description != null) { - builder.append("description=").append(description); - } - builder.append("]"); - return builder.toString(); - } -} diff --git a/openvidu-client/src/main/java/io/openvidu/client/internal/Notification.java b/openvidu-client/src/main/java/io/openvidu/client/internal/Notification.java deleted file mode 100644 index 85e16a57c9..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/internal/Notification.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.openvidu.client.internal; - -/** - * Wrapper for server events. - * - * @author Radu Tom Vlad - */ -public abstract class Notification { - - public enum Method { - ICECANDIDATE_METHOD(ProtocolElements.ICECANDIDATE_METHOD), MEDIAERROR_METHOD( - ProtocolElements.MEDIAERROR_METHOD), PARTICIPANTJOINED_METHOD( - ProtocolElements.PARTICIPANTJOINED_METHOD), PARTICIPANTLEFT_METHOD( - ProtocolElements.PARTICIPANTLEFT_METHOD), PARTICIPANTEVICTED_METHOD( - ProtocolElements.PARTICIPANTEVICTED_METHOD), PARTICIPANTPUBLISHED_METHOD( - ProtocolElements.PARTICIPANTPUBLISHED_METHOD), PARTICIPANTUNPUBLISHED_METHOD( - ProtocolElements.PARTICIPANTUNPUBLISHED_METHOD), ROOMCLOSED_METHOD( - ProtocolElements.ROOMCLOSED_METHOD), PARTICIPANTSENDMESSAGE_METHOD( - ProtocolElements.PARTICIPANTSENDMESSAGE_METHOD); - - private String methodValue; - - private Method(String val) { - this.methodValue = val; - } - - public String getMethodValue() { - return methodValue; - } - - public static Method getFromValue(String val) { - for (Method m : Method.values()) { - if (m.methodValue.equals(val)) { - return m; - } - } - return null; - } - - @Override - public String toString() { - return getMethodValue().toString(); - } - } - - private Method method; - - public Notification(Method method) { - this.setMethod(method); - } - - public Notification(String methodValue) { - this(Method.getFromValue(methodValue)); - } - - public Method getMethod() { - return method; - } - - public void setMethod(Method method) { - this.method = method; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - if (method != null) { - builder.append("method=").append(method); - } - builder.append("]"); - return builder.toString(); - } -} diff --git a/openvidu-client/src/main/java/io/openvidu/client/internal/ParticipantEvictedInfo.java b/openvidu-client/src/main/java/io/openvidu/client/internal/ParticipantEvictedInfo.java deleted file mode 100644 index 5c3562b466..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/internal/ParticipantEvictedInfo.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.openvidu.client.internal; - -/** - * @see Notification - * - * @author Radu Tom Vlad - */ -public class ParticipantEvictedInfo extends Notification { - - public ParticipantEvictedInfo() { - super(ProtocolElements.PARTICIPANTEVICTED_METHOD); - } - -} diff --git a/openvidu-client/src/main/java/io/openvidu/client/internal/ParticipantJoinedInfo.java b/openvidu-client/src/main/java/io/openvidu/client/internal/ParticipantJoinedInfo.java deleted file mode 100644 index ee8b0c01ee..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/internal/ParticipantJoinedInfo.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.openvidu.client.internal; - -/** - * @see Notification - * - * @author Radu Tom Vlad - */ -public class ParticipantJoinedInfo extends Notification { - - private String id; - - public ParticipantJoinedInfo(String id) { - super(ProtocolElements.PARTICIPANTJOINED_METHOD); - this.id = id; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - if (getMethod() != null) { - builder.append("method=").append(getMethod()).append(", "); - } - if (id != null) { - builder.append("id=").append(id); - } - builder.append("]"); - return builder.toString(); - } -} diff --git a/openvidu-client/src/main/java/io/openvidu/client/internal/ParticipantLeftInfo.java b/openvidu-client/src/main/java/io/openvidu/client/internal/ParticipantLeftInfo.java deleted file mode 100644 index 10217338dc..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/internal/ParticipantLeftInfo.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.openvidu.client.internal; - -/** - * @see Notification - * - * @author Radu Tom Vlad - */ -public class ParticipantLeftInfo extends Notification { - - private String name; - - public ParticipantLeftInfo(String name) { - super(ProtocolElements.PARTICIPANTLEFT_METHOD); - this.name = name; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - if (getMethod() != null) { - builder.append("method=").append(getMethod()).append(", "); - } - if (name != null) { - builder.append("name=").append(name); - } - builder.append("]"); - return builder.toString(); - } -} diff --git a/openvidu-client/src/main/java/io/openvidu/client/internal/ParticipantPublishedInfo.java b/openvidu-client/src/main/java/io/openvidu/client/internal/ParticipantPublishedInfo.java deleted file mode 100644 index ab96089639..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/internal/ParticipantPublishedInfo.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.openvidu.client.internal; - -import java.util.List; - -/** - * @see Notification - * - * @author Radu Tom Vlad - */ -public class ParticipantPublishedInfo extends Notification { - - private String id; - private List streams; - - public ParticipantPublishedInfo(String id, List streams) { - super(ProtocolElements.PARTICIPANTPUBLISHED_METHOD); - this.id = id; - this.streams = streams; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public List getStreams() { - return streams; - } - - public void setStreams(List streams) { - this.streams = streams; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - if (getMethod() != null) { - builder.append("method=").append(getMethod()).append(", "); - } - if (id != null) { - builder.append("id=").append(id).append(", "); - } - if (streams != null) { - builder.append("streams=").append(streams); - } - builder.append("]"); - return builder.toString(); - } -} diff --git a/openvidu-client/src/main/java/io/openvidu/client/internal/ParticipantUnpublishedInfo.java b/openvidu-client/src/main/java/io/openvidu/client/internal/ParticipantUnpublishedInfo.java deleted file mode 100644 index ae2e4e6205..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/internal/ParticipantUnpublishedInfo.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.openvidu.client.internal; - -/** - * @see Notification - * - * @author Radu Tom Vlad - */ -public class ParticipantUnpublishedInfo extends Notification { - - private String name; - - public ParticipantUnpublishedInfo(String name) { - super(ProtocolElements.PARTICIPANTUNPUBLISHED_METHOD); - this.name = name; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - if (getMethod() != null) { - builder.append("method=").append(getMethod()).append(", "); - } - if (name != null) { - builder.append("name=").append(name); - } - builder.append("]"); - return builder.toString(); - } -} diff --git a/openvidu-client/src/main/java/io/openvidu/client/internal/ProtocolElements.java b/openvidu-client/src/main/java/io/openvidu/client/internal/ProtocolElements.java deleted file mode 100644 index a5e2ea9901..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/internal/ProtocolElements.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.openvidu.client.internal; - -/** - * This class defines constant values of client-server messages and their - * parameters. - * - * @author Radu Tom Vlad - */ -public class ProtocolElements { - - // ---------------------------- CLIENT REQUESTS ----------------------- - - public static final String SENDMESSAGE_ROOM_METHOD = "sendMessage"; - public static final String SENDMESSAGE_MESSAGE_PARAM = "message"; - - public static final String LEAVEROOM_METHOD = "leaveRoom"; - - public static final String JOINROOM_METHOD = "joinRoom"; - public static final String JOINROOM_USER_PARAM = "user"; - public static final String JOINROOM_TOKEN_PARAM = "token"; - public static final String JOINROOM_ROOM_PARAM = "session"; - public static final String JOINROOM_METADATA_PARAM = "metadata"; - public static final String JOINROOM_SECRET_PARAM = "secret"; - public static final String JOINROOM_PLATFORM_PARAM = "platform"; - public static final String JOINROOM_SDKVERSION_PARAM = "sdkVersion"; - public static final String JOINROOM_RECORDER_PARAM = "recorder"; - public static final String JOINROOM_STT_PARAM = "stt"; - - public static final String JOINROOM_PEERID_PARAM = "id"; - public static final String JOINROOM_PEERCREATEDAT_PARAM = "createdAt"; - public static final String JOINROOM_PEERSTREAMS_PARAM = "streams"; - public static final String JOINROOM_PEERSTREAMID_PARAM = "id"; - public static final String JOINROOM_PEERSTREAMHASAUDIO_PARAM = "hasAudio"; - public static final String JOINROOM_PEERSTREAMHASVIDEO_PARAM = "hasVideo"; - public static final String JOINROOM_PEERSTREAMAUDIOACTIVE_PARAM = "audioActive"; - public static final String JOINROOM_PEERSTREAMVIDEOACTIVE_PARAM = "videoActive"; - public static final String JOINROOM_PEERSTREAMTYPEOFVIDEO_PARAM = "typeOfVideo"; - public static final String JOINROOM_PEERSTREAMFRAMERATE_PARAM = "frameRate"; - public static final String JOINROOM_PEERSTREAMVIDEODIMENSIONS_PARAM = "videoDimensions"; - public static final String JOINROOM_PEERSTREAMFILTER_PARAM = "filter"; - - public static final String PUBLISHVIDEO_METHOD = "publishVideo"; - public static final String PUBLISHVIDEO_SDPOFFER_PARAM = "sdpOffer"; - public static final String PUBLISHVIDEO_DOLOOPBACK_PARAM = "doLoopback"; - public static final String PUBLISHVIDEO_SDPANSWER_PARAM = "sdpAnswer"; - public static final String PUBLISHVIDEO_STREAMID_PARAM = "id"; - public static final String PUBLISHVIDEO_CREATEDAT_PARAM = "createdAt"; - public static final String PUBLISHVIDEO_HASAUDIO_PARAM = "hasAudio"; - public static final String PUBLISHVIDEO_HASVIDEO_PARAM = "hasVideo"; - public static final String PUBLISHVIDEO_AUDIOACTIVE_PARAM = "audioActive"; - public static final String PUBLISHVIDEO_VIDEOACTIVE_PARAM = "videoActive"; - public static final String PUBLISHVIDEO_TYPEOFVIDEO_PARAM = "typeOfVideo"; - public static final String PUBLISHVIDEO_FRAMERATE_PARAM = "frameRate"; - public static final String PUBLISHVIDEO_VIDEODIMENSIONS_PARAM = "videoDimensions"; - public static final String PUBLISHVIDEO_KURENTOFILTER_PARAM = "filter"; - - public static final String UNPUBLISHVIDEO_METHOD = "unpublishVideo"; - - public static final String PREPARERECEIVEVIDEO_METHOD = "prepareReceiveVideoFrom"; - public static final String PREPARERECEIVEVIDEO_SDPOFFER_PARAM = "sdpOffer"; - public static final String PREPARERECEIVEVIDEO_RECONNECT_PARAM = "reconnect"; - - public static final String RECEIVEVIDEO_METHOD = "receiveVideoFrom"; - public static final String RECEIVEVIDEO_SDPOFFER_PARAM = "sdpOffer"; - public static final String RECEIVEVIDEO_SENDER_PARAM = "sender"; - public static final String RECEIVEVIDEO_SDPANSWER_PARAM = "sdpAnswer"; - - public static final String UNSUBSCRIBEFROMVIDEO_METHOD = "unsubscribeFromVideo"; - public static final String UNSUBSCRIBEFROMVIDEO_SENDER_PARAM = "sender"; - - public static final String ONICECANDIDATE_METHOD = "onIceCandidate"; - public static final String ONICECANDIDATE_EPNAME_PARAM = "endpointName"; - public static final String ONICECANDIDATE_CANDIDATE_PARAM = "candidate"; - public static final String ONICECANDIDATE_SDPMIDPARAM = "sdpMid"; - public static final String ONICECANDIDATE_SDPMLINEINDEX_PARAM = "sdpMLineIndex"; - - public static final String CUSTOMREQUEST_METHOD = "customRequest"; - - public static final String STREAMPROPERTYCHANGED_METHOD = "streamPropertyChanged"; - public static final String STREAMPROPERTYCHANGED_CONNECTIONID_PARAM = "connectionId"; - public static final String STREAMPROPERTYCHANGED_STREAMID_PARAM = "streamId"; - public static final String STREAMPROPERTYCHANGED_PROPERTY_PARAM = "property"; - public static final String STREAMPROPERTYCHANGED_NEWVALUE_PARAM = "newValue"; - public static final String STREAMPROPERTYCHANGED_REASON_PARAM = "reason"; - - public static final String CONNECTIONPERTYCHANGED_METHOD = "connectionPropertyChanged"; - public static final String CONNECTIONROPERTYCHANGED_PROPERTY_PARAM = "property"; - public static final String CONNECTIONPROPERTYCHANGED_NEWVALUE_PARAM = "newValue"; - - public static final String NETWORKQUALITYLEVELCHANGED_METHOD = "networkQualityLevelChanged"; - public static final String NETWORKQUALITYCHANGED_CONNECTIONID_PARAM = "connectionId"; - public static final String NETWORKQUALITYCHANGED_NEWVALUE_PARAM = "newValue"; - public static final String NETWORKQUALITYCHANGED_OLDVALUE_PARAM = "oldValue"; - - public static final String FORCEDISCONNECT_METHOD = "forceDisconnect"; - public static final String FORCEDISCONNECT_CONNECTIONID_PARAM = "connectionId"; - - public static final String FORCEUNPUBLISH_METHOD = "forceUnpublish"; - public static final String FORCEUNPUBLISH_STREAMID_PARAM = "streamId"; - - public static final String APPLYFILTER_METHOD = "applyFilter"; - public static final String FILTER_STREAMID_PARAM = "streamId"; - public static final String FILTER_TYPE_PARAM = "type"; - public static final String FILTER_OPTIONS_PARAM = "options"; - public static final String FILTER_METHOD_PARAM = "method"; - public static final String FILTER_PARAMS_PARAM = "params"; - public static final String EXECFILTERMETHOD_METHOD = "execFilterMethod"; - public static final String EXECFILTERMETHOD_LASTEXECMETHOD_PARAM = "lastExecMethod"; - public static final String REMOVEFILTER_METHOD = "removeFilter"; - public static final String ADDFILTEREVENTLISTENER_METHOD = "addFilterEventListener"; - public static final String REMOVEFILTEREVENTLISTENER_METHOD = "removeFilterEventListener"; - - public static final String FILTEREVENTDISPATCHED_METHOD = "filterEventDispatched"; - public static final String FILTEREVENTLISTENER_CONNECTIONID_PARAM = "connectionId"; - public static final String FILTEREVENTLISTENER_STREAMID_PARAM = "streamId"; - public static final String FILTEREVENTLISTENER_FILTERTYPE_PARAM = "filterType"; - public static final String FILTEREVENTLISTENER_EVENTTYPE_PARAM = "eventType"; - public static final String FILTEREVENTLISTENER_DATA_PARAM = "data"; - - public static final String RECONNECTSTREAM_METHOD = "reconnectStream"; - public static final String RECONNECTSTREAM_STREAM_PARAM = "stream"; - public static final String RECONNECTSTREAM_SDPSTRING_PARAM = "sdpString"; - public static final String RECONNECTSTREAM_FORCIBLYRECONNECT_PARAM = "forciblyReconnect"; - public static final String RECONNECTSTREAM_SDPOFFER_PARAM = "sdpOffer"; - - public static final String VIDEODATA_METHOD = "videoData"; - - public static final String ECHO_METHOD = "echo"; - - public static final String FORCIBLYRECONNECTSUBSCRIBER_METHOD = "forciblyReconnectSubscriber"; - public static final String FORCIBLYRECONNECTSUBSCRIBER_CONNECTIONID_PARAM = "connectionId"; - public static final String FORCIBLYRECONNECTSUBSCRIBER_STREAMID_PARAM = "streamId"; - public static final String FORCIBLYRECONNECTSUBSCRIBER_SDPOFFER_PARAM = "sdpOffer"; - - public static final String SUBSCRIBETOSPEECHTOTEXT_METHOD = "subscribeToSpeechToText"; - public static final String SUBSCRIBETOSPEECHTOTEXT_CONNECTIONID_PARAM = "connectionId"; - public static final String SUBSCRIBETOSPEECHTOTEXT_LANG_PARAM = "lang"; - - public static final String UNSUBSCRIBEFROMSPEECHTOTEXT_METHOD = "unsubscribeFromSpeechToText"; - public static final String UNSUBSCRIBEFROMSPEECHTOTEXT_CONNECTIONID_PARAM = "connectionId"; - - // ---------------------------- SERVER RESPONSES & EVENTS ----------------- - - public static final String PARTICIPANTJOINED_METHOD = "participantJoined"; - public static final String PARTICIPANTJOINED_USER_PARAM = "id"; - public static final String PARTICIPANTJOINED_FINALUSERID_PARAM = "finalUserId"; - public static final String PARTICIPANTJOINED_CREATEDAT_PARAM = "createdAt"; - public static final String PARTICIPANTJOINED_METADATA_PARAM = "metadata"; - public static final String PARTICIPANTJOINED_VALUE_PARAM = "value"; - public static final String PARTICIPANTJOINED_SESSION_PARAM = "session"; - public static final String PARTICIPANTJOINED_VERSION_PARAM = "version"; - public static final String PARTICIPANTJOINED_MEDIASERVER_PARAM = "mediaServer"; - public static final String PARTICIPANTJOINED_SIMULCAST_PARAM = "videoSimulcast"; - public static final String PARTICIPANTJOINED_RECORD_PARAM = "record"; - public static final String PARTICIPANTJOINED_ROLE_PARAM = "role"; - public static final String PARTICIPANTJOINED_COTURNIP_PARAM = "coturnIp"; - public static final String PARTICIPANTJOINED_COTURNPORT_PARAM = "coturnPort"; - public static final String PARTICIPANTJOINED_CUSTOM_ICE_SERVERS = "customIceServers"; - public static final String PARTICIPANTJOINED_TURNUSERNAME_PARAM = "turnUsername"; - public static final String PARTICIPANTJOINED_TURNCREDENTIAL_PARAM = "turnCredential"; - public static final String PARTICIPANTJOINED_RECORDINGID_PARAM = "recordingId"; - public static final String PARTICIPANTJOINED_RECORDINGNAME_PARAM = "recordingName"; - - public static final String PARTICIPANTLEFT_METHOD = "participantLeft"; - public static final String PARTICIPANTLEFT_NAME_PARAM = "connectionId"; - public static final String PARTICIPANTLEFT_REASON_PARAM = "reason"; - - public static final String PARTICIPANTEVICTED_METHOD = "participantEvicted"; - public static final String PARTICIPANTEVICTED_CONNECTIONID_PARAM = "connectionId"; - public static final String PARTICIPANTEVICTED_REASON_PARAM = "reason"; - - public static final String PARTICIPANTPUBLISHED_METHOD = "participantPublished"; - public static final String PARTICIPANTPUBLISHED_USER_PARAM = "id"; - public static final String PARTICIPANTPUBLISHED_STREAMS_PARAM = "streams"; - public static final String PARTICIPANTPUBLISHED_STREAMID_PARAM = "id"; - public static final String PARTICIPANTPUBLISHED_CREATEDAT_PARAM = "createdAt"; - public static final String PARTICIPANTPUBLISHED_HASAUDIO_PARAM = "hasAudio"; - public static final String PARTICIPANTPUBLISHED_HASVIDEO_PARAM = "hasVideo"; - public static final String PARTICIPANTPUBLISHED_AUDIOACTIVE_PARAM = "audioActive"; - public static final String PARTICIPANTPUBLISHED_VIDEOACTIVE_PARAM = "videoActive"; - public static final String PARTICIPANTPUBLISHED_TYPEOFVIDEO_PARAM = "typeOfVideo"; - public static final String PARTICIPANTPUBLISHED_FRAMERATE_PARAM = "frameRate"; - public static final String PARTICIPANTPUBLISHED_VIDEODIMENSIONS_PARAM = "videoDimensions"; - public static final String PARTICIPANTPUBLISHED_FILTER_PARAM = "filter"; - - public static final String PARTICIPANTUNPUBLISHED_METHOD = "participantUnpublished"; - public static final String PARTICIPANTUNPUBLISHED_NAME_PARAM = "connectionId"; - public static final String PARTICIPANTUNPUBLISHED_REASON_PARAM = "reason"; - - public static final String PARTICIPANTSENDMESSAGE_METHOD = "sendMessage"; - public static final String PARTICIPANTSENDMESSAGE_DATA_PARAM = "data"; - public static final String PARTICIPANTSENDMESSAGE_FROM_PARAM = "from"; - public static final String PARTICIPANTSENDMESSAGE_TYPE_PARAM = "type"; - - public static final String ROOMCLOSED_METHOD = "roomClosed"; - public static final String ROOMCLOSED_ROOM_PARAM = "sessionId"; - - public static final String MEDIAERROR_METHOD = "mediaError"; - public static final String MEDIAERROR_ERROR_PARAM = "error"; - - public static final String ICECANDIDATE_METHOD = "iceCandidate"; - public static final String ICECANDIDATE_SENDERCONNECTIONID_PARAM = "senderConnectionId"; - public static final String ICECANDIDATE_EPNAME_PARAM = "endpointName"; - public static final String ICECANDIDATE_CANDIDATE_PARAM = "candidate"; - public static final String ICECANDIDATE_SDPMID_PARAM = "sdpMid"; - public static final String ICECANDIDATE_SDPMLINEINDEX_PARAM = "sdpMLineIndex"; - - public static final String RECORDINGSTARTED_METHOD = "recordingStarted"; - public static final String RECORDINGSTARTED_ID_PARAM = "id"; - public static final String RECORDINGSTARTED_NAME_PARAM = "name"; - public static final String RECORDINGSTOPPED_REASON_PARAM = "reason"; - - public static final String RECORDINGSTOPPED_METHOD = "recordingStopped"; - public static final String RECORDINGSTOPPED_ID_PARAM = "id"; - - public static final String BROADCASTSTARTED_METHOD = "broadcastStarted"; - - public static final String BROADCASTSTOPPED_METHOD = "broadcastStopped"; - - public static final String SPEECHTOTEXTMESSAGE_METHOD = "speechToTextMessage"; - public static final String SPEECHTOTEXTMESSAGE_TIMESTAMP_PARAM = "timestamp"; - public static final String SPEECHTOTEXTMESSAGE_SESSIONID_PARAM = "sessionId"; - public static final String SPEECHTOTEXTMESSAGE_CONNECTIONID_PARAM = "connectionId"; - public static final String SPEECHTOTEXTMESSAGE_TEXT_PARAM = "text"; - public static final String SPEECHTOTEXTMESSAGE_REASON_PARAM = "reason"; - public static final String SPEECHTOTEXTMESSAGE_RAW_PARAM = "raw"; - public static final String SPEECHTOTEXTMESSAGE_LANG_PARAM = "lang"; - - public static final String SPEECHTOTEXTDISCONNECTED_METHOD = "speechToTextDisconnected"; - public static final String SPEECHTOTEXTDISCONNECTED_MESSAGE_PARAM = "message"; - - public static final String CUSTOM_NOTIFICATION = "customNotification"; - - public static final String RECORDER_PARTICIPANT_PUBLICID = "RECORDER"; - public static final String STT_PARTICIPANT_PUBLICID = "SPEECH_TO_TEXT"; -} diff --git a/openvidu-client/src/main/java/io/openvidu/client/internal/RoomClosedInfo.java b/openvidu-client/src/main/java/io/openvidu/client/internal/RoomClosedInfo.java deleted file mode 100644 index b29c1ae483..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/internal/RoomClosedInfo.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.openvidu.client.internal; - -/** - * @see Notification - * - * @author Radu Tom Vlad - */ -public class RoomClosedInfo extends Notification { - - private String room; - - public RoomClosedInfo(String room) { - super(ProtocolElements.ROOMCLOSED_METHOD); - this.room = room; - } - - public String getRoom() { - return room; - } - - public void setRoom(String room) { - this.room = room; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - if (getMethod() != null) { - builder.append("method=").append(getMethod()).append(", "); - } - if (room != null) { - builder.append("room=").append(room); - } - builder.append("]"); - return builder.toString(); - } -} diff --git a/openvidu-client/src/main/java/io/openvidu/client/internal/SendMessageInfo.java b/openvidu-client/src/main/java/io/openvidu/client/internal/SendMessageInfo.java deleted file mode 100644 index 21f3c651d1..0000000000 --- a/openvidu-client/src/main/java/io/openvidu/client/internal/SendMessageInfo.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.openvidu.client.internal; - -/** - * @see Notification - * - * @author Radu Tom Vlad - */ -public class SendMessageInfo extends Notification { - - private String room; - private String user; - private String message; - - public SendMessageInfo(String room, String user, String message) { - super(ProtocolElements.PARTICIPANTSENDMESSAGE_METHOD); - this.room = room; - this.user = user; - this.message = message; - } - - public String getRoom() { - return room; - } - - public void setRoom(String room) { - this.room = room; - } - - public String getUser() { - return user; - } - - public void setUser(String user) { - this.user = user; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - if (getMethod() != null) { - builder.append("method=").append(getMethod()).append(", "); - } - if (room != null) { - builder.append("room=").append(room).append(", "); - } - if (user != null) { - builder.append("user=").append(user).append(", "); - } - if (message != null) { - builder.append("message=").append(message); - } - builder.append("]"); - return builder.toString(); - } -} diff --git a/openvidu-client/src/test/java/io/openvidu/client/test/OpenViduClientTest.java b/openvidu-client/src/test/java/io/openvidu/client/test/OpenViduClientTest.java deleted file mode 100644 index 2bee120179..0000000000 --- a/openvidu-client/src/test/java/io/openvidu/client/test/OpenViduClientTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * (C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.openvidu.client.test; - -import static io.openvidu.client.internal.ProtocolElements.JOINROOM_METHOD; -import static io.openvidu.client.internal.ProtocolElements.JOINROOM_ROOM_PARAM; -import static io.openvidu.client.internal.ProtocolElements.JOINROOM_USER_PARAM; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.kurento.jsonrpc.client.JsonRpcClient; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; - -import io.openvidu.client.OpenViduClient; -import io.openvidu.client.ServerJsonRpcHandler; - -/** - * Unit tests for the room client protocol. - * - * @author Radu Tom Vlad (rvlad@naevatec.com) - * @since 6.3.1 - */ -public class OpenViduClientTest { - - private static OpenViduClient client; - private static ServerJsonRpcHandler serverHandler; - private static JsonRpcClient jsonRpcClient; - - @BeforeAll - public static void setup() { - jsonRpcClient = mock(JsonRpcClient.class); - serverHandler = new ServerJsonRpcHandler(); - client = new OpenViduClient(jsonRpcClient, serverHandler); - } - - @Test - public void testRoomJoin() throws IOException { - JsonObject params = new JsonObject(); - params.addProperty(JOINROOM_ROOM_PARAM, "room"); - params.addProperty(JOINROOM_USER_PARAM, "user"); - - JsonObject result = new JsonObject(); - JsonArray value = new JsonArray(); - result.add("value", value); - - Map> joinResult = new HashMap>(); - - when(jsonRpcClient.sendRequest(JOINROOM_METHOD, params)).thenReturn(result); - Assertions.assertEquals(client.joinRoom("room", "user"), joinResult); - } -} diff --git a/openvidu-server/.gitignore b/openvidu-server/.gitignore deleted file mode 100644 index 26a13b52b3..0000000000 --- a/openvidu-server/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/target/ -*.factorypath - -/src/main/resources/static/dashboard/ diff --git a/openvidu-server/LICENSE b/openvidu-server/LICENSE deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/openvidu-server/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/openvidu-server/NOTICE b/openvidu-server/NOTICE deleted file mode 100644 index 4be7fbe249..0000000000 --- a/openvidu-server/NOTICE +++ /dev/null @@ -1,13 +0,0 @@ -(C) Copyright 2017-2022 OpenVidu (https://openvidu.io) - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. \ No newline at end of file diff --git a/openvidu-server/README.md b/openvidu-server/README.md deleted file mode 100644 index ba4caa3a75..0000000000 --- a/openvidu-server/README.md +++ /dev/null @@ -1,18 +0,0 @@ -[![License badge](https://img.shields.io/badge/license-Apache2-orange.svg)](http://www.apache.org/licenses/LICENSE-2.0) -[![OpenVidu Tests](https://github.com/OpenVidu/openvidu/actions/workflows/openvidu-ce-test.yml/badge.svg)](https://github.com/OpenVidu/openvidu/actions/workflows/openvidu-ce-test.yml) -[![Documentation Status](https://readthedocs.org/projects/openvidu/badge/?version=stable)](https://docs.openvidu.io/en/stable/?badge=stable) -[![Docker badge](https://img.shields.io/docker/pulls/fiware/orion.svg)](https://hub.docker.com/r/openvidu/) -[![Support badge](https://img.shields.io/badge/support-sof-yellowgreen.svg)](https://openvidu.discourse.group/) - -[![][OpenViduLogo]](https://openvidu.io) - -openvidu-server -=== - -- **Description**: OpenVidu server side. It receives the remote procedure calls from openvidu-browser and manage all the media streams operations. You don't have to make direct use of it. Just to run it. - -- **Docs**: [REST API](https://docs.openvidu.io/en/stable/reference-docs/REST-API/) - -- **Release**: [OpenVidu Artifacts](https://docs.openvidu.io/en/stable/releases/) - -[OpenViduLogo]: https://secure.gravatar.com/avatar/5daba1d43042f2e4e85849733c8e5702?s=120 diff --git a/openvidu-server/deployments/ce/aws/CF-OpenVidu.yaml.template b/openvidu-server/deployments/ce/aws/CF-OpenVidu.yaml.template deleted file mode 100644 index 038104e8f0..0000000000 --- a/openvidu-server/deployments/ce/aws/CF-OpenVidu.yaml.template +++ /dev/null @@ -1,581 +0,0 @@ -AWSTemplateFormatVersion: 2010-09-09 -Description: OpenVidu Platform - -Parameters: - - # Domain and SSL certificate configuration - - WhichCert: - Description: > - [selfsigned] Self signed certificate. Not recommended for production use. - [owncert] Valid certificate purchased in a Internet services company. - [letsencrypt] Generate a new certificate using Let's Encrypt. - Type: String - AllowedValues: - - selfsigned - - owncert - - letsencrypt - Default: selfsigned - - PublicElasticIP: - Description: "Previously created AWS Elastic IP to associate it to the OpenVidu EC2 instance. If certificate type is 'selfsigned' this value is optional. If certificate type is 'owncert' or 'letsencrypt' this value is mandatory. Example 13.33.145.23." - Type: String - AllowedPattern: ^$|^([01]?\d{1,2}|2[0-4]\d|25[0-5])\.([01]?\d{1,2}|2[0-4]\d|25[0-5])\.([01]?\d{1,2}|2[0-4]\d|25[0-5])\.([01]?\d{1,2}|2[0-4]\d|25[0-5])$ - ConstraintDescription: The public Elastic IP does not have a valid IPv4 format - - MyDomainName: - Description: "Valid domain name pointing to previous IP. If certificate type is 'selfsigned' this value is optional. If certificate type is 'owncert' or 'letsencrypt' this value is mandatory. Example: openvidu.company.com" - Type: String - AllowedPattern: ^$|^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$ - ConstraintDescription: The domain name does not have a valid domain name format - - OwnCertCRT: - Description: "If certificate type is 'owncert' this is the URL where CRT file will be downloaded" - Type: String - - OwnCertKEY: - Description: "If certificate type is 'owncert' this is the URL where KEY file will be downloaded" - Type: String - - LetsEncryptEmail: - Description: "If certificate type is 'letsencrypt', this email will be used for Let's Encrypt notifications" - Type: String - - # OpenVidu configuration - - OpenViduSecret: - Description: "Secret to connect to this OpenVidu Platform. Cannot be empty and must contain only alphanumeric characters [a-zA-Z0-9], hypens ('-') and underscores ('_')" - Type: String - AllowedPattern: ^[a-zA-Z0-9_-]+$ - NoEcho: true - ConstraintDescription: "Cannot be empty and must contain only alphanumeric characters [a-zA-Z0-9], hypens ('-') and underscores ('_')" - - # EC2 Instance configuration - - InstanceType: - Description: "Specifies the EC2 instance type for your OpenVidu instance" - Type: String - Default: c5.xlarge - AllowedValues: - - t2.large - - t2.xlarge - - t2.2xlarge - - t3.large - - t3.xlarge - - t3.2xlarge - - m4.large - - m4.xlarge - - m4.2xlarge - - m4.4xlarge - - m4.10xlarge - - m4.16xlarge - - m5.large - - m5.xlarge - - m5.2xlarge - - m5.4xlarge - - m5.8xlarge - - m5.12xlarge - - m5.16xlarge - - m5.24xlarge - - c4.large - - c4.xlarge - - c4.2xlarge - - c4.4xlarge - - c4.8xlarge - - c5.large - - c5.xlarge - - c5.2xlarge - - c5.4xlarge - - c5.9xlarge - - c5.12xlarge - - c5.18xlarge - - c5.24xlarge - - c6a.large - - c6a.xlarge - - c6a.2xlarge - - c6a.4xlarge - - c6a.8xlarge - - c6a.12xlarge - - c6a.16xlarge - - c6a.24xlarge - - c6a.32xlarge - - c6a.48xlarge - - c6a.metal - ConstraintDescription: "Must be a valid EC2 instance type" - - KeyName: - Description: "Name of an existing EC2 KeyPair to enable SSH access to the instance. It is mandatory to perform some administrative tasks of OpenVidu." - Type: 'AWS::EC2::KeyPair::KeyName' - ConstraintDescription: "must be the name of an existing EC2 KeyPair" - - # Other configuration - - WantToDeployDemos: - Description: "Choose if you want to deploy OpenVidu Call application alongside OpenVidu platform." - Type: String - AllowedValues: - - true - - false - Default: true - - WantToSendInfo: - Description: "Choose if you want to send to OpenVidu team the version deployed and AWS region." - Type: String - AllowedValues: - - true - - false - Default: true - -#start_mappings -Mappings: - OVAMIMAP: - eu-west-1: - AMI: OV_AMI_ID -#end_mappings - -Metadata: - 'AWS::CloudFormation::Interface': - ParameterGroups: - - Label: - default: Domain and SSL certificate configuration - Parameters: - - WhichCert - - PublicElasticIP - - MyDomainName - - OwnCertCRT - - OwnCertKEY - - LetsEncryptEmail - - Label: - default: OpenVidu configuration - Parameters: - - OpenViduSecret - - Label: - default: EC2 Instance configuration - Parameters: - - InstanceType - - KeyName - - Label: - default: Other configuration - Parameters: - - WantToDeployDemos - - WantToSendInfo - - ParameterLabels: - # SSL certificate configuration - WhichCert: - default: "Certificate Type" - PublicElasticIP: - default: "AWS Elastic IP (EIP)" - MyDomainName: - default: "Domain Name pointing to Elastic IP" - OwnCertCRT: - default: "URL to the CRT file (owncert)" - OwnCertKEY: - default: "URL to the key file (owncert)" - LetsEncryptEmail: - default: "Email for Let's Encrypt (letsencrypt)" - # OpenVidu configuration - OpenViduSecret: - default: "Openvidu Secret" - # EC2 Instance configuration - InstanceType: - default: "Instance type" - KeyName: - default: "SSH Key" - # Other configuration - WantToDeployDemos: - default: "Deploy OpenVidu Call application" - WantToSendInfo: - default: "Send deployment info to OpenVidu team" - -Conditions: - WhichCertPresent: !Not [ !Equals [!Ref WhichCert, ""] ] - PublicElasticIPPresent: !Not [ !Equals [!Ref PublicElasticIP, ""] ] - -Resources: - - LaunchTemplate: - Type: AWS::EC2::LaunchTemplate - Properties: - LaunchTemplateName: IMDSV2 - LaunchTemplateData: - MetadataOptions: - HttpEndpoint: enabled - HttpPutResponseHopLimit: 1 - HttpTokens: required - - OpenviduServer: - Type: 'AWS::EC2::Instance' - Metadata: - Comment: 'Install and configure OpenVidu Server and Demos' - AWS::CloudFormation::Init: - config: - files: - '/usr/local/bin/ping.sh': - content: | - #!/bin/bash - - INXDB_URL=193.147.51.51 - INXDB_DB=ov_server - INXDB_MEASUREMENT=server - - OV_VERSION=OPENVIDU_VERSION - TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") - EC2_AVAIL_ZONE=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/availability-zone) - EC2_REGION=$(echo "$EC2_AVAIL_ZONE" | sed 's/[a-z]$//') - - curl -i -XPOST "http://$INXDB_URL:8086/write?db=$INXDB_DB" \ - --data-binary "$INXDB_MEASUREMENT,region=$EC2_REGION ov_version=\"$OV_VERSION\" " - mode: "000755" - owner: "root" - group: "root" - '/usr/local/bin/check_app_ready.sh': - content: | - #!/bin/bash - while true; do - HTTP_STATUS=$(curl -Ik http://localhost:5443 | head -n1 | awk '{print $2}') - if [ $HTTP_STATUS == 200 ]; then - break - fi - sleep 5 - done - mode: "000755" - owner: "root" - group: "root" - '/usr/local/bin/feedGroupVars.sh': - content: !Sub | - #!/bin/bash -x - WORKINGDIR=/opt/openvidu - - # Replace secret - sed -i "s/OPENVIDU_SECRET=/OPENVIDU_SECRET=${OpenViduSecret}/" $WORKINGDIR/.env - - # Replace domain name - if [[ "${MyDomainName}" != '' && "${PublicElasticIP}" != '' ]]; then - sed -i "s/DOMAIN_OR_PUBLIC_IP=/DOMAIN_OR_PUBLIC_IP=${MyDomainName}/" $WORKINGDIR/.env - elif [[ "${MyDomainName}" == '' && "${PublicElasticIP}" != '' ]]; then - sed -i "s/DOMAIN_OR_PUBLIC_IP=/DOMAIN_OR_PUBLIC_IP=${PublicElasticIP}/" $WORKINGDIR/.env - else - [ ! -d "/usr/share/openvidu" ] && mkdir -p /usr/share/openvidu - TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") - PublicHostname=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-hostname) - sed -i "s/DOMAIN_OR_PUBLIC_IP=/DOMAIN_OR_PUBLIC_IP=$PublicHostname/" $WORKINGDIR/.env - echo $PublicHostname > /usr/share/openvidu/old-host-name - fi - - # Replace certificated type - sed -i "s/CERTIFICATE_TYPE=selfsigned/CERTIFICATE_TYPE=${WhichCert}/" $WORKINGDIR/.env - sed -i "s/LETSENCRYPT_EMAIL=user@example.com/LETSENCRYPT_EMAIL=${LetsEncryptEmail}/" $WORKINGDIR/.env - - # Without Application - if [ "${WantToDeployDemos}" == "false" ]; then - sed -i "s/WITH_APP=true/WITH_APP=false/" $WORKINGDIR/docker-compose.yml - rm $WORKINGDIR/docker-compose.override.yml - fi - mode: "000755" - owner: "root" - group: "root" - '/usr/local/bin/buildCerts.sh': - content: !Sub | - #!/bin/bash -x - WORKINGDIR=/opt/openvidu - wget --no-check-certificate -O $WORKINGDIR/owncert/certificate.cert ${OwnCertCRT} - wget --no-check-certificate -O $WORKINGDIR/owncert/certificate.key ${OwnCertKEY} - mode: "000755" - owner: "root" - group: "root" - '/usr/local/bin/restartCE.sh': - content: !Sub | - #!/bin/bash -x - WORKINGDIR=/opt/openvidu - - # Get new amazon URL - OldPublicHostname=$(cat /usr/share/openvidu/old-host-name) - TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") - PublicHostname=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-hostname) - sed -i "s/$OldPublicHostname/$PublicHostname/" $WORKINGDIR/.env - echo $PublicHostname > /usr/share/openvidu/old-host-name - - # Restart all services - pushd "$WORKINGDIR" - ./openvidu restart >/dev/null 2>&1 & - popd - mode: "000755" - owner: "root" - group: "root" - Properties: - ImageId: !GetAtt CloudformationLambdaInvoke.ImageId - LaunchTemplate: - LaunchTemplateName: IMDSV2 - Version: 1 - InstanceType: !Ref InstanceType - SecurityGroups: - - !Ref WebServerSecurityGroup - KeyName: !Ref KeyName - Tags: - - Key: Name - Value: !Ref 'AWS::StackName' - UserData: - Fn::Base64: !Sub | - #!/bin/bash -x - set -eu -o pipefail - - cfn-init --region ${AWS::Region} --stack ${AWS::StackId} --resource OpenviduServer - - export HOME="/root" - - # Replace .env variables - /usr/local/bin/feedGroupVars.sh || { echo "[OpenVidu] Parameters incorrect/insufficient"; exit 1; } - - # Launch on reboot - echo "@reboot /usr/local/bin/restartCE.sh" | crontab - - # Download certs if "WichCert" mode - if [ "${WhichCert}" == "owncert" ]; then - /usr/local/bin/buildCerts.sh || { echo "[OpenVidu] error with the certificate files"; exit 1; } - fi - - # Start openvidu application - pushd /opt/openvidu - ./openvidu start >/dev/null 2>&1 & - popd - - # Send info to openvidu - if [ "${WantToSendInfo}" == "true" ]; then - /usr/local/bin/ping.sh || true - fi - rm /usr/local/bin/ping.sh - - # Wait for the app - /usr/local/bin/check_app_ready.sh - - # sending the finish call - /usr/local/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource WaitCondition --region ${AWS::Region} - - BlockDeviceMappings: - - DeviceName: /dev/sda1 - Ebs: - VolumeType: gp2 - DeleteOnTermination: true - VolumeSize: 200 - - MyEIP: - Type: 'AWS::EC2::EIPAssociation' - Condition: PublicElasticIPPresent - Properties: - InstanceId: !Ref OpenviduServer - EIP: !Ref PublicElasticIP - - WaitCondition: - Type: 'AWS::CloudFormation::WaitCondition' - CreationPolicy: - ResourceSignal: - Timeout: PT30M - Count: '1' - - WebServerSecurityGroup: - Type: 'AWS::EC2::SecurityGroup' - Properties: - GroupDescription: SSH, Proxy and OpenVidu WebRTC Ports - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: 22 - ToPort: 22 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 22 - ToPort: 22 - CidrIpv6: ::/0 - - IpProtocol: tcp - FromPort: 80 - ToPort: 80 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 80 - ToPort: 80 - CidrIpv6: ::/0 - - IpProtocol: tcp - FromPort: 443 - ToPort: 443 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 443 - ToPort: 443 - CidrIpv6: ::/0 - - IpProtocol: tcp - FromPort: 3478 - ToPort: 3478 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 3478 - ToPort: 3478 - CidrIpv6: ::/0 - - IpProtocol: udp - FromPort: 3478 - ToPort: 3478 - CidrIp: 0.0.0.0/0 - - IpProtocol: udp - FromPort: 3478 - ToPort: 3478 - CidrIpv6: ::/0 - - IpProtocol: udp - FromPort: 40000 - ToPort: 57000 - CidrIp: 0.0.0.0/0 - - IpProtocol: udp - FromPort: 40000 - ToPort: 57000 - CidrIpv6: ::/0 - - IpProtocol: tcp - FromPort: 40000 - ToPort: 57000 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 40000 - ToPort: 57000 - CidrIpv6: ::/0 - - ########## - # Lambda to Copy original AMI to the deployment region - ########## - CloudformationLambdaRole: - Type: 'AWS::IAM::Role' - DeletionPolicy: Delete - Properties: - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - Service: - - lambda.amazonaws.com - Action: - - 'sts:AssumeRole' - Path: / - Policies: - - PolicyName: !Join ['', [ !Ref AWS::StackName, '-cf-lambda-policy'] ] - PolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Action: - - 'ec2:DescribeImages' - - 'ec2:CopyImage' - Resource: '*' - RoleName: !Join ['', [ !Ref AWS::StackName, '-cf-lambda-role'] ] - - CloudformationLambda: - Type: AWS::Lambda::Function - DeletionPolicy: Delete - Properties: - FunctionName: !Join ['', [ !Ref AWS::StackName, '-cf-lambda'] ] - Code: - ZipFile: | - import boto3 - import cfnresponse - from botocore.config import Config - - def handler(event, context): - try: - if (event['RequestType'] == 'Create'): - copy_ami(event, context) - return - else: - cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) - except Exception: - cfnresponse.send(event, context, cfnresponse.FAILED, {}) - - def copy_ami(event, context): - new_images=[] - cfn_output = {} - source_image_id = event['ResourceProperties']['AmiSourceId'] - source_region = event['ResourceProperties']['AmiSourceRegion'] - deployment_region = event['ResourceProperties']['DeploymentRegion'] - - # Clients init - ec2_client = boto3.client('ec2', config = Config(region_name=deployment_region)) - ec2_client_ov = boto3.client('ec2', config = Config(region_name=source_region)) - img_exists_waiter= ec2_client.get_waiter('image_exists') - img_avail_waiter = ec2_client.get_waiter('image_available') - - # Get original ami name - public_ami_filter = [{ 'Name': 'image-id', 'Values': [ source_image_id ] }] - - response = ec2_client_ov.describe_images(Filters=public_ami_filter) - new_ami_name= "[ OpenVidu CE AMI Copy ] - " + response['Images'][0]['Name'] - - own_ami_filter = [{ 'Name': 'name', 'Values': [new_ami_name] }] - response = ec2_client.describe_images(Filters=own_ami_filter) - if (len(response['Images']) == 1): - # If AMI exists, don't copy - new_images.append(response['Images'][0]['ImageId']) - cfn_output['ImageId'] = response['Images'][0]['ImageId'] - else: - # If AMI does not exist, copy - response = ec2_client.copy_image( - SourceImageId=source_image_id, - SourceRegion=source_region, - Name=new_ami_name - ) - new_images.append(response['ImageId']) - cfn_output['ImageId'] = response['ImageId'] - - # Wait images to be available - waiter_config = {'Delay': 15, 'MaxAttempts': 59 - } - # Wait image to exist - response = img_exists_waiter.wait(ImageIds=new_images, WaiterConfig=waiter_config - ) - # Wait image to be available - response = img_avail_waiter.wait(ImageIds=new_images, WaiterConfig=waiter_config) - - # Return AMI - cfnresponse.send(event, context, cfnresponse.SUCCESS, cfn_output) - - Handler: index.handler - Role: - !GetAtt CloudformationLambdaRole.Arn - Runtime: python3.11 - Timeout: 900 - - CloudformationLambdaInvoke: - Type: AWS::CloudFormation::CustomResource - DeletionPolicy: Delete - Version: "1.0" - Properties: - ServiceToken: !GetAtt CloudformationLambda.Arn - AmiSourceRegion: 'eu-west-1' - AmiSourceId: !FindInMap [OVAMIMAP, 'eu-west-1', AMI] - DeploymentRegion: !Ref AWS::Region - -Outputs: - OpenViduServerURL: - Description: Use this URL to connect OpenVidu Server - Value: !Join - - '' - - - 'https://' - - !GetAtt - - OpenviduServer - - PublicDnsName - OpenViduServerURLLE: - Description: Use this URL to connect OpenVidu Server - Value: !Join - - '' - - - 'https://' - - !Ref MyDomainName - Condition: WhichCertPresent - OpenViduCallURL: - Description: If you choose to deploy OpenVidu Call application, use this URL - Value: !Join - - '' - - - 'https://' - - !GetAtt - - OpenviduServer - - PublicDnsName - OpenViduCallURLLE: - Description: If you choose to deploy OpenVidu Call application, use this URL - Value: !Join - - '' - - - 'https://' - - !Ref MyDomainName - Condition: WhichCertPresent diff --git a/openvidu-server/deployments/ce/aws/cfn-mkt-ov-ce-ami.yaml.template b/openvidu-server/deployments/ce/aws/cfn-mkt-ov-ce-ami.yaml.template deleted file mode 100644 index 926fc9e271..0000000000 --- a/openvidu-server/deployments/ce/aws/cfn-mkt-ov-ce-ami.yaml.template +++ /dev/null @@ -1,199 +0,0 @@ ---- -AWSTemplateFormatVersion: 2010-09-09 -Description: Openvidu Server CE CloudFormation AMI template. - -Mappings: - AMIMAP: - eu-west-1: - AMI: AMIEUWEST1 - us-east-1: - AMI: AMIUSEAST1 - -Resources: - OpenviduServerCE: - Type: 'AWS::EC2::Instance' - Metadata: - Comment: "Install OpenVidu Server CE" - AWS::CloudFormation::Init: - config: - files: - "/etc/cfn/cfn-hup.conf": - content: !Sub | - [main] - stack=${AWS::StackId} - region=${AWS::Region} - mode: "000400" - owner: "root" - group: "root" - "/etc/cfn/hooks.d/cfn-auto-reloader.conf": - content: !Sub | - [cfn-auto-reloader-hook] - triggers=post.update - path=Resources.OpenviduServerCE.Metadata.AWS::CloudFormation::Init - action=/usr/local/bin/cfn-init -v --stack ${AWS::StackName} --resource OpenviduServerCE --region ${AWS::Region} - mode: "000400" - owner: "root" - group: "root" - "/usr/local/bin/installDockerAndDockerCompose.sh": - content: | - #!/bin/bash - set -eu -o pipefail - - # Install Docker - apt-get update && apt-get install -y \ - apt-transport-https \ - ca-certificates \ - curl \ - gnupg-agent \ - software-properties-common - - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg - echo \ - "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ - $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - - apt-get update && apt-get install -y \ - docker-ce \ - docker-ce-cli \ - containerd.io - - # Install docker-compose v2 - LATEST_DOCKER_COMPOSE_VERSION=$(curl -sSL https://api.github.com/repos/docker/compose/tags | grep name | head -n1 | cut -d'"' -f4) - - OS="$(uname -s | awk '{print tolower($0)}')" - ARCH="$(uname -m)" - - mkdir -p /usr/local/lib/docker/cli-plugins - rm -f /usr/local/lib/docker/cli-plugins/docker-compose - curl -SL "https://github.com/docker/compose/releases/download/${LATEST_DOCKER_COMPOSE_VERSION}/docker-compose-${OS}-${ARCH}" \ - -o /usr/local/lib/docker/cli-plugins/docker-compose - chmod +x /usr/local/lib/docker/cli-plugins/docker-compose - ln -s /usr/local/lib/docker/cli-plugins/docker-compose /usr/local/bin - - mode: "000755" - owner: "root" - group: "root" - "/usr/local/bin/installOpenviduCE.sh": - content: | - #!/bin/bash - set -eu -o pipefail - - # Install openvidu-ce - cd /opt - curl https://s3-eu-west-1.amazonaws.com/aws.openvidu.io/install_openvidu_OPENVIDU_VERSION.sh | bash - - if [[ USE_MASTER_DOCKER_IMAGES == "true" ]]; then - pushd openvidu - # docker-compose.yml replace with master version - IMAGES="$(cat docker-compose.yml | grep 'image: openvidu/' | cut -d':' -f2 | sed -e 's/^[[:space:]]*//')" - for IMG in $IMAGES - do - sed -i "s|$IMG.*|$IMG:master|g" docker-compose.yml - done - - # docker-compose.override.yml replace with master version - IMAGES="$(cat docker-compose.override.yml | grep 'image: openvidu/' | cut -d':' -f2 | sed -e 's/^[[:space:]]*//')" - for IMG in $IMAGES - do - sed -i "s|$IMG.*|$IMG:master|g" docker-compose.override.yml - done - popd - - # openvidu-recording replace with master version - echo "OPENVIDU_RECORDING_VERSION=OPENVIDU_RECORDING_DOCKER_TAG" >> /opt/openvidu/.env - fi - - # Define Installation Type - sed -i "s/Installation Mode: On Premises/Installation Mode: Cloud Formation/" /opt/openvidu/docker-compose.yml - - # Configure crash report - mkdir -p /opt/openvidu/kms-crashes - sed -i "s/enabled=1/enabled=0/" /etc/default/apport - echo "kernel.core_pattern=/opt/openvidu/kms-crashes/core_%e_%p_%u_%t" >> /etc/sysctl.conf - sysctl --system - mode: "000755" - owner: "root" - group: "root" - "/usr/local/bin/getDockerImages.sh": - content: !Sub | - #!/bin/bash - set -eu -o pipefail - - # Openvidu recording - docker pull openvidu/openvidu-recording:OPENVIDU_RECORDING_DOCKER_TAG - - # OpenVidu CE images - cd /opt/openvidu - docker-compose pull - mode: "000755" - owner: "root" - group: "root" - "/usr/local/bin/testRecording.sh": - content: | - #!/bin/bash -x - TEST_RECORDING_DIR="/opt/openvidu/test-recording" - - docker run -d --rm --name=test-recording -e URL=https://openvidu.io/ -v "${TEST_RECORDING_DIR}":/recordings openvidu/openvidu-recording:OPENVIDU_RECORDING_DOCKER_TAG - - # Wait to file to be created - TIMEOUT_WAIT_FILE=30 - ELAPSED=0 - while [[ ! -f "${TEST_RECORDING_DIR}/video/video.mp4" ]] && [[ "${ELAPSED}" -lt "${TIMEOUT_WAIT_FILE}" ]]; do - sleep 1; - ELAPSED=$((ELAPSED+1)) - done - - # Sleep 30 seconds - sleep 30 - - # Clean test recording - docker rm -f test-recording - rm -rf "${TEST_RECORDING_DIR}" - mode: "000755" - owner: "root" - group: "root" - Properties: - ImageId: !FindInMap [AMIMAP, !Ref 'AWS::Region', AMI] - InstanceType: "t2.2xlarge" - Tags: - - Key: Name - Value: !Ref AWS::StackName - KeyName: AWS_KEY_NAME - UserData: - "Fn::Base64": - !Sub | - #!/bin/bash -x - set -eu -o pipefail - apt-get update && apt-get install -y \ - python3-pip \ - ec2-instance-connect - pip3 install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz - - cfn-init --region ${AWS::Region} --stack ${AWS::StackId} --resource OpenviduServerCE - - /usr/local/bin/installDockerAndDockerCompose.sh || { echo "[OpenVidu] error installing docker and compose"; exit 1; } - - /usr/local/bin/installOpenviduCE.sh || { echo "[OpenVidu] error installing OpenVidu CE"; exit 1; } - - /usr/local/bin/getDockerImages.sh || { echo "[OpenVidu] error getting docker images"; exit 1; } - - echo "@reboot /usr/local/bin/testRecording.sh >> /var/log/testRecording.log 2>&1" | crontab - - # sending the finish call - /usr/local/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource WaitCondition --region ${AWS::Region} - - # Cleaning the house - shred -u /var/log/cloud-init-output.log - shred -u /etc/ssh/*_key /etc/ssh/*_key.pub - shred -u /usr/local/bin/installDockerAndDockerCompose.sh - shred -u /usr/local/bin/installOpenviduCE.sh - shred -u /usr/local/bin/getDockerImages.sh - find /var/lib/cloud/instances/$(curl http://169.254.169.254/latest/meta-data/instance-id) -type f | xargs shred -u - rm -rf /var/lib/cloud/instances/$(curl http://169.254.169.254/latest/meta-data/instance-id) - - WaitCondition: - Type: AWS::CloudFormation::WaitCondition - CreationPolicy: - ResourceSignal: - Timeout: PT20M - Count: 1 diff --git a/openvidu-server/deployments/ce/aws/createAMI.sh b/openvidu-server/deployments/ce/aws/createAMI.sh deleted file mode 100755 index 24124a3649..0000000000 --- a/openvidu-server/deployments/ce/aws/createAMI.sh +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/bash -x -set -eu -o pipefail - -CF_RELEASE=${CF_RELEASE:-false} -AWS_KEY_NAME=${AWS_KEY_NAME:-} - -if [[ $CF_RELEASE == "true" ]]; then - git checkout v$OPENVIDU_VERSION -fi - -export AWS_DEFAULT_REGION=eu-west-1 - -DATESTAMP=$(date +%s) -TEMPJSON=$(mktemp -t cloudformation-XXX --suffix .json) - -# Get Latest Ubuntu AMI id from specified region -getUbuntuAmiId() { - local AMI_ID=$( - aws --region ${1} ec2 describe-images \ - --filters "Name=name,Values=*ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*" \ - "Name=owner-alias,Values=amazon" \ - --query "sort_by(Images, &CreationDate)" | - jq -r '.[-1].ImageId' - ) - echo $AMI_ID -} - -AMIEUWEST1=$(getUbuntuAmiId 'eu-west-1') -AMIUSEAST1=$(getUbuntuAmiId 'us-east-1') - -# Copy templates to feed -cp cfn-mkt-ov-ce-ami.yaml.template cfn-mkt-ov-ce-ami.yaml - -## Setting Openvidu Version and Ubuntu Latest AMIs -if [[ ! -z ${AWS_KEY_NAME} ]]; then - sed -i "s/ KeyName: AWS_KEY_NAME/ KeyName: ${AWS_KEY_NAME}/g" cfn-mkt-ov-ce-ami.yaml -else - sed -i '/ KeyName: AWS_KEY_NAME/d' cfn-mkt-ov-ce-ami.yaml -fi -sed -i "s/AWS_KEY_NAME/${AWS_KEY_NAME}/g" cfn-mkt-ov-ce-ami.yaml -sed -i "s/USE_MASTER_DOCKER_IMAGES/${USE_MASTER_DOCKER_IMAGES}/g" cfn-mkt-ov-ce-ami.yaml -sed -i "s/OPENVIDU_VERSION/${OPENVIDU_VERSION}/g" cfn-mkt-ov-ce-ami.yaml -sed -i "s/OPENVIDU_RECORDING_DOCKER_TAG/${OPENVIDU_RECORDING_DOCKER_TAG}/g" cfn-mkt-ov-ce-ami.yaml -sed -i "s/AMIEUWEST1/${AMIEUWEST1}/g" cfn-mkt-ov-ce-ami.yaml -sed -i "s/AMIUSEAST1/${AMIUSEAST1}/g" cfn-mkt-ov-ce-ami.yaml - -## OpenVidu AMI - -# Copy template to S3 -aws s3 cp cfn-mkt-ov-ce-ami.yaml s3://aws.openvidu.io -TEMPLATE_URL=https://s3-eu-west-1.amazonaws.com/aws.openvidu.io/cfn-mkt-ov-ce-ami.yaml - -# Update installation script -if [[ ${UPDATE_S3_FILES} == "true" ]]; then - # Avoid overriding existing versions - # Only master and non existing versions can be overriden - if [[ ${OPENVIDU_VERSION} != "master" ]]; then - INSTALL_SCRIPT_EXISTS=true - aws s3api head-object --bucket aws.openvidu.io --key install_openvidu_$OPENVIDU_VERSION.sh || INSTALL_SCRIPT_EXISTS=false - if [[ ${INSTALL_SCRIPT_EXISTS} == "true" ]]; then - echo "Aborting updating s3://aws.openvidu.io/install_openvidu_${OPENVIDU_VERSION}.sh. File actually exists." - exit 1 - fi - fi - aws s3 cp ../docker-compose/install_openvidu.sh s3://aws.openvidu.io/install_openvidu_$OPENVIDU_VERSION.sh --acl public-read -fi - -aws cloudformation create-stack \ - --stack-name openvidu-ce-${DATESTAMP} \ - --template-url ${TEMPLATE_URL} - # --disable-rollback - -aws cloudformation wait stack-create-complete --stack-name openvidu-ce-${DATESTAMP} - -echo "Getting instance ID" -INSTANCE_ID=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=openvidu-ce-${DATESTAMP}" | jq -r ' .Reservations[] | .Instances[] | .InstanceId') - -echo "Stopping the instance" -aws ec2 stop-instances --instance-ids ${INSTANCE_ID} - -echo "wait for the instance to stop" -aws ec2 wait instance-stopped --instance-ids ${INSTANCE_ID} - -echo "Creating AMI" -OV_RAW_AMI_ID=$(aws ec2 create-image --instance-id ${INSTANCE_ID} --name OpenViduServerCE-${OPENVIDU_VERSION}-${DATESTAMP} --description "Openvidu Server CE" --output text) - -echo "Cleaning up" -aws cloudformation delete-stack --stack-name openvidu-ce-${DATESTAMP} - -# Wait for the instance -# Unfortunately, aws cli does not have a way to increase timeout -WAIT_RETRIES=0 -WAIT_MAX_RETRIES=5 -until [ "${WAIT_RETRIES}" -ge "${WAIT_MAX_RETRIES}" ]; do - aws ec2 wait image-available --image-ids ${OV_RAW_AMI_ID} && break - WAIT_RETRIES=$((WAIT_RETRIES + 1)) - sleep 5 -done - -if [[ $CF_RELEASE == "true" ]]; then - aws ec2 modify-image-attribute --image-id ${OV_RAW_AMI_ID} --launch-permission "Add=[{Group=all}]" - aws ec2 describe-images --image-ids ${OV_RAW_AMI_ID} | jq -r '.Images[0].BlockDeviceMappings[0].Ebs.SnapshotId' - SNAPSHOT_ID=$(aws ec2 describe-images --image-ids ${OV_RAW_AMI_ID} | jq -r '.Images[0].BlockDeviceMappings[0].Ebs.SnapshotId') - aws ec2 modify-snapshot-attribute --snapshot-id ${SNAPSHOT_ID} --create-volume-permission "Add=[{Group=all}]" -fi - -# Updating the template -sed "s/OV_AMI_ID/${OV_RAW_AMI_ID}/" CF-OpenVidu.yaml.template >CF-OpenVidu-${OPENVIDU_VERSION}.yaml -sed -i "s/OPENVIDU_VERSION/${OPENVIDU_VERSION}/g" CF-OpenVidu-${OPENVIDU_VERSION}.yaml - -# Update CF template -if [[ ${UPDATE_S3_FILES} == "true" ]]; then - # Avoid overriding existing versions - # Only master and non existing versions can be overriden - if [[ ${OPENVIDU_VERSION} != "master" ]]; then - CF_EXIST=true - aws s3api head-object --bucket aws.openvidu.io --key CF-OpenVidu-${OPENVIDU_VERSION}.yaml || CF_EXIST=false - if [[ ${CF_EXIST} == "true" ]]; then - echo "Aborting updating s3://aws.openvidu.io/CF-OpenVidu-${OPENVIDU_VERSION}.yaml. File actually exists." - exit 1 - fi - fi - aws s3 cp CF-OpenVidu-${OPENVIDU_VERSION}.yaml s3://aws.openvidu.io/CF-OpenVidu-${OPENVIDU_VERSION}.yaml --acl public-read -fi - -rm $TEMPJSON -rm cfn-mkt-ov-ce-ami.yaml -aws s3api delete-object --bucket aws.openvidu.io --key cfn-mkt-ov-ce-ami.yaml diff --git a/openvidu-server/deployments/ce/docker-compose/.env b/openvidu-server/deployments/ce/docker-compose/.env deleted file mode 100644 index 6544bdd85a..0000000000 --- a/openvidu-server/deployments/ce/docker-compose/.env +++ /dev/null @@ -1,200 +0,0 @@ -# OpenVidu configuration -# ---------------------- -# Documentation: https://docs.openvidu.io/en/stable/reference-docs/openvidu-config/ - -# NOTE: This file doesn't need to quote assignment values, like most shells do. -# All values are stored as-is, even if they contain spaces, so don't quote them. - -# Domain name. If you do not have one, the public IP of the machine. -# For example: 198.51.100.1, or openvidu.example.com -DOMAIN_OR_PUBLIC_IP= - -# OpenVidu SECRET used for apps to connect to OpenVidu server and users to access to OpenVidu Dashboard -OPENVIDU_SECRET= - -# Certificate type: -# - selfsigned: Self signed certificate. Not recommended for production use. -# Users will see an ERROR when connected to web page. -# - owncert: Valid certificate purchased in a Internet services company. -# Please put the certificates files inside folder ./owncert -# with names certificate.key and certificate.cert -# - letsencrypt: Generate a new certificate using letsencrypt. Please set the -# required contact email for Let's Encrypt in LETSENCRYPT_EMAIL -# variable. -CERTIFICATE_TYPE=selfsigned - -# If CERTIFICATE_TYPE=letsencrypt, you need to configure a valid email for notifications -LETSENCRYPT_EMAIL=user@example.com - -# Proxy configuration -# If you want to change the ports on which openvidu listens, uncomment the following lines - -# Allows any request to http://DOMAIN_OR_PUBLIC_IP:HTTP_PORT/ to be automatically -# redirected to https://DOMAIN_OR_PUBLIC_IP:HTTPS_PORT/. -# WARNING: the default port 80 cannot be changed during the first boot -# if you have chosen to deploy with the option CERTIFICATE_TYPE=letsencrypt -# HTTP_PORT=80 - -# Changes the port of all services exposed by OpenVidu. -# SDKs, REST clients and browsers will have to connect to this port -# HTTPS_PORT=443 - -# Old paths are considered now deprecated, but still supported by default. -# OpenVidu Server will log a WARN message every time a deprecated path is called, indicating -# the new path that should be used instead. You can set property SUPPORT_DEPRECATED_API=false -# to stop allowing the use of old paths. -# Default value is true -# SUPPORT_DEPRECATED_API=false - -# If true request to with www will be redirected to non-www requests -# Default value is false -# REDIRECT_WWW=false - -# How many workers to configure in nginx proxy. -# The more workers, the more requests will be handled -# Default value is 10240 -# WORKER_CONNECTIONS=10240 - -# Access restrictions -# In this section you will be able to restrict the IPs from which you can access to -# Openvidu API and the Administration Panel -# WARNING! If you touch this configuration you can lose access to the platform from some IPs. -# Use it carefully. - -# This section limits access to the /dashboard (OpenVidu CE) and /inspector (OpenVidu Pro) pages. -# The form for a single IP or an IP range is: -# ALLOWED_ACCESS_TO_DASHBOARD=198.51.100.1 and ALLOWED_ACCESS_TO_DASHBOARD=198.51.100.0/24 -# To limit multiple IPs or IP ranges, separate by commas like this: -# ALLOWED_ACCESS_TO_DASHBOARD=198.51.100.1, 198.51.100.0/24 -# ALLOWED_ACCESS_TO_DASHBOARD= - -# This section limits access to the Openvidu REST API. -# The form for a single IP or an IP range is: -# ALLOWED_ACCESS_TO_RESTAPI=198.51.100.1 and ALLOWED_ACCESS_TO_RESTAPI=198.51.100.0/24 -# To limit multiple IPs or or IP ranges, separate by commas like this: -# ALLOWED_ACCESS_TO_RESTAPI=198.51.100.1, 198.51.100.0/24 -# ALLOWED_ACCESS_TO_RESTAPI= - -# Whether to enable recording module or not -OPENVIDU_RECORDING=false - -# Use recording module with debug mode. -OPENVIDU_RECORDING_DEBUG=false - -# Openvidu Folder Record used for save the openvidu recording videos. Change it -# with the folder you want to use from your host. -OPENVIDU_RECORDING_PATH=/opt/openvidu/recordings - -# System path where OpenVidu Server should look for custom recording layouts -OPENVIDU_RECORDING_CUSTOM_LAYOUT=/opt/openvidu/custom-layout - -# if true any client can connect to -# https://OPENVIDU_SERVER_IP:OPENVIDU_PORT/recordings/any_session_file.mp4 -# and access any recorded video file. If false this path will be secured with -# OPENVIDU_SECRET param just as OpenVidu Server dashboard at -# https://OPENVIDU_SERVER_IP:OPENVIDU_PORT -# Values: true | false -OPENVIDU_RECORDING_PUBLIC_ACCESS=false - -# Which users should receive the recording events in the client side -# (recordingStarted, recordingStopped). Can be all (every user connected to -# the session), publisher_moderator (users with role 'PUBLISHER' or -# 'MODERATOR'), moderator (only users with role 'MODERATOR') or none -# (no user will receive these events) -OPENVIDU_RECORDING_NOTIFICATION=publisher_moderator - -# Timeout in seconds for recordings to automatically stop (and the session involved to be closed) -# when conditions are met: a session recording is started but no user is publishing to it or a session -# is being recorded and last user disconnects. If a user publishes within the timeout in either case, -# the automatic stop of the recording is cancelled -# 0 means no timeout -OPENVIDU_RECORDING_AUTOSTOP_TIMEOUT=120 - -# Maximum video bandwidth sent from clients to OpenVidu Server, in kbps. -# 0 means unconstrained -OPENVIDU_STREAMS_VIDEO_MAX_RECV_BANDWIDTH=1000 - -# Minimum video bandwidth sent from clients to OpenVidu Server, in kbps. -# 0 means unconstrained -OPENVIDU_STREAMS_VIDEO_MIN_RECV_BANDWIDTH=300 - -# Maximum video bandwidth sent from OpenVidu Server to clients, in kbps. -# 0 means unconstrained -OPENVIDU_STREAMS_VIDEO_MAX_SEND_BANDWIDTH=1000 - -# Minimum video bandwidth sent from OpenVidu Server to clients, in kbps. -# 0 means unconstrained -OPENVIDU_STREAMS_VIDEO_MIN_SEND_BANDWIDTH=300 - -# All sessions of OpenVidu will try to force this codec. If OPENVIDU_STREAMS_ALLOW_TRANSCODING=true -# when a codec can not be forced, transcoding will be allowed -# Values: MEDIA_SERVER_PREFERRED, NONE, VP8, VP9, H264 -# Default value is MEDIA_SERVER_PREFERRED -# OPENVIDU_STREAMS_FORCED_VIDEO_CODEC=MEDIA_SERVER_PREFERRED - -# Allow transcoding if codec specified in OPENVIDU_STREAMS_FORCED_VIDEO_CODEC can not be applied -# Values: true | false -# Default value is false -# OPENVIDU_STREAMS_ALLOW_TRANSCODING=false - -# true to enable OpenVidu Webhook service. false' otherwise -# Values: true | false -OPENVIDU_WEBHOOK=false - -# HTTP endpoint where OpenVidu Server will send Webhook HTTP POST messages -# Must be a valid URL: http(s)://ENDPOINT -#OPENVIDU_WEBHOOK_ENDPOINT= - -# List of headers that OpenVidu Webhook service will attach to HTTP POST messages -#OPENVIDU_WEBHOOK_HEADERS= - -# List of events that will be sent by OpenVidu Webhook service -# Default value is all available events -OPENVIDU_WEBHOOK_EVENTS=[sessionCreated,sessionDestroyed,participantJoined,participantLeft,webrtcConnectionCreated,webrtcConnectionDestroyed,recordingStatusChanged,filterEventDispatched,mediaNodeStatusChanged,nodeCrashed,nodeRecovered,broadcastStarted,broadcastStopped] - -# How often the garbage collector of non active sessions runs. -# This helps cleaning up sessions that have been initialized through -# REST API (and maybe tokens have been created for them) but have had no users connected. -# Default to 900s (15 mins). 0 to disable non active sessions garbage collector -OPENVIDU_SESSIONS_GARBAGE_INTERVAL=900 - -# Minimum time in seconds that a non active session must have been in existence -# for the garbage collector of non active sessions to remove it. Default to 3600s (1 hour). -# If non active sessions garbage collector is disabled -# (property 'OPENVIDU_SESSIONS_GARBAGE_INTERVAL' to 0) this property is ignored -OPENVIDU_SESSIONS_GARBAGE_THRESHOLD=3600 - -# Call Detail Record enabled -# Whether to enable Call Detail Record or not -# Values: true | false -OPENVIDU_CDR=false - -# Path where the cdr log files are hosted -OPENVIDU_CDR_PATH=/opt/openvidu/cdr - -# Kurento Media Server image -# -------------------------- -# Docker hub kurento media server: https://hub.docker.com/r/kurento/kurento-media-server -# Uncomment the next line and define this variable with KMS image that you want use -# KMS_IMAGE=kurento/kurento-media-server:7.0.1 - -# Kurento Media Server Level logs -# ------------------------------- -# Uncomment the next line and define this variable to change -# the verbosity level of the logs of KMS -# Documentation: https://doc-kurento.readthedocs.io/en/stable/features/logging.html -# KMS_DOCKER_ENV_GST_DEBUG= - -# Openvidu Server Level logs -# -------------------------- -# Uncomment the next line and define this variable to change -# the verbosity level of the logs of Openvidu Service -# RECOMENDED VALUES: INFO for normal logs DEBUG for more verbose logs -# OV_CE_DEBUG_LEVEL=INFO - -# Java Options -# -------------------------- -# Uncomment the next line and define this to add -# options to java command -# Documentation: https://docs.oracle.com/cd/E37116_01/install.111210/e23737/configuring_jvm.htm#OUDIG00058 -# JAVA_OPTIONS=-Xms2048m -Xmx4096m -Duser.timezone=UTC diff --git a/openvidu-server/deployments/ce/docker-compose/docker-compose.override.yml b/openvidu-server/deployments/ce/docker-compose/docker-compose.override.yml deleted file mode 100644 index 0557ae64c3..0000000000 --- a/openvidu-server/deployments/ce/docker-compose/docker-compose.override.yml +++ /dev/null @@ -1,31 +0,0 @@ -version: '3.1' - -services: - # -------------------------------------------------------------- - # - # Change this if your want use your own application. - # It's very important expose your application in port 5442 - # and use the http protocol. - # - # Default Application - # - # Openvidu-Call Version: 2.30.0 - # - # -------------------------------------------------------------- - app: - image: openvidu/openvidu-call:2.30.0 - restart: on-failure - network_mode: host - environment: - - SERVER_PORT=5442 - - OPENVIDU_URL=http://localhost:5443 - - OPENVIDU_SECRET=${OPENVIDU_SECRET} - - CALL_OPENVIDU_CERTTYPE=${CERTIFICATE_TYPE} - - CALL_PRIVATE_ACCESS=${CALL_PRIVATE_ACCESS:-} - - CALL_USER=${CALL_USER:-} - - CALL_SECRET=${CALL_SECRET:-} - - CALL_ADMIN_SECRET=${CALL_ADMIN_SECRET:-} - - CALL_RECORDING=${CALL_RECORDING:-} - logging: - options: - max-size: "${DOCKER_LOGS_MAX_SIZE:-100M}" diff --git a/openvidu-server/deployments/ce/docker-compose/docker-compose.yml b/openvidu-server/deployments/ce/docker-compose/docker-compose.yml deleted file mode 100644 index 5b57bab86f..0000000000 --- a/openvidu-server/deployments/ce/docker-compose/docker-compose.yml +++ /dev/null @@ -1,120 +0,0 @@ -# ------------------------------------------------------------------------------ -# -# DO NOT MODIFY THIS FILE !!! -# -# Configuration properties should be specified in .env file -# -# Application based on OpenVidu should be specified in -# docker-compose.override.yml file -# -# This docker-compose file coordinates all services of OpenVidu CE Platform -# -# This file will be overridden when update OpenVidu Platform -# -# Openvidu Version: 2.30.0 -# -# Installation Mode: On Premises -# -# ------------------------------------------------------------------------------ - -version: '3.1' - -services: - - openvidu-server: - image: openvidu/openvidu-server:2.30.0 - restart: on-failure - network_mode: host - entrypoint: ['/usr/local/bin/entrypoint.sh'] - volumes: - - ./coturn:/run/secrets/coturn - - /var/run/docker.sock:/var/run/docker.sock - - ${OPENVIDU_RECORDING_PATH}:${OPENVIDU_RECORDING_PATH} - - ${OPENVIDU_RECORDING_CUSTOM_LAYOUT}:${OPENVIDU_RECORDING_CUSTOM_LAYOUT} - - ${OPENVIDU_CDR_PATH}:${OPENVIDU_CDR_PATH} - env_file: - - .env - environment: - - SERVER_SSL_ENABLED=false - - SERVER_PORT=5443 - - KMS_URIS=["ws://localhost:8888/kurento"] - - COTURN_IP=${COTURN_IP:-auto-ipv4} - - COTURN_PORT=${COTURN_PORT:-3478} - logging: - options: - max-size: "${DOCKER_LOGS_MAX_SIZE:-100M}" - - kms: - image: ${KMS_IMAGE:-kurento/kurento-media-server:7.0.1} - restart: always - network_mode: host - ulimits: - core: -1 - volumes: - - /opt/openvidu/kms-crashes:/opt/openvidu/kms-crashes - - ${OPENVIDU_RECORDING_PATH}:${OPENVIDU_RECORDING_PATH} - - /opt/openvidu/kurento-logs:/opt/openvidu/kurento-logs - environment: - - KMS_MIN_PORT=40000 - - KMS_MAX_PORT=57000 - - GST_DEBUG=${KMS_DOCKER_ENV_GST_DEBUG:-} - - KURENTO_LOG_FILE_SIZE=${KMS_DOCKER_ENV_KURENTO_LOG_FILE_SIZE:-100} - - KURENTO_LOGS_PATH=/opt/openvidu/kurento-logs - logging: - options: - max-size: "${DOCKER_LOGS_MAX_SIZE:-100M}" - - coturn: - image: openvidu/openvidu-coturn:2.30.0 - restart: on-failure - ports: - - "${COTURN_PORT:-3478}:${COTURN_PORT:-3478}/tcp" - - "${COTURN_PORT:-3478}:${COTURN_PORT:-3478}/udp" - env_file: - - .env - volumes: - - ./coturn:/run/secrets/coturn - command: - - --log-file=stdout - - --listening-port=${COTURN_PORT:-3478} - - --fingerprint - - --min-port=${COTURN_MIN_PORT:-57001} - - --max-port=${COTURN_MAX_PORT:-65535} - - --realm=openvidu - - --verbose - - --use-auth-secret - - --static-auth-secret=$${COTURN_SHARED_SECRET_KEY} - logging: - options: - max-size: "${DOCKER_LOGS_MAX_SIZE:-100M}" - - nginx: - image: openvidu/openvidu-proxy:2.30.0 - restart: always - network_mode: host - volumes: - - ./certificates:/etc/letsencrypt - - ./owncert:/owncert - - ./custom-nginx-vhosts:/etc/nginx/vhost.d/ - - ./custom-nginx-locations:/custom-nginx-locations - - ${OPENVIDU_RECORDING_CUSTOM_LAYOUT}:/opt/openvidu/custom-layout - environment: - - DOMAIN_OR_PUBLIC_IP=${DOMAIN_OR_PUBLIC_IP} - - CERTIFICATE_TYPE=${CERTIFICATE_TYPE} - - LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL} - - PROXY_HTTP_PORT=${HTTP_PORT:-} - - PROXY_HTTPS_PORT=${HTTPS_PORT:-} - - PROXY_HTTPS_PROTOCOLS=${HTTPS_PROTOCOLS:-} - - PROXY_HTTPS_CIPHERS=${HTTPS_CIPHERS:-} - - PROXY_HTTPS_HSTS=${HTTPS_HSTS:-} - - ALLOWED_ACCESS_TO_DASHBOARD=${ALLOWED_ACCESS_TO_DASHBOARD:-} - - ALLOWED_ACCESS_TO_RESTAPI=${ALLOWED_ACCESS_TO_RESTAPI:-} - - PROXY_MODE=CE - - WITH_APP=true - - SUPPORT_DEPRECATED_API=${SUPPORT_DEPRECATED_API:-false} - - REDIRECT_WWW=${REDIRECT_WWW:-false} - - WORKER_CONNECTIONS=${WORKER_CONNECTIONS:-10240} - - PUBLIC_IP=${PROXY_PUBLIC_IP:-auto-ipv4} - logging: - options: - max-size: "${DOCKER_LOGS_MAX_SIZE:-100M}" diff --git a/openvidu-server/deployments/ce/docker-compose/install_openvidu.sh b/openvidu-server/deployments/ce/docker-compose/install_openvidu.sh deleted file mode 100755 index e9e092c6f6..0000000000 --- a/openvidu-server/deployments/ce/docker-compose/install_openvidu.sh +++ /dev/null @@ -1,328 +0,0 @@ -#!/usr/bin/env bash - -# Global variables -OPENVIDU_FOLDER=openvidu -OPENVIDU_VERSION=master -OPENVIDU_UPGRADABLE_VERSION="2.30" -DOWNLOAD_URL=https://raw.githubusercontent.com/OpenVidu/openvidu/${OPENVIDU_VERSION} - -# Support docker compose v1 and v2 -shopt -s expand_aliases -alias docker-compose='docker compose' -if ! docker compose version &> /dev/null; then - unalias docker-compose -fi - -# Change default http timeout for slow networks -export COMPOSE_HTTP_TIMEOUT=500 -export DOCKER_CLIENT_TIMEOUT=500 - -fatal_error() { - printf "\n =======¡ERROR!=======" - printf "\n %s" "$1" - printf "\n" - exit 1 -} - -new_ov_installation() { - printf '\n' - printf '\n =======================================' - printf '\n Install OpenVidu CE %s' "${OPENVIDU_VERSION}" - printf '\n =======================================' - printf '\n' - - # Create folder openvidu-docker-compose - printf '\n => Creating folder '%s'...' "${OPENVIDU_FOLDER}" - mkdir "${OPENVIDU_FOLDER}" || fatal_error "Error while creating the folder '${OPENVIDU_FOLDER}'" - - # Download necessary files - printf '\n => Downloading OpenVidu CE files:' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/ce/docker-compose/.env \ - --output "${OPENVIDU_FOLDER}/.env" || fatal_error "Error when downloading the file '.env'" - printf '\n - .env' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/ce/docker-compose/docker-compose.override.yml \ - --output "${OPENVIDU_FOLDER}/docker-compose.override.yml" || fatal_error "Error when downloading the file 'docker-compose.override.yml'" - printf '\n - docker-compose.override.yml' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/ce/docker-compose/docker-compose.yml \ - --output "${OPENVIDU_FOLDER}/docker-compose.yml" || fatal_error "Error when downloading the file 'docker-compose.yml'" - printf '\n - docker-compose.yml' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/ce/docker-compose/openvidu \ - --output "${OPENVIDU_FOLDER}/openvidu" || fatal_error "Error when downloading the file 'openvidu'" - printf '\n - openvidu' - - # Add execution permissions - printf "\n => Adding permission to 'openvidu' program..." - chmod +x "${OPENVIDU_FOLDER}/openvidu" || fatal_error "Error while adding permission to 'openvidu' program" - - # Change recording folder with all permissions - printf "\n => Adding permission to 'recordings' folder..." - mkdir -p "${OPENVIDU_FOLDER}/recordings" - - # Create own certificated folder - printf "\n => Creating folder 'owncert'..." - mkdir "${OPENVIDU_FOLDER}/owncert" || fatal_error "Error while creating the folder 'owncert'" - - # Create vhost nginx folder - printf "\n => Creating folder 'custom-nginx-vhosts'..." - mkdir "${OPENVIDU_FOLDER}/custom-nginx-vhosts" || fatal_error "Error while creating the folder 'custom-nginx-vhosts'" - - # Create vhost nginx folder - printf "\n => Creating folder 'custom-nginx-locations'..." - mkdir "${OPENVIDU_FOLDER}/custom-nginx-locations" || fatal_error "Error while creating the folder 'custom-nginx-locations'" - - # Ready to use - printf '\n' - printf '\n' - printf '\n =======================================' - printf '\n Openvidu Platform successfully installed.' - printf '\n =======================================' - printf '\n' - printf '\n 1. Go to openvidu folder:' - printf '\n $ cd openvidu' - printf '\n' - printf '\n 2. Configure DOMAIN_OR_PUBLIC_IP and OPENVIDU_SECRET in .env file:' - printf '\n $ nano .env' - printf '\n' - printf '\n 3. Start OpenVidu' - printf '\n $ ./openvidu start' - printf '\n' - printf '\n For more information, check:' - printf '\n https://docs.openvidu.io/en/%s/deployment/deploying-on-premises/' "${OPENVIDU_VERSION//v}" - printf '\n' - printf '\n' - exit 0 -} - -upgrade_ov() { - # Search local Openvidu installation - printf '\n' - printf '\n ============================================' - printf '\n Search Previous Installation of Openvidu' - printf '\n ============================================' - printf '\n' - - SEARCH_IN_FOLDERS=( - "${PWD}" - "/opt/${OPENVIDU_FOLDER}" - ) - - for folder in "${SEARCH_IN_FOLDERS[@]}"; do - printf "\n => Searching in '%s' folder..." "${folder}" - - if [ -f "${folder}/docker-compose.yml" ]; then - OPENVIDU_PREVIOUS_FOLDER="${folder}" - - printf "\n => Found installation in folder '%s'" "${folder}" - break - fi - done - - [ -z "${OPENVIDU_PREVIOUS_FOLDER}" ] && fatal_error "No previous Openvidu installation found" - - # Upgrade Openvidu - OPENVIDU_PREVIOUS_VERSION=$(grep 'Openvidu Version:' "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.yml" | awk '{ print $4 }') - [ -z "${OPENVIDU_PREVIOUS_VERSION}" ] && fatal_error "Can't find previous OpenVidu version" - - # In this point using the variable 'OPENVIDU_PREVIOUS_VERSION' we can verify if the upgrade is - # posible or not. If it is not posible launch a warning and stop the upgrade. - if [[ "${OPENVIDU_PREVIOUS_VERSION}" != "${OPENVIDU_UPGRADABLE_VERSION}."* ]]; then - fatal_error "You can't update from version ${OPENVIDU_PREVIOUS_VERSION} to ${OPENVIDU_VERSION}.\nNever upgrade across multiple major versions." - fi - - # Check installation is a valid OpenVidu edition - if grep -q '.*image:.*\/openvidu-server-pro:.*' "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.yml"; then - if grep -q '.*image:.*\/replication-manager:.*' "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.yml"; then - fatal_error "You can't upgrade. Installed version is OpenVidu Enterprise" - else - fatal_error "You can't upgrade. Installed version is OpenVidu PRO." - fi - fi - - printf '\n' - printf '\n =======================================' - printf '\n Upgrade OpenVidu CE %s to %s' "${OPENVIDU_PREVIOUS_VERSION}" "${OPENVIDU_VERSION}" - printf '\n =======================================' - printf '\n' - - ROLL_BACK_FOLDER="${OPENVIDU_PREVIOUS_FOLDER}/.old-${OPENVIDU_PREVIOUS_VERSION}" - TMP_FOLDER="${OPENVIDU_PREVIOUS_FOLDER}/tmp" - ACTUAL_FOLDER="$PWD" - USE_OV_CALL=$(grep -E '^ image: openvidu/openvidu-call:.*$' "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.override.yml" | tr -d '[:space:]') - - printf "\n Creating rollback folder '%s'..." ".old-${OPENVIDU_PREVIOUS_VERSION}" - mkdir "${ROLL_BACK_FOLDER}" || fatal_error "Error while creating the folder '.old-${OPENVIDU_PREVIOUS_VERSION}'" - - printf "\n Creating temporal folder 'tmp'..." - mkdir "${TMP_FOLDER}" || fatal_error "Error while creating the folder 'temporal'" - - # Download necessary files - printf '\n => Downloading new OpenVidu CE files:' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/ce/docker-compose/docker-compose.yml \ - --output "${TMP_FOLDER}/docker-compose.yml" || fatal_error "Error when downloading the file 'docker-compose.yml'" - printf '\n - docker-compose.yml' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/ce/docker-compose/docker-compose.override.yml \ - --output "${TMP_FOLDER}/docker-compose.override.yml" || fatal_error "Error when downloading the file 'docker-compose.override.yml'" - printf "\n - docker-compose.override.yml" - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/ce/docker-compose/.env \ - --output "${TMP_FOLDER}/.env" || fatal_error "Error when downloading the file '.env'" - printf '\n - .env' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/ce/docker-compose/openvidu \ - --output "${TMP_FOLDER}/openvidu" || fatal_error "Error when downloading the file 'openvidu'" - printf '\n - openvidu' - - # Downloading new images and stopped actual Openvidu - printf '\n => Downloading new images...' - printf '\n' - sleep 1 - - printf "\n => Moving to 'tmp' folder..." - printf '\n' - cd "${TMP_FOLDER}" || fatal_error "Error when moving to 'tmp' folder" - docker-compose pull || true - - printf '\n => Stopping Openvidu...' - printf '\n' - sleep 1 - - printf "\n => Moving to 'openvidu' folder..." - printf '\n' - cd "${OPENVIDU_PREVIOUS_FOLDER}" || fatal_error "Error when moving to 'openvidu' folder" - docker-compose down || true - - printf '\n' - printf '\n => Moving to working dir...' - cd "${ACTUAL_FOLDER}" || fatal_error "Error when moving to working dir" - - # Move old files to rollback folder - printf '\n => Moving previous installation files to rollback folder:' - - mv "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.yml" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous 'docker-compose.yml'" - printf '\n - docker-compose.yml' - - if [ -n "${USE_OV_CALL}" ]; then - mv "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.override.yml" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous 'docker-compose.override.yml'" - printf '\n - docker-compose.override.yml' - fi - - mv "${OPENVIDU_PREVIOUS_FOLDER}/openvidu" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous 'openvidu'" - printf '\n - openvidu' - - cp "${OPENVIDU_PREVIOUS_FOLDER}/.env" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous '.env'" - printf '\n - .env' - - if [ -d "${OPENVIDU_PREVIOUS_FOLDER}/custom-nginx-vhosts" ]; then - mv "${OPENVIDU_PREVIOUS_FOLDER}/custom-nginx-vhosts" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous directory 'custom-nginx-vhosts'" - printf '\n - custom-nginx-vhosts' - fi - - if [ -d "${OPENVIDU_PREVIOUS_FOLDER}/custom-nginx-locations" ]; then - mv "${OPENVIDU_PREVIOUS_FOLDER}/custom-nginx-locations" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous directory 'custom-nginx-locations'" - printf '\n - custom-nginx-locations' - fi - - if [ -d "${OPENVIDU_PREVIOUS_FOLDER}/coturn" ]; then - mv "${OPENVIDU_PREVIOUS_FOLDER}/coturn" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous directory 'coturn'" - fi - - # Move tmp files to Openvidu - printf '\n => Updating files:' - - mv "${TMP_FOLDER}/docker-compose.yml" "${OPENVIDU_PREVIOUS_FOLDER}" || fatal_error "Error while updating 'docker-compose.yml'" - printf '\n - docker-compose.yml' - - if [ -n "${USE_OV_CALL}" ]; then - mv "${TMP_FOLDER}/docker-compose.override.yml" "${OPENVIDU_PREVIOUS_FOLDER}" || fatal_error "Error while updating 'docker-compose.override.yml'" - printf '\n - docker-compose.override.yml' - else - mv "${TMP_FOLDER}/docker-compose.override.yml" "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.override.yml-${OPENVIDU_VERSION}" || fatal_error "Error while updating 'docker-compose.override.yml'" - printf '\n - docker-compose.override.yml-%s' "${OPENVIDU_VERSION}" - fi - - mv "${TMP_FOLDER}/.env" "${OPENVIDU_PREVIOUS_FOLDER}/.env-${OPENVIDU_VERSION}" || fatal_error "Error while moving previous '.env'" - printf '\n - .env-%s' "${OPENVIDU_VERSION}" - - mv "${TMP_FOLDER}/openvidu" "${OPENVIDU_PREVIOUS_FOLDER}" || fatal_error "Error while updating 'openvidu'" - printf '\n - openvidu' - - printf "\n => Deleting 'tmp' folder" - rm -rf "${TMP_FOLDER}" || fatal_error "Error deleting 'tmp' folder" - - # Add execution permissions - printf "\n => Adding permission to 'openvidu' program..." - chmod +x "${OPENVIDU_PREVIOUS_FOLDER}/openvidu" || fatal_error "Error while adding permission to 'openvidu' program" - - # Change recording folder with all permissions - printf "\n => Adding permission to 'recordings' folder..." - mkdir -p "${OPENVIDU_PREVIOUS_FOLDER}/recordings" - - # Define old mode: On Premise or Cloud Formation - OLD_MODE=$(grep -E "Installation Mode:.*$" "${ROLL_BACK_FOLDER}/docker-compose.yml" | awk '{ print $4,$5 }') - [ -n "${OLD_MODE}" ] && sed -i -r "s/Installation Mode:.+/Installation Mode: ${OLD_MODE}/" "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.yml" - - # Ready to use - printf '\n' - printf '\n' - printf '\n ================================================' - printf "\n Openvidu successfully upgraded to version %s" "${OPENVIDU_VERSION}" - printf '\n ================================================' - printf '\n' - printf "\n 1. A new file 'docker-compose.yml' has been created with the new OpenVidu %s services" "${OPENVIDU_VERSION}" - printf '\n' - printf "\n 2. The previous file '.env' remains intact, but a new file '.env-%s' has been created." "${OPENVIDU_VERSION}" - printf "\n Transfer any configuration you wish to keep in the upgraded version from '.env' to '.env-%s'." "${OPENVIDU_VERSION}" - printf "\n When you are OK with it, rename and leave as the only '.env' file of the folder the new '.env-%s'." "${OPENVIDU_VERSION}" - printf '\n' - printf "\n 3. If you were using Openvidu Call application, it has been automatically updated in file 'docker-compose.override.yml'." - printf "\n However, if you were using your own application, a file called 'docker-compose.override.yml-%s'" "${OPENVIDU_VERSION}" - printf "\n has been created with the latest version of Openvidu Call. If you don't plan to use it you can delete it." - printf '\n' - printf '\n 4. Start new version of Openvidu' - printf '\n $ ./openvidu start' - printf '\n' - printf "\n If you want to rollback, all the files from the previous installation have been copied to folder '.old-%s'" "${OPENVIDU_PREVIOUS_VERSION}" - printf '\n' - printf '\n For more information, check:' - printf '\n https://docs.openvidu.io/en/%s/deployment/deploying-on-premises/' "${OPENVIDU_VERSION//v}" - printf '\n https://docs.openvidu.io/en/%s/deployment/upgrading/' "${OPENVIDU_VERSION//v}" - printf '\n' - printf '\n' -} - -# Check docker and docker-compose installation -if ! command -v docker > /dev/null; then - echo "You don't have docker installed, please install it and re-run the command" - exit 1 -else - # Check version of docker is equal or higher than 20.10.10 - DOCKER_VERSION=$(docker version --format '{{.Server.Version}}' | sed "s/-rc[0-9]*//") - if ! printf '%s\n%s\n' "20.10.10" "$DOCKER_VERSION" | sort -V -C; then - echo "You need a docker version equal or higher than 20.10.10, please update your docker and re-run the command"; \ - exit 1 - fi -fi - -if ! command -v docker-compose > /dev/null; then - echo "You don't have docker-compose installed, please install it and re-run the command" - exit 1 -else - COMPOSE_VERSION=$(docker-compose version --short | sed "s/-rc[0-9]*//") - if ! printf '%s\n%s\n' "1.24" "$COMPOSE_VERSION" | sort -V -C; then - echo "You need a docker-compose version equal or higher than 1.24, please update your docker-compose and re-run the command"; \ - exit 1 - fi -fi - -# Check type of installation -if [[ -n "$1" && "$1" == "upgrade" ]]; then - upgrade_ov -else - new_ov_installation -fi diff --git a/openvidu-server/deployments/ce/docker-compose/openvidu b/openvidu-server/deployments/ce/docker-compose/openvidu deleted file mode 100755 index 882e138e65..0000000000 --- a/openvidu-server/deployments/ce/docker-compose/openvidu +++ /dev/null @@ -1,305 +0,0 @@ -#!/bin/bash - -# Support docker compose v1 and v2 -shopt -s expand_aliases -alias docker-compose='docker compose' -if ! docker compose version &> /dev/null; then - unalias docker-compose -fi - -# Change default http timeout for slow networks -export COMPOSE_HTTP_TIMEOUT=500 -export DOCKER_CLIENT_TIMEOUT=500 - -upgrade_ov() { - UPGRADE_SCRIPT_URL="https://s3-eu-west-1.amazonaws.com/aws.openvidu.io/install_openvidu_OVVERSION.sh" - HTTP_STATUS=$(curl -s -o /dev/null -I -w "%{http_code}" ${UPGRADE_SCRIPT_URL//OVVERSION/$1}) - - printf " => Upgrading OpenVidu CE to '%s' version" "$1" - - if [ "$HTTP_STATUS" == "200" ]; then - printf "\n => Downloading and upgrading new version" - printf "\n" - - curl --silent ${UPGRADE_SCRIPT_URL//OVVERSION/$1} | bash -s upgrade - else - printf "\n =======¡ERROR!=======" - printf "\n OpenVidu CE Version '%s' not exist" "$1" - printf "\n" - exit 0 - fi -} - -collect_basic_information() { - LINUX_VERSION=$(lsb_release -d) - DOCKER_PS=$(docker ps) - DOCKER_VERSION=$(docker version --format '{{.Server.Version}}') - DOCKER_COMPOSE_VERSION=$(docker-compose version --short) - OV_FOLDER="${PWD}" - OV_VERSION=$(grep 'Openvidu Version:' "${OV_FOLDER}/docker-compose.yml" | awk '{ print $4 }') - CONTAINERS=$(docker ps | awk '{if(NR>1) print $NF}') - - if [ -n "$(grep -E '^ image: openvidu/openvidu-call:.*$' "${OV_FOLDER}/docker-compose.override.yml" | tr -d '[:space:]')" ]; then - OV_CALL_VERSION=$(grep -E 'Openvidu-Call Version:' "${OV_FOLDER}/docker-compose.override.yml" | awk '{ print $4 }') - fi - [ -z "${OV_CALL_VERSION}" ] && OV_CALL_VERSION="No present" - - OV_TYPE_INSTALLATION=$(grep 'Installation Mode:' "${OV_FOLDER}/docker-compose.yml" | awk '{ print $4,$5 }') - TREE_OV_DIRECTORY=$(find "." | sed -e "s/[^-][^\/]*\// |/g" -e "s/|\([^ ]\)/|-\1/") -} - -version_ov() { - collect_basic_information - - printf '\nOpenvidu Information:' - printf '\n' - printf '\n Installation Type: %s' "${OV_TYPE_INSTALLATION}" - printf '\n Openvidu Version: %s' "${OV_VERSION}" - printf '\n Openvidu Call Version: %s' "${OV_CALL_VERSION}" - printf '\n' - printf '\nSystem Information:' - printf '\n' - printf '\n Linux Version:' - printf '\n - %s' "${LINUX_VERSION}" - printf '\n Docker Version: %s' "${DOCKER_VERSION}" - printf '\n Docker Compose Version: %s' "${DOCKER_COMPOSE_VERSION}" - printf '\n' - printf '\nInstallation Information:' - printf '\n' - printf '\n Installation Folder: %s' "${OV_FOLDER}" - printf '\n Installation Folder Tree:' - printf '\n%s' "$(echo "${TREE_OV_DIRECTORY}" | sed -e 's/.//' -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')" - printf '\n' - printf '\nDocker Running Services:' - printf '\n' - printf '\n %s' "$(echo "${DOCKER_PS}" | sed -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')" - printf '\n' -} - -generate_report() { - collect_basic_information - - REPORT_CREATION_DATE=$(date +"%d-%m-%Y") - REPORT_CREATION_TIME=$(date +"%H:%M:%S") - REPORT_NAME="openvidu-report-${REPORT_CREATION_DATE}-$(date +"%H-%M").txt" - REPORT_OUTPUT="${OV_FOLDER}/${REPORT_NAME}" - - { - printf "\n =======================================" - printf "\n = REPORT INFORMATION =" - printf "\n =======================================" - printf '\n' - printf '\n Creation Date: %s' "${REPORT_CREATION_DATE}" - printf '\n Creation Time: %s' "${REPORT_CREATION_TIME}" - printf '\n' - printf "\n =======================================" - printf "\n = OPENVIDU INFORMATION =" - printf "\n =======================================" - printf '\n' - printf '\n Installation Type: %s' "${OV_TYPE_INSTALLATION}" - printf '\n Openvidu Version: %s' "${OV_VERSION}" - printf '\n Openvidu Call Version: %s' "${OV_CALL_VERSION}" - printf '\n' - printf "\n =======================================" - printf "\n = SYSTEM INFORMATION =" - printf "\n =======================================" - printf '\n' - printf '\n Linux Version:' - printf '\n - %s' "${LINUX_VERSION}" - printf '\n Docker Version: %s' "${DOCKER_VERSION}" - printf '\n Docker Compose Version: %s' "${DOCKER_COMPOSE_VERSION}" - printf '\n' - printf "\n =======================================" - printf "\n = INSTALLATION INFORMATION =" - printf "\n =======================================" - printf '\n' - printf '\n Installation Folder: %s' "${OV_FOLDER}" - printf '\n Installation Folder Tree:' - printf '\n%s' "$(echo "${TREE_OV_DIRECTORY}" | sed -e 's/.//' -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')" - printf '\n' - printf "\n =======================================" - printf "\n = DOCKER RUNNING SERVICES =" - printf "\n =======================================" - printf '\n' - printf '\n %s' "$(echo "${DOCKER_PS}" | sed -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')" - printf '\n' - printf "\n =======================================" - printf "\n = CONFIGURATION FILES =" - printf "\n =======================================" - printf '\n' - printf '\n ================ .env =================' - printf '\n' - printf '\n' - - cat < "${OV_FOLDER}/.env" | sed -r -e "s/OPENVIDU_SECRET=.+/OPENVIDU_SECRET=****/" - - printf '\n' - printf '\n ========= docker-compose.yml ==========' - printf '\n' - printf '\n' - - cat "${OV_FOLDER}/docker-compose.yml" - - printf '\n' - printf '\n ==== docker-compose.override.yml ====' - printf '\n' - printf '\n' - - if [ -f "${OV_FOLDER}/docker-compose.override.yml" ]; then - cat < "${OV_FOLDER}/docker-compose.override.yml" - else - printf '\n The docker-compose.override.yml file is not present' - fi - - printf '\n' - printf '\n' - printf "\n =======================================" - printf "\n = LOGS =" - printf "\n =======================================" - - for CONTAINER in $CONTAINERS - do - printf '\n' - printf "\n ---------------------------------------" - printf "\n %s" "$CONTAINER" - printf "\n ---------------------------------------" - printf '\n' - docker logs "$CONTAINER" - printf "\n ---------------------------------------" - printf '\n' - printf '\n' - done - - printf '\n' - printf "\n ---------------------------------------" - printf "\n KMS" - printf "\n ---------------------------------------" - printf '\n' - kurento_logs - printf "\n ---------------------------------------" - printf '\n' - printf '\n' - - printf "\n =======================================" - printf "\n = CONTAINER ENVS VARIABLES =" - printf "\n =======================================" - - for CONTAINER in $CONTAINERS - do - printf '\n' - printf "\n =======================================" - printf "\n %s" "$CONTAINER" - printf "\n ---------------------------------------" - printf '\n' - docker exec "$CONTAINER" env - printf "\n ---------------------------------------" - printf '\n' - printf '\n' - done - - } >> "${REPORT_OUTPUT}" 2>&1 - - printf "\n Generation of the report completed with success" - printf "\n You can get your report at path '%s'" "${REPORT_OUTPUT}" - printf "\n" -} - -usage() { - printf "Usage: \n\t openvidu [command]" - printf "\n\nAvailable Commands:" - printf "\n\tstart\t\t\tStart all services" - printf "\n\tstop\t\t\tStop all services" - printf "\n\trestart\t\t\tRestart all stopped and running services" - printf "\n\tlogs [-f]\t\tShow openvidu logs." - printf "\n\tkms-logs [-f]\t\tShow kms logs" - printf "\n\tupgrade\t\t\tUpgrade to the latest Openvidu version" - printf "\n\tupgrade [version]\tUpgrade to the specific Openvidu version" - printf "\n\tversion\t\t\tShow version of Openvidu Server" - printf "\n\treport\t\t\tGenerate a report with the current status of Openvidu" - printf "\n\thelp\t\t\tShow help for openvidu command" - printf "\n" -} - -kurento_logs() { - if [[ "$1" == "-f" ]]; then - tail -f /opt/openvidu/kurento-logs/*.log - else - cat /opt/openvidu/kurento-logs/*.log - fi -} - -[[ -z "${FOLLOW_OPENVIDU_LOGS}" ]] && FOLLOW_OPENVIDU_LOGS=true - -case $1 in - start) - docker-compose up -d - if [[ "${FOLLOW_OPENVIDU_LOGS}" == "true" ]]; then - docker-compose logs -f --tail 10 openvidu-server - fi - ;; - - stop) - docker-compose down - ;; - - restart) - docker-compose down - docker-compose up -d - if [[ "${FOLLOW_OPENVIDU_LOGS}" == "true" ]]; then - docker-compose logs -f --tail 10 openvidu-server - fi - ;; - - logs) - case "${2-}" in - --follow|-f) - docker-compose logs -f --tail 10 openvidu-server - ;; - *) - docker-compose logs openvidu-server - ;; - esac - ;; - - kms-logs) - kurento_logs "$2" - ;; - - upgrade) - if [ -z "$2" ]; then - UPGRADE_VERSION="latest" - else - UPGRADE_VERSION="$2" - fi - - read -r -p " You're about to update OpenVidu CE to '${UPGRADE_VERSION}' version. Are you sure? [y/N]: " response - case "$response" in - [yY][eE][sS]|[yY]) - upgrade_ov "${UPGRADE_VERSION}" - ;; - *) - exit 0 - ;; - esac - ;; - - version) - version_ov - ;; - - report) - read -r -p " You are about to generate a report on the current status of Openvidu, this may take some time. Do you want to continue? [y/N]: " response - case "$response" in - [yY][eE][sS]|[yY]) - generate_report - ;; - *) - exit 0 - ;; - esac - ;; - - *) - usage - ;; -esac diff --git a/openvidu-server/deployments/ce/docker-compose/owncert/.gitignore b/openvidu-server/deployments/ce/docker-compose/owncert/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/.env b/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/.env deleted file mode 100644 index ddb72aebfe..0000000000 --- a/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/.env +++ /dev/null @@ -1,52 +0,0 @@ -# OpenVidu Enterprise HA Base Services Configuration -# ---------------------- -# Documentation: https://docs.openvidu.io/en/stable/deployment/enterprise/on-premises/#high-availability-deployment -# NOTE: This file doesn't need to quote assignment values, like most shells do. -# All values are stored as-is, even if they contain spaces, so don't quote them. - -# Domain name. If you do not have one, the public IP of the machine. -# For example: 198.51.100.1, or openvidu.example.com -# This domain name will be the one that should be used to access the OpenVidu Server -# All nodes in your cluster should have this same value at DOMAIN_OR_PUBLIC_IP -DOMAIN_OR_PUBLIC_IP= - -# OpenVidu SECRET used for apps to connect to OpenVidu server and users to access to OpenVidu Dashboard -# This secret is needed for default Openvidu Call app to connect to OpenVidu Server -OPENVIDU_SECRET= - -# Certificate type: -# - selfsigned: Self signed certificate. Not recommended for production use. -# Users will see an ERROR when connected to web page. -# - owncert: Valid certificate purchased in a Internet services company. -# Please put the certificates files inside folder ./owncert -# with names certificate.key and certificate.cert -# - letsencrypt: Generate a new certificate using letsencrypt. Please set the -# required contact email for Let's Encrypt in LETSENCRYPT_EMAIL -# variable. -CERTIFICATE_TYPE=selfsigned - -# If CERTIFICATE_TYPE=letsencrypt, you need to configure a valid email for notifications -LETSENCRYPT_EMAIL= - -# A list separated by commas of the private IP addresses of the nodes in your cluster. -# This machine should be able to reach all the nodes in this list. -# For example: 10.0.0.5,10.0.0.6 -OPENVIDU_ENTERPRISE_HA_NODE_IPS= - -# Redis password used by OpenVidu Nodes to connect to Redis server -OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD= - - -# Name of the bucket in S3 where OpenVidu will store the configuration file -OPENVIDU_ENTERPRISE_HA_S3_CONFIG_BUCKET=openvidu-enterprise - -# Configured user for S3 at deployed MinIO server -OPENVIDU_ENTERPRISE_HA_S3_CONFIG_ACCESS_KEY=minioadmin - -# Configured password for S3 at deployed MinIO server -OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY= - -# Kibana And ElasticSearch Basic Auth configuration (Credentials) -# This credentials will aso be valid for Kibana dashboard -ELASTICSEARCH_USERNAME=elasticadmin -ELASTICSEARCH_PASSWORD= \ No newline at end of file diff --git a/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/base-services b/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/base-services deleted file mode 100644 index 3b22909266..0000000000 --- a/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/base-services +++ /dev/null @@ -1,377 +0,0 @@ -#!/bin/bash - -# Support docker compose v1 and v2 -shopt -s expand_aliases -alias docker-compose='docker compose' -if ! docker compose version &> /dev/null; then - unalias docker-compose -fi - -# Change default http timeout for slow networks -export COMPOSE_HTTP_TIMEOUT=500 -export DOCKER_CLIENT_TIMEOUT=500 - -collect_basic_information() { - LINUX_VERSION=$(lsb_release -d) - DOCKER_PS=$(docker ps) - DOCKER_VERSION=$(docker version --format '{{.Server.Version}}') - DOCKER_COMPOSE_VERSION=$(docker-compose version --short) - OV_FOLDER="${PWD}" - OV_VERSION=$(grep 'Openvidu Version:' "${OV_FOLDER}/docker-compose.yml" | awk '{ print $4 }') - CONTAINERS=$(docker ps | awk '{if(NR>1) print $NF}') - if [ -n "$(grep -E '^ image: openvidu/openvidu-call:.*$' "${OV_FOLDER}/docker-compose.override.yml" | tr -d '[:space:]')" ]; then - OV_CALL_VERSION=$(grep -E 'Openvidu-Call Version:' "${OV_FOLDER}/docker-compose.override.yml" | awk '{ print $4 }') - fi - [ -z "${OV_CALL_VERSION}" ] && OV_CALL_VERSION="No present" - OV_TYPE_INSTALLATION=$(grep 'Installation Mode:' "${OV_FOLDER}/docker-compose.yml" | awk '{ print $4,$5 }') - TREE_OV_DIRECTORY=$(find "." ! -path '*/0/*' | sed -e "s/[^-][^\/]*\// |/g" -e "s/|\([^ ]\)/|-\1/") -} - -version_ov() { - collect_basic_information - - printf '\nOpenvidu Information:' - printf '\n' - printf '\n Openvidu Enterprise HA Base Services' - printf '\n Installation Type: %s' "${OV_TYPE_INSTALLATION}" - printf '\n Openvidu Version: %s' "${OV_VERSION}" - printf '\n Openvidu Call Version: %s' "${OV_CALL_VERSION}" - printf '\n' - printf '\nSystem Information:' - printf '\n' - printf '\n Linux Version:' - printf '\n - %s' "${LINUX_VERSION}" - printf '\n Docker Version: %s' "${DOCKER_VERSION}" - printf '\n Docker Compose Version: %s' "${DOCKER_COMPOSE_VERSION}" - printf '\n' - printf '\nInstallation Information:' - printf '\n' - printf '\n Installation Folder: %s' "${OV_FOLDER}" - printf '\n Installation Folder Tree:' - printf '\n%s' "$(echo "${TREE_OV_DIRECTORY}" | sed -e 's/.//' -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')" - printf '\n' - printf '\nDocker Running Services:' - printf '\n' - printf '\n %s' "$(echo "${DOCKER_PS}" | sed -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')" - printf '\n' -} - -generate_report() { - collect_basic_information - - REPORT_CREATION_DATE=$(date +"%d-%m-%Y") - REPORT_CREATION_TIME=$(date +"%H:%M:%S") - REPORT_NAME="openvidu-report-${REPORT_CREATION_DATE}-$(date +"%H-%M").txt" - REPORT_OUTPUT="${OV_FOLDER}/${REPORT_NAME}" - - { - printf "\n =======================================" - printf "\n = REPORT INFORMATION =" - printf "\n =======================================" - printf '\n' - printf '\n Creation Date: %s' "${REPORT_CREATION_DATE}" - printf '\n Creation Time: %s' "${REPORT_CREATION_TIME}" - printf '\n' - printf "\n =======================================" - printf "\n = OPENVIDU INFORMATION =" - printf "\n =======================================" - printf '\n' - printf '\n Openvidu Enterprise HA Base Services' - printf '\n Installation Type: %s' "${OV_TYPE_INSTALLATION}" - printf '\n Openvidu Version: %s' "${OV_VERSION}" - printf '\n Openvidu Call Version: %s' "${OV_CALL_VERSION}" - printf '\n' - printf "\n =======================================" - printf "\n = SYSTEM INFORMATION =" - printf "\n =======================================" - printf '\n' - printf '\n Linux Version:' - printf '\n - %s' "${LINUX_VERSION}" - printf '\n Docker Version: %s' "${DOCKER_VERSION}" - printf '\n Docker Compose Version: %s' "${DOCKER_COMPOSE_VERSION}" - printf '\n' - printf "\n =======================================" - printf "\n = INSTALLATION INFORMATION =" - printf "\n =======================================" - printf '\n' - printf '\n Installation Folder: %s' "${OV_FOLDER}" - printf '\n Installation Folder Tree:' - printf '\n%s' "$(echo "${TREE_OV_DIRECTORY}" | sed -e 's/.//' -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')" - printf '\n' - printf "\n =======================================" - printf "\n = DOCKER RUNNING SERVICES =" - printf "\n =======================================" - printf '\n' - printf '\n %s' "$(echo "${DOCKER_PS}" | sed -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')" - printf '\n' - printf "\n =======================================" - printf "\n = CONFIGURATION FILES =" - printf "\n =======================================" - printf '\n' - printf '\n ================ .env =================' - printf '\n' - printf '\n' - - cat < "${OV_FOLDER}/.env" | sed -r -e "s/OPENVIDU_SECRET=.+/OPENVIDU_SECRET=****/" -e "s/OPENVIDU_PRO_LICENSE=.+/OPENVIDU_PRO_LICENSE=****/" -e "s/ELASTICSEARCH_PASSWORD=.+/ELASTICSEARCH_PASSWORD=****/" - - printf '\n' - printf '\n ========= docker-compose.yml ==========' - printf '\n' - printf '\n' - - cat "${OV_FOLDER}/docker-compose.yml" - - printf '\n' - printf '\n ==== docker-compose.override.yml ====' - printf '\n' - printf '\n' - - if [ -f "${OV_FOLDER}/docker-compose.override.yml" ]; then - cat < "${OV_FOLDER}/docker-compose.override.yml" - else - printf '\n The docker-compose.override.yml file is not present' - fi - - printf '\n' - printf '\n' - printf "\n =======================================" - printf "\n = LOGS =" - printf "\n =======================================" - - for CONTAINER in $CONTAINERS - do - printf '\n' - printf "\n ---------------------------------------" - printf "\n %s" "$CONTAINER" - printf "\n ---------------------------------------" - printf '\n' - docker logs "$CONTAINER" - printf "\n ---------------------------------------" - printf '\n' - printf '\n' - done - - printf "\n =======================================" - printf "\n = CONTAINER ENVS VARIABLES =" - printf "\n =======================================" - - for CONTAINER in $CONTAINERS - do - printf '\n' - printf "\n =======================================" - printf "\n %s" "$CONTAINER" - printf "\n ---------------------------------------" - printf '\n' - docker exec "$CONTAINER" env - printf "\n ---------------------------------------" - printf '\n' - printf '\n' - done - - } >> "${REPORT_OUTPUT}" 2>&1 - - printf "\n Generation of the report completed with success" - printf "\n You can get your report at path '%s'" "${REPORT_OUTPUT}" - printf "\n" -} - -print_env_error() { - printf "\n =======¡ERROR!=======" - printf "\n ERROR: You must set the '%s' variable in the .env file" "${1}" - printf "\n" -} - -check_non_empty_parameters() { - local NON_EMPTY_ENV_VARS=("$@") - for ENV_VAR_NAME in "${NON_EMPTY_ENV_VARS[@]}" ; do - ENV_VAR_VALUE=$(grep -v '^#' .env | grep "${ENV_VAR_NAME}" | cut -d '=' -f2) - if [[ -z "${ENV_VAR_VALUE}" ]]; then - print_env_error "${ENV_VAR_NAME}" - exit 1 - fi - done -} - -get_env_var_value() { - local ENV_VAR_NAME=$1 - local ENV_VAR_VALUE - ENV_VAR_VALUE=$(grep -v '^#' .env | grep "${ENV_VAR_NAME}" | cut -d '=' -f2) - echo "${ENV_VAR_VALUE}" -} - -check_env_var_is_value() { - local ENV_VAR_NAME=$1 - local ENV_VAR_VALUE=$2 - local ENV_VAR_VALUE_TO_CHECK - ENV_VAR_VALUE_TO_CHECK=$(get_env_var_value "${ENV_VAR_NAME}") - if [[ "${ENV_VAR_VALUE_TO_CHECK}" != "${ENV_VAR_VALUE}" ]]; then - print_env_error "${ENV_VAR_NAME}" - exit 1 - fi -} - -print_env_error() { - printf "\n =======¡ERROR!=======" - printf "\n %s" "$1" - printf "\n" -} - -check_non_empty_parameters() { - local NON_EMPTY_ENV_VARS=("$@") - for ENV_VAR_NAME in "${NON_EMPTY_ENV_VARS[@]}" ; do - ENV_VAR_VALUE=$(grep -v '^#' .env | grep "${ENV_VAR_NAME}" | cut -d '=' -f2) - if [[ -z "${ENV_VAR_VALUE}" ]]; then - ERRORS+=("ERROR: You must set the '${ENV_VAR_NAME}' variable in the .env file") - fi - done -} - -get_env_var_value() { - local ENV_VAR_NAME=$1 - local ENV_VAR_VALUE - ENV_VAR_VALUE=$(grep -v '^#' .env | grep "${ENV_VAR_NAME}" | cut -d '=' -f2) - echo "${ENV_VAR_VALUE}" -} - -validate_env_vars() { - ERRORS=() - check_non_empty_parameters "DOMAIN_OR_PUBLIC_IP" \ - "OPENVIDU_SECRET" \ - "CERTIFICATE_TYPE" \ - "OPENVIDU_ENTERPRISE_HA_NODE_IPS" \ - "OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD" \ - "OPENVIDU_ENTERPRISE_HA_S3_CONFIG_BUCKET" \ - "OPENVIDU_ENTERPRISE_HA_S3_CONFIG_ACCESS_KEY" \ - "OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY" \ - "ELASTICSEARCH_USERNAME" \ - "ELASTICSEARCH_PASSWORD" - - local OPENVIDU_SECRET - OPENVIDU_SECRET=$(get_env_var_value "OPENVIDU_SECRET") - if [[ ! "${OPENVIDU_SECRET}" =~ ^[a-zA-Z0-9_-]+$ ]]; then - ERRORS+=("OPENVIDU_SECRET: Value must be alphanumeric and can include '-' or '_'.") - fi - - local CERTIFICATE_TYPE - CERTIFICATE_TYPE=$(get_env_var_value "CERTIFICATE_TYPE") - if [[ "${CERTIFICATE_TYPE}" == "letsencrypt" ]]; then - local LETSENCRYPT_EMAIL - LETSENCRYPT_EMAIL=$(get_env_var_value "LETSENCRYPT_EMAIL") - if [[ -z "${LETSENCRYPT_EMAIL}" ]]; then - ERRORS+=("LETSENCRYPT_EMAIL: Value must not be empty when CERTIFICATE_TYPE is 'letsencrypt'.") - fi - fi - - local OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD - OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD=$(get_env_var_value "OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD") - if [[ ! "${OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD}" =~ ^[a-zA-Z0-9_-]+$ ]]; then - ERRORS+=("OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD: Value must be alphanumeric and can include '-' or '_'.") - fi - - local OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY - OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY=$(get_env_var_value "OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY") - if [[ ! "${OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY}" =~ ^[a-zA-Z0-9_-]+$ ]]; then - ERRORS+=("OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY: Value must be alphanumeric and can include '-' or '_'.") - fi - - local ELASTICSEARCH_PASSWORD - ELASTICSEARCH_PASSWORD=$(get_env_var_value "ELASTICSEARCH_PASSWORD") - if [[ ! "${ELASTICSEARCH_PASSWORD}" =~ ^[a-zA-Z0-9_-]{7,}$ ]]; then - ERRORS+=("ELASTICSEARCH_PASSWORD: Value must be alphanumeric (and can include '-' or '_') with a minimum length of 7.") - fi - - if [[ ${#ERRORS[@]} -ne 0 ]]; then - for error in "${ERRORS[@]}"; do - print_env_error "${error}" - done - exit 1 - fi -} - -start_openvidu() { - docker-compose up -d -} - -usage() { - printf "Usage: \n\t base-services [command]" - printf "\n\nAvailable Commands:" - printf "\n\tstart\t\t\tStart all services" - printf "\n\tstop\t\t\tStop all services" - printf "\n\trestart\t\t\tRestart all stopped and running services" - printf "\n\tupdate-loadbalancer\tUpdate load balancer IPs \n\t\t\t\tfrom OPENVIDU_ENTERPRISE_HA_NODE_IPS" - printf "\n\tlogs\t\t\tShow openvidu-server logs" - printf "\n\tupgrade\t\t\tUpgrade to the latest Openvidu version" - printf "\n\tupgrade [version]\tUpgrade to the specific Openvidu version" - printf "\n\tversion\t\t\tShow version of Openvidu Server" - printf "\n\treport\t\t\tGenerate a report with the current status of Openvidu" - printf "\n\thelp\t\t\tShow help for openvidu command" - printf "\n" -} - -[[ -z "${FOLLOW_OPENVIDU_LOGS}" ]] && FOLLOW_OPENVIDU_LOGS=true - -case $1 in - -start) - validate_env_vars - start_openvidu - if [[ "${FOLLOW_OPENVIDU_LOGS}" == "true" ]]; then - # Docker compose logs of openvidu-server and repliation-manager containers - docker-compose logs -f --tail 10 - fi -;; - -stop) - docker-compose down -;; - -restart) - validate_env_vars - docker-compose down - start_openvidu - if [[ "${FOLLOW_OPENVIDU_LOGS}" == "true" ]]; then - docker-compose logs -f --tail 10 - fi -;; - -update-loadbalancer) - validate_env_vars - OPENVIDU_ENTERPRISE_HA_NODE_IPS=$(get_env_var_value "OPENVIDU_ENTERPRISE_HA_NODE_IPS") - docker-compose exec -it \ - -e OPENVIDU_ENTERPRISE_HA_NODE_IPS="${OPENVIDU_ENTERPRISE_HA_NODE_IPS}" \ - loadbalancer update_enterprise_ha_nodes.sh -;; - -logs) - case "${2-}" in - --follow|-f) - docker-compose logs -f --tail 10 - ;; - - *) - docker-compose logs - ;; - esac -;; - -version) - version_ov -;; - -report) - read -r -p " You are about to generate a report on the current status of Openvidu, this may take some time. Do you want to continue? [y/N]: " response - case "$response" in - [yY][eE][sS]|[yY]) - generate_report - ;; - - *) - exit 0 - ;; - esac -;; - -*) - usage -;; -esac diff --git a/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/docker-compose.override.yml b/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/docker-compose.override.yml deleted file mode 100644 index 4f29238534..0000000000 --- a/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/docker-compose.override.yml +++ /dev/null @@ -1,32 +0,0 @@ -version: '3.1' - -services: - # -------------------------------------------------------------- - # - # Change this if your want use your own application. - # It's very important expose your application in port 5442 - # and use the http protocol. - # - # Default Application - # - # Openvidu-Call Version: 2.30.0 - # - # -------------------------------------------------------------- - app: - image: openvidu/openvidu-call:2.30.0 - restart: on-failure - ports: - - 5442:5442 - environment: - - SERVER_PORT=5442 - - OPENVIDU_URL=http://loadbalancer:5443 - - OPENVIDU_SECRET=${OPENVIDU_SECRET} - - CALL_OPENVIDU_CERTTYPE=${CERTIFICATE_TYPE} - - CALL_PRIVATE_ACCESS=${CALL_PRIVATE_ACCESS:-} - - CALL_USER=${CALL_USER:-} - - CALL_SECRET=${CALL_SECRET:-} - - CALL_ADMIN_SECRET=${CALL_ADMIN_SECRET:-} - - CALL_RECORDING=${CALL_RECORDING:-} - logging: - options: - max-size: "${DOCKER_LOGS_MAX_SIZE:-100M}" \ No newline at end of file diff --git a/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/docker-compose.yml b/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/docker-compose.yml deleted file mode 100644 index 97571b0ad1..0000000000 --- a/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/docker-compose.yml +++ /dev/null @@ -1,134 +0,0 @@ -# ------------------------------------------------------------------------------ -# -# DO NOT MODIFY THIS FILE !!! -# -# Configuration properties should be specified in .env file -# -# This docker-compose file coordinates all needed services by OpenVidu Enterprise HA -# -# This file will be overridden when updating OpenVidu Enterprise HA -# -# Openvidu Version: 2.30.0 -# -# Installation Mode: On Premises -# -# ------------------------------------------------------------------------------ - -version: '3.1' - -services: - loadbalancer: - image: openvidu/openvidu-proxy:2.30.0 - restart: always - volumes: - - ./certificates:/etc/letsencrypt - - ./owncert:/owncert - - ./custom-nginx-vhosts:/etc/nginx/vhost.d/ - - ./custom-nginx-locations:/custom-nginx-locations - - ${OPENVIDU_RECORDING_CUSTOM_LAYOUT:-/opt/openvidu/custom-layout}:/opt/openvidu/custom-layout - ports: - # Nginx letsencrypt port - - "${HTTP_PORT:-80}:${HTTP_PORT:-80}" - # External Load Balancer port - - "${HTTPS_PORT:-443}:${HTTPS_PORT:-443}" - # Internal Load Balancer port - - 5443:5443 - environment: - - DOMAIN_OR_PUBLIC_IP=${DOMAIN_OR_PUBLIC_IP} - - CERTIFICATE_TYPE=${CERTIFICATE_TYPE} - - LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL} - - OPENVIDU_ENTERPRISE_HA_NODE_IPS=${OPENVIDU_ENTERPRISE_HA_NODE_IPS} - - PROXY_HTTP_PORT=${HTTP_PORT:-} - - PROXY_HTTPS_PORT=${HTTPS_PORT:-} - - PROXY_HTTPS_PROTOCOLS=${HTTPS_PROTOCOLS:-} - - PROXY_HTTPS_CIPHERS=${HTTPS_CIPHERS:-} - - PROXY_HTTPS_HSTS=${HTTPS_HSTS:-} - - ALLOWED_ACCESS_TO_DASHBOARD=${ALLOWED_ACCESS_TO_DASHBOARD:-} - - ALLOWED_ACCESS_TO_RESTAPI=${ALLOWED_ACCESS_TO_RESTAPI:-} - - PROXY_MODE=ENTERPRISE_HA - - WITH_APP=true - - REDIRECT_WWW=${REDIRECT_WWW:-false} - - WORKER_CONNECTIONS=${WORKER_CONNECTIONS:-10240} - - PUBLIC_IP=${PROXY_PUBLIC_IP:-auto-ipv4} - logging: - options: - max-size: "${DOCKER_LOGS_MAX_SIZE:-100M}" - - minio-s3: - image: minio/minio:RELEASE.2023-01-06T18-11-18Z - restart: always - environment: - - MINIO_ACCESS_KEY=${OPENVIDU_ENTERPRISE_HA_S3_CONFIG_ACCESS_KEY} - - MINIO_SECRET_KEY=${OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY} - - MINIO_BROWSER_REDIRECT_URL=https://${DOMAIN_OR_PUBLIC_IP}:${HTTPS_PORT:-443}/minio/ - - CONSOLE_SUBPATH=/minio/ - volumes: - - ./minio-s3:/data - ports: - - "9000:9000" - - "9001:9001" - command: server --console-address ":9001" /data - logging: - options: - max-size: "${DOCKER_LOGS_MAX_SIZE:-100M}" - - createbuckets: - image: minio/mc:RELEASE.2022-12-24T15-21-38Z - depends_on: - - minio-s3 - entrypoint: > - /bin/sh -c " - /usr/bin/mc config host add openvidu-minio \ - http://minio-s3:9000 \ - '${OPENVIDU_ENTERPRISE_HA_S3_CONFIG_ACCESS_KEY}' \ - '${OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY}'; - /usr/bin/mc mb 'openvidu-minio/${OPENVIDU_ENTERPRISE_HA_S3_CONFIG_BUCKET}'; - exit 0; - " - - redis: - image: redis:7.0.8-alpine - restart: always - ports: - - "${OPENVIDU_ENTERPRISE_HA_REDIS_PORT:-6379}:${OPENVIDU_ENTERPRISE_HA_REDIS_PORT:-6379}" - command: /bin/sh -c "redis-server - --bind 0.0.0.0 - --port ${OPENVIDU_ENTERPRISE_HA_REDIS_PORT:-6379} - --requirepass ${OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD}" - logging: - options: - max-size: "${DOCKER_LOGS_MAX_SIZE:-100M}" - - elasticsearch: - image: openvidu/openvidu-elasticsearch:7.8.0 - restart: always - environment: - - discovery.type=single-node - - xpack.security.enabled=true - - "ES_JAVA_OPTS=${ES_JAVA_OPTS:--Xms2g -Xmx2g}" - ports: - - 9200:9200 - volumes: - - ./elasticsearch:/usr/share/elasticsearch/data - command: > - /bin/bash -c "elasticsearch-users useradd ${ELASTICSEARCH_USERNAME} - -p ${ELASTICSEARCH_PASSWORD} -r superuser; - elasticsearch-users passwd ${ELASTICSEARCH_USERNAME} -p ${ELASTICSEARCH_PASSWORD}; - docker-entrypoint.sh" - logging: - options: - max-size: "${DOCKER_LOGS_MAX_SIZE:-100M}" - - kibana: - image: docker.elastic.co/kibana/kibana:7.8.0 - restart: always - environment: - - SERVER_BASEPATH="/kibana" - - xpack.security.enabled=true - - ELASTICSEARCH_USERNAME=${ELASTICSEARCH_USERNAME} - - ELASTICSEARCH_PASSWORD=${ELASTICSEARCH_PASSWORD} - ports: - - 5601:5601 - logging: - options: - max-size: "${DOCKER_LOGS_MAX_SIZE:-100M}" \ No newline at end of file diff --git a/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/install_ov_enterprise_ha_base.sh b/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/install_ov_enterprise_ha_base.sh deleted file mode 100644 index 3b06dd4b3c..0000000000 --- a/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/install_ov_enterprise_ha_base.sh +++ /dev/null @@ -1,324 +0,0 @@ -#!/usr/bin/env bash - -# Global variables -OPENVIDU_FOLDER=ov-enterprise-base-services -ELASTICSEARCH_FOLDER=${OPENVIDU_FOLDER}/elasticsearch -OPENVIDU_VERSION=master -OPENVIDU_UPGRADABLE_VERSION="2.30" -DOWNLOAD_URL=https://raw.githubusercontent.com/OpenVidu/openvidu/${OPENVIDU_VERSION} - -# Support docker compose v1 and v2 -shopt -s expand_aliases -alias docker-compose='docker compose' -if ! docker compose version &> /dev/null; then - unalias docker-compose -fi - -# Change default http timeout for slow networks -export COMPOSE_HTTP_TIMEOUT=500 -export DOCKER_CLIENT_TIMEOUT=500 - -pull_images() { - OV_DIRECTORY="$1" - pushd "${OV_DIRECTORY}" > /dev/null || fatal_error "Error: can not access to '${OV_DIRECTORY}' folder" - ALL_IMAGES=$(grep -h 'image:' docker-compose.yml docker-compose.override.yml | awk '{print $2}') - for IMAGE in ${ALL_IMAGES}; do - docker pull "${IMAGE}" || fatal_error "Error while pulling image '${IMAGE}'" - done - popd > /dev/null || fatal_error "Error: can not access to previous folder" -} - -fatal_error() { - printf "\n =======¡ERROR!=======" - printf "\n %s" "$1" - printf "\n" - exit 1 -} - -new_ov_installation() { - printf '\n' - printf '\n =======================================' - printf '\n Install OpenVidu Enterprise HA Base Services %s' "${OPENVIDU_VERSION}" - printf '\n =======================================' - printf '\n' - - # Create folder openvidu-docker-compose - printf '\n => Creating folder '%s'...' "${OPENVIDU_FOLDER}" - mkdir "${OPENVIDU_FOLDER}" || fatal_error "Error while creating the folder '${OPENVIDU_FOLDER}'" - - # Create elasticsearch folder - printf "\n => Creating folder 'elasticsearch'..." - mkdir -p "${ELASTICSEARCH_FOLDER}" || fatal_error "Error while creating the folder 'elasticsearch'" - - printf "\n => Changing permission to 'elasticsearch' folder..." - chown 1000:1000 "${ELASTICSEARCH_FOLDER}" || fatal_error "Error while changing permission to 'elasticsearch' folder" - - # Download necessary files - printf '\n => Downloading OpenVidu Enterprise HA files:' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/.env \ - --output "${OPENVIDU_FOLDER}/.env" || fatal_error "Error when downloading the file '.env'" - printf '\n - .env' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/docker-compose.yml \ - --output "${OPENVIDU_FOLDER}/docker-compose.yml" || fatal_error "Error when downloading the file 'docker-compose.yml'" - printf '\n - docker-compose.yml' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/docker-compose.override.yml \ - --output "${OPENVIDU_FOLDER}/docker-compose.override.yml" || fatal_error "Error when downloading the file 'docker-compose.override.yml'" - printf '\n - docker-compose.override.yml' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/base-services \ - --output "${OPENVIDU_FOLDER}/base-services" || fatal_error "Error when downloading the file 'base-services'" - printf '\n - base-services' - - # Add execution permissions - printf "\n => Adding permission:" - - chmod +x "${OPENVIDU_FOLDER}/base-services" || fatal_error "Error while adding permission to 'base-services' program" - printf '\n - base-services' - - # Pull all docker images - pull_images "${OPENVIDU_FOLDER}" - - # Ready to use - printf '\n' - printf '\n' - printf '\n =======================================' - printf '\n OpenVidu Enterprise HA successfully installed.' - printf '\n =======================================' - printf '\n' - printf '\n 1. Go to openvidu folder:' - printf '\n ------------------------------------------------' - printf '\n $ cd ov-enterprise-base-services' - printf '\n ------------------------------------------------' - printf '\n' - printf '\n' - printf '\n 2. Configure the .env file with your own values:' - printf '\n Check the documentation for more information:' - printf '\n https://docs.openvidu.io/en/%s/deployment/enterprise/on-premises/#high-availability-deployment' "${OPENVIDU_VERSION//v}" - printf '\n ------------------------------------------------' - printf '\n $ nano .env' - printf '\n ------------------------------------------------' - printf '\n' - printf '\n' - printf '\n 3. Start OpenVidu Enterprise HA Base Services:' - printf '\n ------------------------------------------------' - printf '\n $ ./base-services start' - printf '\n ------------------------------------------------' - printf '\n' - printf '\n' - printf '\n' - exit 0 -} - -get_previous_env_variable() { - local ENV_VARIABLE_NAME=$1 - echo "$(grep -E "${ENV_VARIABLE_NAME}=.*$" "${OPENVIDU_PREVIOUS_FOLDER}/.env" | cut -d'=' -f2)" -} - -replace_variable_in_new_env_file() { - local ENV_VARIABLE_NAME=$1 - local ENV_VARIABLE_VALUE=$2 - [[ -n "${ENV_VARIABLE_VALUE}" ]] && sed -i "s|#${ENV_VARIABLE_NAME}=|${ENV_VARIABLE_NAME}=${ENV_VARIABLE_VALUE}|" "${OPENVIDU_PREVIOUS_FOLDER}/.env-${OPENVIDU_VERSION}" -} - -upgrade_ov() { - # Search local Openvidu installation - printf '\n' - printf '\n =========================================================' - printf '\n Search Previous Installation of Openvidu Enterprise HA' - printf '\n =========================================================' - printf '\n' - - SEARCH_IN_FOLDERS=( - "${PWD}" - "/opt/${OPENVIDU_FOLDER}" - ) - - for folder in "${SEARCH_IN_FOLDERS[@]}"; do - printf "\n => Searching in '%s' folder..." "${folder}" - - if [ -f "${folder}/docker-compose.yml" ]; then - OPENVIDU_PREVIOUS_FOLDER="${folder}" - - printf "\n => Found installation in folder '%s'" "${folder}" - break - fi - done - - [ -z "${OPENVIDU_PREVIOUS_FOLDER}" ] && fatal_error "No previous Openvidu installation found" - - # Upgrade Openvidu - OPENVIDU_PREVIOUS_VERSION=$(grep 'Openvidu Version:' "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.yml" | awk '{ print $4 }') - [ -z "${OPENVIDU_PREVIOUS_VERSION}" ] && fatal_error "Can't find previous OpenVidu version" - - # In this point using the variable 'OPENVIDU_PREVIOUS_VERSION' we can verify if the upgrade is - # posible or not. If it is not posible launch a warning and stop the upgrade. - if [[ "${OPENVIDU_PREVIOUS_VERSION}" != "${OPENVIDU_UPGRADABLE_VERSION}."* ]] && [[ "${OPENVIDU_PREVIOUS_VERSION}" != "${OPENVIDU_VERSION//v}"* ]]; then - fatal_error "You can't update from version ${OPENVIDU_PREVIOUS_VERSION} to ${OPENVIDU_VERSION}.\nNever upgrade across multiple major versions." - fi - - printf '\n' - printf '\n =======================================' - printf '\n Upgrade OpenVidu Enterprise HA base services %s to %s' "${OPENVIDU_PREVIOUS_VERSION}" "${OPENVIDU_VERSION}" - printf '\n =======================================' - printf '\n' - - ROLL_BACK_FOLDER="${OPENVIDU_PREVIOUS_FOLDER}/.old-${OPENVIDU_PREVIOUS_VERSION}" - TMP_FOLDER="${OPENVIDU_PREVIOUS_FOLDER}/tmp" - ACTUAL_FOLDER="${PWD}" - - printf "\n Creating rollback folder '%s'..." ".old-${OPENVIDU_PREVIOUS_VERSION}" - mkdir "${ROLL_BACK_FOLDER}" || fatal_error "Error while creating the folder '.old-${OPENVIDU_PREVIOUS_VERSION}'" - - printf "\n Creating temporal folder 'tmp'..." - mkdir "${TMP_FOLDER}" || fatal_error "Error while creating the folder 'temporal'" - - # Download necessary files - printf '\n => Downloading new OpenVidu Enterprise HA base services files:' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/.env \ - --output "${TMP_FOLDER}/.env" || fatal_error "Error when downloading the file '.env'" - printf '\n - .env' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/docker-compose.yml \ - --output "${TMP_FOLDER}/docker-compose.yml" || fatal_error "Error when downloading the file 'docker-compose.yml'" - printf '\n - docker-compose.yml' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/docker-compose.override.yml \ - --output "${TMP_FOLDER}/docker-compose.override.yml" || fatal_error "Error when downloading the file 'docker-compose.override.yml'" - printf '\n - docker-compose.override.yml' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/base-services/base-services \ - --output "${TMP_FOLDER}/base-services" || fatal_error "Error when downloading the file 'base-services'" - printf '\n - base-services' - - # Downloading new images and stopped actual Openvidu - printf '\n => Downloading new images...' - printf '\n' - sleep 1 - - printf "\n => Moving to 'tmp' folder..." - printf '\n' - cd "${TMP_FOLDER}" || fatal_error "Error when moving to 'tmp' folder" - printf '\n' - docker-compose pull || true - - printf '\n => Stopping base services...' - printf '\n' - sleep 1 - - printf "\n => Moving to 'base-services' folder..." - printf '\n' - cd "${OPENVIDU_PREVIOUS_FOLDER}" || fatal_error "Error when moving to 'base-services' folder" - printf '\n' - docker-compose down || true - - printf '\n' - printf '\n => Moving to working dir...' - cd "${ACTUAL_FOLDER}" || fatal_error "Error when moving to working dir" - - # Move old files to rollback folder - printf '\n => Moving previous installation files to rollback folder:' - - mv "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.yml" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous 'docker-compose.yml'" - printf '\n - docker-compose.yml' - - mv "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.override.yml" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous 'docker-compose.override.yml'" - printf '\n - docker-compose.override.yml' - - mv "${OPENVIDU_PREVIOUS_FOLDER}/base-services" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous 'base-services'" - printf '\n - base-services' - - cp "${OPENVIDU_PREVIOUS_FOLDER}/.env" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous '.env'" - printf '\n - .env' - - # Move tmp files to Openvidu - printf '\n => Updating files:' - - mv "${TMP_FOLDER}/docker-compose.yml" "${OPENVIDU_PREVIOUS_FOLDER}" || fatal_error "Error while updating 'docker-compose.yml'" - printf '\n - docker-compose.yml' - - mv "${TMP_FOLDER}/docker-compose.override.yml" "${OPENVIDU_PREVIOUS_FOLDER}" || fatal_error "Error while updating 'docker-compose.override.yml'" - printf '\n - docker-compose.override.yml' - - mv "${TMP_FOLDER}/.env" "${OPENVIDU_PREVIOUS_FOLDER}/.env-${OPENVIDU_VERSION}" || fatal_error "Error while moving previous '.env'" - printf '\n - .env-%s' "${OPENVIDU_VERSION}" - - mv "${TMP_FOLDER}/base-services" "${OPENVIDU_PREVIOUS_FOLDER}" || fatal_error "Error while updating 'base-services'" - printf '\n - base-services' - - printf "\n => Deleting 'tmp' folder" - rm -rf "${TMP_FOLDER}" || fatal_error "Error deleting 'tmp' folder" - - # Add execution permissions - printf "\n => Adding permission to 'base-services' program..." - - chmod +x "${OPENVIDU_PREVIOUS_FOLDER}/base-services" || fatal_error "Error while adding permission to 'base-services' program" - printf '\n - base-services' - - # Define old mode: On Premise or Cloud Formation - OLD_MODE=$(grep -E "Installation Mode:.*$" "${ROLL_BACK_FOLDER}/docker-compose.yml" | awk '{ print $4,$5 }') - [ -n "${OLD_MODE}" ] && sed -i -r "s/Installation Mode:.+/Installation Mode: ${OLD_MODE}/" "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.yml" - - pull_images "${OPENVIDU_PREVIOUS_FOLDER}" - - # Ready to use - printf '\n' - printf '\n' - printf '\n ================================================' - printf "\n Openvidu Enterprise HA base services successfully upgraded to version %s" "${OPENVIDU_VERSION}" - printf '\n ================================================' - printf '\n' - printf "\n 1. A new file 'docker-compose.yml' has been created with the new OpenVidu Enterprise HA %s services" "${OPENVIDU_VERSION}" - printf '\n' - printf "\n 2. The previous file '.env' remains intact, but a new file '.env-%s' has been created." "${OPENVIDU_VERSION}" - printf "\n Transfer any configuration you wish to keep in the upgraded version from '.env' to '.env-%s'." "${OPENVIDU_VERSION}" - printf "\n When you are OK with it, rename and leave as the only '.env' file of the folder the new '.env-%s'." "${OPENVIDU_VERSION}" - printf '\n' - printf "\n 3. If you were using Openvidu Call application, it has been automatically updated in file 'docker-compose.override.yml'." - printf "\n However, if you were using your own application, a file called 'docker-compose.override.yml-%s'" "${OPENVIDU_VERSION}" - printf "\n has been created with the latest version of Openvidu Call. If you don't plan to use it you can delete it." - printf '\n' - printf '\n 3. Start new versions of Openvidu Enterprise HA Base Services' - printf '\n ------------------------------------------------' - printf '\n $ ./base-services start' - printf '\n ------------------------------------------------' - printf '\n' - printf "\n If you want to rollback, all the files from the previous installation have been copied to folder '.old-%s'" "${OPENVIDU_PREVIOUS_VERSION}" - printf '\n' - printf '\n' - printf '\n' -} - -# Check docker and docker-compose installation -if ! command -v docker > /dev/null; then - echo "You don't have docker installed, please install it and re-run the command" - exit 1 -else - # Check version of docker is equal or higher than 20.10.10 - DOCKER_VERSION=$(docker version --format '{{.Server.Version}}' | sed "s/-rc[0-9]*//") - if ! printf '%s\n%s\n' "20.10.10" "$DOCKER_VERSION" | sort -V -C; then - echo "You need a docker version equal or higher than 20.10.10, please update your docker and re-run the command"; \ - exit 1 - fi -fi - -if ! command -v docker-compose > /dev/null; then - echo "You don't have docker-compose installed, please install it and re-run the command" - exit 1 -else - COMPOSE_VERSION=$(docker-compose version --short | sed "s/-rc[0-9]*//") - if ! printf '%s\n%s\n' "1.24" "$COMPOSE_VERSION" | sort -V -C; then - echo "You need a docker-compose version equal or higher than 1.24, please update your docker-compose and re-run the command"; \ - exit 1 - fi -fi - -# Check type of installation -if [[ -n "$1" && "$1" == "upgrade" ]]; then - upgrade_ov "$2" -else - new_ov_installation -fi \ No newline at end of file diff --git a/openvidu-server/deployments/enterprise-ha/docker-compose/node/.env b/openvidu-server/deployments/enterprise-ha/docker-compose/node/.env deleted file mode 100644 index d7284f8a09..0000000000 --- a/openvidu-server/deployments/enterprise-ha/docker-compose/node/.env +++ /dev/null @@ -1,327 +0,0 @@ -# OpenVidu configuration -# ---------------------- -# Documentation: https://docs.openvidu.io/en/stable/reference-docs/openvidu-config/ -# NOTE: This file doesn't need to quote assignment values, like most shells do. -# All values are stored as-is, even if they contain spaces, so don't quote them. - - - - -# -------------------------- -# OpenVidu Enterprise HA - General configuration: -# -------------------------- - -# Domain name. If you do not have one, the public IP of the machine. -# For example: 198.51.100.1, or openvidu.example.com -DOMAIN_OR_PUBLIC_IP= - -# OpenVidu Pro License -OPENVIDU_PRO_LICENSE= - -# OpenVidu SECRET used for apps to connect to OpenVidu server and users to access to OpenVidu Dashboard -OPENVIDU_SECRET= - -# Media Server to use -# Possible values are: -# - kurento -# - mediasoup -OPENVIDU_ENTERPRISE_MEDIA_SERVER=mediasoup - -# Port used for the Load Balancer in front of OpenVidu Enterprise Nodes -HTTPS_PORT=443 - - - - -# ---------------------- -# OpenVidu Enterprise HA - Clustering and S3 Configuration: -# ---------------------- - -# This is the IP address that will be used by the node to communicate with the other nodes in the cluster. -OPENVIDU_ENTERPRISE_HA_NODE_PRIVATE_IP= - -# These parameters are used to configure the Redis server used by the cluster. -OPENVIDU_ENTERPRISE_HA_REDIS_HOST= -OPENVIDU_ENTERPRISE_HA_REDIS_PORT= -OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD= - -# This parameter is used to configure the S3 service endpoint used by the cluster to store the global configuration file. -OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SERVICE_ENDPOINT= - -# The specified s3 bucket will be used to store a global configuration file that is used by all the nodes in the cluster. -OPENVIDU_ENTERPRISE_HA_S3_CONFIG_BUCKET= - -# Access key for the s3 bucket defined at OPENVIDU_ENTERPRISE_HA_S3_CONFIG_BUCKET -OPENVIDU_ENTERPRISE_HA_S3_CONFIG_ACCESS_KEY= - -# Secret key for the s3 bucket defined at OPENVIDU_ENTERPRISE_HA_S3_CONFIG_BUCKET -OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY= - -# Region where the s3 bucket defined at OPENVIDU_ENTERPRISE_HA_S3_CONFIG_BUCKET is located -OPENVIDU_ENTERPRISE_HA_S3_CONFIG_REGION= - -# Optional. Use path style access for the s3 bucket defined at OPENVIDU_ENTERPRISE_HA_S3_CONFIG_BUCKET -# Default value is: false -# Check https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#path-style-access -# With Minio, this property must be set to true -OPENVIDU_ENTERPRISE_HA_S3_CONFIG_PATH_STYLE_ACCESS=true - -# Optional: If your S3 bucket needs some specific headers to be set, you can define them here. -# This property is a key-value map of strings, following the format of a JSON object. -# For example, for applying server-side encryption with AES-256, this header is mandatory: -# {"x-amz-server-side-encryption":"AES256"}. -# The list of available headers can be found here: https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/Headers.html -# OPENVIDU_ENTERPRISE_HA_S3_CONFIG_HEADERS= - -# -------------------------- -# OpenVidu Enterprise HA -Kibana And ElasticSearch Configuration -# -------------------------- -# If you want to use Elasticsearch and Kibana, this variable should be set to true. -OPENVIDU_PRO_ELASTICSEARCH=true - -# Put here the url to elasticsearch and kibana services if OPENVIDU_PRO_ELASTICSEARCH=true -# If you want to use the deployed Elasticsearch and Kibana locally, keep these variables commented. -OPENVIDU_PRO_ELASTICSEARCH_HOST= -OPENVIDU_PRO_KIBANA_HOST= - -# Kibana And ElasticSearch Basic Auth configuration (Credentials) -# This credentials will aso be valid for Kibana dashboard -ELASTICSEARCH_USERNAME=elasticadmin -ELASTICSEARCH_PASSWORD= - - - - -# -------------------------- -# OpenVidu Enterprise HA - Other configuration parameters -# -------------------------- - -# What parameter should be used to distribute the creation of new sessions -# (and therefore distribution of load) among all available Media Nodes -OPENVIDU_PRO_CLUSTER_LOAD_STRATEGY=streams - -# Whether to enable or disable Network Quality API. You can monitor and -# warn users about the quality of their networks with this feature -# OPENVIDU_PRO_NETWORK_QUALITY=false - -# If OPENVIDU_PRO_NETWORK_QUALITY=true, how often the network quality -# algorithm will be invoked for each user, in seconds -# OPENVIDU_PRO_NETWORK_QUALITY_INTERVAL=5 - -# Max days until delete indexes in state of rollover on Elasticsearch -# Type number >= 0 -# Default Value is 7 -# OPENVIDU_PRO_ELASTICSEARCH_MAX_DAYS_DELETE= - -# Speech To Text service module to be enabled. Can be: [disabled, vosk, azure] -# Default is disabled -# OPENVIDU_PRO_SPEECH_TO_TEXT=disabled - -# Speech To Text service module Docker image to be used in media nodes -# This parameter is empty by default, because the default image is the one provided by OpenVidu -# If defined, it will override the default image -# OPENVIDU_PRO_SPEECH_TO_TEXT_IMAGE= - -# If OPENVIDU_PRO_SPEECH_TO_TEXT=azure, Azure key for the Speech To Text service. -# See https://azure.microsoft.com/en-us/products/cognitive-services/speech-to-text/ -# OPENVIDU_PRO_SPEECH_TO_TEXT_AZURE_KEY= - -# If OPENVIDU_PRO_SPEECH_TO_TEXT=azure, Azure region in which the Speech To Text service is located (e.g. 'westeurope'). -# Default value is empty -# See https://azure.microsoft.com/en-us/products/cognitive-services/speech-to-text/" -# OPENVIDU_PRO_SPEECH_TO_TEXT_AZURE_REGION= - -# Where to store recording files. Can be 'local' (local storage) or 's3' (AWS bucket). -# You will need to define a OPENVIDU_PRO_AWS_S3_BUCKET if you use it. -OPENVIDU_PRO_RECORDING_STORAGE=s3 - -# This parameter is used to configure the S3 service endpoint used by the cluster to store recordings -OPENVIDU_PRO_AWS_S3_SERVICE_ENDPOINT= - -# S3 Bucket where to store recording files. May include paths to allow navigating -# folder structures inside the bucket. This property is only taken into account -# if OPENVIDU_PRO_RECORDING_STORAGE=s3 -#OPENVIDU_PRO_AWS_S3_BUCKET= - -# If OPENVIDU_PRO_RECORDING_STORAGE=s3, the collection of HTTP header values that the internal AWS client will use during -# the upload process. The property is a key-value map of strings, following the format of a JSON object. For example, for applying -# server-side encryption with AES-256, this header is mandatory: {"x-amz-server-side-encryption":"AES256"}. -# The list of available headers can be found here: https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/Headers.html -# This property is only taken into account if OPENVIDU_PRO_RECORDING_STORAGE=s3 -#OPENVIDU_PRO_AWS_S3_HEADERS= - -# This property applies to OPENVIDU_PRO_RECORDING_STORAGE=s3 and/or OPENVIDU_PRO_SPEECH_TO_TEXT=aws. -# It is the AWS long-lived credentials access key. Depending on the service you have enabled: -# - OPENVIDU_PRO_RECORDING_STORAGE=s3: Must have read and write permissions over the bucket defined in property -# OPENVIDU_PRO_AWS_S3_BUCKET. In this case credentials are optional: -# if not provided the internal S3 client will try to use the default AWS credentials of the Master Node, if available -# - OPENVIDU_PRO_SPEECH_TO_TEXT=aws: Must have permissions to manage Amazon Transcribe services. -# In this case credentials are mandatory. -# OPENVIDU_PRO_AWS_ACCESS_KEY= - -# This property applies to OPENVIDU_PRO_RECORDING_STORAGE=s3 and/or OPENVIDU_PRO_SPEECH_TO_TEXT=aws. -# It is the AWS long-lived credentials secret key. Depending on the service you have enabled: -# - OPENVIDU_PRO_RECORDING_STORAGE=s3: In this case credentials are optional: if not provided then the internal -# S3 client will try to use the default AWS credentials of the machine, if available. -# - OPENVIDU_PRO_SPEECH_TO_TEXT=aws: In this case credentials are mandatory. -# OPENVIDU_PRO_AWS_SECRET_KEY= - - -# This property applies to OPENVIDU_PRO_RECORDING_STORAGE=s3 and/or OPENVIDU_PRO_SPEECH_TO_TEXT=aws. -# It is the AWS region hosting the services. Depending on the service you have enabled: -# - OPENVIDU_PRO_RECORDING_STORAGE=s3: AWS region in which the S3 bucket is located (e.g. "eu-west-1"). -# If not provided, the region will try to be discovered automatically, although this is not always possible. -# - OPENVIDU_PRO_SPEECH_TO_TEXT=aws: AWS region where Amazon Transcribe will operate. In this case the property is always mandatory. -#OPENVIDU_PRO_AWS_REGION= - -# Optional. Use path style access for the s3 bucket defined at OPENVIDU_ENTERPRISE_HA_S3_CONFIG_BUCKET -# Default value is: false -# Check https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#path-style-access -# With Minio, this property must be set to true -OPENVIDU_PRO_AWS_S3_WITH_PATH_STYLE_ACCESS=true - -# Whether to enable recording module or not -OPENVIDU_RECORDING=false - -# Use recording module with debug mode. -OPENVIDU_RECORDING_DEBUG=false - -# Openvidu Folder Record used for save the openvidu recording videos. Change it -# with the folder you want to use from your host. -OPENVIDU_RECORDING_PATH=/opt/openvidu/recordings - -# System path where OpenVidu Server should look for custom recording layouts -OPENVIDU_RECORDING_CUSTOM_LAYOUT=/opt/openvidu/custom-layout - -# if true any client can connect to -# https://OPENVIDU_SERVER_IP:OPENVIDU_PORT/recordings/any_session_file.mp4 -# and access any recorded video file. If false this path will be secured with -# OPENVIDU_SECRET param just as OpenVidu Server dashboard at -# https://OPENVIDU_SERVER_IP:OPENVIDU_PORT -# Values: true | false -OPENVIDU_RECORDING_PUBLIC_ACCESS=false - -# Which users should receive the recording events in the client side -# (recordingStarted, recordingStopped). Can be all (every user connected to -# the session), publisher_moderator (users with role 'PUBLISHER' or -# 'MODERATOR'), moderator (only users with role 'MODERATOR') or none -# (no user will receive these events) -OPENVIDU_RECORDING_NOTIFICATION=publisher_moderator - -# Timeout in seconds for recordings to automatically stop (and the session involved to be closed) -# when conditions are met: a session recording is started but no user is publishing to it or a session -# is being recorded and last user disconnects. If a user publishes within the timeout in either case, -# the automatic stop of the recording is cancelled -# 0 means no timeout -OPENVIDU_RECORDING_AUTOSTOP_TIMEOUT=120 - -# Maximum video bandwidth sent from clients to OpenVidu Server, in kbps. -# 0 means unconstrained -OPENVIDU_STREAMS_VIDEO_MAX_RECV_BANDWIDTH=1000 - -# Minimum video bandwidth sent from clients to OpenVidu Server, in kbps. -# 0 means unconstrained -OPENVIDU_STREAMS_VIDEO_MIN_RECV_BANDWIDTH=300 - -# Maximum video bandwidth sent from OpenVidu Server to clients, in kbps. -# 0 means unconstrained -OPENVIDU_STREAMS_VIDEO_MAX_SEND_BANDWIDTH=1000 - -# Minimum video bandwidth sent from OpenVidu Server to clients, in kbps. -# 0 means unconstrained -OPENVIDU_STREAMS_VIDEO_MIN_SEND_BANDWIDTH=300 - -# All sessions of OpenVidu will try to force this codec. If OPENVIDU_STREAMS_ALLOW_TRANSCODING=true -# when a codec can not be forced, transcoding will be allowed -# Values: MEDIA_SERVER_PREFERRED, NONE, VP8, VP9, H264 -# Default value is MEDIA_SERVER_PREFERRED -# OPENVIDU_STREAMS_FORCED_VIDEO_CODEC=MEDIA_SERVER_PREFERRED - -# Allow transcoding if codec specified in OPENVIDU_STREAMS_FORCED_VIDEO_CODEC can not be applied -# Values: true | false -# Default value is false -# OPENVIDU_STREAMS_ALLOW_TRANSCODING=false - -# Use Simulcast video on WebRTC Publishers. -# Senders will encode duplicate video streams with different qualities, -# so the media server is able to select the most appropriate quality stream -# for each Subscriber. -# This setting is honored only if OpenVidu Server was configured to use the -# mediasoup media server. Otherwise, Simulcast will be disabled. -# Values: true | false -# Default: false -#OPENVIDU_WEBRTC_SIMULCAST=false - -# Send openvidu-browser logs of clients to Elasticsearch -# Possible values: -# - disabled: Don't send logs. (default) -# - debug: Send all openvidu-browser logs -# - debug_app: Send openvidu-browser logs and frontend app logs -# OPENVIDU_BROWSER_LOGS=disabled - -# true to enable OpenVidu Webhook service. false' otherwise -# Values: true | false -OPENVIDU_WEBHOOK=false - -# HTTP endpoint where OpenVidu Server will send Webhook HTTP POST messages -# Must be a valid URL: http(s)://ENDPOINT -#OPENVIDU_WEBHOOK_ENDPOINT= - -# List of headers that OpenVidu Webhook service will attach to HTTP POST messages -#OPENVIDU_WEBHOOK_HEADERS= - -# List of events that will be sent by OpenVidu Webhook service -# Default value is all available events -OPENVIDU_WEBHOOK_EVENTS=[sessionCreated,sessionDestroyed,participantJoined,participantLeft,webrtcConnectionCreated,webrtcConnectionDestroyed,recordingStatusChanged,filterEventDispatched,mediaNodeStatusChanged,nodeCrashed,nodeRecovered,HANodeRegistered,HANodeDeregistered] - -# How often the garbage collector of non active sessions runs. -# This helps cleaning up sessions that have been initialized through -# REST API (and maybe tokens have been created for them) but have had no users connected. -# Default to 900s (15 mins). 0 to disable non active sessions garbage collector -OPENVIDU_SESSIONS_GARBAGE_INTERVAL=900 - -# Minimum time in seconds that a non active session must have been in existence -# for the garbage collector of non active sessions to remove it. Default to 3600s (1 hour). -# If non active sessions garbage collector is disabled -# (property 'OPENVIDU_SESSIONS_GARBAGE_INTERVAL' to 0) this property is ignored -OPENVIDU_SESSIONS_GARBAGE_THRESHOLD=3600 - -# Call Detail Record enabled -# Whether to enable Call Detail Record or not -# Values: true | false -OPENVIDU_CDR=false - -# Path where the cdr log files are hosted -OPENVIDU_CDR_PATH=/opt/openvidu/cdr - -# Openvidu Server Level logs -# -------------------------- -# Uncomment the next line and define this variable to change -# the verbosity level of the logs of Openvidu Service -# RECOMENDED VALUES: INFO for normal logs DEBUG for more verbose logs -# OV_CE_DEBUG_LEVEL=INFO - -# OpenVidu Java Options -# -------------------------- -# Uncomment the next line and define this to add options to java command -# Documentation: https://docs.oracle.com/cd/E37116_01/install.111210/e23737/configuring_jvm.htm#OUDIG00058 -# JAVA_OPTIONS=-Xms2048m -Xmx4096m - -# Media Node Configuration -# -------------------------- -# You can add any KMS environment variable as described in the -# documentation of the docker image: https://hub.docker.com/r/kurento/kurento-media-server -# If you want to add an environment variable to KMS, you must add a variable using this prefix: 'KMS_DOCKER_ENV_', -# followed by the environment variable you want to setup. -# For example if you want to setup KMS_MIN_PORT to 50000, it would be KMS_DOCKER_ENV_KMS_MIN_PORT=50000 - -# Docker hub kurento media server: https://hub.docker.com/r/kurento/kurento-media-server -# Uncomment the next line and define this variable with KMS image that you want use -# By default, KMS_IMAGE is defined in media nodes and it does not need to be specified unless -# you want to use a specific version of KMS -# KMS_IMAGE=kurento/kurento-media-server:6.18.0 - -# Uncomment the next line and define this variable to change -# the verbosity level of the logs of KMS -# Documentation: https://doc-kurento.readthedocs.io/en/stable/features/logging.html -# KMS_DOCKER_ENV_GST_DEBUG= diff --git a/openvidu-server/deployments/enterprise-ha/docker-compose/node/beats/filebeat.yml b/openvidu-server/deployments/enterprise-ha/docker-compose/node/beats/filebeat.yml deleted file mode 100644 index 5d46b2c1ea..0000000000 --- a/openvidu-server/deployments/enterprise-ha/docker-compose/node/beats/filebeat.yml +++ /dev/null @@ -1,88 +0,0 @@ -filebeat.inputs: - - type: container - paths: - - '/var/lib/docker/containers/*/*.log' - - type: log - paths: - - /opt/openvidu/kurento-logs/*.log - fields: - kurento-media-server: true - ip: ${MEDIA_NODE_IP} - cluster_id: ${CLUSTER_ID} - node_id: ${NODE_ID} - node_role: medianode - fields_under_root: true - - type: container - paths: - - '/var/lib/docker/containers/*/*.log' - fields: - cluster_id: ${OPENVIDU_PRO_CLUSTER_ID:${DOMAIN_OR_PUBLIC_IP:undefined}} - node_id: master_${AWS_INSTANCE_ID:${OPENVIDU_PRO_CLUSTER_ID:${DOMAIN_OR_PUBLIC_IP:undefined}}} - node_role: masternode - fields_under_root: true - -processors: - - add_docker_metadata: - host: "unix:///var/run/docker.sock" - - add_host_metadata: - netinfo.enabled: true - - - decode_json_fields: - fields: ["message"] - target: "json" - overwrite_keys: true - - drop_event: - when.or: - - contains: - container.image.name: docker.elastic.co/beats/filebeat-oss - - contains: - container.image.name: docker.elastic.co/beats/metricbeat-oss - - contains: - container.image.name: openvidu/openvidu-coturn - - contains: - container.image.name: docker.elastic.co/elasticsearch/elasticsearch - - contains: - container.image.name: docker.elastic.co/kibana/kibana - - contains: - container.image.name: docker.elastic.co/beats/filebeat-oss - - contains: - container.image.name: docker.elastic.co/beats/metricbeat-oss - - contains: - container.image.name: openvidu/openvidu-server-pro - -output: - elasticsearch: - indices: - - index: "filebeat-kurento-%{+yyyy.MM.dd}" - when.or: - - equals: - kurento-media-server: true - - index: "filebeat-mediasoup-%{+yyyy.MM.dd}" - when.or: - - contains: - container.image.name: openvidu/mediasoup-controller - - index: "filebeat-media-node-controller-%{+yyyy.MM.dd}" - when.or: - - contains: - container.image.name: openvidu/media-node-controller - - index: "filebeat-openvidu-recording-%{+yyyy.MM.dd}" - when.or: - - contains: - container.image.name: openvidu/openvidu-recording - - index: "filebeat-nginx-%{+yyyy.MM.dd}" - when.or: - - contains: - container.image.name: openvidu/openvidu-proxy - - index: "filebeat-openvidu-recording-%{+yyyy.MM.dd}" - when.or: - - contains: - container.image.name: openvidu/openvidu-recording - pipelines: - - pipeline: kurento-pipeline - when.or: - - equals: - kurento-media-server: true - -logging.json: true -logging.metrics.enabled: false -setup.ilm.enabled: false \ No newline at end of file diff --git a/openvidu-server/deployments/enterprise-ha/docker-compose/node/beats/metricbeat-elasticsearch.yml b/openvidu-server/deployments/enterprise-ha/docker-compose/node/beats/metricbeat-elasticsearch.yml deleted file mode 100644 index 886a5b49cb..0000000000 --- a/openvidu-server/deployments/enterprise-ha/docker-compose/node/beats/metricbeat-elasticsearch.yml +++ /dev/null @@ -1,44 +0,0 @@ -metricbeat.modules: - - module: nginx - metricsets: ["stubstatus"] - enabled: true - period: ${OPENVIDU_PRO_STATS_MONITORING_INTERVAL}s - hosts: ["http://127.0.0.1"] - server_status_path: "nginx_status" - - module: system - metricsets: - - cpu - - diskio - - memory - - network - - filesystem - - fsstat - #- process - - process_summary - - uptime - filesystem.ignore_types: [nfs, smbfs, autofs, devtmpfs, devpts, hugetlbfs, tmpfs, sysfs, securityfs, cgroup2, cgroup, pstore, debugfs, configfs, fusectl, proc, fuse.lxcfs, squashfs] - processes: ['.*'] - # process.include_top_n: - # by_cpu: 2 - # by_memory: 2 - processors: - - drop_event: - when: - or: - - regexp: - system.network.name: '^(veth|lo|docker|br-)($|)' - - regexp: - system.filesystem.mount_point: '^/(sys|cgroup|proc|dev|etc|host)($|/)' - - regexp: - system.filesystem.mount_point: '^/hostfs/(sys|cgroup|proc|dev|etc|host)($|/)' - enabled: true - period: ${OPENVIDU_PRO_STATS_MONITORING_INTERVAL}s - cpu.metrics: [normalized_percentages] -fields: - ip: "${MEDIA_NODE_IP}" - cluster_id: ${OPENVIDU_PRO_CLUSTER_ID:${DOMAIN_OR_PUBLIC_IP:undefined}} - node_id: master_${AWS_INSTANCE_ID:${OPENVIDU_PRO_CLUSTER_ID:${DOMAIN_OR_PUBLIC_IP:undefined}}} - node_role: masternode -pipeline: - queue.mem.events: 0 -setup.ilm.enabled: false \ No newline at end of file diff --git a/openvidu-server/deployments/enterprise-ha/docker-compose/node/docker-compose.yml b/openvidu-server/deployments/enterprise-ha/docker-compose/node/docker-compose.yml deleted file mode 100644 index d207d5bcf4..0000000000 --- a/openvidu-server/deployments/enterprise-ha/docker-compose/node/docker-compose.yml +++ /dev/null @@ -1,155 +0,0 @@ -# ------------------------------------------------------------------------------ -# -# DO NOT MODIFY THIS FILE !!! -# -# Configuration properties should be specified in .env file -# -# This docker-compose file coordinates all services of OpenVidu Enterprise HA Node -# -# This file will be overridden when update OpenVidu Enterprise HA Node -# -# Openvidu Version: 2.30.0 -# -# Installation Mode: On Premises -# -# ------------------------------------------------------------------------------ - -version: '3.1' - -services: - - openvidu-server: - image: openvidu/openvidu-server-pro:2.30.0 - container_name: openvidu-server - restart: on-failure - network_mode: host - entrypoint: ['/usr/local/bin/entrypoint.sh'] - volumes: - - ./coturn:/run/secrets/coturn - - /var/run/docker.sock:/var/run/docker.sock - - ${OPENVIDU_RECORDING_PATH}:${OPENVIDU_RECORDING_PATH} - - ${OPENVIDU_RECORDING_CUSTOM_LAYOUT}:${OPENVIDU_RECORDING_CUSTOM_LAYOUT} - - ${OPENVIDU_CDR_PATH}:${OPENVIDU_CDR_PATH} - - ./cluster:/opt/openvidu/cluster - - .env:${PWD}/.env - env_file: - - .env - environment: - - SERVER_SSL_ENABLED=false - - SERVER_PORT=5443 - - KMS_URIS=[] - - OPENVIDU_WEBHOOK=false - - OPENVIDU_WEBHOOK_ENDPOINT=http://127.0.0.1:7777/webhook - - MULTI_MASTER_REPLICATION_MANAGER_WEBHOOK=http://127.0.0.1:4443/openvidu/replication-manager-webhook?OPENVIDU_SECRET=${OPENVIDU_SECRET} - - COTURN_IP=${COTURN_IP:-auto-ipv4} - - COTURN_PORT=${COTURN_PORT:-443} - - OPENVIDU_PRO_CLUSTER=true - - OPENVIDU_EDITION=enterprise - - OPENVIDU_PRO_CLUSTER_ENVIRONMENT=${OPENVIDU_PRO_CLUSTER_ENVIRONMENT:-on_premise} - - OPENVIDU_PRO_CLUSTER_MODE=manual - - OPENVIDU_PRO_CLUSTER_AUTOSCALING=false - - OPENVIDU_PRO_RECORDING_STORAGE=${OPENVIDU_PRO_RECORDING_STORAGE:-s3} - - OPENVIDU_PRO_AWS_S3_WITH_PATH_STYLE_ACCESS=${OPENVIDU_PRO_AWS_S3_WITH_PATH_STYLE_ACCESS:-true} - - OPENVIDU_PRO_ELASTICSEARCH=${OPENVIDU_PRO_ELASTICSEARCH:-true} - - OPENVIDU_PRO_KIBANA_HOST=${OPENVIDU_PRO_KIBANA_HOST:-http://127.0.0.1/kibana} - - OPENVIDU_PRO_ELASTICSEARCH_HOST=${OPENVIDU_PRO_ELASTICSEARCH_HOST:-http://127.0.0.1:9200} - - OPENVIDU_PRO_COTURN_IN_MEDIA_NODES=${OPENVIDU_PRO_COTURN_IN_MEDIA_NODES:-false} - - OPENVIDU_PRO_COTURN_PORT_MEDIA_NODES=${OPENVIDU_PRO_COTURN_PORT_MEDIA_NODES:-443} - - OPENVIDU_PRO_MEDIA_NODE_PUBLIC_IP_AUTODISCOVER=${OPENVIDU_PRO_MEDIA_NODE_PUBLIC_IP_AUTODISCOVER:-auto-ipv4} - - OPENVIDU_PRO_CLUSTER_RECONNECTION_TIMEOUT=60 - - WAIT_KIBANA_URL=${OPENVIDU_PRO_KIBANA_HOST:-http://127.0.0.1/kibana} - - MULTI_MASTER_NODE_ID=${OPENVIDU_ENTERPRISE_HA_NODE_PRIVATE_IP} - - DOTENV_PATH=${PWD} - - SUPPORT_DEPRECATED_API=false - logging: - options: - max-size: "${DOCKER_LOGS_MAX_SIZE:-100M}" - - replication-manager: - image: openvidu/replication-manager-on-prem:2.30.0 - container_name: replication-manager - restart: always - network_mode: host - volumes: - - ./:/opt/openvidu - - /var/run/docker.sock:/var/run/docker.sock - environment: - - SERVER_PORT=4443 - - SERVER_SSL_ENABLED=false - - OPENVIDU_SECRET=${OPENVIDU_SECRET} - - LOCAL_OPENVIDU_SERVER_URI=http://127.0.0.1:5443/ - - OPENVIDU_PRO_CLUSTER_ENVIRONMENT=${OPENVIDU_PRO_CLUSTER_ENVIRONMENT:-on_premise} - - OPENVIDU_PRO_LICENSE=${OPENVIDU_PRO_LICENSE:-} - - OPENVIDU_ENTERPRISE_MEDIA_SERVER=${OPENVIDU_ENTERPRISE_MEDIA_SERVER:-} - - OPENVIDU_ENTERPRISE_HA_REDIS_HOST=${OPENVIDU_ENTERPRISE_HA_REDIS_HOST} - - OPENVIDU_ENTERPRISE_HA_REDIS_PORT=${OPENVIDU_ENTERPRISE_HA_REDIS_PORT} - - OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD=${OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD} - - REDIS_TIMEOUT=5 - - REDIS_DB=replicationmanager - - OPENVIDU_ENTERPRISE_HA_NODE_PRIVATE_IP=${OPENVIDU_ENTERPRISE_HA_NODE_PRIVATE_IP} - - OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SERVICE_ENDPOINT=${OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SERVICE_ENDPOINT} - - OPENVIDU_ENTERPRISE_HA_S3_CONFIG_BUCKET=${OPENVIDU_ENTERPRISE_HA_S3_CONFIG_BUCKET} - - OPENVIDU_ENTERPRISE_HA_S3_CONFIG_REGION=${OPENVIDU_ENTERPRISE_HA_S3_CONFIG_REGION:-} - - OPENVIDU_ENTERPRISE_HA_S3_CONFIG_ACCESS_KEY=${OPENVIDU_ENTERPRISE_HA_S3_CONFIG_ACCESS_KEY:-} - - OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY=${OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY:-} - - OPENVIDU_ENTERPRISE_HA_S3_CONFIG_PATH_STYLE_ACCESS=${OPENVIDU_ENTERPRISE_HA_S3_CONFIG_PATH_STYLE_ACCESS:-true} - - OPENVIDU_ENTERPRISE_HA_S3_CONFIG_HEADERS=${OPENVIDU_ENTERPRISE_HA_S3_CONFIG_HEADERS:-} - - OPENVIDU_ENTERPRISE_S3_CONFIG_AUTORESTART=${OPENVIDU_ENTERPRISE_S3_CONFIG_AUTORESTART:-true} - - INITIAL_CONFIG_SYNC=${INITIAL_CONFIG_SYNC:-false} - logging: - options: - max-size: "${DOCKER_LOGS_MAX_SIZE:-100M}" - - coturn: - image: openvidu/openvidu-coturn:2.30.0 - restart: on-failure - env_file: - - .env - ports: - - 443:443/tcp - - 443:443/udp - environment: - - COTURN_INTERNAL_RELAY=${COTURN_INTERNAL_RELAY:-true} - volumes: - - ./coturn:/run/secrets/coturn - command: - - --log-file=stdout - - --external-ip=$$(detect-external-ip) - - --listening-port=${COTURN_PORT:-443} - - --fingerprint - - --min-port=${COTURN_MIN_PORT:-40000} - - --max-port=${COTURN_MAX_PORT:-65535} - - --realm=openvidu - - --verbose - - --use-auth-secret - - --static-auth-secret=$${COTURN_SHARED_SECRET_KEY} - logging: - options: - max-size: "${DOCKER_LOGS_MAX_SIZE:-100M}" - - media-node-controller: - image: openvidu/media-node-controller:2.30.0 - restart: always - ulimits: - core: -1 - environment: - - MEDIA_NODE_CONTROLLER_RECORDINGS_PATH=/opt/openvidu/mncontroller/recordings - - KMS_IMAGE=kurento/kurento-media-server:7.0.1 - - MEDIASOUP_IMAGE=openvidu/mediasoup-controller:2.30.0 - - METRICBEAT_IMAGE=docker.elastic.co/beats/metricbeat-oss:7.8.0 - - FILEBEAT_IMAGE=docker.elastic.co/beats/filebeat-oss:7.8.0 - - OPENVIDU_RECORDING_IMAGE=openvidu/openvidu-recording:2.30.0 - - COTURN_IMAGE=openvidu/openvidu-coturn:2.30.0 - - SPEECH_TO_TEXT_IMAGE=openvidu/speech-to-text-service:2.30.0 - - NO_COLOR=true - ports: - - 3000:3000 - volumes: - - /opt/openvidu/mncontroller/recordings:/opt/openvidu/mncontroller/recordings - - /opt/openvidu/beats:/opt/openvidu/beats - - /var/run/docker.sock:/var/run/docker.sock - - /opt/openvidu/kurento-logs:/opt/openvidu/kurento-logs - - ./beats:/beats - logging: - options: - max-size: "100M" \ No newline at end of file diff --git a/openvidu-server/deployments/enterprise-ha/docker-compose/node/install_openvidu_enterprise_ha_node.sh b/openvidu-server/deployments/enterprise-ha/docker-compose/node/install_openvidu_enterprise_ha_node.sh deleted file mode 100755 index 5eb5a6e5e9..0000000000 --- a/openvidu-server/deployments/enterprise-ha/docker-compose/node/install_openvidu_enterprise_ha_node.sh +++ /dev/null @@ -1,365 +0,0 @@ -#!/usr/bin/env bash - -# Global variables -OPENVIDU_FOLDER=openvidu -OPENVIDU_VERSION=master -OPENVIDU_UPGRADABLE_VERSION="2.30" -BEATS_FOLDER=${OPENVIDU_FOLDER}/beats -DOWNLOAD_URL=https://raw.githubusercontent.com/OpenVidu/openvidu/${OPENVIDU_VERSION} -IMAGES_MEDIA_NODE_CONTROLLER=( - "kurento-media-server" - "docker.elastic.co/beats/filebeat" - "docker.elastic.co/beats/metricbeat" - "openvidu/mediasoup-controller" - "openvidu/openvidu-recording" - "openvidu/speech-to-text-service" -) - -# Support docker compose v1 and v2 -shopt -s expand_aliases -alias docker-compose='docker compose' -if ! docker compose version &> /dev/null; then - unalias docker-compose -fi - -# Change default http timeout for slow networks -export COMPOSE_HTTP_TIMEOUT=500 -export DOCKER_CLIENT_TIMEOUT=500 - -pull_images() { - OV_DIRECTORY="$1" - pushd "${OV_DIRECTORY}" > /dev/null || fatal_error "Error: can not access to '${OV_DIRECTORY}'" - echo "Pulling images..." - for image in "${IMAGES_MEDIA_NODE_CONTROLLER[@]}"; do - IMAGE_PULL="$(grep "$image" docker-compose.yml | cut -d "=" -f2)" - docker pull "$IMAGE_PULL" || fatal_error "Error: can not pull '${IMAGE_PULL}'" - done - DEPLOYMENT_IMAGES=$(grep 'image:' docker-compose.yml | awk '{print $2}') - for IMAGE in ${DEPLOYMENT_IMAGES}; do - docker pull "${IMAGE}" || fatal_error "Error while pulling image '${IMAGE}'" - done - popd > /dev/null || fatal_error "Error: can not access to previous directory" -} - -fatal_error() { - printf "\n =======¡ERROR!=======" - printf "\n %s" "$1" - printf "\n" - exit 1 -} - -new_ov_installation() { - printf '\n' - printf '\n =======================================' - printf '\n Install OpenVidu Enterprise HA %s' "${OPENVIDU_VERSION}" - printf '\n =======================================' - printf '\n' - - # Create folder openvidu-docker-compose - printf '\n => Creating folder '%s'...' "${OPENVIDU_FOLDER}" - mkdir "${OPENVIDU_FOLDER}" || fatal_error "Error while creating the folder '${OPENVIDU_FOLDER}'" - - # Create beats folder - printf "\n => Creating folder 'beats'..." - mkdir -p "${BEATS_FOLDER}" || fatal_error "Error while creating the folder 'beats'" - - # Download necessary files - printf '\n => Downloading OpenVidu Enterprise HA files:' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/node/beats/filebeat.yml \ - --output "${BEATS_FOLDER}/filebeat.yml" || fatal_error "Error when downloading the file 'filebeat.yml'" - printf '\n - filebeat.yml' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/node/beats/metricbeat-elasticsearch.yml \ - --output "${BEATS_FOLDER}/metricbeat-elasticsearch.yml" || fatal_error "Error when downloading the file 'metricbeat-elasticsearch.yml'" - printf '\n - metricbeat-elasticsearch.yml' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/node/.env \ - --output "${OPENVIDU_FOLDER}/.env" || fatal_error "Error when downloading the file '.env'" - printf '\n - .env' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/node/docker-compose.yml \ - --output "${OPENVIDU_FOLDER}/docker-compose.yml" || fatal_error "Error when downloading the file 'docker-compose.yml'" - printf '\n - docker-compose.yml' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/node/openvidu \ - --output "${OPENVIDU_FOLDER}/openvidu" || fatal_error "Error when downloading the file 'openvidu'" - printf '\n - openvidu' - - # Add execution permissions - printf "\n => Adding permission:" - - chmod +x "${OPENVIDU_FOLDER}/openvidu" || fatal_error "Error while adding permission to 'openvidu' program" - printf '\n - openvidu' - - # Change recording folders with all permissions - printf "\n => Adding permission to 'recordings' folder...\n" - mkdir -p "${OPENVIDU_FOLDER}/recordings" - mkdir -p "${OPENVIDU_FOLDER}/mncontroller/recordings" - chmod 777 "${OPENVIDU_FOLDER}/mncontroller/recordings" - - # Pull all docker images - pull_images "${OPENVIDU_FOLDER}" - - # Ready to use - printf '\n' - printf '\n' - printf '\n =======================================' - printf '\n OpenVidu Enterprise HA successfully installed.' - printf '\n =======================================' - printf '\n' - printf '\n 1. Go to openvidu folder:' - printf '\n ------------------------------------------------' - printf '\n $ cd openvidu' - printf '\n ------------------------------------------------' - printf '\n' - printf '\n' - printf '\n 2. Configure the .env file with your own values:' - printf '\n Check the documentation for more information:' - printf '\n https://docs.openvidu.io/en/%s/deployment/enterprise/on-premises/#high-availability-deployment' "${OPENVIDU_VERSION//v}" - printf '\n ------------------------------------------------' - printf '\n $ nano .env' - printf '\n ------------------------------------------------' - printf '\n' - printf '\n' - printf '\n 3. Start OpenVidu' - printf '\n ------------------------------------------------' - printf '\n $ ./openvidu start' - printf '\n ------------------------------------------------' - printf '\n' - printf '\n' - printf '\n' - exit 0 -} - -get_previous_env_variable() { - local ENV_VARIABLE_NAME=$1 - echo "$(grep -E "${ENV_VARIABLE_NAME}=.*$" "${OPENVIDU_PREVIOUS_FOLDER}/.env" | cut -d'=' -f2)" -} - -replace_variable_in_new_env_file() { - local ENV_VARIABLE_NAME=$1 - local ENV_VARIABLE_VALUE=$2 - [[ -n "${ENV_VARIABLE_VALUE}" ]] && sed -i "s|#${ENV_VARIABLE_NAME}=|${ENV_VARIABLE_NAME}=${ENV_VARIABLE_VALUE}|" "${OPENVIDU_PREVIOUS_FOLDER}/.env-${OPENVIDU_VERSION}" -} - -upgrade_ov() { - # Search local Openvidu installation - printf '\n' - printf '\n =========================================================' - printf '\n Search Previous Installation of Openvidu Enterprise HA' - printf '\n =========================================================' - printf '\n' - - SEARCH_IN_FOLDERS=( - "${PWD}" - "/opt/${OPENVIDU_FOLDER}" - ) - - for folder in "${SEARCH_IN_FOLDERS[@]}"; do - printf "\n => Searching in '%s' folder..." "${folder}" - - if [ -f "${folder}/docker-compose.yml" ]; then - OPENVIDU_PREVIOUS_FOLDER="${folder}" - - printf "\n => Found installation in folder '%s'" "${folder}" - break - fi - done - - [ -z "${OPENVIDU_PREVIOUS_FOLDER}" ] && fatal_error "No previous Openvidu installation found" - - # Upgrade Openvidu - OPENVIDU_PREVIOUS_VERSION=$(grep 'Openvidu Version:' "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.yml" | awk '{ print $4 }') - [ -z "${OPENVIDU_PREVIOUS_VERSION}" ] && fatal_error "Can't find previous OpenVidu version" - - # In this point using the variable 'OPENVIDU_PREVIOUS_VERSION' we can verify if the upgrade is - # posible or not. If it is not posible launch a warning and stop the upgrade. - if [[ "${OPENVIDU_PREVIOUS_VERSION}" != "${OPENVIDU_UPGRADABLE_VERSION}."* ]] && [[ "${OPENVIDU_PREVIOUS_VERSION}" != "${OPENVIDU_VERSION//v}"* ]]; then - fatal_error "You can't update from version ${OPENVIDU_PREVIOUS_VERSION} to ${OPENVIDU_VERSION}.\nNever upgrade across multiple major versions." - fi - - # Check installation is a valid OpenVidu edition - if grep -q '.*image:.*\/openvidu-server:.*' "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.yml"; then - fatal_error "You can't upgrade. Installed version is OpenVidu CE" - fi - if ! grep -q '.*image:.*\/replication-manager-on-prem:.*' "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.yml"; then - fatal_error "You can't upgrade. Installed version is OpenVidu PRO" - fi - - printf '\n' - printf '\n =======================================' - printf '\n Upgrade OpenVidu Enterprise HA %s to %s' "${OPENVIDU_PREVIOUS_VERSION}" "${OPENVIDU_VERSION}" - printf '\n =======================================' - printf '\n' - - ROLL_BACK_FOLDER="${OPENVIDU_PREVIOUS_FOLDER}/.old-${OPENVIDU_PREVIOUS_VERSION}" - TMP_FOLDER="${OPENVIDU_PREVIOUS_FOLDER}/tmp" - ACTUAL_FOLDER="${PWD}" - - printf "\n Creating rollback folder '%s'..." ".old-${OPENVIDU_PREVIOUS_VERSION}" - mkdir "${ROLL_BACK_FOLDER}" || fatal_error "Error while creating the folder '.old-${OPENVIDU_PREVIOUS_VERSION}'" - - printf "\n Creating temporal folder 'tmp'..." - mkdir "${TMP_FOLDER}" || fatal_error "Error while creating the folder 'temporal'" - - # Download necessary files - printf '\n => Downloading new OpenVidu Enterprise files:' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/node/beats/filebeat.yml \ - --output "${TMP_FOLDER}/filebeat.yml" || fatal_error "Error when downloading the file 'filebeat.yml'" - printf '\n - filebeat.yml' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/node/beats/metricbeat-elasticsearch.yml \ - --output "${TMP_FOLDER}/metricbeat-elasticsearch.yml" || fatal_error "Error when downloading the file 'metricbeat-elasticsearch.yml'" - printf '\n - metricbeat-elasticsearch.yml' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/node/.env \ - --output "${TMP_FOLDER}/.env" || fatal_error "Error when downloading the file '.env'" - printf '\n - .env' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/node/docker-compose.yml \ - --output "${TMP_FOLDER}/docker-compose.yml" || fatal_error "Error when downloading the file 'docker-compose.yml'" - printf '\n - docker-compose.yml' - - curl --silent ${DOWNLOAD_URL}/openvidu-server/deployments/enterprise-ha/docker-compose/node/openvidu \ - --output "${TMP_FOLDER}/openvidu" || fatal_error "Error when downloading the file 'openvidu'" - printf '\n - openvidu' - - # Downloading new images and stopped actual Openvidu - printf '\n => Downloading new images...' - printf '\n' - sleep 1 - - printf "\n => Moving to 'tmp' folder..." - printf '\n' - cd "${TMP_FOLDER}" || fatal_error "Error when moving to 'tmp' folder" - printf '\n' - docker-compose pull || true - - printf '\n => Stopping Openvidu...' - printf '\n' - sleep 1 - - printf "\n => Moving to 'openvidu' folder..." - printf '\n' - cd "${OPENVIDU_PREVIOUS_FOLDER}" || fatal_error "Error when moving to 'openvidu' folder" - printf '\n' - docker-compose down || true - - printf '\n' - printf '\n => Moving to working dir...' - cd "${ACTUAL_FOLDER}" || fatal_error "Error when moving to working dir" - - # Move old files to rollback folder - printf '\n => Moving previous installation files to rollback folder:' - - mv "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.yml" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous 'docker-compose.yml'" - printf '\n - docker-compose.yml' - - mv "${OPENVIDU_PREVIOUS_FOLDER}/openvidu" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous 'openvidu'" - printf '\n - openvidu' - - mv "${OPENVIDU_PREVIOUS_FOLDER}/beats" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous 'beats'" - printf '\n - beats' - - cp "${OPENVIDU_PREVIOUS_FOLDER}/.env" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous '.env'" - printf '\n - .env' - - if [ -d "${OPENVIDU_PREVIOUS_FOLDER}/coturn" ]; then - mv "${OPENVIDU_PREVIOUS_FOLDER}/coturn" "${ROLL_BACK_FOLDER}" || fatal_error "Error while moving previous directory 'coturn'" - fi - - # Move tmp files to Openvidu - printf '\n => Updating files:' - - mv "${TMP_FOLDER}/docker-compose.yml" "${OPENVIDU_PREVIOUS_FOLDER}" || fatal_error "Error while updating 'docker-compose.yml'" - printf '\n - docker-compose.yml' - - mv "${TMP_FOLDER}/.env" "${OPENVIDU_PREVIOUS_FOLDER}/.env-${OPENVIDU_VERSION}" || fatal_error "Error while moving previous '.env'" - printf '\n - .env-%s' "${OPENVIDU_VERSION}" - - mv "${TMP_FOLDER}/openvidu" "${OPENVIDU_PREVIOUS_FOLDER}" || fatal_error "Error while updating 'openvidu'" - printf '\n - openvidu' - - mkdir "${OPENVIDU_PREVIOUS_FOLDER}/beats" || fatal_error "Error while creating the folder 'beats'" - - mv "${TMP_FOLDER}/filebeat.yml" "${OPENVIDU_PREVIOUS_FOLDER}/beats/filebeat.yml" || fatal_error "Error while updating 'filebeat.yml'" - printf '\n - beats/filebeat.yml' - - mv "${TMP_FOLDER}/metricbeat-elasticsearch.yml" "${OPENVIDU_PREVIOUS_FOLDER}/beats/metricbeat-elasticsearch.yml" || fatal_error "Error while updating 'metricbeat-elasticsearch.yml'" - printf '\n - beats/metricbeat-elasticsearch.yml' - - printf "\n => Deleting 'tmp' folder" - rm -rf "${TMP_FOLDER}" || fatal_error "Error deleting 'tmp' folder" - - # Add execution permissions - printf "\n => Adding permission to 'openvidu' program..." - - chmod +x "${OPENVIDU_PREVIOUS_FOLDER}/openvidu" || fatal_error "Error while adding permission to 'openvidu' program" - printf '\n - openvidu' - - # Change recording folder with all permissions - printf "\n => Adding permission to 'recordings' folder..." - mkdir -p "${OPENVIDU_PREVIOUS_FOLDER}/recordings" - - # Define old mode: On Premise or Cloud Formation - OLD_MODE=$(grep -E "Installation Mode:.*$" "${ROLL_BACK_FOLDER}/docker-compose.yml" | awk '{ print $4,$5 }') - [ -n "${OLD_MODE}" ] && sed -i -r "s/Installation Mode:.+/Installation Mode: ${OLD_MODE}/" "${OPENVIDU_PREVIOUS_FOLDER}/docker-compose.yml" - - pull_images "${OPENVIDU_PREVIOUS_FOLDER}" - - # Ready to use - printf '\n' - printf '\n' - printf '\n ================================================' - printf "\n Openvidu Enterprise HA successfully upgraded to version %s" "${OPENVIDU_VERSION}" - printf '\n ================================================' - printf '\n' - printf "\n 1. A new file 'docker-compose.yml' has been created with the new OpenVidu Enterprise HA %s services" "${OPENVIDU_VERSION}" - printf '\n' - printf "\n 2. The previous file '.env' remains intact, but a new file '.env-%s' has been created." "${OPENVIDU_VERSION}" - printf "\n Transfer any configuration you wish to keep in the upgraded version from '.env' to '.env-%s'." "${OPENVIDU_VERSION}" - printf "\n When you are OK with it, rename and leave as the only '.env' file of the folder the new '.env-%s'." "${OPENVIDU_VERSION}" - printf '\n' - printf '\n 3. Start new version of Openvidu' - printf '\n ------------------------------------------------' - printf '\n $ ./openvidu start' - printf '\n ------------------------------------------------' - printf '\n' - printf "\n If you want to rollback, all the files from the previous installation have been copied to folder '.old-%s'" "${OPENVIDU_PREVIOUS_VERSION}" - printf '\n' - printf '\n' - printf '\n' -} - -# Check docker and docker-compose installation -if ! command -v docker > /dev/null; then - echo "You don't have docker installed, please install it and re-run the command" - exit 1 -else - # Check version of docker is equal or higher than 20.10.10 - DOCKER_VERSION=$(docker version --format '{{.Server.Version}}' | sed "s/-rc[0-9]*//") - if ! printf '%s\n%s\n' "20.10.10" "$DOCKER_VERSION" | sort -V -C; then - echo "You need a docker version equal or higher than 20.10.10, please update your docker and re-run the command"; \ - exit 1 - fi -fi - -if ! command -v docker-compose > /dev/null; then - echo "You don't have docker-compose installed, please install it and re-run the command" - exit 1 -else - COMPOSE_VERSION=$(docker-compose version --short | sed "s/-rc[0-9]*//") - if ! printf '%s\n%s\n' "1.24" "$COMPOSE_VERSION" | sort -V -C; then - echo "You need a docker-compose version equal or higher than 1.24, please update your docker-compose and re-run the command"; \ - exit 1 - fi -fi - -# Check type of installation -if [[ -n "$1" && "$1" == "upgrade" ]]; then - upgrade_ov "$2" -else - new_ov_installation -fi diff --git a/openvidu-server/deployments/enterprise-ha/docker-compose/node/openvidu b/openvidu-server/deployments/enterprise-ha/docker-compose/node/openvidu deleted file mode 100755 index a3640dd012..0000000000 --- a/openvidu-server/deployments/enterprise-ha/docker-compose/node/openvidu +++ /dev/null @@ -1,337 +0,0 @@ -#!/bin/bash - -# Support docker compose v1 and v2 -shopt -s expand_aliases -alias docker-compose='docker compose' -if ! docker compose version &> /dev/null; then - unalias docker-compose -fi - -# Change default http timeout for slow networks -export COMPOSE_HTTP_TIMEOUT=500 -export DOCKER_CLIENT_TIMEOUT=500 - -# Deployed images by media-node-controller -IMAGES=( - "kurento-media-server" - "docker.elastic.co/beats/filebeat" - "docker.elastic.co/beats/metricbeat" - "openvidu/media-node-controller" - "openvidu/speech-to-text-service" - "openvidu/mediasoup-controller" - "openvidu/openvidu-coturn" -) - -docker_command_by_container_image() { - IMAGE_NAME=$1 - COMMAND=$2 - if [[ -n "${IMAGE_NAME}" ]]; then - CONTAINERS="$(docker ps -a | grep "${IMAGE_NAME}" | awk '{print $1}')" - for CONTAINER_ID in $CONTAINERS; do - if [[ -n "${CONTAINER_ID}" ]] && [[ -n "${COMMAND}" ]]; then - bash -c "docker ${COMMAND} ${CONTAINER_ID}" - fi - done - fi -} - -collect_basic_information() { - LINUX_VERSION=$(lsb_release -d) - DOCKER_PS=$(docker ps) - DOCKER_VERSION=$(docker version --format '{{.Server.Version}}') - DOCKER_COMPOSE_VERSION=$(docker-compose version --short) - OV_FOLDER="${PWD}" - OV_VERSION=$(grep 'Openvidu Version:' "${OV_FOLDER}/docker-compose.yml" | awk '{ print $4 }') - CONTAINERS=$(docker ps | awk '{if(NR>1) print $NF}') - OV_TYPE_INSTALLATION=$(grep 'Installation Mode:' "${OV_FOLDER}/docker-compose.yml" | awk '{ print $4,$5 }') - TREE_OV_DIRECTORY=$(find "." ! -path '*/0/*' | sed -e "s/[^-][^\/]*\// |/g" -e "s/|\([^ ]\)/|-\1/") -} - -version_ov() { - collect_basic_information - - printf '\nOpenvidu Information:' - printf '\n' - printf '\n OpenVidu Edition: Enterprise HA' - printf '\n Installation Type: %s' "${OV_TYPE_INSTALLATION}" - printf '\n Openvidu Version: %s' "${OV_VERSION}" - printf '\n' - printf '\nSystem Information:' - printf '\n' - printf '\n Linux Version:' - printf '\n - %s' "${LINUX_VERSION}" - printf '\n Docker Version: %s' "${DOCKER_VERSION}" - printf '\n Docker Compose Version: %s' "${DOCKER_COMPOSE_VERSION}" - printf '\n' - printf '\nInstallation Information:' - printf '\n' - printf '\n Installation Folder: %s' "${OV_FOLDER}" - printf '\n Installation Folder Tree:' - printf '\n%s' "$(echo "${TREE_OV_DIRECTORY}" | sed -e 's/.//' -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')" - printf '\n' - printf '\nDocker Running Services:' - printf '\n' - printf '\n %s' "$(echo "${DOCKER_PS}" | sed -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')" - printf '\n' -} - -generate_report() { - collect_basic_information - - REPORT_CREATION_DATE=$(date +"%d-%m-%Y") - REPORT_CREATION_TIME=$(date +"%H:%M:%S") - REPORT_NAME="openvidu-report-${REPORT_CREATION_DATE}-$(date +"%H-%M").txt" - REPORT_OUTPUT="${OV_FOLDER}/${REPORT_NAME}" - - { - printf "\n =======================================" - printf "\n = REPORT INFORMATION =" - printf "\n =======================================" - printf '\n' - printf '\n Creation Date: %s' "${REPORT_CREATION_DATE}" - printf '\n Creation Time: %s' "${REPORT_CREATION_TIME}" - printf '\n' - printf "\n =======================================" - printf "\n = OPENVIDU INFORMATION =" - printf "\n =======================================" - printf '\n' - printf '\n OpenVidu Edition: Enterprise HA' - printf '\n Installation Type: %s' "${OV_TYPE_INSTALLATION}" - printf '\n Openvidu Version: %s' "${OV_VERSION}" - # printf '\n Openvidu Call Version: %s' "${OV_CALL_VERSION}" - printf '\n' - printf "\n =======================================" - printf "\n = SYSTEM INFORMATION =" - printf "\n =======================================" - printf '\n' - printf '\n Linux Version:' - printf '\n - %s' "${LINUX_VERSION}" - printf '\n Docker Version: %s' "${DOCKER_VERSION}" - printf '\n Docker Compose Version: %s' "${DOCKER_COMPOSE_VERSION}" - printf '\n' - printf "\n =======================================" - printf "\n = INSTALLATION INFORMATION =" - printf "\n =======================================" - printf '\n' - printf '\n Installation Folder: %s' "${OV_FOLDER}" - printf '\n Installation Folder Tree:' - printf '\n%s' "$(echo "${TREE_OV_DIRECTORY}" | sed -e 's/.//' -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')" - printf '\n' - printf "\n =======================================" - printf "\n = DOCKER RUNNING SERVICES =" - printf "\n =======================================" - printf '\n' - printf '\n %s' "$(echo "${DOCKER_PS}" | sed -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')" - printf '\n' - printf "\n =======================================" - printf "\n = CONFIGURATION FILES =" - printf "\n =======================================" - printf '\n' - printf '\n ================ .env =================' - printf '\n' - printf '\n' - - cat < "${OV_FOLDER}/.env" | sed -r -e "s/OPENVIDU_SECRET=.+/OPENVIDU_SECRET=****/" -e "s/OPENVIDU_PRO_LICENSE=.+/OPENVIDU_PRO_LICENSE=****/" -e "s/ELASTICSEARCH_PASSWORD=.+/ELASTICSEARCH_PASSWORD=****/" - - printf '\n' - printf '\n ========= docker-compose.yml ==========' - printf '\n' - printf '\n' - - cat "${OV_FOLDER}/docker-compose.yml" - - printf '\n' - printf '\n ==== docker-compose.override.yml ====' - printf '\n' - printf '\n' - - if [ -f "${OV_FOLDER}/docker-compose.override.yml" ]; then - cat < "${OV_FOLDER}/docker-compose.override.yml" - else - printf '\n The docker-compose.override.yml file is not present' - fi - - printf '\n' - printf '\n' - printf "\n =======================================" - printf "\n = LOGS =" - printf "\n =======================================" - - for CONTAINER in $CONTAINERS - do - printf '\n' - printf "\n ---------------------------------------" - printf "\n %s" "$CONTAINER" - printf "\n ---------------------------------------" - printf '\n' - docker logs "$CONTAINER" - printf "\n ---------------------------------------" - printf '\n' - printf '\n' - done - - printf "\n =======================================" - printf "\n = CONTAINER ENVS VARIABLES =" - printf "\n =======================================" - - for CONTAINER in $CONTAINERS - do - printf '\n' - printf "\n =======================================" - printf "\n %s" "$CONTAINER" - printf "\n ---------------------------------------" - printf '\n' - docker exec "$CONTAINER" env - printf "\n ---------------------------------------" - printf '\n' - printf '\n' - done - - } >> "${REPORT_OUTPUT}" 2>&1 - - printf "\n Generation of the report completed with success" - printf "\n You can get your report at path '%s'" "${REPORT_OUTPUT}" - printf "\n" -} - -is_external_url() { - local URL=$1 - if [[ -z "$URL" ]]; then - return 1 - fi - if [[ "${URL}" == *"localhost"* ]] || [[ "${URL}" == *"127.0.0.1"* ]] || [[ "${URL}" == *"::1"* ]]; then - return 1 - else - return 0 - fi -} - -print_env_error() { - printf "\n ERROR: You must set the '%s' variable in the .env file" "${1}" - printf "\n" -} - -check_non_empty_parameters() { - local NON_EMPTY_ENV_VARS=("$@") - for ENV_VAR_NAME in "${NON_EMPTY_ENV_VARS[@]}" ; do - ENV_VAR_VALUE=$(grep -v '^#' .env | grep "${ENV_VAR_NAME}" | cut -d '=' -f2) - if [[ -z "${ENV_VAR_VALUE}" ]]; then - print_env_error "${ENV_VAR_NAME}" - exit 1 - fi - done -} - -get_env_var_value() { - local ENV_VAR_NAME=$1 - local ENV_VAR_VALUE - ENV_VAR_VALUE=$(grep -v '^#' .env | grep "${ENV_VAR_NAME}" | cut -d '=' -f2) - echo "${ENV_VAR_VALUE}" -} - -check_env_var_is_value() { - local ENV_VAR_NAME=$1 - local ENV_VAR_VALUE=$2 - local ENV_VAR_VALUE_TO_CHECK - ENV_VAR_VALUE_TO_CHECK=$(get_env_var_value "${ENV_VAR_NAME}") - if [[ "${ENV_VAR_VALUE_TO_CHECK}" != "${ENV_VAR_VALUE}" ]]; then - print_env_error "${ENV_VAR_NAME}" - exit 1 - fi -} - -start_openvidu() { - export INITIAL_CONFIG_SYNC=true - if ! docker-compose up --exit-code-from replication-manager replication-manager; then - printf "\n ERROR: Openvidu Node failed to start" - printf "\n" - unset INITIAL_CONFIG_SYNC - docker-compose down - exit 1 - fi - docker-compose down - unset INITIAL_CONFIG_SYNC - docker-compose up -d -} - -stop_containers() { - printf "Stopping containers..." - for IMAGE in "${IMAGES[@]}"; do - docker_command_by_container_image "${IMAGE}" "rm -f" - done -} - -usage() { - printf "Usage: \n\t openvidu [command]" - printf "\n\nAvailable Commands:" - printf "\n\tstart\t\t\tStart all services" - printf "\n\tstop\t\t\tStop all services" - printf "\n\trestart\t\t\tRestart all stopped and running services" - printf "\n\tlogs\t\t\tShow openvidu-server logs" - printf "\n\tupgrade\t\t\tUpgrade to the latest Openvidu version" - printf "\n\tupgrade [version]\tUpgrade to the specific Openvidu version" - printf "\n\tversion\t\t\tShow version of Openvidu Server" - printf "\n\treport\t\t\tGenerate a report with the current status of Openvidu" - printf "\n\thelp\t\t\tShow help for openvidu command" - printf "\n" -} - -[[ -z "${FOLLOW_OPENVIDU_LOGS}" ]] && FOLLOW_OPENVIDU_LOGS=true - -case $1 in - -start) - start_openvidu - if [[ "${FOLLOW_OPENVIDU_LOGS}" == "true" ]]; then - # Docker compose logs of openvidu-server and repliation-manager containers - docker-compose logs -f --tail 10 openvidu-server replication-manager - fi -;; - -stop) - docker-compose down - stop_containers -;; - -restart) - docker-compose down - stop_containers - start_openvidu - if [[ "${FOLLOW_OPENVIDU_LOGS}" == "true" ]]; then - docker-compose logs -f --tail 10 openvidu-server replication-manager - fi -;; - -logs) - case "${2-}" in - --follow|-f) - docker-compose logs -f --tail 10 openvidu-server replication-manager - ;; - - *) - docker-compose logs openvidu-server replication-manager - ;; - esac -;; - -version) - version_ov -;; - -report) - read -r -p " You are about to generate a report on the current status of Openvidu, this may take some time. Do you want to continue? [y/N]: " response - case "$response" in - [yY][eE][sS]|[yY]) - generate_report - ;; - - *) - exit 0 - ;; - esac -;; - -*) - usage -;; -esac diff --git a/openvidu-server/deployments/enterprise/aws/CF-OpenVidu-Enterprise.yaml.template b/openvidu-server/deployments/enterprise/aws/CF-OpenVidu-Enterprise.yaml.template deleted file mode 100644 index 88d35fbd2b..0000000000 --- a/openvidu-server/deployments/enterprise/aws/CF-OpenVidu-Enterprise.yaml.template +++ /dev/null @@ -1,1432 +0,0 @@ ---- -AWSTemplateFormatVersion: 2010-09-09 -Description: Openvidu Pro With Master Replication - -Parameters: - - DomainName: - Description: 'Domain name which will be used to access OpenVidu Pro. This domain name should point to the Load Balancer URL after the stack is deployed.' - Type: 'String' - AllowedPattern: ^$|^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$ - MinLength: 1 - ConstraintDescription: The domain name does not have a valid domain name format - - KeyName: - Description: 'Name of an existing EC2 KeyPair to enable SSH access to the instance. It is mandatory to perform some administrative tasks on instances.' - Type: 'AWS::EC2::KeyPair::KeyName' - AllowedPattern : '.+' - ConstraintDescription: 'Must be defined and to be an existing EC2 KeyPair' - - OpenViduLicense: - Description: 'Visit https://openvidu.io/account' - Type: String - AllowedPattern: ^(?!\s*$).+$ - MinLength: 1 - NoEcho: true - ConstraintDescription: OpenVidu Pro License is mandatory - - OpenViduSecret: - Description: 'Secret to connect to this OpenVidu Platform. Cannot be empty and must contain only alphanumeric characters [a-zA-Z0-9], hypens ("-") and underscores ("_")' - Type: String - AllowedPattern: ^[a-zA-Z0-9_-]+$ - MinLength: 1 - NoEcho: true - ConstraintDescription: 'Cannot be empty and must contain only alphanumeric characters [a-zA-Z0-9], hypens ("-") and underscores ("_")' - - MediaServer: - Description: 'Media Server to be deployed in Media Nodes' - Type: String - Default: mediasoup - AllowedValues: - - mediasoup - - kurento - ConstraintDescription: 'Must be a valid EC2 instance type' - - OpenViduProClusterId: - Description: 'Unique identifier for the OpenVidu Pro cluster' - Type: String - MinLength: 1 - AllowedPattern: ^[a-z0-9_-]+$ - ConstraintDescription: 'Cannot be empty and must contain only lowercase characters [a-z0-9], hypens ("-") and underscores ("_")' - - - OpenViduS3BucketName: - Description: "Bucket to save configuration and recordings. If not defined, a default one will be created" - Type: String - Default: '' - - OpenViduS3ConfigAutoRestart: - Description: "If true, changes at in .env file in S3 bucket will restart automatically all master nodes." - Type: String - AllowedValues: - - true - - false - Default: true - - OpenViduRecording: - Description: "If 'true', recordings will be saved in an s3 bucket created by this cloudformation, or the defined one at OpenViduS3Bucket" - Type: String - AllowedValues: - - true - - false - Default: true - - CoturnInMediaNodes: - Description: "If true, Coturn will be deployed on media nodes. Otherwise it will be deployed in master nodes." - Type: String - AllowedValues: - - true - - false - Default: false - - # Enable Elasticsearch and Kibana - ElasticsearchEnabled: - Description: "Choose if you want OpenVidu to use Elasticsearch." - Type: String - AllowedValues: - - true - - false - Default: true - - # Elasticsearch configuration - ElasticsearchUser: - Description: "Username for Elasticsearch and Kibana. ('ElasticSearch Enabled' must be true)" - Type: String - AllowedPattern: ^$|^[^" ]+$ - ConstraintDescription: Elasticsearch user is mandatory (no whitespaces or quotations allowed) - Default: elasticadmin - - ElasticsearchPassword: - Description: "Password for Elasticsearch and Kibana ('ElasticSearch Enabled' must be true)" - Type: String - AllowedPattern: ^$|^[^" ]+$ - NoEcho: true - ConstraintDescription: Elasticsearch password is mandatory and it should have at least 6 characters (no whitespaces or quotations allowed) - - # Elasticsearch configuration - ElasticsearchUrl: - Description: "If you have an external Elasticsearch service running, put here the url to the service. If empty, an Elasticsearch service will be deployed next to OpenVidu. ('ElasticSearch Enabled' must be true)" - Type: String - AllowedPattern: (^(https?:\/\/)?([^:\/]+)(:([0-9]+))?(\/.*)?$|^$) - ConstraintDescription: "It is very important to specify the Elasticsearch URL with the port used by this service. For example: https://es-example" - - KibanaUrl: - Description: "If you have an external Kibana service running, put here the url to the service. If empty, a Kibana service will be deployed next to OpenVidu. ('ElasticSearch Enabled' must be true)" - Type: String - AllowedPattern: (^(https?:\/\/)?([^:\/]+)(:([0-9]+))?(\/.*)?$|^$) - ConstraintDescription: "It is very important to specify the url with port used by this service. For example: https://kibana-example" - - LoadBalancerCertificateARN: - Description: 'Amazon certificate arn resource to load into the LoadBalancer' - Type: String - AllowedPattern: '.+' - ConstraintDescription: The Load Balancer domain name must be defined - - AwsInstanceTypeOV: - Description: 'Specifies the EC2 instance type for your OpenVidu Server Pro Node' - Type: String - Default: c5.xlarge - AllowedValues: - - t2.medium - - t2.large - - t2.xlarge - - t2.2xlarge - - t3.large - - t3.xlarge - - t3.2xlarge - - m4.large - - m4.xlarge - - m4.2xlarge - - m4.4xlarge - - m4.10xlarge - - m4.16xlarge - - m5.large - - m5.xlarge - - m5.2xlarge - - m5.4xlarge - - m5.8xlarge - - m5.12xlarge - - m5.16xlarge - - m5.24xlarge - - c4.large - - c4.xlarge - - c4.2xlarge - - c4.4xlarge - - c4.8xlarge - - c5.large - - c5.xlarge - - c5.2xlarge - - c5.4xlarge - - c5.9xlarge - - c5.12xlarge - - c5.18xlarge - - c5.24xlarge - - c6a.large - - c6a.xlarge - - c6a.2xlarge - - c6a.4xlarge - - c6a.8xlarge - - c6a.12xlarge - - c6a.16xlarge - - c6a.24xlarge - - c6a.32xlarge - - c6a.48xlarge - - c6a.metal - ConstraintDescription: 'Must be a valid EC2 instance type' - - AwsInstanceTypeKMS: - Description: 'Specifies the EC2 instance type for your Media Nodes' - Type: String - Default: c5.xlarge - AllowedValues: - - t2.medium - - t2.large - - t2.xlarge - - t2.2xlarge - - t3.large - - t3.xlarge - - t3.2xlarge - - m4.large - - m4.xlarge - - m4.2xlarge - - m4.4xlarge - - m4.10xlarge - - m4.16xlarge - - m5.large - - m5.xlarge - - m5.2xlarge - - m5.4xlarge - - m5.8xlarge - - m5.12xlarge - - m5.16xlarge - - m5.24xlarge - - c4.large - - c4.xlarge - - c4.2xlarge - - c4.4xlarge - - c4.8xlarge - - c5.large - - c5.xlarge - - c5.2xlarge - - c5.4xlarge - - c5.9xlarge - - c5.12xlarge - - c5.18xlarge - - c5.24xlarge - - c6a.large - - c6a.xlarge - - c6a.2xlarge - - c6a.4xlarge - - c6a.8xlarge - - c6a.12xlarge - - c6a.16xlarge - - c6a.24xlarge - - c6a.32xlarge - - c6a.48xlarge - - c6a.metal - ConstraintDescription: 'Must be a valid EC2 instance type' - - MinMasterNodes: - Description: 'Minimun number of Master Nodes' - Type: Number - Default: 1 - MinValue: 1 - ConstraintDescription: 'A Minimun number of Master Nodes is mandatory' - - MaxMasterNodes: - Description: 'Maximum number of Master Nodes' - Type: Number - Default: 4 - MinValue: 1 - ConstraintDescription: 'A Maximum number of Master Nodes is mandatory' - - DesiredMasterNodes: - Description: 'Desired number of Master Nodes' - Type: Number - Default: 1 - MinValue: 1 - ConstraintDescription: 'A desired number of Master Nodes is mandatory' - - MinMediaNodes: - Description: 'Minimun number of Media Nodes' - Type: Number - Default: 1 - MinValue: 1 - ConstraintDescription: 'A Minimun number of Master Nodes is mandatory' - - MaxMediaNodes: - Description: 'Maximum number of Media Nodes' - Type: Number - Default: 4 - MinValue: 1 - ConstraintDescription: 'A Maximum number of Master Nodes is mandatory' - - ScaleUpMediaNodesAvgCpu: - Description: 'Scale up media nodes when avg cpu is greater the specified value' - Type: Number - Default: 70 - MinValue: 0 - ConstraintDescription: 'A desired number of Master Nodes is mandatory' - - ScaleDownMediaNodesAvgCpu: - Description: 'Scale down media nodes when avg cpu is below the specified value' - Type: Number - Default: 30 - MinValue: 1 - ConstraintDescription: 'A desired number of Master Nodes is mandatory' - - DesiredMediaNodes: - Description: 'Desired number of Media Nodes' - Type: Number - Default: 1 - MinValue: 1 - ConstraintDescription: 'A desired number of Master Nodes is mandatory' - - OpenViduVPC: - Description: 'Dedicated VPC for OpenVidu cluster' - Type: AWS::EC2::VPC::Id - AllowedPattern: ^.+$ - ConstraintDescription: You must specify a VPC ID - - OpenViduSubnets: - Description: 'Subnet for OpenVidu cluster' - Type: List - AllowedPattern: ^.+$ - ConstraintDescription: You must specify a subnet ID - -#start_mappings -Mappings: - OVAMIMAP: - eu-west-1: - AMI: OV_MASTER_REPLICATION_AMI_ID - - KMSAMIMAP: - eu-west-1: - AMI: KMS_AMI_ID -#end_mappings - -Metadata: - 'AWS::CloudFormation::Interface': - ParameterGroups: - - Label: - default: OpenVidu configuration - Parameters: - - DomainName - - OpenViduProClusterId - - OpenViduLicense - - OpenViduSecret - - MediaServer - - OpenViduS3BucketName - - OpenViduS3ConfigAutoRestart - - OpenViduRecording - - CoturnInMediaNodes - - Label: - default: Elasticsearch and Kibana configuration - Parameters: - - ElasticsearchEnabled - - ElasticsearchUrl - - KibanaUrl - - ElasticsearchUser - - ElasticsearchPassword - - Label: - default: EC2 and Autoscaling configuration - Parameters: - - AwsInstanceTypeOV - - AwsInstanceTypeKMS - - KeyName - - MinMasterNodes - - MaxMasterNodes - - DesiredMasterNodes - - MinMediaNodes - - MaxMediaNodes - - DesiredMediaNodes - - ScaleUpMediaNodesAvgCpu - - ScaleDownMediaNodesAvgCpu - - Label: - default: Load Balancer Certificate Configuration - Parameters: - - LoadBalancerCertificateARN - - Label: - default: Networking configuration - Parameters: - - OpenViduVPC - - OpenViduSubnets - ParameterLabels: - # OpenVidu General Configuration - DomainName: - default: 'Domain Name' - OpenViduProClusterId: - default: 'OpenVidu Pro Cluster Id' - OpenViduLicense: - default: 'OpenVidu Pro License' - OpenViduSecret: - default: 'OpenVidu Secret' - MediaServer: - default: 'Media Server' - OpenViduS3BucketName: - default: 'S3 Bucket where recordings and OpenVidu configuration will be stored' - OpenViduS3ConfigAutoRestart: - default: 'Auto Restart OpenVidu on S3 bucket .env changes' - OpenViduRecording: - default: 'Enable OpenVidu Recording' - CoturnInMediaNodes: - default: 'Deploy Coturn in Media Nodes. (Experimental)' - # Elasticsearch and Kibana Configuration - ElasticsearchEnabled: - default: "Enable Elasticsearch and Kibana" - ElasticsearchUrl: - default: 'Elasticsearch URL' - KibanaUrl: - default: 'Kibana URL' - ElasticsearchUser: - default: 'Elasticsearch and Kibana username' - ElasticsearchPassword: - default: 'Elasticsearch and Kibana password' - # SSL Certificate Configuration - LoadBalancerCertificateARN: - default: 'ARN of the AWS Certificate. This certificate must be valid for "Domain Name"' - # EC2 And Autoscaling Configuration - AwsInstanceTypeOV: - default: "Master Nodes instance type" - AwsInstanceTypeKMS: - default: 'Media Nodes instance type' - KeyName: - default: 'SSH Key Name' - MinMasterNodes: - default: 'Minimum Master Nodes' - MaxMasterNodes: - default: 'Maximum Master Nodes' - DesiredMasterNodes: - default: 'Desired Master Nodes' - DesiredMediaNodes: - default: 'Desired Media Nodes' - MinMediaNodes: - default: 'Minimum Media Nodes' - MaxMediaNodes: - default: 'Maximum Media Nodes' - ScaleUpMediaNodesAvgCpu: - default: 'Scale Up Media Nodes on Average CPU' - ScaleDownMediaNodesAvgCpu: - default: 'Scale Down Media Nodes on Average CPU' - # Networking Configuration - OpenViduVPC: - default: 'OpenVidu Pro VPC' - OpenViduSubnets: - default: 'OpenVIdu Pro Subnets' - -Conditions: - CreateS3Bucket: !Equals [ !Ref OpenViduS3BucketName, ''] - -Rules: - - # Check when Elasticsearch is enabled that all the parameters are present - ElasticsearchValidation: - RuleCondition: !Equals [ !Ref ElasticsearchEnabled, 'true' ] - Assertions: - - AssertDescription: Paramter 'Elasticsearch and Kibana username' (ElasticsearchUser) is needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'true'. - Assert: !Not [ !Equals [!Ref ElasticsearchUser, ''] ] - - AssertDescription: Parameter 'Elasticsearch and Kibana password' (ElasticsearchPassword) is needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'true'. - Assert: !Not [ !Equals [!Ref ElasticsearchPassword, ''] ] - - # Check when Elasticsearch is disabled that any parameter of elasticsearch is not present - ElasticsearchDisabledValidation: - RuleCondition: !Equals [ !Ref ElasticsearchEnabled, 'false' ] - Assertions: - - AssertDescription: Parameter 'Elasticsearch URL' (ElasticsearchUrl) is not needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'false'. - Assert: !Equals [ !Ref ElasticsearchUrl, "" ] - - AssertDescription: Parameter 'Kibana URL' (KibanaUrl) is not needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'false'. - Assert: !Equals [ !Ref KibanaUrl, "" ] - - AssertDescription: Parameter 'Elasticsearch and Kibana username' (ElasticsearchUser) is not needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'false'. - Assert: !Equals [ !Ref ElasticsearchUser, "" ] - - AssertDescription: Parameter 'Elasticsearch and Kibana password' (ElasticsearchPassword) is not needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'false'. - Assert: !Equals [ !Ref ElasticsearchPassword, "" ] - - -Resources: - - ##### - # S3 bucket - ##### - S3OpenViduBucket: - Type: 'AWS::S3::Bucket' - DeletionPolicy: Retain - UpdateReplacePolicy: Retain - Properties: - ### Unique bucket name using Stack ID - BucketName: !Join [ "-", [ !Ref OpenViduProClusterId, !Select [0, !Split ["-", !Select [2, !Split [/, !Ref AWS::StackId ]]]] ] ] - AccessControl: Private - PublicAccessBlockConfiguration: - BlockPublicAcls: true - BlockPublicPolicy: true - IgnorePublicAcls : true - RestrictPublicBuckets: true - Condition: CreateS3Bucket - - ##### - # Security groups - ##### - - # Security group with all open ports necessary for OpenVidu Pro to work - # Only the Load Balancer has access to replication-manager port 4443 which proxies to OpenVidu Pro - OpenViduSecurityGroup: - Type: 'AWS::EC2::SecurityGroup' - Properties: - GroupDescription: SSH and OpenVidu WebRTC Ports - GroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'OpenViduSecurityGroup'] ] - VpcId: !Ref OpenViduVPC - Tags: - - Key: Name - Value: !Join [ "-", [ !Ref 'AWS::StackName', 'OpenViduSecurityGroup'] ] - SecurityGroupIngress: - - IpProtocol: udp - FromPort: 3478 - ToPort: 3478 - CidrIp: 0.0.0.0/0 - - IpProtocol: udp - FromPort: 3478 - ToPort: 3478 - CidrIpv6: ::/0 - - IpProtocol: tcp - FromPort: 3478 - ToPort: 3478 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 3478 - ToPort: 3478 - CidrIpv6: ::/0 - - IpProtocol: tcp - FromPort: 4443 - ToPort: 4443 - SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup - - IpProtocol: udp - FromPort: 40000 - ToPort: 65535 - CidrIp: 0.0.0.0/0 - - IpProtocol: udp - FromPort: 40000 - ToPort: 65535 - CidrIpv6: ::/0 - - IpProtocol: tcp - FromPort: 40000 - ToPort: 65535 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 40000 - ToPort: 65535 - CidrIpv6: ::/0 - SecurityGroupEgress: - - IpProtocol: tcp - FromPort: 1 - ToPort: 65535 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 1 - ToPort: 65535 - CidrIpv6: ::/0 - - IpProtocol: udp - FromPort: 1 - ToPort: 65535 - CidrIp: 0.0.0.0/0 - - IpProtocol: udp - FromPort: 1 - ToPort: 65535 - CidrIpv6: ::/0 - - # This security groups Ingress rule is for OpenVidu Pro Master instances which only need access - # to other OpenVidu Pro instances at port 5443 and 4443 to proxy requests from replication-manager - OpenViduSecurityGroupIngressServer: - Type: AWS::EC2::SecurityGroupIngress - Properties: - GroupId: !Ref OpenViduSecurityGroup - IpProtocol: tcp - FromPort: 5443 - ToPort: 5443 - SourceSecurityGroupId: !Ref OpenViduSecurityGroup - - OpenViduSecurityGroupIngressReplicationManager: - Type: AWS::EC2::SecurityGroupIngress - Properties: - GroupId: !Ref OpenViduSecurityGroup - IpProtocol: tcp - FromPort: 4443 - ToPort: 4443 - SourceSecurityGroupId: !Ref OpenViduSecurityGroup - - LoadBalancerSecurityGroup: - Type: 'AWS::EC2::SecurityGroup' - Properties: - VpcId: !Ref OpenViduVPC - GroupDescription: Load Balancer Security group - GroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'LoadBalancerSecurityGroup'] ] - Tags: - - Key: Name - Value: !Join [ "-", [ !Ref 'AWS::StackName', 'LoadBalancerSecurityGroup'] ] - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: 80 - ToPort: 80 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 80 - ToPort: 80 - CidrIpv6: ::/0 - - IpProtocol: tcp - FromPort: 443 - ToPort: 443 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 443 - ToPort: 443 - CidrIpv6: ::/0 - SecurityGroupEgress: - - IpProtocol: tcp - FromPort: 1 - ToPort: 65535 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 1 - ToPort: 65535 - CidrIpv6: ::/0 - - IpProtocol: udp - FromPort: 1 - ToPort: 65535 - CidrIp: 0.0.0.0/0 - - IpProtocol: udp - FromPort: 1 - ToPort: 65535 - CidrIpv6: ::/0 - - - # Redis Security group. - # Let access only to instances with OpenVidu Pro security group attached - RedisSecurityGroup: - Type: 'AWS::EC2::SecurityGroup' - Properties: - VpcId: !Ref OpenViduVPC - GroupDescription: Security Group for OpenVidu Pro Redis - GroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'RedisSecurityGroup'] ] - Tags: - - Key: Name - Value: !Join [ "-", [ !Ref 'AWS::StackName', 'RedisSecurityGroup'] ] - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: 6379 - ToPort: 6379 - SourceSecurityGroupId: !Ref OpenViduSecurityGroup - SecurityGroupEgress: - - IpProtocol: tcp - FromPort: 1 - ToPort: 65535 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 1 - ToPort: 65535 - CidrIpv6: ::/0 - - # Media Nodes Security group. Let access only to - # instances with OpenVidu Pro security group attached - # to ports 3000, 4000, and 8888 - MediaNodeSecurityGroup: - Type: 'AWS::EC2::SecurityGroup' - Properties: - VpcId: !Ref OpenViduVPC - GroupDescription: SSH, Media Node controller and KMS WebRTC Ports - GroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'KMSSecurityGroup'] ] - Tags: - - Key: Name - Value: !Join [ "-", [ !Ref 'AWS::StackName', 'KMSSecurityGroup'] ] - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: 443 - ToPort: 443 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 443 - ToPort: 443 - CidrIpv6: ::/0 - - IpProtocol: udp - FromPort: 443 - ToPort: 443 - CidrIp: 0.0.0.0/0 - - IpProtocol: udp - FromPort: 443 - ToPort: 443 - CidrIpv6: ::/0 - - IpProtocol: tcp - FromPort: 3000 - ToPort: 3000 - SourceSecurityGroupId: !Ref OpenViduSecurityGroup - - IpProtocol: tcp - FromPort: 4000 - ToPort: 4000 - SourceSecurityGroupId: !Ref OpenViduSecurityGroup - - IpProtocol: tcp - FromPort: 8888 - ToPort: 8888 - SourceSecurityGroupId: !Ref OpenViduSecurityGroup - - IpProtocol: udp - FromPort: 40000 - ToPort: 65535 - CidrIp: 0.0.0.0/0 - - IpProtocol: udp - FromPort: 40000 - ToPort: 65535 - CidrIpv6: ::/0 - - IpProtocol: tcp - FromPort: 40000 - ToPort: 65535 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 40000 - ToPort: 65535 - CidrIpv6: ::/0 - SecurityGroupEgress: - - IpProtocol: tcp - FromPort: 1 - ToPort: 65535 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 1 - ToPort: 65535 - CidrIpv6: ::/0 - - IpProtocol: udp - FromPort: 1 - ToPort: 65535 - CidrIp: 0.0.0.0/0 - - IpProtocol: udp - FromPort: 1 - ToPort: 65535 - CidrIpv6: ::/0 - - ##### - # Redis Cluster - ##### - RedisClusterSubnetGroup: - Type: AWS::ElastiCache::SubnetGroup - Properties: - CacheSubnetGroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'RedisSubnetGroup'] ] - Description: Subnet where to deploy Redis - SubnetIds: !Ref OpenViduSubnets - - RedisCluster: - Type: AWS::ElastiCache::CacheCluster - Properties: - ClusterName: !Join [ "-", [ !Ref 'AWS::StackName', 'Redis'] ] - CacheNodeType: cache.t3.medium - Engine: redis - EngineVersion: 6.x - NumCacheNodes: 1 - CacheParameterGroupName: default.redis6.x - CacheSubnetGroupName: !Ref RedisClusterSubnetGroup - VpcSecurityGroupIds: - - !Ref RedisSecurityGroup - Tags: - - Key: Name - Value: !Join [ "-", [ !Ref 'AWS::StackName', 'Redis'] ] - - ##### - # Media Node Autoscaling Group - ##### - MediaNodeLaunchTemplateConfiguration: - Type: AWS::EC2::LaunchTemplate - Properties: - LaunchTemplateName: !Join [ "-", [ !Ref 'AWS::StackName', 'ASGMediaNodeLaunchTemplate'] ] - LaunchTemplateData: - MetadataOptions: - HttpEndpoint: enabled - HttpPutResponseHopLimit: 1 - HttpTokens: required - SecurityGroupIds: - - !GetAtt MediaNodeSecurityGroup.GroupId - ImageId: !GetAtt LambdaOnCreateInvoke.MediaNodeImageId - KeyName: !Ref KeyName - InstanceType: !Ref AwsInstanceTypeKMS - BlockDeviceMappings: - - DeviceName: /dev/sda1 - Ebs: - VolumeType: gp2 - DeleteOnTermination: true - VolumeSize: 50 - - MediaNodeAutoScalingGroup: - Type: AWS::AutoScaling::AutoScalingGroup - Properties: - AutoScalingGroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'ASGMediaNode'] ] - LaunchTemplate: - LaunchTemplateId: !Ref MediaNodeLaunchTemplateConfiguration - Version: !GetAtt MediaNodeLaunchTemplateConfiguration.LatestVersionNumber - MinSize: !Ref MinMediaNodes - MaxSize: !Ref MaxMediaNodes - DesiredCapacity: !Ref DesiredMediaNodes - VPCZoneIdentifier: !Ref OpenViduSubnets - NewInstancesProtectedFromScaleIn: true - Tags: - - Key: Name - Value: !Join [ "-", [ !Ref 'AWS::StackName', 'Media Node'] ] - PropagateAtLaunch: true - - Key: ov-cluster-member - Value: kms - PropagateAtLaunch: true - - Key: ov-medianode-status - Value: running - PropagateAtLaunch: true - - ##### - # SQS Queue - ##### - SQSPolicy: - Type: AWS::SQS::QueuePolicy - Properties: - Queues: - - !Ref SQSQueue - PolicyDocument: - Statement: - - Effect: Allow - Action: - - 'sqs:SendMessage' - Principal: - Service: - - events.amazonaws.com - Resource: - - !GetAtt SQSQueue.Arn - - SQSQueue: - Type: AWS::SQS::Queue - Properties: - QueueName: !Join ['-', [ !Ref 'AWS::StackName', 'SQS.fifo'] ] - FifoQueue: true - MessageRetentionPeriod: 60 - VisibilityTimeout: 50 - ContentBasedDeduplication: true - Tags: - - Key: Name - Value: !Join ['-', [ !Ref 'AWS::StackName', 'SQS'] ] - - ##### - # Load Balancer - ##### - LoadBalancer: - Type: AWS::ElasticLoadBalancingV2::LoadBalancer - Properties: - Name: !Join ['-', [ !Ref 'AWS::StackName', 'lb'] ] - Subnets: !Ref OpenViduSubnets - SecurityGroups: - - !Ref LoadBalancerSecurityGroup - Tags: - - Key: Name - Value: !Join ['-', [ !Ref 'AWS::StackName', 'lb'] ] - - HttpLoadBalancerListener: - Type: "AWS::ElasticLoadBalancingV2::Listener" - Properties: - DefaultActions: - - Type: "redirect" - RedirectConfig: - Protocol: "HTTPS" - Port: '443' - Host: "#{host}" - Path: "/#{path}" - Query: "#{query}" - StatusCode: "HTTP_301" - LoadBalancerArn: !Ref LoadBalancer - Port: 80 - Protocol: "HTTP" - - LoadBalancerListener: - Type: 'AWS::ElasticLoadBalancingV2::Listener' - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref TargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: 443 - Protocol: HTTPS - Certificates: - - CertificateArn: !Ref LoadBalancerCertificateARN - - RootListenerRule: - Type: 'AWS::ElasticLoadBalancingV2::ListenerRule' - Properties: - ListenerArn: !Ref LoadBalancerListener - Priority: 1 - Conditions: - - Field: path-pattern - Values: - - / - Actions: - - Type: "fixed-response" - FixedResponseConfig: - StatusCode: "401" - - InspectorListenerRule: - Type: 'AWS::ElasticLoadBalancingV2::ListenerRule' - Properties: - ListenerArn: !Ref LoadBalancerListener - Priority: 2 - Conditions: - - Field: path-pattern - Values: - - /inspector - Actions: - - Type: "redirect" - RedirectConfig: - Protocol: "HTTPS" - Port: '443' - Host: "#{host}" - Path: "/inspector/" - Query: "#{query}" - StatusCode: "HTTP_301" - - ListenerRule: - Type: 'AWS::ElasticLoadBalancingV2::ListenerRule' - Properties: - ListenerArn: !Ref LoadBalancerListener - Priority: 3 - Conditions: - - Field: path-pattern - Values: - - /openvidu* - Actions: - - TargetGroupArn: !Ref TargetGroup - Type: forward - - TargetGroup: - Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' - Properties: - Name: !Ref 'AWS::StackName' - VpcId: !Ref OpenViduVPC - Port: 4443 - Protocol: HTTP - Matcher: - HttpCode: '200' - HealthCheckIntervalSeconds: 10 - HealthCheckPath: /openvidu/health - HealthCheckProtocol: HTTP - HealthCheckPort: '4443' - HealthCheckTimeoutSeconds: 5 - HealthyThresholdCount: 3 - UnhealthyThresholdCount: 4 - Tags: - - Key: Name - Value: !Join [ "-", [ !Ref 'AWS::StackName', 'TargetGroup'] ] - - ##### - # OpenVidu Pro Master Role - ##### - OpenViduProMasterRole: - Type: 'AWS::IAM::Role' - Properties: - Tags: - - Key: Name - Value: !Join [ "-", [ !Ref 'AWS::StackName', 'MasterNodeRole'] ] - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - Service: - - ec2.amazonaws.com - Action: - - 'sts:AssumeRole' - Path: / - Policies: - - PolicyName: !Join ['-', [ !Ref 'AWS::StackName', 'MasterNodePolicy'] ] - PolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Action: - - 'ec2:Describe*' - - 'ec2:CreateTags' - - 'ec2:DescribeTags' - Resource: '*' - - Effect: Allow - Action: - - 'sqs:*' - Resource: !GetAtt SQSQueue.Arn - - Effect: Allow - Action: - - 'autoscaling:SetInstanceHealth' - - 'autoscaling:DescribeAutoScalingInstances' - - 'autoscaling:DescribeAutoScalingGroups' - - 'autoscaling:SetInstanceProtection' - Resource: '*' - - Effect: Allow - Action: - - 's3:DeleteObject' - - 's3:GetObject' - - 's3:PutObject' - Resource: - - Fn::If: - - CreateS3Bucket - # If bucket is created, get ARN - - !Join [ "", [ !GetAtt S3OpenViduBucket.Arn, "/*" ] ] - # If bucket name is defined, use bucket name - - !Join [ "", [ 'arn:aws:s3:::', !Ref OpenViduS3BucketName, '/*'] ] - - Effect: Allow - Action: - - 's3:ListBucket' - - 's3:GetBucketLocation' - Resource: - - Fn::If: - - CreateS3Bucket - # If bucket is created, get ARN - - !Join [ "", [ !GetAtt S3OpenViduBucket.Arn ] ] - # If bucket name is defined, use bucket name - - !Join [ "", [ 'arn:aws:s3:::', !Ref OpenViduS3BucketName ]] - RoleName: !Join ['-', [ !Ref 'AWS::StackName', 'MasterNodeRole'] ] - - OpenViduProMasterInstanceProfile: - Type: 'AWS::IAM::InstanceProfile' - Properties: - Path: / - Roles: - - !Ref OpenViduProMasterRole - - ##### - # OpenVidu Pro Master AutoScaling Group - ##### - OpenViduProMasterNodeAutoScalingLaunchTemplate: - Type: AWS::EC2::LaunchTemplate - Properties: - LaunchTemplateName: !Join [ "-", [ !Ref 'AWS::StackName', 'ASGMasterNodeLaunchConfiguration'] ] - LaunchTemplateData: - MetadataOptions: - HttpEndpoint: enabled - HttpPutResponseHopLimit: 1 - HttpTokens: required - SecurityGroupIds: - - !GetAtt OpenViduSecurityGroup.GroupId - IamInstanceProfile: - Arn: !GetAtt OpenViduProMasterInstanceProfile.Arn - ImageId: !GetAtt LambdaOnCreateInvoke.MasterNodeImageId - KeyName: !Ref KeyName - InstanceType: !Ref AwsInstanceTypeOV - BlockDeviceMappings: - - DeviceName: /dev/sda1 - Ebs: - VolumeType: gp2 - DeleteOnTermination: true - VolumeSize: 100 - UserData: - Fn::Base64: - Fn::Sub: - - | - DOMAIN_OR_PUBLIC_IP=${DomainNameVar} | \ - OPENVIDU_ENTERPRISE_MEDIA_SERVER=${MediaServer} | \ - OPENVIDU_PRO_LICENSE=${OpenViduLicense} | \ - OPENVIDU_SECRET=${OpenViduSecret} | \ - OPENVIDU_PRO_CLUSTER_ID=${OpenViduProClusterId} | \ - OPENVIDU_PRO_ELASTICSEARCH_HOST=${ElasticsearchUrl} | \ - OPENVIDU_PRO_KIBANA_HOST=${KibanaUrl} | \ - ELASTICSEARCH_USERNAME=${ElasticsearchUser} | \ - ELASTICSEARCH_PASSWORD=${ElasticsearchPassword} | \ - RM_REDIS_IP=${RedisHostName} | \ - RM_REDIS_PORT=${RedisPort} | \ - RM_SQS_QUEUE=${SqsQueueName} | \ - RM_CLOUDFORMATION_ARN=${AWS::StackId} | \ - OPENVIDU_PRO_CONFIG_S3_BUCKET=${OpenViduS3BucketParam} | \ - RM_MEDIA_NODES_AUTOSCALING_GROUP_NAME=${MediaNodesAutoscalingGroupName} | \ - RM_MASTER_NODES_AUTOSCALING_GROUP_NAME=${MasterNodesAutoscalingGroupName} | \ - OPENVIDU_RECORDING=${OpenViduRecording} | \ - OPENVIDU_PRO_COTURN_IN_MEDIA_NODES=${CoturnInMediaNodes} | \ - OPENVIDU_ENTERPRISE_S3_CONFIG_AUTORESTART=${OpenViduS3ConfigAutoRestart} | \ - OPENVIDU_PRO_ELASTICSEARCH=${ElasticsearchEnabled} - - DomainNameVar: !Ref DomainName - RedisHostName: !GetAtt RedisCluster.RedisEndpoint.Address - RedisPort: !GetAtt RedisCluster.RedisEndpoint.Port - SqsQueueName: !GetAtt SQSQueue.QueueName - MediaNodesAutoscalingGroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'ASGMediaNode'] ] - MasterNodesAutoscalingGroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'ASGOpenViduProMasterNode'] ] - OpenViduS3BucketParam: !If [ CreateS3Bucket, !Ref S3OpenViduBucket, !Ref OpenViduS3BucketName ] - - OpenViduProMasterNodeAutoScalingGroup: - Type: AWS::AutoScaling::AutoScalingGroup - Properties: - AutoScalingGroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'ASGOpenViduProMasterNode'] ] - LaunchTemplate: - LaunchTemplateId: !Ref OpenViduProMasterNodeAutoScalingLaunchTemplate - Version: !GetAtt OpenViduProMasterNodeAutoScalingLaunchTemplate.LatestVersionNumber - TargetGroupARNs: - - !Ref TargetGroup - MinSize: !Ref MinMasterNodes - MaxSize: !Ref MaxMasterNodes - DesiredCapacity: !Ref DesiredMasterNodes - VPCZoneIdentifier: !Ref OpenViduSubnets - HealthCheckType: ELB - HealthCheckGracePeriod: 180 - Tags: - - Key: Name - Value: !Join [ "-", [ !Ref 'AWS::StackName', 'Master Node'] ] - PropagateAtLaunch: true - - Key: ov-cluster-member - Value: server - PropagateAtLaunch: true - - ##### - # Media Node Autoscaling Lifecycle hooks - ##### - LaunchMediaNodeLifeCycleHook: - Type: AWS::AutoScaling::LifecycleHook - Properties: - LifecycleHookName: !Join [ "-", [ !Ref 'AWS::StackName', 'LaunchMediaNodeLifeCycleHook'] ] - AutoScalingGroupName: !Ref MediaNodeAutoScalingGroup - LifecycleTransition: autoscaling:EC2_INSTANCE_LAUNCHING - DefaultResult: CONTINUE - HeartbeatTimeout: 30 - - TerminateMediaNodeLifeCycleHook: - Type: AWS::AutoScaling::LifecycleHook - Properties: - LifecycleHookName: !Join [ "-", [ !Ref 'AWS::StackName', 'TerminateMediaNodeLifeCycleHook'] ] - AutoScalingGroupName: !Ref MediaNodeAutoScalingGroup - LifecycleTransition: autoscaling:EC2_INSTANCE_TERMINATING - DefaultResult: ABANDON - HeartbeatTimeout: 30 - - ########## - # AWS Events - ########## - # Send event with launched and terminated autoscaling group instances - LifeCycleMediaNodesRule: - Type: AWS::Events::Rule - Properties: - Name: !Join ['', [ !Ref AWS::StackName, '-asg-lifecycle-rule'] ] - State: 'ENABLED' - EventPattern: !Sub | - { - "source": [ "aws.autoscaling" ], - "detail": { - "LifecycleTransition": ["autoscaling:EC2_INSTANCE_LAUNCHING", "autoscaling:EC2_INSTANCE_TERMINATING"], - "AutoScalingGroupName": [ "${MediaNodeAutoScalingGroup}" ] - } - } - Targets: - - Arn: !GetAtt SQSQueue.Arn - Id: AsgLifecycleMediaNodes - SqsParameters: - MessageGroupId: sqs-notification - InputTransformer: - InputPathsMap: - source: $.source - lifecycle-transition: $.detail.LifecycleTransition - ec2-instance: $.detail.EC2InstanceId - autoscaling-groupname: $.detail.AutoScalingGroupName - InputTemplate: >- - { - "source": , - "detail": { - "LifecycleTransition": , - "AutoScalingGroupName": , - "EC2InstanceId": - }, - "role": "MediaNode" - } - - # Send event to update cluster state on autoscaling actions from AWS - AutoscalingScheduleRule: - Type: AWS::Events::Rule - Properties: - Description: 'Executes periodically lambda which sends information about the OpenVidu Pro Cluster' - Name: !Join ['', [ !Ref AWS::StackName, '-asg-rule'] ] - ScheduleExpression: 'rate(1 minute)' - State: 'ENABLED' - Targets: - - Arn: !GetAtt SQSQueue.Arn - Id: AsgSchedule - SqsParameters: - MessageGroupId: sqs-notification - InputTransformer: - InputPathsMap: - time: $.time - InputTemplate: >- - { - "source": "custom.autoscaling_schedule", - "detail": { - "time":