Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee45042cca |
113
.github/workflows/openvidu-ce-test.yml
vendored
Normal file
113
.github/workflows/openvidu-ce-test.yml
vendored
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
name: OpenVidu CE Tests
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths-ignore:
|
||||||
|
- ".github/workflows/openvidu-components-angular-E2E.yml"
|
||||||
|
- "openvidu-components-angular/**"
|
||||||
|
- "openvidu-server/docker/**"
|
||||||
|
- "openvidu-server/deployments/**"
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
TEST_IMAGE:
|
||||||
|
description: "Docker image where to run the tests"
|
||||||
|
required: true
|
||||||
|
default: "openvidu/openvidu-test-e2e:22.04"
|
||||||
|
KURENTO_JAVA_COMMIT:
|
||||||
|
description: 'Commit to use in kurento-java dependencies. If "default" the release version declared in property "version.kurento" of openvidu-parent/pom.xml will be used'
|
||||||
|
required: true
|
||||||
|
default: "default"
|
||||||
|
KURENTO_MEDIA_SERVER_IMAGE:
|
||||||
|
description: "Docker image of kurento-media-server"
|
||||||
|
required: true
|
||||||
|
default: "kurento/kurento-media-server:7.0.1"
|
||||||
|
DOCKER_RECORDING_VERSION:
|
||||||
|
description: "Force version of openvidu/openvidu-recording container"
|
||||||
|
required: true
|
||||||
|
default: "default"
|
||||||
|
CHROME_VERSION:
|
||||||
|
description: "Version of Chrome to use. Must be a valid image tag from https://hub.docker.com/r/selenium/standalone-chrome/tags"
|
||||||
|
required: true
|
||||||
|
default: "latest"
|
||||||
|
FIREFOX_VERSION:
|
||||||
|
description: "Version of Firefox to use. Must be a valid image tag from https://hub.docker.com/r/selenium/standalone-firefox/tags"
|
||||||
|
required: true
|
||||||
|
default: "latest"
|
||||||
|
EDGE_VERSION:
|
||||||
|
description: "Version of Edge to use. Must be a valid image tag from https://hub.docker.com/r/selenium/standalone-edge/tags"
|
||||||
|
required: true
|
||||||
|
default: "latest"
|
||||||
|
jobs:
|
||||||
|
main:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ inputs.TEST_IMAGE || 'openvidu/openvidu-test-e2e:22.04' }}
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- /opt/openvidu:/opt/openvidu
|
||||||
|
env:
|
||||||
|
TEST_IMAGE: ${{ inputs.TEST_IMAGE || 'openvidu/openvidu-test-e2e:22.04' }}
|
||||||
|
KURENTO_SNAPSHOTS_URL: ${{ secrets.KURENTO_SNAPSHOTS_URL }}
|
||||||
|
KURENTO_MEDIA_SERVER_IMAGE: ${{ inputs.KURENTO_MEDIA_SERVER_IMAGE || 'kurento/kurento-media-server:7.0.1' }}
|
||||||
|
KURENTO_JAVA_COMMIT: ${{ inputs.KURENTO_JAVA_COMMIT || 'default' }}
|
||||||
|
DOCKER_RECORDING_VERSION: ${{ inputs.DOCKER_RECORDING_VERSION || 'default' }}
|
||||||
|
CHROME_VERSION: ${{ inputs.CHROME_VERSION || 'latest' }}
|
||||||
|
FIREFOX_VERSION: ${{ inputs.FIREFOX_VERSION || 'latest' }}
|
||||||
|
EDGE_VERSION: ${{ inputs.EDGE_VERSION || 'latest' }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Setup scripts
|
||||||
|
run: |
|
||||||
|
curl -sOJ --output-dir /opt https://raw.githubusercontent.com/OpenVidu/openvidu/master/ci-scripts/commons/build.sh
|
||||||
|
curl -sOJ --output-dir /opt https://raw.githubusercontent.com/OpenVidu/openvidu/master/ci-scripts/commons/test-utils.sh
|
||||||
|
cp ci-scripts/openvidu-e2e-tests.sh /opt/openvidu-e2e-tests.sh
|
||||||
|
find /opt/*.sh -type f -print0 | xargs -0 chmod u+x
|
||||||
|
- name: Clean environment
|
||||||
|
run: /opt/build.sh --clean-environment
|
||||||
|
- name: Prepare test environment
|
||||||
|
run: /opt/test-utils.sh --prepare-test-environment "${TEST_IMAGE}"
|
||||||
|
- name: Check and prepare kurento snapshots
|
||||||
|
run: /opt/build.sh --check-and-prepare-kurento-snapshot
|
||||||
|
- name: Use specific kurento-java commit
|
||||||
|
if: ${{ env.KURENTO_JAVA_COMMIT != 'default'}}
|
||||||
|
run: /opt/test-utils.sh --use-specific-kurento-java-commit
|
||||||
|
- name: Build openvidu-browser
|
||||||
|
run: /opt/build.sh --build-openvidu-browser
|
||||||
|
- name: Build openvidu-node-client
|
||||||
|
run: /opt/build.sh --build-openvidu-node-client
|
||||||
|
- name: Build openvidu-java-client
|
||||||
|
run: /opt/build.sh --build-openvidu-java-client
|
||||||
|
- name: Build openvidu-parent
|
||||||
|
run: /opt/build.sh --build-openvidu-parent
|
||||||
|
- name: Build openvidu-testapp
|
||||||
|
run: /opt/build.sh --build-openvidu-testapp
|
||||||
|
- name: Build openvidu-server dashboard
|
||||||
|
run: /opt/build.sh --build-openvidu-server-dashboard true
|
||||||
|
- name: Build openvidu-server
|
||||||
|
run: /opt/build.sh --build-openvidu-server
|
||||||
|
- name: openvidu-server unit tests
|
||||||
|
run: /opt/openvidu-e2e-tests.sh --openvidu-server-unit-tests
|
||||||
|
- name: openvidu-server integration tests
|
||||||
|
run: /opt/openvidu-e2e-tests.sh --openvidu-server-integration-tests
|
||||||
|
- name: Environment launch Kurento
|
||||||
|
run: /opt/openvidu-e2e-tests.sh --environment-launch-kurento
|
||||||
|
- name: Serve openvidu-testapp
|
||||||
|
run: /opt/test-utils.sh --serve-openvidu-testapp
|
||||||
|
- name: OpenVidu E2E Tests Kurento
|
||||||
|
run: /opt/openvidu-e2e-tests.sh --openvidu-e2e-tests-kurento
|
||||||
|
- name: Test reports
|
||||||
|
uses: mikepenz/action-junit-report@v3
|
||||||
|
if: always() # always run even if the previous step fails
|
||||||
|
with:
|
||||||
|
report_paths: "**/target/surefire-reports/TEST-*.xml"
|
||||||
|
- name: Upload logs
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
if: always() # always run even if the previous step fails
|
||||||
|
with:
|
||||||
|
name: Logs
|
||||||
|
path: |
|
||||||
|
/opt/openvidu/*.log
|
||||||
158
.github/workflows/openvidu-components-angular-E2E.yml
vendored
Normal file
158
.github/workflows/openvidu-components-angular-E2E.yml
vendored
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
name: openvidu-components-angular E2E
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- 'openvidu-components-angular/**'
|
||||||
|
- 'openvidu-browser/**'
|
||||||
|
- 'openvidu-node-client/**'
|
||||||
|
- '.github/workflows/openvidu-components-angular-E2E.yml'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
commit_sha:
|
||||||
|
description: 'Commit SHA'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
test_setup:
|
||||||
|
name: Test setup
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.commit_sha || github.sha }}
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '16'
|
||||||
|
- name: Commit URL
|
||||||
|
run: echo https://github.com/OpenVidu/openvidu/commit/${{ inputs.commit_sha || github.sha }}
|
||||||
|
- name: Send repository dispatch event
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.OPENVIDU_DISPATCH_EVENT_GA }}
|
||||||
|
COMMIT_MESSAGE: ${{ github.event.head_commit.message || 'Manually' }}
|
||||||
|
COMMIT_URL: ${{ github.event.commits[0].url || 'Manually' }}
|
||||||
|
BRANCH_NAME: ${{ github.ref_name }}
|
||||||
|
run: |
|
||||||
|
curl \
|
||||||
|
-X POST \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
|
||||||
|
https://api.github.com/repos/OpenVidu/openvidu-call/dispatches \
|
||||||
|
-d '{"event_type":"openvidu-components-angular","client_payload":{"commit-message":"'"$COMMIT_MESSAGE"'","commit-ref":"'"$COMMIT_URL"'", "branch-name":"'"$BRANCH_NAME"'"}}'
|
||||||
|
- name: Build openvidu-browser
|
||||||
|
run: |
|
||||||
|
cd openvidu-browser
|
||||||
|
npm install
|
||||||
|
npm run build && \
|
||||||
|
npm pack
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: openvidu-browser
|
||||||
|
path: openvidu-browser/openvidu-browser-*.tgz
|
||||||
|
|
||||||
|
|
||||||
|
openvidu_angular_e2e:
|
||||||
|
needs: test_setup
|
||||||
|
name: OpenVidu Angular E2E tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.commit_sha || github.sha }}
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '16'
|
||||||
|
- uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: openvidu-browser
|
||||||
|
path: openvidu-components-angular
|
||||||
|
- name: Run Browserless Chrome
|
||||||
|
run: docker run -d -p 3000:3000 --network host browserless/chrome:1.57-chrome-stable
|
||||||
|
- name: Run openvidu-server-kms
|
||||||
|
run: |
|
||||||
|
docker run -p 4443:4443 --rm -d \
|
||||||
|
-e OPENVIDU_SECRET=MY_SECRET \
|
||||||
|
openvidu/openvidu-dev:latest
|
||||||
|
- name: Install openvidu-browser and dependencies
|
||||||
|
run: |
|
||||||
|
cd openvidu-components-angular
|
||||||
|
npm install openvidu-browser-*.tgz
|
||||||
|
- name: Build openvidu-angular
|
||||||
|
run: npm run lib:build --prefix openvidu-components-angular
|
||||||
|
- name: Build openvidu-angular-testapp
|
||||||
|
run: npm run build --prefix openvidu-components-angular
|
||||||
|
- name: Serve openvidu-angular-testapp
|
||||||
|
run: npm run start-prod --prefix openvidu-components-angular &
|
||||||
|
- name: Run openvidu-angular E2E
|
||||||
|
run: npm run lib:e2e-ci --prefix openvidu-components-angular
|
||||||
|
|
||||||
|
webcomponent_e2e:
|
||||||
|
needs: test_setup
|
||||||
|
name: Webcomponent E2E CE tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.commit_sha || github.sha }}
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '16'
|
||||||
|
- uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: openvidu-browser
|
||||||
|
path: openvidu-components-angular
|
||||||
|
- name: Run Browserless Chrome
|
||||||
|
run: docker run -d -p 3000:3000 --network host browserless/chrome:1.57-chrome-stable
|
||||||
|
- name: Run openvidu-server-kms
|
||||||
|
run: |
|
||||||
|
docker run -p 4443:4443 --rm -d \
|
||||||
|
-e OPENVIDU_SECRET=MY_SECRET \
|
||||||
|
openvidu/openvidu-dev:latest
|
||||||
|
- name: Install openvidu-browser and dependencies
|
||||||
|
run: |
|
||||||
|
cd openvidu-components-angular
|
||||||
|
npm install openvidu-browser-*.tgz
|
||||||
|
- name: Build openvidu-angular
|
||||||
|
run: npm run lib:build --prefix openvidu-components-angular
|
||||||
|
- name: Build openvidu-webcomponent
|
||||||
|
run: npm run webcomponent:build --prefix openvidu-components-angular
|
||||||
|
- name: Serve Webcomponent Testapp
|
||||||
|
run: npm run webcomponent:serve-testapp --prefix openvidu-components-angular &
|
||||||
|
- name: Run Webcomponent E2E
|
||||||
|
run: npm run webcomponent:e2e-ci --prefix openvidu-components-angular
|
||||||
|
|
||||||
|
webcomponent_e2e_pro:
|
||||||
|
if: false #Skip PRO test because infra is unstable
|
||||||
|
needs: test_setup
|
||||||
|
name: Webcomponent E2E PRO tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '16'
|
||||||
|
- uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: openvidu-browser
|
||||||
|
path: openvidu-components-angular
|
||||||
|
- name: Run Browserless Chrome
|
||||||
|
run: docker run -d -p 3000:3000 --network host browserless/chrome:1.57-chrome-stable
|
||||||
|
- name: Install openvidu-browser and dependencies
|
||||||
|
run: |
|
||||||
|
cd openvidu-components-angular
|
||||||
|
npm install openvidu-browser-*.tgz
|
||||||
|
- name: Build openvidu-angular
|
||||||
|
run: npm run lib:build --prefix openvidu-components-angular
|
||||||
|
- name: Build openvidu-webcomponent
|
||||||
|
run: npm run webcomponent:build --prefix openvidu-components-angular
|
||||||
|
- name: Serve Webcomponent Testapp
|
||||||
|
run: npm run webcomponent:serve-testapp --prefix openvidu-components-angular &
|
||||||
|
- name: Run Webcomponent E2E PRO
|
||||||
|
env:
|
||||||
|
OPENVIDU_SERVER_URL: ${{ secrets.OPENVIDU_CALL_NEXT_URL }}
|
||||||
|
OPENVIDU_SECRET: ${{ secrets.OPENVIDU_CALL_NEXT_SECRET }}
|
||||||
|
run: npm run webcomponent:e2e-pro-ci --prefix openvidu-components-angular
|
||||||
@ -1,117 +0,0 @@
|
|||||||
name: openvidu-components-angular E2E
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
paths:
|
|
||||||
- 'openvidu-components-angular/**'
|
|
||||||
- '.github/workflows/openvidu-components-angular-tests.yml'
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
commit_sha:
|
|
||||||
description: 'Commit SHA'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
|
|
||||||
env:
|
|
||||||
NODE_VERSION: '20'
|
|
||||||
CHROME_IMAGE: selenium/standalone-chrome:138.0
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test_setup:
|
|
||||||
name: Test setup
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: ${{ inputs.commit_sha || github.sha }}
|
|
||||||
- name: Set up Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- name: Commit URL
|
|
||||||
run: echo https://github.com/OpenVidu/openvidu/commit/${{ inputs.commit_sha || github.sha }}
|
|
||||||
- name: Send Dispatch Event
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.OPENVIDU_DISPATCH_EVENT_GA }}
|
|
||||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message || 'Manually' }}
|
|
||||||
COMMIT_URL: ${{ github.event.commits[0].url || 'Manually' }}
|
|
||||||
BRANCH_NAME: ${{ github.ref_name }}
|
|
||||||
run: |
|
|
||||||
curl -X POST \
|
|
||||||
-H "Accept: application/vnd.github+json" \
|
|
||||||
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
|
|
||||||
https://api.github.com/repos/OpenVidu/openvidu-tutorials/dispatches \
|
|
||||||
-d '{"event_type":"openvidu-components-angular","client_payload":{"commit-message":"'"$COMMIT_MESSAGE"'","commit-ref":"'"$COMMIT_URL"'", "branch-name":"'"$BRANCH_NAME"'"}}'
|
|
||||||
|
|
||||||
e2e_tests:
|
|
||||||
needs: test_setup
|
|
||||||
name: ${{ matrix.name }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- name: Nested events
|
|
||||||
script: e2e:nested-events
|
|
||||||
- name: Nested Structural Directives
|
|
||||||
script: e2e:nested-structural-directives
|
|
||||||
- name: Nested Attribute Directives
|
|
||||||
script: e2e:nested-attribute-directives
|
|
||||||
- name: API Directives Tests
|
|
||||||
script: e2e:lib-directives
|
|
||||||
- name: Internal Directives Tests
|
|
||||||
script: e2e:lib-internal-directives
|
|
||||||
- name: Chat E2E
|
|
||||||
script: e2e:lib-chat
|
|
||||||
- name: Events E2E
|
|
||||||
script: e2e:lib-events
|
|
||||||
- name: Media devices E2E
|
|
||||||
script: e2e:lib-media-devices
|
|
||||||
- name: Panels E2E
|
|
||||||
script: e2e:lib-panels
|
|
||||||
- name: Screen sharing E2E
|
|
||||||
script: e2e:lib-screensharing
|
|
||||||
- name: Stream E2E
|
|
||||||
script: e2e:lib-stream
|
|
||||||
mount_assets: true
|
|
||||||
- name: Toolbar E2E
|
|
||||||
script: e2e:lib-toolbar
|
|
||||||
- name: Virtual Backgrounds E2E
|
|
||||||
script: e2e:lib-virtual-backgrounds
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: ${{ inputs.commit_sha || github.sha }}
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- name: Install wait-on package
|
|
||||||
run: npm install -g wait-on
|
|
||||||
- name: Run Chrome
|
|
||||||
run: |
|
|
||||||
if [ "${{ matrix.mount_assets }}" = "true" ]; then
|
|
||||||
docker run --network=host -d -p 4444:4444 -v $(pwd)/openvidu-components-angular/e2e/assets:/e2e-assets ${{ env.CHROME_IMAGE }}
|
|
||||||
else
|
|
||||||
docker run --network=host -d -p 4444:4444 ${{ env.CHROME_IMAGE }}
|
|
||||||
fi
|
|
||||||
- name: Run openvidu-local-deployment
|
|
||||||
uses: OpenVidu/actions/start-openvidu-local-deployment@main
|
|
||||||
- name: Start OpenVidu Call backend
|
|
||||||
uses: OpenVidu/actions/start-openvidu-call@main
|
|
||||||
- name: Build and Serve openvidu-components-angular Testapp
|
|
||||||
uses: OpenVidu/actions/start-openvidu-components-testapp@main
|
|
||||||
- name: Run Tests
|
|
||||||
env:
|
|
||||||
LAUNCH_MODE: CI
|
|
||||||
run: npm run ${{ matrix.script }} --prefix openvidu-components-angular
|
|
||||||
- name: Cleanup
|
|
||||||
if: always()
|
|
||||||
uses: OpenVidu/actions/cleanup@main
|
|
||||||
56
.github/workflows/openvidu-integration-tests.yml
vendored
56
.github/workflows/openvidu-integration-tests.yml
vendored
@ -1,56 +0,0 @@
|
|||||||
name: OpenVidu integration tests
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
paths:
|
|
||||||
- "openvidu-test-integration/**"
|
|
||||||
- ".github/workflows/openvidu-integration-tests.yml"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
integration-tests:
|
|
||||||
name: Integration tests
|
|
||||||
timeout-minutes: 30
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Configure OpenVidu Local Deployment
|
|
||||||
uses: OpenVidu/actions/start-openvidu-local-deployment@main
|
|
||||||
with:
|
|
||||||
ref-openvidu-local-deployment: development
|
|
||||||
pre_startup_commands: |
|
|
||||||
sed -i 's/interval: 10s/interval: 1s/' livekit.yaml
|
|
||||||
sed -i '/interval: 1s/a \ fixer_interval: 10s' livekit.yaml
|
|
||||||
- name: Install LiveKit CLI
|
|
||||||
run: |
|
|
||||||
curl -sSL https://get.livekit.io/cli | bash
|
|
||||||
|
|
||||||
- name: Checkout current repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
path: openvidu
|
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
working-directory: ./openvidu/openvidu-test-integration
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Run tests
|
|
||||||
working-directory: ./openvidu/openvidu-test-integration
|
|
||||||
run: npm run test:ci
|
|
||||||
|
|
||||||
- name: Upload report
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: openvidu-integration-tests-report
|
|
||||||
path: ./openvidu/openvidu-test-integration/test-results.json
|
|
||||||
retention-days: 7
|
|
||||||
- name: Cleanup
|
|
||||||
if: always()
|
|
||||||
uses: OpenVidu/actions/cleanup@main
|
|
||||||
|
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
@ -27,9 +27,3 @@ nbactions.xml
|
|||||||
*/.tscache/*
|
*/.tscache/*
|
||||||
|
|
||||||
.factorypath
|
.factorypath
|
||||||
.terraform
|
|
||||||
.terraform.lock.hcl
|
|
||||||
*.tfstate
|
|
||||||
*.tfstate.backup
|
|
||||||
*.tfstate.lock.info
|
|
||||||
*.tfvars
|
|
||||||
|
|||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
|||||||
[submodule "openvidu-livekit"]
|
|
||||||
path = openvidu-livekit
|
|
||||||
url = https://github.com/OpenVidu/openvidu-livekit.git
|
|
||||||
@ -35,11 +35,6 @@ Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com
|
|||||||
|
|
||||||
<a href="https://opencollective.com/openvidu#backers" target="_blank"><img src="https://opencollective.com/openvidu/backers.svg?width=890"></a>
|
<a href="https://opencollective.com/openvidu#backers" target="_blank"><img src="https://opencollective.com/openvidu/backers.svg?width=890"></a>
|
||||||
|
|
||||||
## 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.
|
|
||||||
|
|
||||||
<img height="75px" src="https://docs.openvidu.io/en/stable/img/logos/support.jpg">
|
|
||||||
|
|
||||||
## Sponsors
|
## Sponsors
|
||||||
|
|
||||||
|
|||||||
248
ci-scripts/commons/build.sh
Normal file
248
ci-scripts/commons/build.sh
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
#!/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'[<>]' '/<version.kurento>/ {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
|
||||||
307
ci-scripts/commons/bump.sh
Normal file
307
ci-scripts/commons/bump.sh
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
#!/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>" $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
|
||||||
161
ci-scripts/commons/test-utils.sh
Normal file
161
ci-scripts/commons/test-utils.sh
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
#!/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
|
||||||
43
ci-scripts/kurento-snapshots.xml
Normal file
43
ci-scripts/kurento-snapshots.xml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
|
||||||
|
<pluginGroups></pluginGroups>
|
||||||
|
<proxies></proxies>
|
||||||
|
<servers></servers>
|
||||||
|
<mirrors></mirrors>
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>default</id>
|
||||||
|
<activation>
|
||||||
|
<activeByDefault>true</activeByDefault>
|
||||||
|
</activation>
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>kurento-github-public</id>
|
||||||
|
<name>Kurento GitHub Maven packages (public access)</name>
|
||||||
|
<url>KURENTO_SNAPSHOTS_URL</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
<pluginRepositories>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>kurento-github-public</id>
|
||||||
|
<name>Kurento GitHub Maven packages (public access)</name>
|
||||||
|
<url>KURENTO_SNAPSHOTS_URL</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</pluginRepository>
|
||||||
|
</pluginRepositories>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
</settings>
|
||||||
241
ci-scripts/openvidu-e2e-tests.sh
Executable file
241
ci-scripts/openvidu-e2e-tests.sh
Executable file
@ -0,0 +1,241 @@
|
|||||||
|
#!/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
|
||||||
62
openvidu-browser/.gitignore
vendored
Normal file
62
openvidu-browser/.gitignore
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# 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/**
|
||||||
1
openvidu-browser/.npmignore
Normal file
1
openvidu-browser/.npmignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
docs/
|
||||||
10
openvidu-browser/.prettierrc
Normal file
10
openvidu-browser/.prettierrc
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 140,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"semi": true,
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"useTabs": false,
|
||||||
|
"jsxSingleQuote": true,
|
||||||
|
"tabWidth": 4
|
||||||
|
}
|
||||||
201
openvidu-browser/LICENSE
Normal file
201
openvidu-browser/LICENSE
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
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.
|
||||||
7
openvidu-browser/config/replace_for_ts44.sh
Executable file
7
openvidu-browser/config/replace_for_ts44.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
SEARCH_STRING_1="<K extends keyof SessionEventMap>(type: K,"
|
||||||
|
REPLACE_STRING_1="<K extends keyof SessionEventMap>(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
|
||||||
20
openvidu-browser/config/tsconfig.json
Normal file
20
openvidu-browser/config/tsconfig.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
}
|
||||||
154
openvidu-browser/config/tslint.json
Normal file
154
openvidu-browser/config/tslint.json
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
}
|
||||||
19
openvidu-browser/generate-docs.sh
Executable file
19
openvidu-browser/generate-docs.sh
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
#!/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
|
||||||
10711
openvidu-browser/package-lock.json
generated
Normal file
10711
openvidu-browser/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
57
openvidu-browser/package.json
Normal file
57
openvidu-browser/package.json
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"author": "OpenVidu",
|
||||||
|
"dependencies": {
|
||||||
|
"freeice": "2.2.2",
|
||||||
|
"hark": "1.2.3",
|
||||||
|
"jsnlog": "2.30.0",
|
||||||
|
"mime": "3.0.0",
|
||||||
|
"platform": "1.3.6",
|
||||||
|
"semver": "7.3.8",
|
||||||
|
"uuid": "9.0.0",
|
||||||
|
"wolfy87-eventemitter": "5.2.9",
|
||||||
|
"events": "3.3.0",
|
||||||
|
"inherits": "2.0.4"
|
||||||
|
},
|
||||||
|
"description": "OpenVidu Browser",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "18.11.9",
|
||||||
|
"@types/platform": "1.3.4",
|
||||||
|
"browserify": "17.0.0",
|
||||||
|
"grunt": "1.5.3",
|
||||||
|
"grunt-cli": "1.4.3",
|
||||||
|
"grunt-contrib-copy": "1.0.0",
|
||||||
|
"grunt-contrib-sass": "2.0.0",
|
||||||
|
"grunt-contrib-uglify": "5.2.2",
|
||||||
|
"grunt-contrib-watch": "1.1.0",
|
||||||
|
"grunt-postcss": "0.9.0",
|
||||||
|
"grunt-string-replace": "1.3.3",
|
||||||
|
"grunt-ts": "6.0.0-beta.22",
|
||||||
|
"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.29.1"
|
||||||
|
}
|
||||||
9
openvidu-browser/src/Main.ts
Normal file
9
openvidu-browser/src/Main.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
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 });
|
||||||
217
openvidu-browser/src/OpenVidu/Connection.ts
Normal file
217
openvidu-browser/src/OpenVidu/Connection.ts
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
* (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) <a href="https://docs.openvidu.io/en/stable/openvidu-pro/" style="display: inline-block; background-color: rgb(0, 136, 170); color: white; font-weight: bold; padding: 0px 5px; margin-right: 5px; border-radius: 3px; font-size: 13px; line-height:21px; font-family: Montserrat, sans-serif">PRO</a>
|
||||||
|
*
|
||||||
|
* **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 (!!(<LocalConnectionOptions>connectionOptions).role) {
|
||||||
|
// Connection is local
|
||||||
|
this.localOptions = <LocalConnectionOptions>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 = <RemoteConnectionOptions>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();
|
||||||
|
}
|
||||||
|
}
|
||||||
112
openvidu-browser/src/OpenVidu/EventDispatcher.ts
Normal file
112
openvidu-browser/src/OpenVidu/EventDispatcher.ts
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* (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<K extends keyof EventMap>(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<K extends keyof EventMap>(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<K extends keyof EventMap>(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
285
openvidu-browser/src/OpenVidu/Filter.ts
Normal file
285
openvidu-browser/src/OpenVidu/Filter.ts
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
/*
|
||||||
|
* (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<string, (event: FilterEvent) => 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<void> {
|
||||||
|
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 = (<any>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 = <string>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<void> {
|
||||||
|
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<void> {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
416
openvidu-browser/src/OpenVidu/LocalRecorder.ts
Normal file
416
openvidu-browser/src/OpenVidu/LocalRecorder.ts
Normal file
@ -0,0 +1,416 @@
|
|||||||
|
/*
|
||||||
|
* (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<void> {
|
||||||
|
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<void> {
|
||||||
|
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<void> {
|
||||||
|
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<void> {
|
||||||
|
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(<any>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<any> {
|
||||||
|
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<any> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
1301
openvidu-browser/src/OpenVidu/OpenVidu.ts
Normal file
1301
openvidu-browser/src/OpenVidu/OpenVidu.ts
Normal file
File diff suppressed because it is too large
Load Diff
875
openvidu-browser/src/OpenVidu/Publisher.ts
Normal file
875
openvidu-browser/src/OpenVidu/Publisher.ts
Normal file
File diff suppressed because it is too large
Load Diff
1804
openvidu-browser/src/OpenVidu/Session.ts
Normal file
1804
openvidu-browser/src/OpenVidu/Session.ts
Normal file
File diff suppressed because it is too large
Load Diff
1869
openvidu-browser/src/OpenVidu/Stream.ts
Normal file
1869
openvidu-browser/src/OpenVidu/Stream.ts
Normal file
File diff suppressed because it is too large
Load Diff
621
openvidu-browser/src/OpenVidu/StreamManager.ts
Normal file
621
openvidu-browser/src/OpenVidu/StreamManager.ts
Normal file
File diff suppressed because it is too large
Load Diff
101
openvidu-browser/src/OpenVidu/Subscriber.ts
Normal file
101
openvidu-browser/src/OpenVidu/Subscriber.ts
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* (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);
|
||||||
|
}
|
||||||
|
}
|
||||||
35
openvidu-browser/src/OpenVidu/tsconfig.json
Normal file
35
openvidu-browser/src/OpenVidu/tsconfig.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
//"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* (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'
|
||||||
|
}
|
||||||
141
openvidu-browser/src/OpenViduInternal/Enums/OpenViduError.ts
Normal file
141
openvidu-browser/src/OpenViduInternal/Enums/OpenViduError.ts
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
|
}
|
||||||
23
openvidu-browser/src/OpenViduInternal/Enums/TypeOfVideo.ts
Normal file
23
openvidu-browser/src/OpenViduInternal/Enums/TypeOfVideo.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* (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'
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* (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'
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* (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() { }
|
||||||
|
}
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* (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
|
||||||
|
* <a href="https://docs.openvidu.io/en/stable/openvidu-pro/" style="display: inline-block; background-color: rgb(0, 136, 170); color: white; font-weight: bold; padding: 0px 5px; margin: 0 2px 0 2px; border-radius: 3px; font-size: 13px; line-height:21px; text-decoration: none; font-family: Montserrat, sans-serif">PRO</a>
|
||||||
|
* and
|
||||||
|
* <a href="https://docs.openvidu.io/en/stable/openvidu-enterprise/" style="display: inline-block; background-color: rgb(156, 39, 176); color: white; font-weight: bold; padding: 0px 5px; margin: 0 2px 0 2px; border-radius: 3px; font-size: 13px; line-height:21px; text-decoration: none; font-family: Montserrat, sans-serif">ENTERPRISE</a>
|
||||||
|
* 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() {}
|
||||||
|
}
|
||||||
83
openvidu-browser/src/OpenViduInternal/Events/Event.ts
Normal file
83
openvidu-browser/src/OpenViduInternal/Events/Event.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* (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();
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* (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 {}
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
* (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
|
||||||
|
* <a href="https://docs.openvidu.io/en/stable/openvidu-pro/" style="display: inline-block; background-color: rgb(0, 136, 170); color: white; font-weight: bold; padding: 0px 5px; margin: 0 2px 0 2px; border-radius: 3px; font-size: 13px; line-height:21px; text-decoration: none; font-family: Montserrat, sans-serif">PRO</a>
|
||||||
|
* and
|
||||||
|
* <a href="https://docs.openvidu.io/en/stable/openvidu-enterprise/" style="display: inline-block; background-color: rgb(156, 39, 176); color: white; font-weight: bold; padding: 0px 5px; margin: 0 2px 0 2px; border-radius: 3px; font-size: 13px; line-height:21px; text-decoration: none; font-family: Montserrat, sans-serif">ENTERPRISE</a>
|
||||||
|
* 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)<br><br>
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
* <a href="https://docs.openvidu.io/en/stable/openvidu-pro/" style="display: inline-block; background-color: rgb(0, 136, 170); color: white; font-weight: bold; padding: 0px 5px; margin: 0 2px 0 2px; border-radius: 3px; font-size: 13px; line-height:21px; text-decoration: none; font-family: Montserrat, sans-serif">PRO</a>
|
||||||
|
* and
|
||||||
|
* <a href="https://docs.openvidu.io/en/stable/openvidu-enterprise/" style="display: inline-block; background-color: rgb(156, 39, 176); color: white; font-weight: bold; padding: 0px 5px; margin: 0 2px 0 2px; border-radius: 3px; font-size: 13px; line-height:21px; text-decoration: none; font-family: Montserrat, sans-serif">ENTERPRISE</a>
|
||||||
|
* 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
|
||||||
|
* <a href="https://docs.openvidu.io/en/stable/openvidu-pro/" style="display: inline-block; background-color: rgb(0, 136, 170); color: white; font-weight: bold; padding: 0px 5px; margin: 0 2px 0 2px; border-radius: 3px; font-size: 13px; line-height:21px; text-decoration: none; font-family: Montserrat, sans-serif">PRO</a>
|
||||||
|
* and
|
||||||
|
* <a href="https://docs.openvidu.io/en/stable/openvidu-enterprise/" style="display: inline-block; background-color: rgb(156, 39, 176); color: white; font-weight: bold; padding: 0px 5px; margin: 0 2px 0 2px; border-radius: 3px; font-size: 13px; line-height:21px; text-decoration: none; font-family: Montserrat, sans-serif">ENTERPRISE</a>
|
||||||
|
* 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
|
||||||
|
* <a href="https://docs.openvidu.io/en/stable/openvidu-pro/" style="display: inline-block; background-color: rgb(0, 136, 170); color: white; font-weight: bold; padding: 0px 5px; margin: 0 2px 0 2px; border-radius: 3px; font-size: 13px; line-height:21px; text-decoration: none; font-family: Montserrat, sans-serif">PRO</a>
|
||||||
|
* and
|
||||||
|
* <a href="https://docs.openvidu.io/en/stable/openvidu-enterprise/" style="display: inline-block; background-color: rgb(156, 39, 176); color: white; font-weight: bold; padding: 0px 5px; margin: 0 2px 0 2px; border-radius: 3px; font-size: 13px; line-height:21px; text-decoration: none; font-family: Montserrat, sans-serif">ENTERPRISE</a>
|
||||||
|
* 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
|
||||||
|
* <a href="https://docs.openvidu.io/en/stable/openvidu-pro/" style="display: inline-block; background-color: rgb(0, 136, 170); color: white; font-weight: bold; padding: 0px 5px; margin: 0 2px 0 2px; border-radius: 3px; font-size: 13px; line-height:21px; text-decoration: none; font-family: Montserrat, sans-serif">PRO</a>
|
||||||
|
* and
|
||||||
|
* <a href="https://docs.openvidu.io/en/stable/openvidu-enterprise/" style="display: inline-block; background-color: rgb(156, 39, 176); color: white; font-weight: bold; padding: 0px 5px; margin: 0 2px 0 2px; border-radius: 3px; font-size: 13px; line-height:21px; text-decoration: none; font-family: Montserrat, sans-serif">ENTERPRISE</a>
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
136
openvidu-browser/src/OpenViduInternal/Events/ExceptionEvent.ts
Normal file
136
openvidu-browser/src/OpenViduInternal/Events/ExceptionEvent.ts
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* (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() { }
|
||||||
|
}
|
||||||
43
openvidu-browser/src/OpenViduInternal/Events/FilterEvent.ts
Normal file
43
openvidu-browser/src/OpenViduInternal/Events/FilterEvent.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* (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() {}
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* (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() {}
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* (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() {}
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* (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() { }
|
||||||
|
}
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* (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 = <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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
64
openvidu-browser/src/OpenViduInternal/Events/SignalEvent.ts
Normal file
64
openvidu-browser/src/OpenViduInternal/Events/SignalEvent.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* (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() {}
|
||||||
|
}
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* (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() { }
|
||||||
|
}
|
||||||
113
openvidu-browser/src/OpenViduInternal/Events/StreamEvent.ts
Normal file
113
openvidu-browser/src/OpenViduInternal/Events/StreamEvent.ts
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* (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((<Publisher>this.target).screenShareResizeInterval);
|
||||||
|
this.stream.isLocalStreamReadyToPublish = false;
|
||||||
|
|
||||||
|
// Delete Publisher object from OpenVidu publishers array
|
||||||
|
const openviduPublishers = (<Publisher>this.target).openvidu.publishers;
|
||||||
|
for (let i = 0; i < openviduPublishers.length; i++) {
|
||||||
|
if (openviduPublishers[i] === <Publisher>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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* (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() {}
|
||||||
|
}
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* (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() { }
|
||||||
|
}
|
||||||
42
openvidu-browser/src/OpenViduInternal/Events/Types/Types.ts
Normal file
42
openvidu-browser/src/OpenViduInternal/Events/Types/Types.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
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';
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* (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() {}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* (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
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* (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[];
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* (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).
|
||||||
|
*/
|
||||||
|
iceServers?: RTCIceServer[] | string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
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;
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
@ -0,0 +1,280 @@
|
|||||||
|
/*
|
||||||
|
* (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,
|
||||||
|
* <pre>
|
||||||
|
* 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
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* (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;
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,85 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
function pack(message) {
|
||||||
|
throw new TypeError('Not yet implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
function unpack(message) {
|
||||||
|
throw new TypeError('Not yet implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.pack = pack;
|
||||||
|
exports.unpack = unpack;
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
var JsonRPC = require('./JsonRPC');
|
||||||
|
var XmlRPC = require('./XmlRPC');
|
||||||
|
|
||||||
|
exports.JsonRPC = JsonRPC;
|
||||||
|
exports.XmlRPC = XmlRPC;
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
285
openvidu-browser/src/OpenViduInternal/Logger/OpenViduLogger.ts
Normal file
285
openvidu-browser/src/OpenViduInternal/Logger/OpenViduLogger.ts
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
export enum OpenViduLoggerConfiguration {
|
||||||
|
disabled = 'disabled',
|
||||||
|
debug = 'debug',
|
||||||
|
debug_app = 'debug_app'
|
||||||
|
}
|
||||||
@ -0,0 +1,233 @@
|
|||||||
|
// 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;
|
||||||
@ -0,0 +1,162 @@
|
|||||||
|
// 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;
|
||||||
233
openvidu-browser/src/OpenViduInternal/Utils/Platform.ts
Normal file
233
openvidu-browser/src/OpenViduInternal/Utils/Platform.ts
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
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 || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
592
openvidu-browser/src/OpenViduInternal/WebRtcPeer/WebRtcPeer.ts
Normal file
592
openvidu-browser/src/OpenViduInternal/WebRtcPeer/WebRtcPeer.ts
Normal file
File diff suppressed because it is too large
Load Diff
471
openvidu-browser/src/OpenViduInternal/WebRtcStats/WebRtcStats.ts
Normal file
471
openvidu-browser/src/OpenViduInternal/WebRtcStats/WebRtcStats.ts
Normal file
@ -0,0 +1,471 @@
|
|||||||
|
/*
|
||||||
|
* (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<any> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
const statsReport: any = await this.stream.getRTCPeerConnection().getStats();
|
||||||
|
let transportStat;
|
||||||
|
const candidatePairs: Map<string, any> = new Map();
|
||||||
|
const localCandidates: Map<string, any> = new Map();
|
||||||
|
const remoteCandidates: Map<string, any> = 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<void> {
|
||||||
|
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<void> {
|
||||||
|
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<IWebrtcStats> {
|
||||||
|
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(<Object>response.candidatepair).length === 0) {
|
||||||
|
delete response.candidatepair;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(response);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error getting common stats: ', error);
|
||||||
|
return reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateJSONStatsResponse(stats: IWebrtcStats): JSONStatsResponse {
|
||||||
|
return {
|
||||||
|
'@timestamp': new Date().toISOString(),
|
||||||
|
participant_id: this.stream.connection.data,
|
||||||
|
session_id: this.stream.session.sessionId,
|
||||||
|
platform: platform.getName(),
|
||||||
|
platform_description: platform.getDescription(),
|
||||||
|
stream: 'webRTC',
|
||||||
|
webrtc_stats: stats
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private getWebRtcStatsResponseOutline(): IWebrtcStats {
|
||||||
|
if (this.stream.isLocal()) {
|
||||||
|
return {
|
||||||
|
outbound: {
|
||||||
|
audio: {},
|
||||||
|
video: {}
|
||||||
|
},
|
||||||
|
candidatepair: {}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
inbound: {
|
||||||
|
audio: {},
|
||||||
|
video: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
openvidu-browser/src/index.ts
Normal file
51
openvidu-browser/src/index.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { JL } from 'jsnlog';
|
||||||
|
|
||||||
|
export { OpenVidu } from './OpenVidu/OpenVidu';
|
||||||
|
export { Session } from './OpenVidu/Session';
|
||||||
|
export { Publisher } from './OpenVidu/Publisher';
|
||||||
|
export { Subscriber } from './OpenVidu/Subscriber';
|
||||||
|
export { StreamManager } from './OpenVidu/StreamManager';
|
||||||
|
export { Stream } from './OpenVidu/Stream';
|
||||||
|
export { Connection } from './OpenVidu/Connection';
|
||||||
|
export { LocalRecorder } from './OpenVidu/LocalRecorder';
|
||||||
|
export { Filter } from './OpenVidu/Filter';
|
||||||
|
|
||||||
|
export { LocalRecorderState } from './OpenViduInternal/Enums/LocalRecorderState';
|
||||||
|
export { OpenViduError, OpenViduErrorName } from './OpenViduInternal/Enums/OpenViduError';
|
||||||
|
export { TypeOfVideo } from './OpenViduInternal/Enums/TypeOfVideo';
|
||||||
|
export { VideoInsertMode } from './OpenViduInternal/Enums/VideoInsertMode';
|
||||||
|
|
||||||
|
export { Event } from './OpenViduInternal/Events/Event';
|
||||||
|
export { ConnectionEvent } from './OpenViduInternal/Events/ConnectionEvent';
|
||||||
|
export { PublisherSpeakingEvent } from './OpenViduInternal/Events/PublisherSpeakingEvent';
|
||||||
|
export { RecordingEvent } from './OpenViduInternal/Events/RecordingEvent';
|
||||||
|
export { SessionDisconnectedEvent } from './OpenViduInternal/Events/SessionDisconnectedEvent';
|
||||||
|
export { SignalEvent } from './OpenViduInternal/Events/SignalEvent';
|
||||||
|
export { StreamEvent } from './OpenViduInternal/Events/StreamEvent';
|
||||||
|
export { StreamManagerEvent } from './OpenViduInternal/Events/StreamManagerEvent';
|
||||||
|
export { VideoElementEvent } from './OpenViduInternal/Events/VideoElementEvent';
|
||||||
|
export { StreamPropertyChangedEvent } from './OpenViduInternal/Events/StreamPropertyChangedEvent';
|
||||||
|
export { ConnectionPropertyChangedEvent } from './OpenViduInternal/Events/ConnectionPropertyChangedEvent';
|
||||||
|
export { FilterEvent } from './OpenViduInternal/Events/FilterEvent';
|
||||||
|
export { NetworkQualityLevelChangedEvent } from './OpenViduInternal/Events/NetworkQualityLevelChangedEvent';
|
||||||
|
export { SpeechToTextEvent } from './OpenViduInternal/Events/SpeechToTextEvent';
|
||||||
|
export { ExceptionEvent, ExceptionEventName } from './OpenViduInternal/Events/ExceptionEvent';
|
||||||
|
|
||||||
|
export { Capabilities } from './OpenViduInternal/Interfaces/Public/Capabilities';
|
||||||
|
export { Device } from './OpenViduInternal/Interfaces/Public/Device';
|
||||||
|
export { EventDispatcher } from './OpenVidu/EventDispatcher';
|
||||||
|
export { OpenViduAdvancedConfiguration } from './OpenViduInternal/Interfaces/Public/OpenViduAdvancedConfiguration';
|
||||||
|
export { PublisherProperties } from './OpenViduInternal/Interfaces/Public/PublisherProperties';
|
||||||
|
export { SignalOptions } from './OpenViduInternal/Interfaces/Public/SignalOptions';
|
||||||
|
export { StreamManagerVideo } from './OpenViduInternal/Interfaces/Public/StreamManagerVideo';
|
||||||
|
export { SubscriberProperties } from './OpenViduInternal/Interfaces/Public/SubscriberProperties';
|
||||||
|
|
||||||
|
export { EventMap } from './OpenViduInternal/Events/EventMap/EventMap';
|
||||||
|
export { SessionEventMap } from './OpenViduInternal/Events/EventMap/SessionEventMap';
|
||||||
|
export { StreamManagerEventMap } from './OpenViduInternal/Events/EventMap/StreamManagerEventMap';
|
||||||
|
export { PublisherEventMap } from './OpenViduInternal/Events/EventMap/PublisherEventMap';
|
||||||
|
|
||||||
|
export * from './OpenViduInternal/Events/Types/Types';
|
||||||
|
|
||||||
|
// Disable jsnlog when library is loaded
|
||||||
|
JL.setOptions({ enabled: false });
|
||||||
36
openvidu-browser/tsconfig.json
Normal file
36
openvidu-browser/tsconfig.json
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
//"allowUnusedLabels": true,
|
||||||
|
"allowUnreachableCode": false,
|
||||||
|
"buildOnSave": false,
|
||||||
|
"compileOnSave": true,
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"emitBOM": false,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"es2015.promise",
|
||||||
|
"es5",
|
||||||
|
"scripthost"
|
||||||
|
],
|
||||||
|
"module": "commonjs",
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
//"noImplicitAny": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
//"noUnusedLocals": true,
|
||||||
|
//"noUnusedParameters": true,
|
||||||
|
"outDir": "../../lib",
|
||||||
|
"preserveConstEnums": true,
|
||||||
|
"removeComments": true,
|
||||||
|
"rootDir": "./src",
|
||||||
|
"skipDefaultLibCheck": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"suppressExcessPropertyErrors": true,
|
||||||
|
"suppressImplicitAnyIndexErrors": true,
|
||||||
|
"target": "es5"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
openvidu-client/.gitignore
vendored
Normal file
1
openvidu-client/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target/
|
||||||
14
openvidu-client/README.md
Normal file
14
openvidu-client/README.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[](http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
[](https://github.com/OpenVidu/openvidu/actions/workflows/openvidu-ce-test.yml)
|
||||||
|
[](https://docs.openvidu.io/en/stable/?badge=stable)
|
||||||
|
[](https://hub.docker.com/r/openvidu/)
|
||||||
|
[](https://openvidu.discourse.group/)
|
||||||
|
|
||||||
|
[![][OpenViduLogo]](https://openvidu.io)
|
||||||
|
|
||||||
|
openvidu-client
|
||||||
|
===
|
||||||
|
|
||||||
|
Internal Java client used by [openvidu-server](https://github.com/OpenVidu/openvidu/tree/master/openvidu-server). Can be used to implement an Android client.
|
||||||
|
|
||||||
|
[OpenViduLogo]: https://secure.gravatar.com/avatar/5daba1d43042f2e4e85849733c8e5702?s=120
|
||||||
106
openvidu-client/pom.xml
Normal file
106
openvidu-client/pom.xml
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>io.openvidu</groupId>
|
||||||
|
<artifactId>openvidu-parent</artifactId>
|
||||||
|
<version>2.0.0</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>openvidu-client</artifactId>
|
||||||
|
<version>1.1.0</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>OpenVidu Client</name>
|
||||||
|
<description>
|
||||||
|
OpenVidu client library for the client-side of OpenVidu Server
|
||||||
|
</description>
|
||||||
|
<url>https://github.com/OpenVidu/openvidu</url>
|
||||||
|
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>Apache 2.0</name>
|
||||||
|
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
|
||||||
|
<distribution>repo</distribution>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
|
||||||
|
<organization>
|
||||||
|
<name>OpenVidu</name>
|
||||||
|
<url>https://github.com/OpenVidu/openvidu</url>
|
||||||
|
</organization>
|
||||||
|
|
||||||
|
<scm>
|
||||||
|
<url>${openvidu.scm.url}</url>
|
||||||
|
<connection>scm:git:${openvidu.scm.connection}</connection>
|
||||||
|
<developerConnection>scm:git:${openvidu.scm.connection}</developerConnection>
|
||||||
|
<tag>develop</tag>
|
||||||
|
</scm>
|
||||||
|
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<id>openvidu.io</id>
|
||||||
|
<name>-openvidu.io Community</name>
|
||||||
|
<organization>OpenVidu</organization>
|
||||||
|
<organizationUrl>https://openvidu.io</organizationUrl>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.kurento</groupId>
|
||||||
|
<artifactId>kurento-jsonrpc-client</artifactId>
|
||||||
|
<version>${version.kurento}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.kurento</groupId>
|
||||||
|
<artifactId>kurento-jsonrpc-client-jetty</artifactId>
|
||||||
|
<version>${version.kurento}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<version>${version.junit}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<version>${version.mockito.core}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>default</id>
|
||||||
|
<activation>
|
||||||
|
<property>
|
||||||
|
<name>default</name>
|
||||||
|
<value>true</value>
|
||||||
|
</property>
|
||||||
|
</activation>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skipTests>true</skipTests>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skipTests>true</skipTests>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
|
||||||
|
</project>
|
||||||
@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
* (C) Copyright 2017-2022 OpenVidu (https://openvidu.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.openvidu.client;
|
||||||
|
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.CUSTOMREQUEST_METHOD;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.JOINROOM_METHOD;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.JOINROOM_PEERID_PARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.JOINROOM_PEERSTREAMID_PARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.JOINROOM_PEERSTREAMS_PARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.JOINROOM_ROOM_PARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.JOINROOM_USER_PARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.LEAVEROOM_METHOD;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.ONICECANDIDATE_CANDIDATE_PARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.ONICECANDIDATE_EPNAME_PARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.ONICECANDIDATE_METHOD;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.ONICECANDIDATE_SDPMIDPARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.ONICECANDIDATE_SDPMLINEINDEX_PARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.PUBLISHVIDEO_DOLOOPBACK_PARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.PUBLISHVIDEO_METHOD;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.PUBLISHVIDEO_SDPANSWER_PARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.PUBLISHVIDEO_SDPOFFER_PARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.RECEIVEVIDEO_METHOD;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.RECEIVEVIDEO_SDPANSWER_PARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.RECEIVEVIDEO_SDPOFFER_PARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.RECEIVEVIDEO_SENDER_PARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.SENDMESSAGE_MESSAGE_PARAM;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.SENDMESSAGE_ROOM_METHOD;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.UNPUBLISHVIDEO_METHOD;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.UNSUBSCRIBEFROMVIDEO_METHOD;
|
||||||
|
import static io.openvidu.client.internal.ProtocolElements.UNSUBSCRIBEFROMVIDEO_SENDER_PARAM;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
|
import org.kurento.jsonrpc.client.JsonRpcClient;
|
||||||
|
import org.kurento.jsonrpc.client.JsonRpcClientWebSocket;
|
||||||
|
import org.kurento.jsonrpc.client.JsonRpcWSConnectionListener;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
import io.openvidu.client.internal.JsonRoomUtils;
|
||||||
|
import io.openvidu.client.internal.Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java client for the room server.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:rvlad@naevatec.com">Radu Tom Vlad</a>
|
||||||
|
*/
|
||||||
|
public class OpenViduClient {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(OpenViduClient.class);
|
||||||
|
|
||||||
|
private JsonRpcClient client;
|
||||||
|
private ServerJsonRpcHandler handler;
|
||||||
|
|
||||||
|
public OpenViduClient(String wsUri) {
|
||||||
|
this(new JsonRpcClientWebSocket(wsUri, new JsonRpcWSConnectionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reconnected(boolean sameServer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnected() {
|
||||||
|
log.warn("JsonRpcWebsocket connection: Disconnected");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connectionFailed() {
|
||||||
|
log.warn("JsonRpcWebsocket connection: Connection failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connected() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reconnecting() {
|
||||||
|
log.warn("JsonRpcWebsocket connection: is reconnecting");
|
||||||
|
}
|
||||||
|
}, new SslContextFactory(true)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenViduClient(JsonRpcClient client) {
|
||||||
|
this.client = client;
|
||||||
|
this.handler = new ServerJsonRpcHandler();
|
||||||
|
this.client.setServerRequestHandler(this.handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenViduClient(JsonRpcClient client, ServerJsonRpcHandler handler) {
|
||||||
|
this.client = client;
|
||||||
|
this.handler = handler;
|
||||||
|
this.client.setServerRequestHandler(this.handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws IOException {
|
||||||
|
this.client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, List<String>> joinRoom(String roomName, String userName)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
JsonObject params = new JsonObject();
|
||||||
|
params.addProperty(JOINROOM_ROOM_PARAM, roomName);
|
||||||
|
params.addProperty(JOINROOM_USER_PARAM, userName);
|
||||||
|
|
||||||
|
JsonElement result = client.sendRequest(JOINROOM_METHOD, params);
|
||||||
|
Map<String, List<String>> peers = new HashMap<String, List<String>>();
|
||||||
|
JsonArray jsonPeers = JsonRoomUtils.getResponseProperty(result, "value", JsonArray.class);
|
||||||
|
if (jsonPeers.size() > 0) {
|
||||||
|
Iterator<JsonElement> peerIt = jsonPeers.iterator();
|
||||||
|
while (peerIt.hasNext()) {
|
||||||
|
JsonElement peer = peerIt.next();
|
||||||
|
String peerId = JsonRoomUtils.getResponseProperty(peer, JOINROOM_PEERID_PARAM,
|
||||||
|
String.class);
|
||||||
|
List<String> streams = new ArrayList<String>();
|
||||||
|
JsonArray jsonStreams = JsonRoomUtils.getResponseProperty(peer, JOINROOM_PEERSTREAMS_PARAM,
|
||||||
|
JsonArray.class, true);
|
||||||
|
if (jsonStreams != null) {
|
||||||
|
Iterator<JsonElement> streamIt = jsonStreams.iterator();
|
||||||
|
while (streamIt.hasNext()) {
|
||||||
|
streams.add(JsonRoomUtils.getResponseProperty(streamIt.next(),
|
||||||
|
JOINROOM_PEERSTREAMID_PARAM, String.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
peers.put(peerId, streams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return peers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void leaveRoom() throws IOException {
|
||||||
|
client.sendRequest(LEAVEROOM_METHOD, new JsonObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String publishVideo(String sdpOffer, boolean doLoopback) throws IOException {
|
||||||
|
JsonObject params = new JsonObject();
|
||||||
|
params.addProperty(PUBLISHVIDEO_SDPOFFER_PARAM, sdpOffer);
|
||||||
|
params.addProperty(PUBLISHVIDEO_DOLOOPBACK_PARAM, doLoopback);
|
||||||
|
JsonElement result = client.sendRequest(PUBLISHVIDEO_METHOD, params);
|
||||||
|
return JsonRoomUtils.getResponseProperty(result, PUBLISHVIDEO_SDPANSWER_PARAM, String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unpublishVideo() throws IOException {
|
||||||
|
client.sendRequest(UNPUBLISHVIDEO_METHOD, new JsonObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
// sender should look like 'username_streamId'
|
||||||
|
public String receiveVideoFrom(String sender, String sdpOffer) throws IOException {
|
||||||
|
JsonObject params = new JsonObject();
|
||||||
|
params.addProperty(RECEIVEVIDEO_SENDER_PARAM, sender);
|
||||||
|
params.addProperty(RECEIVEVIDEO_SDPOFFER_PARAM, sdpOffer);
|
||||||
|
JsonElement result = client.sendRequest(RECEIVEVIDEO_METHOD, params);
|
||||||
|
return JsonRoomUtils.getResponseProperty(result, RECEIVEVIDEO_SDPANSWER_PARAM, String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sender should look like 'username_streamId'
|
||||||
|
public void unsubscribeFromVideo(String sender) throws IOException {
|
||||||
|
JsonObject params = new JsonObject();
|
||||||
|
params.addProperty(UNSUBSCRIBEFROMVIDEO_SENDER_PARAM, sender);
|
||||||
|
client.sendRequest(UNSUBSCRIBEFROMVIDEO_METHOD, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onIceCandidate(String endpointName, String candidate, String sdpMid,
|
||||||
|
int sdpMLineIndex) throws IOException {
|
||||||
|
JsonObject params = new JsonObject();
|
||||||
|
params.addProperty(ONICECANDIDATE_EPNAME_PARAM, endpointName);
|
||||||
|
params.addProperty(ONICECANDIDATE_CANDIDATE_PARAM, candidate);
|
||||||
|
params.addProperty(ONICECANDIDATE_SDPMIDPARAM, sdpMid);
|
||||||
|
params.addProperty(ONICECANDIDATE_SDPMLINEINDEX_PARAM, sdpMLineIndex);
|
||||||
|
client.sendRequest(ONICECANDIDATE_METHOD, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendMessage(String userName, String roomName, String message) throws IOException {
|
||||||
|
JsonObject params = new JsonObject();
|
||||||
|
params.addProperty(SENDMESSAGE_MESSAGE_PARAM, message);
|
||||||
|
client.sendRequest(SENDMESSAGE_ROOM_METHOD, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonElement customRequest(JsonObject customReqParams) throws IOException {
|
||||||
|
return client.sendRequest(CUSTOMREQUEST_METHOD, customReqParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Polls the notifications list maintained by this client to obtain new events sent by server.
|
||||||
|
* This method blocks until there is a notification to return. This is a one-time operation for
|
||||||
|
* the returned element.
|
||||||
|
*
|
||||||
|
* @return a server notification object, null when interrupted while waiting
|
||||||
|
*/
|
||||||
|
public Notification getServerNotification() {
|
||||||
|
return this.handler.getNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* (C) Copyright 2017-2022 OpenVidu (https://openvidu.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.openvidu.client;
|
||||||
|
|
||||||
|
import org.kurento.jsonrpc.JsonRpcErrorException;
|
||||||
|
|
||||||
|
public class OpenViduException extends JsonRpcErrorException {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public static enum Code {
|
||||||
|
GENERIC_ERROR_CODE(999), WRONG_PATH_CODE(998), WRONG_OPENVIDU_EDITION_ERROR_CODE(997),
|
||||||
|
SERVICE_NOT_ENABLED_ERROR_CODE(996),
|
||||||
|
|
||||||
|
TRANSPORT_ERROR_CODE(803), TRANSPORT_RESPONSE_ERROR_CODE(802), TRANSPORT_REQUEST_ERROR_CODE(801),
|
||||||
|
|
||||||
|
MEDIA_TYPE_STREAM_INCOMPATIBLE_WITH_RECORDING_PROPERTIES_ERROR_CODE(309),
|
||||||
|
MEDIA_TYPE_RECORDING_PROPERTIES_ERROR_CODE(308), MEDIA_MUTE_ERROR_CODE(307),
|
||||||
|
MEDIA_NOT_A_WEB_ENDPOINT_ERROR_CODE(306), MEDIA_RTP_ENDPOINT_ERROR_CODE(305),
|
||||||
|
MEDIA_WEBRTC_ENDPOINT_ERROR_CODE(304), MEDIA_ENDPOINT_ERROR_CODE(303), MEDIA_SDP_ERROR_CODE(302),
|
||||||
|
MEDIA_GENERIC_ERROR_CODE(301),
|
||||||
|
|
||||||
|
ROOM_CANNOT_BE_CREATED_ERROR_CODE(204), ROOM_CLOSED_ERROR_CODE(203), ROOM_NOT_FOUND_ERROR_CODE(202),
|
||||||
|
ROOM_GENERIC_ERROR_CODE(201),
|
||||||
|
|
||||||
|
USER_ALREADY_STREAMING_ERROR_CODE(106), USER_NOT_STREAMING_ERROR_CODE(105),
|
||||||
|
EXISTING_USER_IN_ROOM_ERROR_CODE(104), USER_CLOSED_ERROR_CODE(103), USER_NOT_FOUND_ERROR_CODE(102),
|
||||||
|
USER_GENERIC_ERROR_CODE(10),
|
||||||
|
|
||||||
|
USER_UNAUTHORIZED_ERROR_CODE(401), ROLE_NOT_FOUND_ERROR_CODE(402), SESSIONID_CANNOT_BE_CREATED_ERROR_CODE(403),
|
||||||
|
TOKEN_CANNOT_BE_CREATED_ERROR_CODE(404), EXISTING_FILTER_ALREADY_APPLIED_ERROR_CODE(405),
|
||||||
|
FILTER_NOT_APPLIED_ERROR_CODE(406), FILTER_EVENT_LISTENER_NOT_FOUND_ERROR_CODE(407),
|
||||||
|
PUBLISHER_ENDPOINT_NOT_FOUND_ERROR_CODE(408),
|
||||||
|
|
||||||
|
USER_METADATA_FORMAT_INVALID_ERROR_CODE(500),
|
||||||
|
|
||||||
|
SIGNAL_FORMAT_INVALID_ERROR_CODE(600), SIGNAL_TO_INVALID_ERROR_CODE(601),
|
||||||
|
|
||||||
|
BROADCAST_CONCURRENT_ERROR_CODE(711), BROADCAST_START_ERROR_CODE(710), DOCKER_NOT_FOUND(709), RECORDING_PATH_NOT_VALID(708), RECORDING_FILE_EMPTY_ERROR(707),
|
||||||
|
RECORDING_DELETE_ERROR_CODE(706), RECORDING_LIST_ERROR_CODE(705), RECORDING_STOP_ERROR_CODE(704),
|
||||||
|
RECORDING_START_ERROR_CODE(703), RECORDING_REPORT_ERROR_CODE(702), RECORDING_COMPLETION_ERROR_CODE(701),
|
||||||
|
|
||||||
|
FORCED_CODEC_NOT_FOUND_IN_SDPOFFER(800),
|
||||||
|
|
||||||
|
MEDIA_NODE_NOT_FOUND(900), MEDIA_NODE_STATUS_WRONG(901), MEDIA_NODE_CONNECTION_ERROR_CODE(902);
|
||||||
|
|
||||||
|
private int value;
|
||||||
|
|
||||||
|
private Code(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Code code = Code.GENERIC_ERROR_CODE;
|
||||||
|
|
||||||
|
public OpenViduException(Code code, String message) {
|
||||||
|
super(code.getValue(), message);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCodeValue() {
|
||||||
|
return code.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
* (C) Copyright 2017-2022 OpenVidu (https://openvidu.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.openvidu.client;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
|
||||||
|
import org.kurento.jsonrpc.DefaultJsonRpcHandler;
|
||||||
|
import org.kurento.jsonrpc.Transaction;
|
||||||
|
import org.kurento.jsonrpc.message.Request;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
import io.openvidu.client.internal.IceCandidate;
|
||||||
|
import io.openvidu.client.internal.IceCandidateInfo;
|
||||||
|
import io.openvidu.client.internal.JsonRoomUtils;
|
||||||
|
import io.openvidu.client.internal.MediaErrorInfo;
|
||||||
|
import io.openvidu.client.internal.Notification;
|
||||||
|
import io.openvidu.client.internal.ParticipantEvictedInfo;
|
||||||
|
import io.openvidu.client.internal.ParticipantJoinedInfo;
|
||||||
|
import io.openvidu.client.internal.ParticipantLeftInfo;
|
||||||
|
import io.openvidu.client.internal.ParticipantPublishedInfo;
|
||||||
|
import io.openvidu.client.internal.ParticipantUnpublishedInfo;
|
||||||
|
import io.openvidu.client.internal.ProtocolElements;
|
||||||
|
import io.openvidu.client.internal.RoomClosedInfo;
|
||||||
|
import io.openvidu.client.internal.SendMessageInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service that handles server JSON-RPC events.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:rvlad@naevatec.com">Radu Tom Vlad</a>
|
||||||
|
*/
|
||||||
|
public class ServerJsonRpcHandler extends DefaultJsonRpcHandler<JsonObject> {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ServerJsonRpcHandler.class);
|
||||||
|
|
||||||
|
private BlockingQueue<Notification> notifications = new ArrayBlockingQueue<Notification>(100);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleRequest(Transaction transaction, Request<JsonObject> request) throws Exception {
|
||||||
|
Notification notif = null;
|
||||||
|
try {
|
||||||
|
switch (request.getMethod()) {
|
||||||
|
case ProtocolElements.ICECANDIDATE_METHOD:
|
||||||
|
notif = iceCandidate(transaction, request);
|
||||||
|
break;
|
||||||
|
case ProtocolElements.MEDIAERROR_METHOD:
|
||||||
|
notif = mediaError(transaction, request);
|
||||||
|
break;
|
||||||
|
case ProtocolElements.PARTICIPANTJOINED_METHOD:
|
||||||
|
notif = participantJoined(transaction, request);
|
||||||
|
break;
|
||||||
|
case ProtocolElements.PARTICIPANTLEFT_METHOD:
|
||||||
|
notif = participantLeft(transaction, request);
|
||||||
|
break;
|
||||||
|
case ProtocolElements.PARTICIPANTEVICTED_METHOD:
|
||||||
|
notif = participantEvicted(transaction, request);
|
||||||
|
break;
|
||||||
|
case ProtocolElements.PARTICIPANTPUBLISHED_METHOD:
|
||||||
|
notif = participantPublished(transaction, request);
|
||||||
|
break;
|
||||||
|
case ProtocolElements.PARTICIPANTUNPUBLISHED_METHOD:
|
||||||
|
notif = participantUnpublished(transaction, request);
|
||||||
|
break;
|
||||||
|
case ProtocolElements.ROOMCLOSED_METHOD:
|
||||||
|
notif = roomClosed(transaction, request);
|
||||||
|
break;
|
||||||
|
case ProtocolElements.PARTICIPANTSENDMESSAGE_METHOD:
|
||||||
|
notif = participantSendMessage(transaction, request);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unrecognized request " + request.getMethod());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Exception processing request {}", request, e);
|
||||||
|
transaction.sendError(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (notif != null) {
|
||||||
|
try {
|
||||||
|
notifications.put(notif);
|
||||||
|
log.debug("Enqueued notification {}", notif);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.warn("Interrupted when enqueuing notification {}", notif, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Notification participantSendMessage(Transaction transaction,
|
||||||
|
Request<JsonObject> request) {
|
||||||
|
String data = JsonRoomUtils.getRequestParam(request,
|
||||||
|
ProtocolElements.PARTICIPANTSENDMESSAGE_DATA_PARAM, String.class);
|
||||||
|
String from = JsonRoomUtils.getRequestParam(request,
|
||||||
|
ProtocolElements.PARTICIPANTSENDMESSAGE_FROM_PARAM, String.class);
|
||||||
|
String type = JsonRoomUtils.getRequestParam(request,
|
||||||
|
ProtocolElements.PARTICIPANTSENDMESSAGE_TYPE_PARAM, String.class);
|
||||||
|
SendMessageInfo eventInfo = new SendMessageInfo(data, from, type);
|
||||||
|
log.debug("Recvd send message event {}", eventInfo);
|
||||||
|
return eventInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Notification roomClosed(Transaction transaction, Request<JsonObject> request) {
|
||||||
|
String room = JsonRoomUtils.getRequestParam(request, ProtocolElements.ROOMCLOSED_ROOM_PARAM,
|
||||||
|
String.class);
|
||||||
|
RoomClosedInfo eventInfo = new RoomClosedInfo(room);
|
||||||
|
log.debug("Recvd room closed event {}", eventInfo);
|
||||||
|
return eventInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Notification participantUnpublished(Transaction transaction,
|
||||||
|
Request<JsonObject> request) {
|
||||||
|
String name = JsonRoomUtils.getRequestParam(request,
|
||||||
|
ProtocolElements.PARTICIPANTUNPUBLISHED_NAME_PARAM, String.class);
|
||||||
|
ParticipantUnpublishedInfo eventInfo = new ParticipantUnpublishedInfo(name);
|
||||||
|
log.debug("Recvd participant unpublished event {}", eventInfo);
|
||||||
|
return eventInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Notification participantPublished(Transaction transaction, Request<JsonObject> request) {
|
||||||
|
String id = JsonRoomUtils.getRequestParam(request,
|
||||||
|
ProtocolElements.PARTICIPANTPUBLISHED_USER_PARAM, String.class);
|
||||||
|
JsonArray jsonStreams = JsonRoomUtils.getRequestParam(request,
|
||||||
|
ProtocolElements.PARTICIPANTPUBLISHED_STREAMS_PARAM, JsonArray.class);
|
||||||
|
Iterator<JsonElement> streamIt = jsonStreams.iterator();
|
||||||
|
List<String> streams = new ArrayList<String>();
|
||||||
|
while (streamIt.hasNext()) {
|
||||||
|
streams.add(JsonRoomUtils.getResponseProperty(streamIt.next(),
|
||||||
|
ProtocolElements.PARTICIPANTPUBLISHED_STREAMID_PARAM, String.class));
|
||||||
|
}
|
||||||
|
ParticipantPublishedInfo eventInfo = new ParticipantPublishedInfo(id, streams);
|
||||||
|
log.debug("Recvd published event {}", eventInfo);
|
||||||
|
return eventInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Notification participantEvicted(Transaction transaction, Request<JsonObject> request) {
|
||||||
|
ParticipantEvictedInfo eventInfo = new ParticipantEvictedInfo();
|
||||||
|
log.debug("Recvd participant evicted event {}", eventInfo);
|
||||||
|
return eventInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Notification participantLeft(Transaction transaction, Request<JsonObject> request) {
|
||||||
|
String name = JsonRoomUtils.getRequestParam(request,
|
||||||
|
ProtocolElements.PARTICIPANTLEFT_NAME_PARAM, String.class);
|
||||||
|
ParticipantLeftInfo eventInfo = new ParticipantLeftInfo(name);
|
||||||
|
log.debug("Recvd participant left event {}", eventInfo);
|
||||||
|
return eventInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Notification participantJoined(Transaction transaction, Request<JsonObject> request) {
|
||||||
|
String id = JsonRoomUtils.getRequestParam(request,
|
||||||
|
ProtocolElements.PARTICIPANTJOINED_USER_PARAM, String.class);
|
||||||
|
ParticipantJoinedInfo eventInfo = new ParticipantJoinedInfo(id);
|
||||||
|
log.debug("Recvd participant joined event {}", eventInfo);
|
||||||
|
return eventInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Notification mediaError(Transaction transaction, Request<JsonObject> request) {
|
||||||
|
String description = JsonRoomUtils.getRequestParam(request,
|
||||||
|
ProtocolElements.MEDIAERROR_ERROR_PARAM, String.class);
|
||||||
|
MediaErrorInfo eventInfo = new MediaErrorInfo(description);
|
||||||
|
log.debug("Recvd media error event {}", eventInfo);
|
||||||
|
return eventInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Notification iceCandidate(Transaction transaction, Request<JsonObject> request) {
|
||||||
|
|
||||||
|
String candidate = JsonRoomUtils.getRequestParam(request,
|
||||||
|
ProtocolElements.ICECANDIDATE_CANDIDATE_PARAM, String.class);
|
||||||
|
String sdpMid = JsonRoomUtils.getRequestParam(request,
|
||||||
|
ProtocolElements.ICECANDIDATE_SDPMID_PARAM, String.class);
|
||||||
|
int sdpMLineIndex = JsonRoomUtils.getRequestParam(request,
|
||||||
|
ProtocolElements.ICECANDIDATE_SDPMLINEINDEX_PARAM, Integer.class);
|
||||||
|
|
||||||
|
IceCandidate iceCandidate = new IceCandidate(candidate, sdpMid, sdpMLineIndex);
|
||||||
|
|
||||||
|
String endpoint = JsonRoomUtils.getRequestParam(request,
|
||||||
|
ProtocolElements.ICECANDIDATE_EPNAME_PARAM, String.class);
|
||||||
|
|
||||||
|
IceCandidateInfo eventInfo = new IceCandidateInfo(iceCandidate, endpoint);
|
||||||
|
log.debug("Recvd ICE candidate event {}", eventInfo);
|
||||||
|
|
||||||
|
return eventInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks until an element is available and then returns it by removing it from the queue.
|
||||||
|
*
|
||||||
|
* @return a {@link Notification} from the queue, null when interrupted
|
||||||
|
* @see BlockingQueue#take()
|
||||||
|
*/
|
||||||
|
public Notification getNotification() {
|
||||||
|
try {
|
||||||
|
Notification notif = notifications.take();
|
||||||
|
log.debug("Dequeued notification {}", notif);
|
||||||
|
return notif;
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.info("Interrupted while polling notifications' queue");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package io.openvidu.client.internal;
|
||||||
|
|
||||||
|
public class IceCandidate {
|
||||||
|
|
||||||
|
private String candidate;
|
||||||
|
private String sdpMid;
|
||||||
|
private int sdpMLineIndex;
|
||||||
|
|
||||||
|
public IceCandidate(String candidate, String sdpMid, int sdpMLineIndex) {
|
||||||
|
super();
|
||||||
|
this.candidate = candidate;
|
||||||
|
this.sdpMid = sdpMid;
|
||||||
|
this.sdpMLineIndex = sdpMLineIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCandidate() {
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSdpMid() {
|
||||||
|
return sdpMid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSdpMLineIndex() {
|
||||||
|
return sdpMLineIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "IceCandidate [candidate=" + candidate + ", sdpMid=" + sdpMid + ", sdpMLineIndex="
|
||||||
|
+ sdpMLineIndex + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user