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(