From 01455bdf30ad5d3d922e4cf5dc1a4c6469ac32aa Mon Sep 17 00:00:00 2001
From: Fabien Lavocat <4154532+FabienLavocat@users.noreply.github.com>
Date: Mon, 23 Jun 2025 10:48:44 -0700
Subject: [PATCH 01/22] Use typedoc for Documentation
Signed-off-by: Fabien Lavocat <4154532+FabienLavocat@users.noreply.github.com>
---
.gitignore | 1 +
package-lock.json | 872 ++++++----------------------
package.json | 5 +-
packages/millicast-sdk/README.md | 167 ++++++
packages/millicast-sdk/package.json | 2 +-
packages/millicast-sdk/typedoc.json | 24 +
typedoc.base.json | 7 +
typedoc.json | 8 +
8 files changed, 394 insertions(+), 692 deletions(-)
create mode 100644 packages/millicast-sdk/README.md
create mode 100644 packages/millicast-sdk/typedoc.json
create mode 100644 typedoc.base.json
create mode 100644 typedoc.json
diff --git a/.gitignore b/.gitignore
index 9c36b523..febe4c2e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,4 @@ test-environment.js
**/src/TransformWorker.worker.ts
vite.config.*.timestamp-*
.nx/
+docs-json/
diff --git a/package-lock.json b/package-lock.json
index 91661a86..28fc7ef8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,7 +16,6 @@
"events": "^3.3.0",
"js-base64": "^3.7.7",
"js-logger": "^1.6.1",
- "jsdoc-i18n-plugin": "^0.0.3",
"jwt-decode": "^3.1.2",
"re-emitter": "^1.1.4",
"semantic-sdp": "^3.22.0",
@@ -31,7 +30,6 @@
"@babel/plugin-transform-runtime": "^7.13.10",
"@babel/preset-env": "^7.23.6",
"@babel/runtime": "^7.13.10",
- "@changesets/cli": "^2.27.1",
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.8.0",
"@maslick/radiaslider": "^1.9.8",
@@ -74,8 +72,6 @@
"jest-environment-node": "^29.4.1",
"jest-puppeteer": "^9.0.1",
"jest-websocket-mock": "^2.2.0",
- "jsdoc": "^4.0.2",
- "jsdoc-export-default-interop": "^0.3.1",
"jsdom": "~22.1.0",
"lint-staged": "^10.5.4",
"mock-socket": "^9.0.3",
@@ -88,6 +84,8 @@
"swc-loader": "0.1.15",
"ts-jest": "^29.1.0",
"ts-node": "10.9.1",
+ "typedoc": "^0.28.5",
+ "typedoc-plugin-mdn-links": "^5.0.2",
"typescript": "^5.6.3",
"underscore": "^1.13.1",
"vite": "^5.2.10",
@@ -1959,301 +1957,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@changesets/apply-release-plan": {
- "version": "7.0.5",
- "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-7.0.5.tgz",
- "integrity": "sha512-1cWCk+ZshEkSVEZrm2fSj1Gz8sYvxgUL4Q78+1ZZqeqfuevPTPk033/yUZ3df8BKMohkqqHfzj0HOOrG0KtXTw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/config": "^3.0.3",
- "@changesets/get-version-range-type": "^0.4.0",
- "@changesets/git": "^3.0.1",
- "@changesets/should-skip-package": "^0.1.1",
- "@changesets/types": "^6.0.0",
- "@manypkg/get-packages": "^1.1.3",
- "detect-indent": "^6.0.0",
- "fs-extra": "^7.0.1",
- "lodash.startcase": "^4.4.0",
- "outdent": "^0.5.0",
- "prettier": "^2.7.1",
- "resolve-from": "^5.0.0",
- "semver": "^7.5.3"
- }
- },
- "node_modules/@changesets/apply-release-plan/node_modules/semver": {
- "version": "7.6.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
- "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@changesets/assemble-release-plan": {
- "version": "6.0.4",
- "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-6.0.4.tgz",
- "integrity": "sha512-nqICnvmrwWj4w2x0fOhVj2QEGdlUuwVAwESrUo5HLzWMI1rE5SWfsr9ln+rDqWB6RQ2ZyaMZHUcU7/IRaUJS+Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/errors": "^0.2.0",
- "@changesets/get-dependents-graph": "^2.1.2",
- "@changesets/should-skip-package": "^0.1.1",
- "@changesets/types": "^6.0.0",
- "@manypkg/get-packages": "^1.1.3",
- "semver": "^7.5.3"
- }
- },
- "node_modules/@changesets/assemble-release-plan/node_modules/semver": {
- "version": "7.6.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
- "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@changesets/changelog-git": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.2.0.tgz",
- "integrity": "sha512-bHOx97iFI4OClIT35Lok3sJAwM31VbUM++gnMBV16fdbtBhgYu4dxsphBF/0AZZsyAHMrnM0yFcj5gZM1py6uQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/types": "^6.0.0"
- }
- },
- "node_modules/@changesets/cli": {
- "version": "2.27.9",
- "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.27.9.tgz",
- "integrity": "sha512-q42a/ZbDnxPpCb5Wkm6tMVIxgeI9C/bexntzTeCFBrQEdpisQqk8kCHllYZMDjYtEc1ZzumbMJAG8H0Z4rdvjg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/apply-release-plan": "^7.0.5",
- "@changesets/assemble-release-plan": "^6.0.4",
- "@changesets/changelog-git": "^0.2.0",
- "@changesets/config": "^3.0.3",
- "@changesets/errors": "^0.2.0",
- "@changesets/get-dependents-graph": "^2.1.2",
- "@changesets/get-release-plan": "^4.0.4",
- "@changesets/git": "^3.0.1",
- "@changesets/logger": "^0.1.1",
- "@changesets/pre": "^2.0.1",
- "@changesets/read": "^0.6.1",
- "@changesets/should-skip-package": "^0.1.1",
- "@changesets/types": "^6.0.0",
- "@changesets/write": "^0.3.2",
- "@manypkg/get-packages": "^1.1.3",
- "ansi-colors": "^4.1.3",
- "ci-info": "^3.7.0",
- "enquirer": "^2.3.0",
- "external-editor": "^3.1.0",
- "fs-extra": "^7.0.1",
- "mri": "^1.2.0",
- "p-limit": "^2.2.0",
- "package-manager-detector": "^0.2.0",
- "picocolors": "^1.1.0",
- "resolve-from": "^5.0.0",
- "semver": "^7.5.3",
- "spawndamnit": "^2.0.0",
- "term-size": "^2.1.0"
- },
- "bin": {
- "changeset": "bin.js"
- }
- },
- "node_modules/@changesets/cli/node_modules/semver": {
- "version": "7.6.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
- "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@changesets/config": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/@changesets/config/-/config-3.0.3.tgz",
- "integrity": "sha512-vqgQZMyIcuIpw9nqFIpTSNyc/wgm/Lu1zKN5vECy74u95Qx/Wa9g27HdgO4NkVAaq+BGA8wUc/qvbvVNs93n6A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/errors": "^0.2.0",
- "@changesets/get-dependents-graph": "^2.1.2",
- "@changesets/logger": "^0.1.1",
- "@changesets/types": "^6.0.0",
- "@manypkg/get-packages": "^1.1.3",
- "fs-extra": "^7.0.1",
- "micromatch": "^4.0.2"
- }
- },
- "node_modules/@changesets/errors": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.2.0.tgz",
- "integrity": "sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "extendable-error": "^0.1.5"
- }
- },
- "node_modules/@changesets/get-dependents-graph": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-2.1.2.tgz",
- "integrity": "sha512-sgcHRkiBY9i4zWYBwlVyAjEM9sAzs4wYVwJUdnbDLnVG3QwAaia1Mk5P8M7kraTOZN+vBET7n8KyB0YXCbFRLQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/types": "^6.0.0",
- "@manypkg/get-packages": "^1.1.3",
- "picocolors": "^1.1.0",
- "semver": "^7.5.3"
- }
- },
- "node_modules/@changesets/get-dependents-graph/node_modules/semver": {
- "version": "7.6.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
- "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@changesets/get-release-plan": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-4.0.4.tgz",
- "integrity": "sha512-SicG/S67JmPTrdcc9Vpu0wSQt7IiuN0dc8iR5VScnnTVPfIaLvKmEGRvIaF0kcn8u5ZqLbormZNTO77bCEvyWw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/assemble-release-plan": "^6.0.4",
- "@changesets/config": "^3.0.3",
- "@changesets/pre": "^2.0.1",
- "@changesets/read": "^0.6.1",
- "@changesets/types": "^6.0.0",
- "@manypkg/get-packages": "^1.1.3"
- }
- },
- "node_modules/@changesets/get-version-range-type": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.4.0.tgz",
- "integrity": "sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@changesets/git": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@changesets/git/-/git-3.0.1.tgz",
- "integrity": "sha512-pdgHcYBLCPcLd82aRcuO0kxCDbw/yISlOtkmwmE8Odo1L6hSiZrBOsRl84eYG7DRCab/iHnOkWqExqc4wxk2LQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/errors": "^0.2.0",
- "@manypkg/get-packages": "^1.1.3",
- "is-subdir": "^1.1.1",
- "micromatch": "^4.0.2",
- "spawndamnit": "^2.0.0"
- }
- },
- "node_modules/@changesets/logger": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.1.1.tgz",
- "integrity": "sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "picocolors": "^1.1.0"
- }
- },
- "node_modules/@changesets/parse": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.4.0.tgz",
- "integrity": "sha512-TS/9KG2CdGXS27S+QxbZXgr8uPsP4yNJYb4BC2/NeFUj80Rni3TeD2qwWmabymxmrLo7JEsytXH1FbpKTbvivw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/types": "^6.0.0",
- "js-yaml": "^3.13.1"
- }
- },
- "node_modules/@changesets/pre": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-2.0.1.tgz",
- "integrity": "sha512-vvBJ/If4jKM4tPz9JdY2kGOgWmCowUYOi5Ycv8dyLnEE8FgpYYUo1mgJZxcdtGGP3aG8rAQulGLyyXGSLkIMTQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/errors": "^0.2.0",
- "@changesets/types": "^6.0.0",
- "@manypkg/get-packages": "^1.1.3",
- "fs-extra": "^7.0.1"
- }
- },
- "node_modules/@changesets/read": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.6.1.tgz",
- "integrity": "sha512-jYMbyXQk3nwP25nRzQQGa1nKLY0KfoOV7VLgwucI0bUO8t8ZLCr6LZmgjXsiKuRDc+5A6doKPr9w2d+FEJ55zQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/git": "^3.0.1",
- "@changesets/logger": "^0.1.1",
- "@changesets/parse": "^0.4.0",
- "@changesets/types": "^6.0.0",
- "fs-extra": "^7.0.1",
- "p-filter": "^2.1.0",
- "picocolors": "^1.1.0"
- }
- },
- "node_modules/@changesets/should-skip-package": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/@changesets/should-skip-package/-/should-skip-package-0.1.1.tgz",
- "integrity": "sha512-H9LjLbF6mMHLtJIc/eHR9Na+MifJ3VxtgP/Y+XLn4BF7tDTEN1HNYtH6QMcjP1uxp9sjaFYmW8xqloaCi/ckTg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/types": "^6.0.0",
- "@manypkg/get-packages": "^1.1.3"
- }
- },
- "node_modules/@changesets/types": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.0.0.tgz",
- "integrity": "sha512-b1UkfNulgKoWfqyHtzKS5fOZYSJO+77adgL7DLRDr+/7jhChN+QcHnbjiQVOz/U+Ts3PGNySq7diAItzDgugfQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@changesets/write": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.3.2.tgz",
- "integrity": "sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/types": "^6.0.0",
- "fs-extra": "^7.0.1",
- "human-id": "^1.0.2",
- "prettier": "^2.7.1"
- }
- },
"node_modules/@cnakazawa/watch": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz",
@@ -2333,9 +2036,9 @@
}
},
"node_modules/@dolbyio/webrtc-stats": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@dolbyio/webrtc-stats/-/webrtc-stats-1.0.2.tgz",
- "integrity": "sha512-hpXUbtJl+yQOGBACWFfFsYFJrBbY8N+pdo5CHQVVKm4CvGaFai6gfW/ged0Hce9G/CvnF2HcZ54jhsnyMYwx4A==",
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@dolbyio/webrtc-stats/-/webrtc-stats-1.0.4.tgz",
+ "integrity": "sha512-QOo1TVQSI3NVaSWG1p3JopLkTDB9z94t9Bi1JvJwaQbwrEkLwGXccOX9U+FjroUsfSh9QK2tlifKJifedEBa7w==",
"license": "MIT",
"dependencies": {
"js-logger": "^1.6.1"
@@ -2856,6 +2559,20 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@gerrit0/mini-shiki": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.6.0.tgz",
+ "integrity": "sha512-KaeJvPNofTEZR9EzVNp/GQzbQqkGfjiu6k3CXKvhVTX+8OoAKSX/k7qxLKOX3B0yh2XqVAc93rsOu48CGt2Qug==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/engine-oniguruma": "^3.6.0",
+ "@shikijs/langs": "^3.6.0",
+ "@shikijs/themes": "^3.6.0",
+ "@shikijs/types": "^3.6.0",
+ "@shikijs/vscode-textmate": "^10.0.2"
+ }
+ },
"node_modules/@hapi/hoek": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
@@ -3700,78 +3417,6 @@
"node": ">=v12.0.0"
}
},
- "node_modules/@manypkg/find-root": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz",
- "integrity": "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.5.5",
- "@types/node": "^12.7.1",
- "find-up": "^4.1.0",
- "fs-extra": "^8.1.0"
- }
- },
- "node_modules/@manypkg/find-root/node_modules/@types/node": {
- "version": "12.20.55",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz",
- "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@manypkg/find-root/node_modules/fs-extra": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
- "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "graceful-fs": "^4.2.0",
- "jsonfile": "^4.0.0",
- "universalify": "^0.1.0"
- },
- "engines": {
- "node": ">=6 <7 || >=8"
- }
- },
- "node_modules/@manypkg/get-packages": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/@manypkg/get-packages/-/get-packages-1.1.3.tgz",
- "integrity": "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.5.5",
- "@changesets/types": "^4.0.1",
- "@manypkg/find-root": "^1.1.0",
- "fs-extra": "^8.1.0",
- "globby": "^11.0.0",
- "read-yaml-file": "^1.1.0"
- }
- },
- "node_modules/@manypkg/get-packages/node_modules/@changesets/types": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/@changesets/types/-/types-4.1.0.tgz",
- "integrity": "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@manypkg/get-packages/node_modules/fs-extra": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
- "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "graceful-fs": "^4.2.0",
- "jsonfile": "^4.0.0",
- "universalify": "^0.1.0"
- },
- "engines": {
- "node": ">=6 <7 || >=8"
- }
- },
"node_modules/@maslick/radiaslider": {
"version": "1.9.8",
"resolved": "https://registry.npmjs.org/@maslick/radiaslider/-/radiaslider-1.9.8.tgz",
@@ -5632,6 +5277,55 @@
"string-argv": "~0.3.1"
}
},
+ "node_modules/@shikijs/engine-oniguruma": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.6.0.tgz",
+ "integrity": "sha512-nmOhIZ9yT3Grd+2plmW/d8+vZ2pcQmo/UnVwXMUXAKTXdi+LK0S08Ancrz5tQQPkxvjBalpMW2aKvwXfelauvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "3.6.0",
+ "@shikijs/vscode-textmate": "^10.0.2"
+ }
+ },
+ "node_modules/@shikijs/langs": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.6.0.tgz",
+ "integrity": "sha512-IdZkQJaLBu1LCYCwkr30hNuSDfllOT8RWYVZK1tD2J03DkiagYKRxj/pDSl8Didml3xxuyzUjgtioInwEQM/TA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "3.6.0"
+ }
+ },
+ "node_modules/@shikijs/themes": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.6.0.tgz",
+ "integrity": "sha512-Fq2j4nWr1DF4drvmhqKq8x5vVQ27VncF8XZMBuHuQMZvUSS3NBgpqfwz/FoGe36+W6PvniZ1yDlg2d4kmYDU6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "3.6.0"
+ }
+ },
+ "node_modules/@shikijs/types": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.6.0.tgz",
+ "integrity": "sha512-cLWFiToxYu0aAzJqhXTQsFiJRTFDAGl93IrMSBNaGSzs7ixkLfdG6pH11HipuWFGW5vyx4X47W8HDQ7eSrmBUg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/vscode-textmate": "^10.0.2",
+ "@types/hast": "^3.0.4"
+ }
+ },
+ "node_modules/@shikijs/vscode-textmate": {
+ "version": "10.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz",
+ "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@sideway/address": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
@@ -6135,6 +5829,16 @@
"@types/node": "*"
}
},
+ "node_modules/@types/hast": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
+ "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "*"
+ }
+ },
"node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
@@ -6205,7 +5909,8 @@
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/@types/long": {
"version": "4.0.2",
@@ -6220,6 +5925,7 @@
"integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/linkify-it": "^5",
"@types/mdurl": "^2"
@@ -6230,7 +5936,8 @@
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/@types/minimatch": {
"version": "5.1.2",
@@ -6297,6 +6004,13 @@
"integrity": "sha512-P/oDfpofrdtF5xw433SPALpdSchtJmY7nsJItf8h3KXqOslkbySh8zq4dSWXH2oTjRvJ5PczVEoCZPow6GicLg==",
"license": "MIT"
},
+ "node_modules/@types/unist": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
+ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/uuid": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
@@ -8010,19 +7724,6 @@
"node": ">=10.0.0"
}
},
- "node_modules/better-path-resolve": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz",
- "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-windows": "^1.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@@ -8075,7 +7776,8 @@
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/boxen": {
"version": "7.0.0",
@@ -8520,6 +8222,7 @@
"integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.15"
},
@@ -8673,13 +8376,6 @@
"node": ">=10"
}
},
- "node_modules/chardet": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
- "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/check-error": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
@@ -9813,16 +9509,6 @@
"node": ">=0.4.0"
}
},
- "node_modules/detect-indent": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
- "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/detect-newline": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
@@ -11327,41 +11013,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/extendable-error": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/extendable-error/-/extendable-error-0.1.7.tgz",
- "integrity": "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/external-editor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
- "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "chardet": "^0.7.0",
- "iconv-lite": "^0.4.24",
- "tmp": "^0.0.33"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/external-editor/node_modules/tmp": {
- "version": "0.0.33",
- "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
- "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "os-tmpdir": "~1.0.2"
- },
- "engines": {
- "node": ">=0.6.0"
- }
- },
"node_modules/extglob": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
@@ -12777,13 +12428,6 @@
"node": ">= 6"
}
},
- "node_modules/human-id": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/human-id/-/human-id-1.0.2.tgz",
- "integrity": "sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/human-signals": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
@@ -13061,19 +12705,6 @@
"node": ">=0.8.19"
}
},
- "node_modules/in-publish": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz",
- "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "in-install": "in-install.js",
- "in-publish": "in-publish.js",
- "not-in-install": "not-in-install.js",
- "not-in-publish": "not-in-publish.js"
- }
- },
"node_modules/indent-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
@@ -13617,19 +13248,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-subdir": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz",
- "integrity": "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "better-path-resolve": "1.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/is-symbol": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
@@ -18979,6 +18597,7 @@
"integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==",
"dev": true,
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
"xmlcreate": "^2.0.4"
}
@@ -18996,6 +18615,7 @@
"integrity": "sha512-Nu7Sf35kXJ1MWDZIMAuATRQTg1iIPdzh7tqJ6jjvaU/GfDf+qi5UV8zJR3Mo+/pYFvm8mzay4+6O5EWigaQBQw==",
"dev": true,
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
"@babel/parser": "^7.20.15",
"@jsdoc/salty": "^0.2.1",
@@ -19020,44 +18640,13 @@
"node": ">=12.0.0"
}
},
- "node_modules/jsdoc-export-default-interop": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/jsdoc-export-default-interop/-/jsdoc-export-default-interop-0.3.1.tgz",
- "integrity": "sha512-8dXuye0ZZcfHO/u3xk3A4TSb2LgWo6HbhoVIj1Igrrpq4t61UnjMIXiqpq6xj4oQgrZHgSy8AWdhNB899BcfFA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "in-publish": "^2.0.0",
- "lodash": "^4.0.1"
- }
- },
- "node_modules/jsdoc-i18n-plugin": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/jsdoc-i18n-plugin/-/jsdoc-i18n-plugin-0.0.3.tgz",
- "integrity": "sha512-JftMOa8qMbITtzdZFWkgjk8WABJ0rjZjwO7FsTCQBWtYJl6OrdWKJf7hkbLUPmrh7j2EnJMg6j1xnSYWOulsbw==",
- "license": "MIT",
- "dependencies": {
- "mkdirp": "^0.5.1"
- }
- },
- "node_modules/jsdoc-i18n-plugin/node_modules/mkdirp": {
- "version": "0.5.6",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
- "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
- "license": "MIT",
- "dependencies": {
- "minimist": "^1.2.6"
- },
- "bin": {
- "mkdirp": "bin/cmd.js"
- }
- },
"node_modules/jsdoc/node_modules/escape-string-regexp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
"integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=8"
}
@@ -19258,6 +18847,7 @@
"integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"graceful-fs": "^4.1.9"
}
@@ -19642,13 +19232,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/lodash.startcase": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz",
- "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@@ -19867,6 +19450,13 @@
"yallist": "^3.0.2"
}
},
+ "node_modules/lunr": {
+ "version": "2.3.9",
+ "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
+ "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/magic-string": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz",
@@ -19970,6 +19560,7 @@
"integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==",
"dev": true,
"license": "Unlicense",
+ "peer": true,
"peerDependencies": {
"@types/markdown-it": "*",
"markdown-it": "*"
@@ -19988,6 +19579,7 @@
"integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"marked": "bin/marked.js"
},
@@ -20116,6 +19708,7 @@
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -20148,6 +19741,7 @@
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"mkdirp": "bin/cmd.js"
},
@@ -39719,23 +39313,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/os-tmpdir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
- "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/outdent": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz",
- "integrity": "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/p-each-series": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz",
@@ -39749,29 +39326,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/p-filter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz",
- "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-map": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/p-filter/node_modules/p-map": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
- "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
@@ -40118,16 +39672,6 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
- "node_modules/pify": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
- "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/pirates": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
@@ -40541,13 +40085,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/pseudomap": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
- "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==",
- "dev": true,
- "license": "ISC"
- },
"node_modules/psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
@@ -40898,32 +40435,6 @@
"node": ">=8"
}
},
- "node_modules/read-yaml-file": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/read-yaml-file/-/read-yaml-file-1.1.0.tgz",
- "integrity": "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "graceful-fs": "^4.1.5",
- "js-yaml": "^3.6.1",
- "pify": "^4.0.1",
- "strip-bom": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/read-yaml-file/node_modules/strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
@@ -41148,6 +40659,7 @@
"integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.21"
}
@@ -42504,83 +42016,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/spawndamnit": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-2.0.0.tgz",
- "integrity": "sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cross-spawn": "^5.1.0",
- "signal-exit": "^3.0.2"
- }
- },
- "node_modules/spawndamnit/node_modules/cross-spawn": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
- "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "lru-cache": "^4.0.1",
- "shebang-command": "^1.2.0",
- "which": "^1.2.9"
- }
- },
- "node_modules/spawndamnit/node_modules/lru-cache": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
- "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "pseudomap": "^1.0.2",
- "yallist": "^2.1.2"
- }
- },
- "node_modules/spawndamnit/node_modules/shebang-command": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
- "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "shebang-regex": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/spawndamnit/node_modules/shebang-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
- "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/spawndamnit/node_modules/which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "which": "bin/which"
- }
- },
- "node_modules/spawndamnit/node_modules/yallist": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
- "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
- "dev": true,
- "license": "ISC"
- },
"node_modules/spdx-correct": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
@@ -43097,19 +42532,6 @@
"node": ">=6"
}
},
- "node_modules/term-size": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz",
- "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/terminal-link": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz",
@@ -43753,6 +43175,79 @@
"is-typedarray": "^1.0.0"
}
},
+ "node_modules/typedoc": {
+ "version": "0.28.5",
+ "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.5.tgz",
+ "integrity": "sha512-5PzUddaA9FbaarUzIsEc4wNXCiO4Ot3bJNeMF2qKpYlTmM9TTaSHQ7162w756ERCkXER/+o2purRG6YOAv6EMA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@gerrit0/mini-shiki": "^3.2.2",
+ "lunr": "^2.3.9",
+ "markdown-it": "^14.1.0",
+ "minimatch": "^9.0.5",
+ "yaml": "^2.7.1"
+ },
+ "bin": {
+ "typedoc": "bin/typedoc"
+ },
+ "engines": {
+ "node": ">= 18",
+ "pnpm": ">= 10"
+ },
+ "peerDependencies": {
+ "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x"
+ }
+ },
+ "node_modules/typedoc-plugin-mdn-links": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/typedoc-plugin-mdn-links/-/typedoc-plugin-mdn-links-5.0.2.tgz",
+ "integrity": "sha512-Bd3lsVWPSpDkn6NGZyPHpcK088PUvH4SRq4RD97OjA6l8PQA3yOnJhGACtjmIDdcenRTgWUosH+55ANZhx/wkw==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "typedoc": "0.27.x || 0.28.x"
+ }
+ },
+ "node_modules/typedoc/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/typedoc/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/typedoc/node_modules/yaml": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
+ "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14.6"
+ }
+ },
"node_modules/typescript": {
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
@@ -45166,7 +44661,8 @@
"resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz",
"integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==",
"dev": true,
- "license": "Apache-2.0"
+ "license": "Apache-2.0",
+ "peer": true
},
"node_modules/y18n": {
"version": "5.0.8",
diff --git a/package.json b/package.json
index 9cc0e056..80fa83c7 100644
--- a/package.json
+++ b/package.json
@@ -33,7 +33,6 @@
"events": "^3.3.0",
"js-base64": "^3.7.7",
"js-logger": "^1.6.1",
- "jsdoc-i18n-plugin": "^0.0.3",
"jwt-decode": "^3.1.2",
"re-emitter": "^1.1.4",
"semantic-sdp": "^3.22.0",
@@ -90,8 +89,6 @@
"jest-environment-node": "^29.4.1",
"jest-puppeteer": "^9.0.1",
"jest-websocket-mock": "^2.2.0",
- "jsdoc": "^4.0.2",
- "jsdoc-export-default-interop": "^0.3.1",
"jsdom": "~22.1.0",
"lint-staged": "^10.5.4",
"mock-socket": "^9.0.3",
@@ -104,6 +101,8 @@
"swc-loader": "0.1.15",
"ts-jest": "^29.1.0",
"ts-node": "10.9.1",
+ "typedoc": "^0.28.5",
+ "typedoc-plugin-mdn-links": "^5.0.2",
"typescript": "^5.6.3",
"underscore": "^1.13.1",
"vite": "^5.2.10",
diff --git a/packages/millicast-sdk/README.md b/packages/millicast-sdk/README.md
new file mode 100644
index 00000000..fba150ff
--- /dev/null
+++ b/packages/millicast-sdk/README.md
@@ -0,0 +1,167 @@
+[](https://www.npmjs.com/package/@millicast/sdk)
+[](https://github.com/millicast/millicast-sdk)
+[](https://millicast.github.io/millicast-sdk/)
+
+This Software Development Kit (SDK) for JavaScript allows developers to simplify Millicast services integration into their own web apps.
+
+## Table of Contents
+
+- [Installation](#installation)
+- [Basic Usage](#basic-usage)
+ - [Publisher app](#publisher-app)
+ - [Viewer app](#viewer-app)
+- [Documentation](#documentation)
+- [Samples](#samples)
+- [JS Frameworks](#js-frameworks)
+ - [React Native](#react-native)
+- [SDK developer information](#sdk-developer-information)
+- [License](#license)
+
+## Installation
+
+You can use the CDN version of the SDK adding this tag to your document's `
`. Then `millicast` global variable will be available to use it.
+
+```html
+
+```
+
+Or if you are building an application with Node.js, you can install the SDK package to your dependencies.
+
+```sh
+npm i --save @millicast/sdk
+```
+
+## Basic Usage
+
+The following examples demonstrate how to broadcast with the Publisher app capturing the user's camera and microphone. You can then view the stream using the Viewer app.
+
+You will need to use a [Dolby Millicast account](https://streaming.dolby.io/) with a valid publishing token.
+
+### Publisher app
+
+Please be sure to set up the credentials filling up the `yourStreamName` and `yourPublishingToken` fields.
+
+In vanilla JavaScript:
+
+`publisher.html`
+
+```html
+
+
+
+
+
+
+
+
+
+
+```
+
+### Viewer app
+
+Please be sure to set up the credentials filling up the `yourStreamName` and `yourStreamAccountId` fields.
+
+In vanilla JavaScript:
+
+`viewer.html`
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Documentation
+
+The [Documentation](https://docs.optiview.dolby.com/millicast/) provides an overview of the Dolby Millicast services. This includes a [Getting Started](https://docs.optiview.dolby.com/millicast/getting-started/) guide as a quick start.
+
+The [SDK Documentation](https://millicast.github.io/millicast-sdk/) details the Modules, Classes, and APIs you can use during development.
+
+### Samples
+
+There are several packages that implement a publisher and viewer. These samples can be run and inspected for examples of how to implement various features.
+
+- [millicast-publisher-demo](https://github.com/millicast/millicast-sdk/tree/main/packages/millicast-publisher-demo#readme)
+- [millicast-viewer-demo](https://github.com/millicast/millicast-sdk/tree/main/packages/millicast-viewer-demo#readme)
+- [millicast-webaudio-delay-demo](https://github.com/millicast/millicast-sdk/tree/main/packages/millicast-webaudio-delay-demo#readme)
+- [millicast-multiview-demo](https://github.com/millicast/millicast-sdk/tree/main/packages/millicast-multiview-demo#readme)
+
+## JS Frameworks
+
+This section is intended to explain how properly integrate this SDK with different JS frameworks, with links to official guides that will contain a more step by step oriented explanation on how to do it.
+
+Right now, we only have a React Native guide.
+
+### React Native
+
+This SDK can be used for React Native based projects. In order to accomplish this integration, some configuration steps are needed. This library assumes all webRTC methods are natively defined (usually, inside web browsers). However this is not the case for native Android/iOS native applications. In order to solve this, we have tested and worked along with [React Native webRTC project](https://github.com/react-native-webrtc/react-native-webrtc) for this purpose.
+
+Check out this guide on [how to integrate Millicast JS SDK with React Native webRTC](https://docs.optiview.dolby.com/millicast/playback/players-sdks/react-native/)!
+
+## SDK developer information
+
+To develop and contribute to this project, there are some instructions of how to set up your environment to start contributing. [Follow this link.](https://github.com/millicast/millicast-sdk/blob/main/CONTRIBUTING.md)
+
+## License
+
+Please refer to [LICENSE](https://github.com/millicast/millicast-sdk/blob/main/LICENSE) file.
diff --git a/packages/millicast-sdk/package.json b/packages/millicast-sdk/package.json
index f7ead05d..be0a6e70 100644
--- a/packages/millicast-sdk/package.json
+++ b/packages/millicast-sdk/package.json
@@ -18,7 +18,7 @@
],
"scripts": {
"build": "nx build @millicast/sdk",
- "build-docs": "jsdoc -c jsdoc.json -R ../../README.md",
+ "build-docs": "typedoc",
"start-docs": "npm run build-docs && serve docs",
"test-unit": "npm run build && jest --testMatch '**/unit/*.steps.js'",
"test-unit-coverage": "npm run build && jest --testMatch '**/unit/*.steps.js' --coverage",
diff --git a/packages/millicast-sdk/typedoc.json b/packages/millicast-sdk/typedoc.json
new file mode 100644
index 00000000..e06fefd3
--- /dev/null
+++ b/packages/millicast-sdk/typedoc.json
@@ -0,0 +1,24 @@
+{
+ "extends": ["../../typedoc.base.json"],
+ "name": "Millicast SDK",
+ "json": "../../docs-json/millicast-sdk.json",
+ "entryPoints": ["src/index.ts"],
+ "entryPointStrategy": "expand",
+ "excludeExternals": true,
+ "excludePrivate": true,
+ "excludeNotDocumented": true,
+ "excludeNotDocumentedKinds": ["Property", "Interface", "TypeAlias"],
+ "plugin": ["typedoc-plugin-mdn-links"],
+ "externalSymbolLinkMappings": {
+ // used by {@link !Promise}
+ "global": {
+ "MediaStreamConstraints": "https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints",
+ "Error": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error"
+ },
+ "typescript": {
+ "MediaStreamConstraints": "https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints",
+ "Error": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error"
+ }
+ },
+ "out": "docs"
+}
\ No newline at end of file
diff --git a/typedoc.base.json b/typedoc.base.json
new file mode 100644
index 00000000..604fb4cb
--- /dev/null
+++ b/typedoc.base.json
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://typedoc.org/schema.json",
+ "navigationLinks": {
+ "GitHub": "https://github.com/millicast/millicast-sdk"
+ },
+ "includeVersion": true
+}
diff --git a/typedoc.json b/typedoc.json
new file mode 100644
index 00000000..23ed47c2
--- /dev/null
+++ b/typedoc.json
@@ -0,0 +1,8 @@
+{
+ "extends": ["./typedoc.base.json"],
+ "name": "Dolby Millicast",
+ "entryPointStrategy": "merge",
+ "entryPoints": ["docs-json/*.json"],
+ "includeVersion": false,
+ "out": "docs"
+}
From 155c091a2046b6d04ff24ed8fa27514dbe4fa76c Mon Sep 17 00:00:00 2001
From: Fabien Lavocat <4154532+FabienLavocat@users.noreply.github.com>
Date: Sun, 29 Jun 2025 21:39:11 +0200
Subject: [PATCH 02/22] Major updates to the SDK workflow
Signed-off-by: Fabien Lavocat <4154532+FabienLavocat@users.noreply.github.com>
---
package-lock.json | 216 ++-
package.json | 6 -
.../src/viewer.ts | 30 +-
.../src/multiviewer.ts | 51 +-
.../src/js/MillicastPublishUserMedia.ts | 16 +-
.../millicast-publisher-demo/src/publisher.ts | 19 +-
.../src/types/MillicastMedia.types.ts | 2 +-
packages/millicast-sdk/README.md | 33 +-
packages/millicast-sdk/package.json | 20 +-
packages/millicast-sdk/src/Director.ts | 281 +--
packages/millicast-sdk/src/PeerConnection.ts | 22 +-
.../millicast-sdk/src/PeerConnectionStats.ts | 2 +-
.../src/{Publish.ts => Publisher.ts} | 225 +--
packages/millicast-sdk/src/Signaling.ts | 92 +-
.../millicast-sdk/src/{View.ts => Viewer.ts} | 399 +++--
packages/millicast-sdk/src/index.ts | 18 +-
.../millicast-sdk/src/types/Director.types.ts | 17 +-
.../{Publish.types.ts => Publisher.types.ts} | 34 +-
.../src/types/Signaling.types.ts | 2 +-
.../src/types/TransformWorker.types.ts | 2 +-
.../types/{View.types.ts => Viewer.types.ts} | 171 +-
packages/millicast-sdk/src/types/events.ts | 240 +++
packages/millicast-sdk/src/types/index.d.ts | 1595 -----------------
packages/millicast-sdk/src/types/others.ts | 6 +
.../millicast-sdk/src/utils/BaseWebRTC.ts | 117 +-
packages/millicast-sdk/src/utils/Codecs.ts | 2 +-
.../src/utils/TypedEventEmitter.ts | 23 +
.../millicast-sdk/src/utils/Validators.ts | 4 +-
.../tests/e2e/FunctionalPublish.steps.js | 4 +-
.../millicast-sdk/tests/e2e/PublishTest.js | 23 +-
.../tests/e2e/PuppeteerJest.html | 7 +-
packages/millicast-sdk/tests/e2e/ViewTest.js | 6 +-
.../tests/features/LoggerDiagnose.feature | 10 +-
.../tests/features/ManageSignaling.feature | 41 +-
.../{Publish.feature => Publisher.feature} | 35 +-
.../features/{View.feature => Viewer.feature} | 13 +-
.../tests/unit/BaseWebRTC.steps.js | 2 +-
.../unit/GetPublisherConnectionPath.steps.js | 10 +-
.../unit/GetSubscriberConnectionPath.steps.js | 10 +-
.../tests/unit/LoggerDiagnose.steps.js | 99 +-
.../tests/unit/LoggerHandlers.steps.js | 16 +-
.../tests/unit/LoggerLevels.steps.js | 4 +-
.../tests/unit/ManagePeerConnection.steps.js | 8 +-
.../tests/unit/ManageSignaling.steps.js | 80 +-
.../tests/unit/PeerConnectionEvent.steps.js | 38 +-
.../{Publish.steps.js => Publisher.steps.js} | 76 +-
.../tests/unit/PublisherReconnect.steps.js | 53 +-
.../tests/unit/SetLocalDescription.steps.js | 2 +-
.../unit/{View.steps.js => Viewer.steps.js} | 60 +-
.../tests/unit/ViewerReconnect.steps.js | 63 +-
packages/millicast-viewer-demo/src/viewer.ts | 51 +-
.../src/viewer.ts | 13 +-
typedoc.base.json | 3 +-
typedoc.json | 2 +-
54 files changed, 1644 insertions(+), 2730 deletions(-)
rename packages/millicast-sdk/src/{Publish.ts => Publisher.ts} (53%)
rename packages/millicast-sdk/src/{View.ts => Viewer.ts} (59%)
rename packages/millicast-sdk/src/types/{Publish.types.ts => Publisher.types.ts} (83%)
rename packages/millicast-sdk/src/types/{View.types.ts => Viewer.types.ts} (55%)
create mode 100644 packages/millicast-sdk/src/types/events.ts
delete mode 100644 packages/millicast-sdk/src/types/index.d.ts
create mode 100644 packages/millicast-sdk/src/types/others.ts
create mode 100644 packages/millicast-sdk/src/utils/TypedEventEmitter.ts
rename packages/millicast-sdk/tests/features/{Publish.feature => Publisher.feature} (88%)
rename packages/millicast-sdk/tests/features/{View.feature => Viewer.feature} (81%)
rename packages/millicast-sdk/tests/unit/{Publish.steps.js => Publisher.steps.js} (73%)
rename packages/millicast-sdk/tests/unit/{View.steps.js => Viewer.steps.js} (64%)
diff --git a/package-lock.json b/package-lock.json
index 28fc7ef8..723dc949 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -66,12 +66,6 @@
"eslint-plugin-promise": "^6.6.0",
"husky": "^4.3.8",
"install": "^0.13.0",
- "jest": "^29.4.1",
- "jest-cucumber": "^3.0.1",
- "jest-environment-jsdom": "^29.7.0",
- "jest-environment-node": "^29.4.1",
- "jest-puppeteer": "^9.0.1",
- "jest-websocket-mock": "^2.2.0",
"jsdom": "~22.1.0",
"lint-staged": "^10.5.4",
"mock-socket": "^9.0.3",
@@ -7734,6 +7728,19 @@
"node": "*"
}
},
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/bl": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
@@ -8389,6 +8396,44 @@
"node": "*"
}
},
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chokidar/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/chrome-trace-event": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
@@ -12625,6 +12670,13 @@
"node": ">= 4"
}
},
+ "node_modules/ignore-by-default": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -12837,6 +12889,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/is-boolean-object": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
@@ -36017,6 +36082,48 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/nodemon": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz",
+ "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^3.5.2",
+ "debug": "^4",
+ "ignore-by-default": "^1.0.1",
+ "minimatch": "^3.1.2",
+ "pstree.remy": "^1.1.8",
+ "semver": "^7.5.3",
+ "simple-update-notifier": "^2.0.0",
+ "supports-color": "^5.5.0",
+ "touch": "^3.1.0",
+ "undefsafe": "^2.0.5"
+ },
+ "bin": {
+ "nodemon": "bin/nodemon.js"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/nodemon"
+ }
+ },
+ "node_modules/nodemon/node_modules/semver": {
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
@@ -36268,6 +36375,20 @@
"node": ">=8"
}
},
+ "node_modules/npm-watch": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/npm-watch/-/npm-watch-0.13.0.tgz",
+ "integrity": "sha512-MYcgocqCzYA44feZhFoYj69FfSaO0EeRE1gcRcmPaXIpNhUMAhNJ1pwic2C4Hn0OPOQmZKSl90CPgmwvOsVhTg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "nodemon": "^3.0.1",
+ "through2": "^4.0.2"
+ },
+ "bin": {
+ "npm-watch": "cli.js"
+ }
+ },
"node_modules/npm/node_modules/@colors/colors": {
"version": "1.5.0",
"dev": true,
@@ -40092,6 +40213,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/pstree.remy": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/pump": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
@@ -40450,6 +40578,19 @@
"node": ">= 6"
}
},
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
"node_modules/regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -41634,6 +41775,32 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/simple-update-notifier": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
+ "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/simple-update-notifier/node_modules/semver": {
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/sirv": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
@@ -42712,6 +42879,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/through2": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz",
+ "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "readable-stream": "3"
+ }
+ },
"node_modules/tiny-typed-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz",
@@ -42837,6 +43014,16 @@
"node": ">=6"
}
},
+ "node_modules/touch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
+ "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "nodetouch": "bin/nodetouch.js"
+ }
+ },
"node_modules/tough-cookie": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
@@ -43354,6 +43541,13 @@
"ieee754": "^1.1.13"
}
},
+ "node_modules/undefsafe": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/underscore": {
"version": "1.13.7",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz",
@@ -44793,7 +44987,15 @@
"name": "@millicast/sdk",
"version": "1.0.0",
"license": "See in LICENSE file",
- "devDependencies": {}
+ "devDependencies": {
+ "jest": "^29.4.1",
+ "jest-cucumber": "^3.0.1",
+ "jest-environment-jsdom": "^29.7.0",
+ "jest-environment-node": "^29.4.1",
+ "jest-puppeteer": "^9.0.1",
+ "jest-websocket-mock": "^2.2.0",
+ "npm-watch": "^0.13.0"
+ }
},
"packages/millicast-viewer-demo": {},
"packages/millicast-webaudio-delay-demo": {}
diff --git a/package.json b/package.json
index 80fa83c7..86338cfd 100644
--- a/package.json
+++ b/package.json
@@ -83,12 +83,6 @@
"eslint-plugin-promise": "^6.6.0",
"husky": "^4.3.8",
"install": "^0.13.0",
- "jest": "^29.4.1",
- "jest-cucumber": "^3.0.1",
- "jest-environment-jsdom": "^29.7.0",
- "jest-environment-node": "^29.4.1",
- "jest-puppeteer": "^9.0.1",
- "jest-websocket-mock": "^2.2.0",
"jsdom": "~22.1.0",
"lint-staged": "^10.5.4",
"mock-socket": "^9.0.3",
diff --git a/packages/millicast-chromecast-receiver/src/viewer.ts b/packages/millicast-chromecast-receiver/src/viewer.ts
index 014acc04..3b8d8195 100644
--- a/packages/millicast-chromecast-receiver/src/viewer.ts
+++ b/packages/millicast-chromecast-receiver/src/viewer.ts
@@ -1,10 +1,10 @@
-import { View, Director, Logger } from '@nx-millicast/millicast-sdk'
+import { Viewer, Director, Logger, LayersEventPayload } from '@nx-millicast/millicast-sdk'
import { DirectorSubscriberOptions } from 'packages/millicast-sdk/src/types/Director.types'
window.Logger = Logger
if (import.meta.env.MILLICAST_DIRECTOR_ENDPOINT) {
- Director.setEndpoint(import.meta.env.MILLICAST_DIRECTOR_ENDPOINT)
+ Director.endpoint = import.meta.env.MILLICAST_DIRECTOR_ENDPOINT
}
const addStream = (stream) => {
@@ -20,21 +20,19 @@ const removeStream = () => {
}
const subscribe = async (streamName, streamAccountId) => {
- const options: DirectorSubscriberOptions = { streamName, streamAccountId }
- const tokenGenerator = () => Director.getSubscriber(options)
- const millicastView = new View(tokenGenerator)
- millicastView.on('broadcastEvent', (event) => {
- const layers = event.data.layers !== null ? event.data.layers : {}
- if (event.name === 'layers' && Object.keys(layers).length <= 0) {
- // call play logic or being reconnect interval
- close().then(() => {
- subscribe(streamName, streamAccountId)
- })
- console.error('Feed no longer found.')
- }
- })
+ const millicastView = new Viewer({ streamName, streamAccountId })
+ // millicastView.on('layers', (event: LayersEventPayload) => {
+ // const layers = event.layers !== null ? event.layers : {}
+ // if (Object.keys(layers).length <= 0) {
+ // // call play logic or being reconnect interval
+ // close().then(() => {
+ // subscribe(streamName, streamAccountId)
+ // })
+ // console.error('Feed no longer found.')
+ // }
+ // })
- millicastView.on('newTrack', (event) => {
+ millicastView.on('track', (event) => {
addStream(event.streams[0])
})
diff --git a/packages/millicast-multiview-demo/src/multiviewer.ts b/packages/millicast-multiview-demo/src/multiviewer.ts
index 14170d93..8b95ad28 100644
--- a/packages/millicast-multiview-demo/src/multiviewer.ts
+++ b/packages/millicast-multiview-demo/src/multiviewer.ts
@@ -1,8 +1,8 @@
-import { View, Director } from '@nx-millicast/millicast-sdk'
+import { Viewer, Director, ActiveEventPayload, InactiveEventPayload, LayersEventPayload } from '@nx-millicast/millicast-sdk'
import { DirectorSubscriberOptions } from 'packages/millicast-sdk/src/types/Director.types'
if (import.meta.env.VITE_DIRECTOR_ENDPOINT) {
- Director.setEndpoint(import.meta.env.VITE_DIRECTOR_ENDPOINT)
+ Director.endpoint = import.meta.env.VITE_DIRECTOR_ENDPOINT
}
// Get query params
@@ -43,8 +43,6 @@ let transceiverMidToSourceIdMap = {}
let transceiverToLayersMap = {}
// Create a new viewer instance
-const options: DirectorSubscriberOptions = { streamName, streamAccountId: accountId, subscriberToken }
-const tokenGenerator = () => Director.getSubscriber(options, enableDRM)
let viewer
document.addEventListener('DOMContentLoaded', async () => {
@@ -52,36 +50,31 @@ document.addEventListener('DOMContentLoaded', async () => {
mainVideoElement = document.getElementById('mid-0')
mainAudioElement = document.getElementById('mid-1')
try {
- viewer = new View(tokenGenerator)
+ viewer = new Viewer({
+ streamName,
+ streamAccountId: accountId,
+ subscriberToken,
+ })
viewer.on('metadata', (metadata) => {
console.log(`Metadata event from ${transceiverToSourceIdMap[metadata.mid] || 'main'}:`, metadata)
})
// Listen for broadcast events
- viewer.on('broadcastEvent', (event) => {
- // Get event name and data
- const { name, data } = event
- switch (name) {
- case 'active': {
- const sourceId = data.sourceId || mainSourceId
- if (sourceId === mainSourceId) {
- addMainSource(data)
- } else {
- addRemoteSource(data)
- }
- addSourceOption(sourceId)
- break
- }
- case 'inactive': {
- const sourceId = data.sourceId || mainSourceId
- unprojectAndRemoveVideo(sourceId)
- removeSourceOption(sourceId)
- break
- }
- case 'layers': {
- if (sourcesDropDown.value) updateLayers(data.medias)
- break
- }
+ viewer.on('active', (event: ActiveEventPayload) => {
+ const sourceId = event.sourceId || mainSourceId
+ if (sourceId === mainSourceId) {
+ addMainSource(event)
+ } else {
+ addRemoteSource(event)
}
+ addSourceOption(sourceId)
+ })
+ viewer.on('inactive', (event: InactiveEventPayload) => {
+ const sourceId = event.sourceId || mainSourceId
+ unprojectAndRemoveVideo(sourceId)
+ removeSourceOption(sourceId)
+ })
+ viewer.on('broadcastEvent', (layers: LayersEventPayload) => {
+ if (sourcesDropDown.value) updateLayers(layers.medias)
})
// This aplication does not support audio only streams. It's not intented to work using audio only streams.
diff --git a/packages/millicast-publisher-demo/src/js/MillicastPublishUserMedia.ts b/packages/millicast-publisher-demo/src/js/MillicastPublishUserMedia.ts
index 9c3141e4..7e4d90e3 100644
--- a/packages/millicast-publisher-demo/src/js/MillicastPublishUserMedia.ts
+++ b/packages/millicast-publisher-demo/src/js/MillicastPublishUserMedia.ts
@@ -1,16 +1,16 @@
-import { Publish } from '@nx-millicast/millicast-sdk'
+import { PublishConnectOptions, Publisher, PublisherOptions } from '@nx-millicast/millicast-sdk'
import MillicastMedia from './MillicastMedia'
-import { PublishConnectOptions } from 'packages/millicast-sdk/src/types/Publish.types'
+import { MillicastMediaOptions } from '../types/MillicastMedia.types'
-export default class MillicastPublishUserMedia extends Publish {
+export default class MillicastPublishUserMedia extends Publisher {
mediaManager: MillicastMedia
- constructor(options, tokenGenerator, autoReconnect) {
- super(tokenGenerator, autoReconnect)
- this.mediaManager = new MillicastMedia(options)
+ constructor(opts: MillicastMediaOptions, options: PublisherOptions) {
+ super(options)
+ this.mediaManager = new MillicastMedia(opts)
}
- static async build(options, tokenGenerator, autoReconnect = true) {
- const instance = new MillicastPublishUserMedia(options, tokenGenerator, autoReconnect)
+ static async build(opts: MillicastMediaOptions, options: PublisherOptions) {
+ const instance = new MillicastPublishUserMedia(opts, options)
await instance.getMediaStream()
return instance
}
diff --git a/packages/millicast-publisher-demo/src/publisher.ts b/packages/millicast-publisher-demo/src/publisher.ts
index 7c76fb0a..a81faa6b 100644
--- a/packages/millicast-publisher-demo/src/publisher.ts
+++ b/packages/millicast-publisher-demo/src/publisher.ts
@@ -10,7 +10,7 @@ window.Logger = Logger
Logger.setLevel(Logger.DEBUG)
if (import.meta.env.VITE_DIRECTOR_ENDPOINT) {
- Director.setEndpoint(import.meta.env.VITE_DIRECTOR_ENDPOINT)
+ Director.endpoint = import.meta.env.VITE_DIRECTOR_ENDPOINT
}
const streamName: string =
@@ -89,12 +89,8 @@ document.addEventListener('DOMContentLoaded', async (event) => {
function setUserCount(): void {
// Add listener of broacastEvent to get UserCount
console.log(millicastPublishUserMedia._events, 'publisher user media')
- millicastPublishUserMedia.on('broadcastEvent', (event) => {
- const { name, data } = event
- console.log(event, 'broadcastEvent')
- if (name === 'viewercount') {
- userCount.innerHTML = data.viewercount
- }
+ millicastPublishUserMedia.on('viewercount', (count) => {
+ userCount.innerHTML = count.toString();
})
}
//////
@@ -143,13 +139,10 @@ document.addEventListener('DOMContentLoaded', async (event) => {
}
/////////////////////////
- const options: DirectorPublisherOptions = { token: publishToken, streamName }
- const tokenGenerator: () => Promise = () => Director.getPublisher(options)
const millicastPublishUserMedia = (window.millicastPublish = await MillicastPublishUserMedia.build(
- { streamName },
- tokenGenerator,
- true
- ))
+ {streamName},
+ {streamName, publishToken, autoReconnect: true}
+ ));
let selectedBandwidthBtn = document.querySelector('#bandwidthMenuButton') as HTMLElement | null
let bandwidth: number = 0
const events: string[] = ['viewercount']
diff --git a/packages/millicast-publisher-demo/src/types/MillicastMedia.types.ts b/packages/millicast-publisher-demo/src/types/MillicastMedia.types.ts
index eb4b9878..8d904e2c 100644
--- a/packages/millicast-publisher-demo/src/types/MillicastMedia.types.ts
+++ b/packages/millicast-publisher-demo/src/types/MillicastMedia.types.ts
@@ -1,5 +1,5 @@
export type MillicastMediaOptions = {
- constraints: MediaStreamConstraints
+ constraints?: MediaStreamConstraints
streamName: String
}
diff --git a/packages/millicast-sdk/README.md b/packages/millicast-sdk/README.md
index fba150ff..934d6a14 100644
--- a/packages/millicast-sdk/README.md
+++ b/packages/millicast-sdk/README.md
@@ -57,27 +57,25 @@ In vanilla JavaScript:
const yourPublishingToken = '...'
const yourStreamName = '...'
- // Define callback for generate new tokens
- const tokenGenerator = () =>
- const options : DirectorPublisherOptions = {token: yourPublishingToken, streamName: yourStreamName}
- millicast.Director.getPublisher(options)
-
// Create a new instance
- const millicastPublish = new millicast.Publish(yourStreamName, tokenGenerator)
+ const millicastPublisher = new millicast.Publisher({
+ streamName: yourStreamName,
+ publishToken: yourPublishingToken,
+ });
// Get user camera and microphone
- const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true })
+ const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
// Publishing options
const broadcastOptions = {
mediaStream,
- }
+ };
// Start broadcast
try {
- await millicastPublish.connect(broadcastOptions)
+ await millicastPublisher.connect(broadcastOptions);
} catch (e) {
- console.log('Connection failed, handle error', e)
+ console.log('Connection failed, handle error', e);
}
@@ -110,19 +108,20 @@ In vanilla JavaScript:
const yourStreamName = '...'
const yourStreamAccountId = '...'
- // Define callback for generate new token
- const options: DirectorSubscriberOptions = {
+ // Create a new instance
+ const millicastViewer = new millicast.View(er{
streamName: yourStreamName,
streamAccountId: yourStreamAccountId,
- }
- const tokenGenerator = () => millicast.Director.getSubscriber(options)
+ });
- // Create a new instance
- const millicastView = new millicast.View(yourStreamName, tokenGenerator, video)
+ // Listen to the track event to receive the streams from the publisher.
+ millicastViewer.on('track', (event) => {
+ video.srcObject = event.streams[0]);
+ });
// Start connection to publisher
try {
- await millicastView.connect()
+ await millicastViewer.connect()
} catch (e) {
console.log('Connection failed, handle error', e)
}
diff --git a/packages/millicast-sdk/package.json b/packages/millicast-sdk/package.json
index be0a6e70..a0e314f5 100644
--- a/packages/millicast-sdk/package.json
+++ b/packages/millicast-sdk/package.json
@@ -16,10 +16,18 @@
"dist",
"scripts"
],
+ "watch": {
+ "build-docs": {
+ "patterns": [
+ "src"
+ ],
+ "extensions": "ts,js"
+ }
+ },
"scripts": {
"build": "nx build @millicast/sdk",
"build-docs": "typedoc",
- "start-docs": "npm run build-docs && serve docs",
+ "start-docs": "npm run build-docs && serve docs & npm-watch",
"test-unit": "npm run build && jest --testMatch '**/unit/*.steps.js'",
"test-unit-coverage": "npm run build && jest --testMatch '**/unit/*.steps.js' --coverage",
"test-e2e": "npm run build && jest --testMatch '**/e2e/*.steps.js' --verbose",
@@ -49,5 +57,13 @@
"type": "git",
"url": "git+https://github.com/millicast/millicast-sdk.git"
},
- "devDependencies": {}
+ "devDependencies": {
+ "jest": "^29.4.1",
+ "jest-cucumber": "^3.0.1",
+ "jest-environment-jsdom": "^29.7.0",
+ "jest-environment-node": "^29.4.1",
+ "jest-puppeteer": "^9.0.1",
+ "jest-websocket-mock": "^2.2.0",
+ "npm-watch": "^0.13.0"
+ }
}
diff --git a/packages/millicast-sdk/src/Director.ts b/packages/millicast-sdk/src/Director.ts
index b7b8ad5a..e1c34291 100644
--- a/packages/millicast-sdk/src/Director.ts
+++ b/packages/millicast-sdk/src/Director.ts
@@ -7,142 +7,79 @@ import {
DirectorSubscriberOptions,
MillicastDirectorResponse,
} from './types/Director.types'
-
-const logger = Logger.get('Director')
-enum StreamTypes {
- WEBRTC = 'WebRtc',
- RTMP = 'Rtmp',
-}
-
-let liveWebsocketDomain = ''
-export const defaultApiEndpoint = 'https://director.millicast.com'
-let apiEndpoint = defaultApiEndpoint
+import { ILogger } from 'js-logger';
/**
- * @module Director
- * @description Simplify API calls to find the best server and region to publish and subscribe to.
- * For security reasons all calls will return a [JWT](https://jwt.io) token for authentication including the required
- * socket path to connect with.
- *
- * You will need your own Publishing token and Stream name, please refer to [Managing Your Tokens](https://docs.dolby.io/streaming-apis/docs/managing-your-tokens).
+ * Simplify API calls to find the best server and region to publish and subscribe to.
+ * For security reasons all calls will return a [JWT](https://jwt.io) token for
+ * authentication including the required socket path to connect with.
+ * @hidden
*/
+export class Director {
-/**
- * @typedef {Object} DRMObject
- * @property {String} fairPlayCertUrl - URL of the FairPlay certificate server.
- * @property {String} fairPlayUrl - URL of the FairPlay license server.
- * @property {String} widevineUrl - URL of the Widevine license server.
- */
+ static #logger: ILogger = Logger.get('Director');
-/**
- * @typedef {Object} MillicastDirectorResponse
- * @global
- * @property {Array} urls - WebSocket available URLs.
- * @property {String} jwt - Access token for signaling initialization.
- * @property {Array} iceServers - Object which represents a list of Ice servers.
- * @property {DRMObject} [drmObject] - DRM proxy server information.
- */
+ /** @ignore */
+ static readonly DEFAULT_API_ENDPOINT: string = 'https://director.millicast.com';
-/**
- * @typedef {Object} DirectorPublisherOptions
- * @global
- * @property {String} token - Millicast Publishing Token.
- * @property {String} streamName - Millicast Stream Name.
- * @property {("WebRtc" | "Rtmp")} [streamType] - Millicast Stream Type.
- */
-
-/**
- * @typedef {Object} DirectorSubscriberOptions
- * @global
- * @property {String} streamName - Millicast publisher Stream Name.
- * @property {String} streamAccountId - Millicast Account ID.
- * @property {String} [subscriberToken] - Token to subscribe to secure streams. If you are subscribing to an unsecure stream, you can omit this param.
- */
+ static #liveWebsocketDomain: string = '';
+ static #apiEndpoint: string = Director.DEFAULT_API_ENDPOINT;
-const Director = {
/**
- * @function
- * @name setEndpoint
- * @description Set Director API endpoint where requests will be sent.
- * @param {String} url - New Director API endpoint
- * @returns {void}
+ * Sets the Director API endpoint where requests will be sent.
+ *
+ * @param url New Director API endpoint
*/
- setEndpoint: (url: string): void => {
- apiEndpoint = url.replace(/\/$/, '')
- },
+ public static set endpoint(url: string) {
+ Director.#apiEndpoint = url.replace(/\/$/, '');
+ }
/**
- * @function
- * @name getEndpoint
- * @description Get current Director API endpoint where requests will be sent. Default endpoint is 'https://director.millicast.com'.
- * @returns {String} API base url
+ * Gets the current Director API endpoint where requests will be sent.
+ *
+ * @returns API base url.
+ *
+ * @defaultValue `https://director.millicast.com`
*/
- getEndpoint: (): string => {
- return apiEndpoint
- },
+ public static get endpoint(): string {
+ return Director.#apiEndpoint;
+ }
/**
- * @function
- * @name setLiveDomain
- * @description Set Websocket Live domain from Director API response.
+ * Sets the Websocket Live domain from Director API response.
* If it is set to empty, it will not parse the response.
- * @param {String} domain - New Websocket Live domain
- * @returns {void}
+ *
+ * @param domain New Websocket Live domain
*/
- setLiveDomain: (domain: string): void => {
- liveWebsocketDomain = domain.replace(/\/$/, '')
- },
+ public static set liveDomain(domain: string) {
+ Director.#liveWebsocketDomain = domain.replace(/\/$/, '');
+ }
/**
- * @function
- * @name getLiveDomain
- * @description Get current Websocket Live domain.
+ * Get current Websocket Live domain.
* By default is empty which corresponds to not parse the Director response.
- * @returns {String} Websocket Live domain
+ *
+ * @returns Websocket Live domain
*/
- getLiveDomain: (): string => {
- return liveWebsocketDomain
- },
+ public static get liveDomain(): string {
+ return Director.#liveWebsocketDomain;
+ }
/**
- * @function
- * @name getPublisher
- * @description Get publisher connection data.
- * @param {DirectorPublisherOptions} options - Millicast options.
- * @returns {Promise} Promise object which represents the result of getting the publishing connection path.
- * @example const response = await Director.getPublisher(options)
- * @example
- * import { Publish, Director } from '@millicast/sdk'
- *
- * //Define getPublisher as callback for Publish
- * const streamName = "My Millicast Stream Name"
- * const token = "My Millicast publishing token"
- * const options: DirectorPublisherOptions = { token, streamName }
- * const tokenGenerator = () => Director.getPublisher(options)
- *
- * //Create a new instance
- * const millicastPublish = new Publish(tokenGenerator)
- *
- * //Get MediaStream
- * const mediaStream = getYourMediaStreamImplementation()
- *
- * //Options
- * const broadcastOptions = {
- * mediaStream: mediaStream
- * }
- *
- * //Start broadcast
- * await millicastPublish.connect(broadcastOptions)
+ * Gets the publisher connection data.
+ *
+ * @param options Millicast options.
+ *
+ * @returns A {@link !Promise Promise} whose fulfillment handler receives a {@link MillicastDirectorResponse} object which represents the result of getting the publishing connection path.
*/
- getPublisher: async (options: DirectorPublisherOptions): Promise => {
- options.streamType = options.streamType || StreamTypes.WEBRTC
- logger.info('Getting publisher connection path for stream name: ', options.streamName)
+ public static async getPublisher(options: DirectorPublisherOptions): Promise {
+ Director.#logger.info('Getting publisher connection path for stream name: ', options.streamName)
const payload = {
streamName: options.streamName,
- streamType: options.streamType,
+ streamType: 'WebRtc',
}
const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${options.token}` }
- const url = `${Director.getEndpoint()}/api/director/publish`
+ const url = `${Director.endpoint}/api/director/publish`
try {
const response = await fetch(url, { method: 'POST', headers, body: JSON.stringify(payload) })
let data = await response.json()
@@ -150,55 +87,27 @@ const Director = {
const error = new FetchError(data.data.message, response.status)
throw error
}
- data = parseIncomingDirectorResponse(data)
- logger.debug('Getting publisher response: ', data)
+ data = Director.parseIncomingDirectorResponse(data)
+ Director.#logger.debug('Getting publisher response: ', data)
Diagnostics.initAccountId(data.data.streamAccountId)
return data.data
} catch (e) {
- logger.error('Error while getting publisher connection path. ', e)
+ Director.#logger.error('Error while getting publisher connection path. ', e)
throw e
}
- },
+ }
/**
- * @function
- * @name getSubscriber
- * @description Get subscriber connection data.
- * @param {DirectorSubscriberOptions} options - Millicast options.
- * @returns {Promise} Promise object which represents the result of getting the subscribe connection data.
- * @example const response = await Director.getSubscriber(options)
- * @example
- * import { View, Director } from '@millicast/sdk'
- *
- * //Define getSubscriber as callback for Subscribe
- * const streamName = "My Millicast Stream Name"
- * const accountId = "Millicast Publisher account Id"
- * const options: DirectorSubscriberOptions = { streamName, streamAccountId }
- * const tokenGenerator = () => Director.getSubscriber(options)
- * //... or for an secure stream
- * const options: DirectorSubscriberOptions = { {streamName, accountId, subscriberToken: '176949b9e57de248d37edcff1689a84a047370ddc3f0dd960939ad1021e0b744'} }
- * const tokenGenerator = () => Director.getSubscriber(options)
- *
- * //Create a new instance
- * const millicastView = new View(tokenGenerator)
- *
- * //Set track event handler to receive streams from Publisher.
- * millicastView.on('track', (event) => {
- * addStreamToYourVideoTag(event.streams[0])
- * })
- *
- * //View Options
- * const options = {
- * }
- *
- * //Start connection to broadcast
- * await millicastView.connect(options)
+ * Get subscriber connection data.
+ *
+ * @param options Millicast options.
+ *
+ * @returns A {@link !Promise Promise} whose fulfillment handler receives a {@link MillicastDirectorResponse} object which represents the result of getting the subscribe connection data.
*/
-
- getSubscriber: async (options: DirectorSubscriberOptions): Promise => {
+ public static async getSubscriber(options: DirectorSubscriberOptions): Promise {
Diagnostics.initAccountId(options.streamAccountId)
- logger.info(
+ Director.#logger.info(
`Getting subscriber connection data for stream name: ${options.streamName} and account id: ${options.streamAccountId}`
)
@@ -211,7 +120,7 @@ const Director = {
if (subscriberToken) {
headers = { ...headers, Authorization: `Bearer ${subscriberToken}` }
}
- const url = `${Director.getEndpoint()}/api/director/subscribe`
+ const url = `${Director.endpoint}/api/director/subscribe`
try {
const response = await fetch(url, { method: 'POST', headers, body: JSON.stringify(payload) })
let data = await response.json()
@@ -219,50 +128,50 @@ const Director = {
const error = new FetchError(data.data.message, response.status)
throw error
}
- data = parseIncomingDirectorResponse(data)
- logger.debug('Getting subscriber response: ', data)
+ data = Director.parseIncomingDirectorResponse(data)
+ Director.#logger.debug('Getting subscriber response: ', data)
if (options.subscriberToken) data.data.subscriberToken = options.subscriberToken
return data.data
} catch (e) {
- logger.error('Error while getting subscriber connection path. ', e)
+ Director.#logger.error('Error while getting subscriber connection path. ', e)
throw e
}
- },
-}
-
-const parseIncomingDirectorResponse = (directorResponse: { data: DirectorResponse }) => {
- if (Director.getLiveDomain()) {
- const domainRegex = /\/\/(.*?)\//
- const urlsParsed = directorResponse.data.urls.map((url) => {
- const matched = domainRegex.exec(url)
- if (!matched) {
- logger.warn('Unable to parse incoming director response')
- return url
- }
- return url.replace(matched[1], Director.getLiveDomain())
- })
- directorResponse.data.urls = urlsParsed
}
- // TODO: remove this when server returns full path of DRM license server URLs
- if (directorResponse.data.drmObject) {
- const playReadyUrl = directorResponse.data.drmObject.playReadyUrl
- if (playReadyUrl) {
- directorResponse.data.drmObject.playReadyUrl = `${Director.getEndpoint()}${playReadyUrl}`
- }
- const widevineUrl = directorResponse.data.drmObject.widevineUrl
- if (widevineUrl) {
- directorResponse.data.drmObject.widevineUrl = `${Director.getEndpoint()}${widevineUrl}`
- }
- const fairPlayUrl = directorResponse.data.drmObject.fairPlayUrl
- if (fairPlayUrl) {
- directorResponse.data.drmObject.fairPlayUrl = `${Director.getEndpoint()}${fairPlayUrl}`
+
+ /** @ignore */
+ private static parseIncomingDirectorResponse = (directorResponse: { data: DirectorResponse }) => {
+ if (Director.liveDomain) {
+ const domainRegex = /\/\/(.*?)\//
+ const urlsParsed = directorResponse.data.urls.map((url) => {
+ const matched = domainRegex.exec(url)
+ if (!matched) {
+ Director.#logger.warn('Unable to parse incoming director response')
+ return url
+ }
+ return url.replace(matched[1], this.liveDomain)
+ })
+ directorResponse.data.urls = urlsParsed
}
- const fairPlayCertUrl = directorResponse.data.drmObject.fairPlayCertUrl
- if (fairPlayCertUrl) {
- directorResponse.data.drmObject.fairPlayCertUrl = `${Director.getEndpoint()}${fairPlayCertUrl}`
+ // TODO: remove this when server returns full path of DRM license server URLs
+ if (directorResponse.data.drmObject) {
+ const playReadyUrl = directorResponse.data.drmObject.playReadyUrl
+ if (playReadyUrl) {
+ directorResponse.data.drmObject.playReadyUrl = `${Director.endpoint}${playReadyUrl}`
+ }
+ const widevineUrl = directorResponse.data.drmObject.widevineUrl
+ if (widevineUrl) {
+ directorResponse.data.drmObject.widevineUrl = `${Director.endpoint}${widevineUrl}`
+ }
+ const fairPlayUrl = directorResponse.data.drmObject.fairPlayUrl
+ if (fairPlayUrl) {
+ directorResponse.data.drmObject.fairPlayUrl = `${Director.endpoint}${fairPlayUrl}`
+ }
+ const fairPlayCertUrl = directorResponse.data.drmObject.fairPlayCertUrl
+ if (fairPlayCertUrl) {
+ directorResponse.data.drmObject.fairPlayCertUrl = `${Director.endpoint}${fairPlayCertUrl}`
+ }
}
+ return directorResponse
}
- return directorResponse
-}
-export default Director
+}
diff --git a/packages/millicast-sdk/src/PeerConnection.ts b/packages/millicast-sdk/src/PeerConnection.ts
index 7a3552a9..aa44f1c1 100644
--- a/packages/millicast-sdk/src/PeerConnection.ts
+++ b/packages/millicast-sdk/src/PeerConnection.ts
@@ -8,6 +8,8 @@ import { SdpOptions, MillicastCapability, ICodecs, PeerConnectionConfig } from '
import { AudioCodec, VideoCodec } from './types/Codecs.types'
import { isAudioCodec, isVideoCodec } from './utils/Codecs'
import { typedKeys } from './utils/ObjectUtils'
+import { TypedEventEmitter } from './utils/TypedEventEmitter'
+import { PeerConnectionEvents } from './types/events'
const logger = Logger.get('PeerConnection')
@@ -18,10 +20,6 @@ export const ConnectionType: {
Publisher: 'Publisher',
Viewer: 'Viewer',
}
-export const webRTCEvents = {
- track: 'track',
- connectionStateChange: 'connectionStateChange',
-}
const localSDPOptions = {
stereo: false,
@@ -39,7 +37,7 @@ const localSDPOptions = {
* @example const peerConnection = new PeerConnection()
* @constructor
*/
-export default class PeerConnection extends EventEmitter {
+export default class PeerConnection extends TypedEventEmitter {
public mode: 'Publisher' | 'Viewer' | null
public peer: RTCPeerConnection | null
public peerConnectionStats: PeerConnectionStats | null
@@ -95,7 +93,7 @@ export default class PeerConnection extends EventEmitter {
this.peer?.close()
this.peer = null
this.stopStats()
- this.emit(webRTCEvents.connectionStateChange, 'closed')
+ this.emit('connectionStateChange', 'closed')
}
/**
@@ -352,10 +350,10 @@ export default class PeerConnection extends EventEmitter {
* @fires PeerConnection#stats
* @example peerConnection.initStats()
* @example
- * import Publish from '@millicast/sdk'
+ * import { Publisher } from '@millicast/sdk'
*
* //Initialize and connect your Publisher
- * const millicastPublish = new Publish(tokenGenerator)
+ * const millicastPublish = new Publisher(tokenGenerator)
* await millicastPublish.connect(options)
*
* //Initialize get stats
@@ -366,7 +364,7 @@ export default class PeerConnection extends EventEmitter {
* console.log('Stats from event: ', stats)
* })
* @example
- * import View from '@millicast/sdk'
+ * import { Viewer } from '@millicast/sdk'
*
* //Initialize and connect your Viewer
* const millicastView = new View(tokenGenerator)
@@ -471,7 +469,7 @@ const addPeerEvents = (instanceClass: PeerConnection, peer: RTCPeerConnection) =
* @type {RTCTrackEvent}
*/
setTimeout(() => {
- instanceClass.emit(webRTCEvents.track, event)
+ instanceClass.emit('track', event)
}, 0)
}
@@ -484,7 +482,7 @@ const addPeerEvents = (instanceClass: PeerConnection, peer: RTCPeerConnection) =
* @event PeerConnection#connectionStateChange
* @type {RTCPeerConnectionState}
*/
- instanceClass.emit(webRTCEvents.connectionStateChange, peer.connectionState)
+ instanceClass.emit('connectionStateChange', peer.connectionState)
}
} else {
// ConnectionStateChange does not exists in Firefox.
@@ -493,7 +491,7 @@ const addPeerEvents = (instanceClass: PeerConnection, peer: RTCPeerConnection) =
/**
* @fires PeerConnection#connectionStateChange
*/
- instanceClass.emit(webRTCEvents.connectionStateChange, peer.iceConnectionState)
+ instanceClass.emit('connectionStateChange', peer.iceConnectionState)
}
}
peer.onnegotiationneeded = async () => {
diff --git a/packages/millicast-sdk/src/PeerConnectionStats.ts b/packages/millicast-sdk/src/PeerConnectionStats.ts
index ac8bd80e..271dcc17 100644
--- a/packages/millicast-sdk/src/PeerConnectionStats.ts
+++ b/packages/millicast-sdk/src/PeerConnectionStats.ts
@@ -89,7 +89,7 @@ export const peerConnectionStatsEvents = {
* This method takes statistical data from @dolbyio/webrtc-stats and transforms it into
* a structured format compatible with previous versions.
*
- * @param {Object} webRTCStats - The statistics object containing various WebRTC stats
+ * @param webRTCStats - The statistics object containing various WebRTC stats
*/
const parseWebRTCStats = (webRTCStats: OnStats): ConnectionStats => {
/* eslint-disable @typescript-eslint/no-unused-vars */
diff --git a/packages/millicast-sdk/src/Publish.ts b/packages/millicast-sdk/src/Publisher.ts
similarity index 53%
rename from packages/millicast-sdk/src/Publish.ts
rename to packages/millicast-sdk/src/Publisher.ts
index 91ef3c9e..0b817cef 100644
--- a/packages/millicast-sdk/src/Publish.ts
+++ b/packages/millicast-sdk/src/Publisher.ts
@@ -2,22 +2,21 @@ import jwtDecode from 'jwt-decode'
import reemit from 're-emitter'
import { atob } from 'js-base64'
import Logger from './Logger'
-import BaseWebRTC from './utils/BaseWebRTC'
-import Signaling, { signalingEvents } from './Signaling'
+import { BaseWebRTC } from './utils/BaseWebRTC'
+import Signaling from './Signaling'
import { DOLBY_SDK_TIMESTAMP_UUID } from './utils/Codecs'
-import PeerConnection, { webRTCEvents, ConnectionType } from './PeerConnection'
+import PeerConnection, { ConnectionType } from './PeerConnection'
import FetchError from './utils/FetchError'
import { supportsInsertableStreams, supportsRTCRtpScriptTransform } from './utils/StreamTransform'
import TransformWorker from './workers/TransformWorker.worker.ts?worker&inline'
-import { PublishConnectOptions } from './types/Publish.types'
+import { PublisherOptions, PublishConnectOptions } from './types/Publisher.types'
import { TokenGeneratorCallback } from './types/Director.types'
import { DecodedJWT, ReconnectData } from './types/BaseWebRTC.types'
-import { SEIUserUnregisteredData } from './types/View.types'
import { SignalingPublishOptions } from './types/Signaling.types'
import { VideoCodec } from './types/Codecs.types'
-import { validatePublishConnectOptions } from './utils/Validators'
-
-const logger = Logger.get('Publish')
+import { isNotDefined, validatePublishConnectOptions } from './utils/Validators'
+import { Director } from './Director'
+import { PublisherEvents, SEIUserUnregisteredData } from './types/events'
const connectOptions: PublishConnectOptions = {
sourceId: null,
@@ -36,107 +35,125 @@ const connectOptions: PublishConnectOptions = {
}
/**
- * @class Publish
- * @extends BaseWebRTC
- * @classdesc Manages connection with a secure WebSocket path to signal the Millicast server
- * and establishes a WebRTC connection to broadcast a MediaStream.
+ * This object manages the connection to the platform to publish a stream.
+ *
+ * Before you can broadcast, you will need a [MediaStream](https://developer.mozilla.org/en-US/docs/Web/API/Media_Streams_API) object
+ * which has at most one audio track and at most one video track. This will be used for stream the contained tracks.
+ *
+ * @example
+ * import { Viewer, PublisherOptions } from '@millicast/sdk';
*
- * Before you can broadcast, you will need:
+ * const streamName = "My Stream Name";
+ * const publishToken = "PUBLISH_TOKEN";
+ * const options: PublisherOptions = {
+ * streamName,
+ * publishToken,
+ * };
*
- * - [MediaStream](https://developer.mozilla.org/en-US/docs/Web/API/Media_Streams_API) which has at most one audio track and at most one video track. This will be used for stream the contained tracks.
+ * // Create a new publisher
+ * const publisher = new Publisher(options);
+ *
+ * // Get a media stream
+ * const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
*
- * - A connection path that you can get from {@link Director} module or from your own implementation.
- * @constructor
- * @param {tokenGeneratorCallback} tokenGenerator - Callback function executed when a new token is needed.
- * @param {Boolean} [autoReconnect=true] - Enable auto reconnect to stream.
+ * // Start the connection
+ * const connecOptions = {
+ * mediaStream
+ * };
+ * await publisher.connect(connecOptions);
*/
-export default class Publish extends BaseWebRTC {
- private recordingAvailable = false
+export class Publisher extends BaseWebRTC {
+ #recordingAvailable: boolean = false
private worker: Worker | null = null
private streamName = ''
private stopReemitingWebRTCPeerInstanceEvents: (() => void) | null = null
private stopReemitingSignalingInstanceEvents: (() => void) | null = null
protected override options: PublishConnectOptions = connectOptions
- constructor(tokenGenerator: TokenGeneratorCallback, autoReconnect = true) {
- super(tokenGenerator, logger, autoReconnect)
+
+ /**
+ * Creates a Publisher object.
+ *
+ * @param options Options for the publisher.
+ */
+ constructor(options: PublisherOptions) {
+ const logger = Logger.get('Publisher');
+
+ if (isNotDefined(options.streamName)) {
+ logger.error('The Stream Name is missing.');
+ throw new Error('The Stream Name is missing.');
+ }
+
+ if (isNotDefined(options.publishToken)) {
+ logger.error('The Publish Token is missing.');
+ throw new Error('The Publish Token is missing.');
+ }
+
+ const tokenGenerator: TokenGeneratorCallback = () => Director.getPublisher({
+ streamName: options.streamName,
+ token: options.publishToken,
+ });
+
+ super(tokenGenerator, logger, options.autoReconnect ?? true);
}
/**
* Starts broadcast to an existing stream name.
*
* In the example, `getYourMediaStream` and `getYourPublisherConnection` is your own implementation.
- * @param {Object} options - General broadcast options.
- * @param {String} options.sourceId - Source unique id. Only avialable if stream is multisource.
- * @param {Boolean} [options.stereo = false] - True to modify SDP for support stereo. Otherwise False.
- * @param {Boolean} [options.dtx = false] - True to modify SDP for supporting dtx in opus. Otherwise False.
- * @param {Boolean} [options.absCaptureTime = false] - True to modify SDP for supporting absolute capture time header extension. Otherwise False.
- * @param {Boolean} [options.dependencyDescriptor = false] - True to modify SDP for supporting aom dependency descriptor header extension. Otherwise False.
- * @param {MediaStream|Array} options.mediaStream - MediaStream to offer in a stream. This object must have
- * 1 audio track and 1 video track, or at least one of them. Alternative you can provide both tracks in an array.
- * @param {Number} [options.bandwidth = 0] - Broadcast bandwidth. 0 for unlimited.
- * @param {Boolean} [options.metadata = false] - Enable metadata insertion if stream is compatible.
- * @param {Boolean} [options.disableVideo = false] - Disable the opportunity to send video stream.
- * @param {Boolean} [options.disableAudio = false] - Disable the opportunity to send audio stream.
- * @param {VideoCodec} [options.codec = 'h264'] - Codec for publish stream.
- * @param {Boolean} [options.simulcast = false] - Enable simulcast. **Only available in Chromium based browsers and with H.264 or VP8 video codecs.**
- * @param {String} [options.scalabilityMode = null] - Selected scalability mode. You can get the available capabilities using PeerConnection.getCapabilities method.
- * **Only available in Google Chrome.**
- * @param {PeerConnectionConfig} [options.peerConfig = null] - Options to configure the new RTCPeerConnection.
- * @param {Boolean} [options.record = false ] - Enable stream recording. If record is not provided, use default Token configuration. **Only available in Tokens with recording enabled.**
- * @param {Array} [options.events = null] - Specify which events will be delivered by the server (any of "active" | "inactive" | "viewercount").*
- * @param {Number} [options.priority = null] - When multiple ingest streams are provided by the customer, add the ability to specify a priority between all ingest streams. Decimal integer between the range [-2^31, +2^31 - 1]. For more information, visit [our documentation](https://docs.dolby.io/streaming-apis/docs/backup-publishing).
- * @returns {Promise} Promise object which resolves when the broadcast started successfully.
- * @fires PeerConnection#connectionStateChange
- * @fires Signaling#broadcastEvent
- * @example await publish.connect(options)
+ * @param options - General broadcast options.@returns {Promise} Promise object which resolves when the broadcast started successfully.
+ *
* @example
- * import Publish from '@millicast/sdk'
- *
- * //Define callback for generate new token
- * const tokenGenerator = () => getYourPublisherConnection(token, streamName)
+ * import { Viewer, PublisherOptions } from '@millicast/sdk';
*
- * //Create a new instance
- * const millicastPublish = new Publish(tokenGenerator)
+ * const streamName = "My Stream Name";
+ * const publishToken = "PUBLISH_TOKEN";
+ * const options: PublisherOptions = {
+ * streamName,
+ * publishToken,
+ * };
*
- * //Get MediaStream
- * const mediaStream = getYourMediaStream()
+ * // Create a new publisher
+ * const publisher = new Publisher(options);
+ *
+ * // Get a media stream
+ * const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
*
- * //Options
- * const broadcastOptions = {
- * mediaStream: mediaStream
- * }
- *
- * //Start broadcast
- * try {
- * await millicastPublish.connect(broadcastOptions)
- * } catch (e) {
- * console.log('Connection failed, handle error', e)
- * }
+ * // Start the connection
+ * const connecOptions = {
+ * mediaStream
+ * };
+ * await publisher.connect(connecOptions);
*/
override async connect(options: PublishConnectOptions = connectOptions): Promise {
- const { error, value } = validatePublishConnectOptions(options)
- if (error) logger.warn(error, value)
+ const { error, value } = validatePublishConnectOptions(options);
+
+ if (error) this.logger.warn(error, value);
+
this.options = {
...connectOptions,
...options,
peerConfig: { ...connectOptions.peerConfig, ...options.peerConfig },
setSDPToPeer: false,
- }
- if (this.options) {
- this.options.metadata =
- this.options.metadata && this.options.codec === VideoCodec.H264 && !this.options.disableVideo
- }
+ };
- await this.initConnection({ migrate: false })
+ this.options.metadata = this.options.metadata && this.options.codec === VideoCodec.H264 && !this.options.disableVideo;
+
+ await this.initConnection({ migrate: false });
}
+ /**
+ * Restart publishing the stream.
+ *
+ * @param data Data object.
+ */
override async reconnect(data?: ReconnectData) {
this.options.mediaStream = this.webRTCPeer?.getTracks() ?? this.options.mediaStream
super.reconnect(data)
}
+ /** @ignore */
override async replaceConnection() {
- logger.info('Migrating current connection')
+ this.logger.info('Migrating current connection')
this.options.mediaStream = this.webRTCPeer?.getTracks() ?? this.options.mediaStream
await this.initConnection({ migrate: true })
}
@@ -144,45 +161,48 @@ export default class Publish extends BaseWebRTC {
/**
* Initialize recording in an active stream and change the current record option.
*/
- async record() {
- if (this.recordingAvailable) {
+ public async startRecording(): Promise {
+ if (this.#recordingAvailable) {
this.options.record = true
await this.signaling?.cmd('record')
- logger.info('Broadcaster start recording')
+ this.logger.info('Broadcaster start recording')
} else {
- logger.error('Record not available')
+ this.logger.error('Record not available')
}
}
/**
- * Finalize recording in an active stream and change the current record option.
+ * Stops the recording in the active stream and change the current record option.
*/
- async unrecord() {
- if (this.recordingAvailable) {
+ public async stopRecording(): Promise {
+ if (this.#recordingAvailable) {
this.options.record = false
await this.signaling?.cmd('unrecord')
- logger.info('Broadcaster stop recording')
+ this.logger.info('Broadcaster stop recording')
} else {
- logger.error('Unrecord not available')
+ this.logger.error('Unrecord not available')
}
}
- override stop() {
+ /**
+ * Stops the publication of the stream.
+ */
+ public override stop() {
super.stop()
this.worker?.terminate()
this.worker = null
}
- async initConnection(data: { migrate: boolean }) {
- logger.debug('Broadcast option values: ', this.options)
+ private async initConnection(data: { migrate: boolean }) {
+ this.logger.debug('Broadcast option values: ', this.options)
this.stopReconnection = false
let promises
if (!this.options.mediaStream) {
- logger.error('Error while broadcasting. MediaStream required')
+ this.logger.error('Error while broadcasting. MediaStream required')
throw new Error('MediaStream required')
}
if (!data.migrate && this.isActive()) {
- logger.warn('Broadcast currently working')
+ this.logger.warn('Broadcast currently working')
throw new Error('Broadcast currently working')
}
let publisherData
@@ -194,7 +214,7 @@ export default class Publish extends BaseWebRTC {
this.options.peerConfig.encodedInsertableStreams = this.options.metadata
}
} catch (error) {
- logger.error('Error generating token.')
+ this.logger.error('Error generating token.')
if (error instanceof FetchError) {
if (error.status === 401 || !this.autoReconnect) {
// should not reconnect
@@ -207,14 +227,14 @@ export default class Publish extends BaseWebRTC {
throw error
}
if (!publisherData) {
- logger.error('Error while broadcasting. Publisher data required')
+ this.logger.error('Error while broadcasting. Publisher data required')
throw new Error('Publisher data required')
}
const decodedJWT = jwtDecode(publisherData.jwt) as DecodedJWT
this.streamName = decodedJWT['millicast'].streamName
- this.recordingAvailable = decodedJWT[atob('bWlsbGljYXN0')].record
- if (this.options.record && !this.recordingAvailable) {
- logger.error('Error while broadcasting. Record option detected but recording is not available')
+ this.#recordingAvailable = decodedJWT[atob('bWlsbGljYXN0')].record
+ if (this.options.record && !this.#recordingAvailable) {
+ this.logger.error('Error while broadcasting. Record option detected but recording is not available')
throw new Error('Record option detected but recording is not available')
}
@@ -225,15 +245,16 @@ export default class Publish extends BaseWebRTC {
const webRTCPeerInstance = data.migrate ? new PeerConnection() : this.webRTCPeer
await webRTCPeerInstance.createRTCPeer(this.options.peerConfig, ConnectionType.Publisher)
+
// Stop emiting events from the previous instances
this.stopReemitingWebRTCPeerInstanceEvents?.()
this.stopReemitingSignalingInstanceEvents?.()
// And start emitting from the new ones
this.stopReemitingWebRTCPeerInstanceEvents = reemit(webRTCPeerInstance, this, [
- webRTCEvents.connectionStateChange,
+ 'connectionStateChange',
])
this.stopReemitingSignalingInstanceEvents = reemit(signalingInstance, this, [
- signalingEvents.broadcastEvent,
+ 'active', 'inactive', 'viewercount',
])
const getLocalSDPPromise = webRTCPeerInstance.getRTCLocalSDP(this.options as SignalingPublishOptions)
@@ -286,14 +307,14 @@ export default class Publish extends BaseWebRTC {
await webRTCPeerInstance.setRTCRemoteSDP(remoteSdp)
- logger.info('Broadcasting to streamName: ', this.streamName)
+ this.logger.info('Broadcasting to streamName:', this.streamName)
let oldWebRTCPeer: PeerConnection | null = this.webRTCPeer
this.webRTCPeer = webRTCPeerInstance
this.setReconnect()
if (data.migrate) {
- this.webRTCPeer.on(webRTCEvents.connectionStateChange, (state) => {
+ this.webRTCPeer.on('connectionStateChange', (state) => {
if (['connected', 'disconnected', 'failed', 'closed'].includes(state)) {
oldSignaling?.close?.()
oldWebRTCPeer?.closeRTCPeer?.()
@@ -304,11 +325,11 @@ export default class Publish extends BaseWebRTC {
}
/**
- * Send SEI user unregistered data as part of the frame being streamed. Only available for H.264 codec.
- * @param {SEIUserUnregisteredData} message The data to be sent as SEI user unregistered data.
- * @param {String} [uuid="d40e38ea-d419-4c62-94ed-20ac37b4e4fa"] String with UUID format as hex digit (XXXX-XX-XX-XX-XXXXXX).
+ * Sends SEI user unregistered data as part of the frame being streamed. Only available for H.264 codec.
+ * @param message The data to be sent as SEI user unregistered data.
+ * @param uuid String with UUID format as hex digit (XXXX-XX-XX-XX-XXXXXX). Default is `"d40e38ea-d419-4c62-94ed-20ac37b4e4fa"`.
*/
- sendMetadata(message: SEIUserUnregisteredData, uuid: string = DOLBY_SDK_TIMESTAMP_UUID) {
+ public sendMetadata(message: SEIUserUnregisteredData, uuid: string = DOLBY_SDK_TIMESTAMP_UUID) {
if (this.options?.metadata && this.worker) {
this.worker.postMessage({
action: 'metadata-sei-user-data-unregistered',
@@ -332,7 +353,7 @@ export default class Publish extends BaseWebRTC {
} else {
warningMessage += '\n- Stream not being published.'
}
- logger.warn(warningMessage)
+ this.logger.warn(warningMessage)
}
}
}
diff --git a/packages/millicast-sdk/src/Signaling.ts b/packages/millicast-sdk/src/Signaling.ts
index c6287f11..6105126a 100644
--- a/packages/millicast-sdk/src/Signaling.ts
+++ b/packages/millicast-sdk/src/Signaling.ts
@@ -1,4 +1,3 @@
-import EventEmitter from 'events'
import TransactionManager from 'transaction-manager'
import Logger from './Logger'
import SdpParser from './utils/SdpParser'
@@ -13,16 +12,11 @@ import {
} from './types/Signaling.types'
import { ICodecs } from './types/PeerConnection.types'
import { VideoCodec } from './types/Codecs.types'
+import { TypedEventEmitter } from './utils/TypedEventEmitter'
+import { ActiveEventPayload, InactiveEventPayload, LayersEventPayload, SignalingEvents } from './types/events'
const logger = Logger.get('Signaling')
-export const signalingEvents = {
- connectionSuccess: 'wsConnectionSuccess',
- connectionError: 'wsConnectionError',
- connectionClose: 'wsConnectionClose',
- broadcastEvent: 'broadcastEvent',
-}
-
/**
* @typedef {Object} LayerInfo
* @property {String} encodingId - rid value of the simulcast encoding of the track (default: automatic selection)
@@ -60,7 +54,7 @@ export const signalingEvents = {
* @param {String} options.url - WebSocket URL to signal Millicast server and establish a WebRTC connection.
*/
-export default class Signaling extends EventEmitter {
+export default class Signaling extends TypedEventEmitter {
public streamName: string | null
public wsUrl: string
public webSocket: WebSocket | null = null
@@ -107,7 +101,7 @@ export default class Signaling extends EventEmitter {
* @property {WebSocket} ws - WebSocket object which represents active connection.
* @property {TransactionManager} tm - [TransactionManager](https://github.com/medooze/transaction-manager) object that simplify WebSocket commands.
*/
- this.emit(signalingEvents.connectionSuccess, { ws: this.webSocket, tm: this.transactionManager })
+ this.emit('wsConnectionSuccess', { ws: this.webSocket, tm: this.transactionManager })
return this.webSocket
}
@@ -118,35 +112,49 @@ export default class Signaling extends EventEmitter {
logger.info('WebSocket opened')
this.transactionManager &&
this.transactionManager.on('event', (evt: TransactionManager.Event) => {
- /**
- * Passthrough of available Millicast broadcast events.
- *
- * Active - Fires when the live stream is, or has started broadcasting.
- *
- * Inactive - Fires when the stream has stopped broadcasting, but is still available.
- *
- * Stopped - Fires when the stream has stopped for a given reason.
- *
- * Vad - Fires when using multiplexed tracks for audio.
- *
- * Layers - Fires when there is an update of the state of the layers in a stream (when broadcasting with simulcast).
- *
- * Migrate - Fires when the server is having problems, is shutting down or when viewers need to move for load balancing purposes.
- *
- * Viewercount - Fires when the viewer count changes.
- *
- * Updated - when an active stream's tracks are updated
- *
- * More information here: {@link https://docs.dolby.io/streaming-apis/docs/web#broadcast-events}
- *
- * @event Signaling#broadcastEvent
- * @type {Object}
- * @property {String} type - In this case the type of this message is "event".
- * @property {("active" | "inactive" | "stopped" | "vad" | "layers" | "migrate" | "viewercount" | "updated")} name - Event name.
- * @property {Object} data - Custom event data.
- */
- this.emit(signalingEvents.broadcastEvent, evt)
- })
+ const data: any = evt.data;
+ switch (evt.name) {
+ case 'active':
+ const activePayload: ActiveEventPayload = {
+ streamId: data.streamId,
+ sourceId: data.sourceId,
+ tracks: data.tracks,
+ encryption: data.encryption,
+ };
+ this.emit('active', activePayload);
+ return;
+ case 'inactive':
+ const inactivePayload: InactiveEventPayload = {
+ streamId: data.streamId,
+ sourceId: data.sourceId,
+ };
+ this.emit('inactive', inactivePayload);
+ return;
+ case 'viewercount':
+ this.emit('viewercount', data.viewerCount);
+ return;
+ case 'migrate':
+ this.emit('migrate');
+ return;
+ case 'updated':
+ this.emit('updated');
+ return;
+ case 'stopped':
+ this.emit('stopped');
+ return;
+ case 'vad':
+ this.emit('vad');
+ return;
+ case 'layers':
+ const layersPayload = data as LayersEventPayload;
+ this.emit('layers', layersPayload);
+ return;
+ default:
+ break
+ }
+ logger.info('The following event was not properly understood', evt);
+ });
+
if (this.webSocket) {
logger.info('Connected to server: ', this.webSocket.url)
logger.debug('WebSocket value: ', {
@@ -156,7 +164,7 @@ export default class Signaling extends EventEmitter {
binaryType: this.webSocket.binaryType,
extensions: this.webSocket.extensions,
})
- this.emit(signalingEvents.connectionSuccess, { ws: this.webSocket, tm: this.transactionManager })
+ this.emit('wsConnectionSuccess', { ws: this.webSocket, tm: this.transactionManager })
resolve(this.webSocket)
}
}
@@ -170,7 +178,7 @@ export default class Signaling extends EventEmitter {
* @event Signaling#wsConnectionError
* @type {String}
*/
- this.emit(signalingEvents.connectionError, this.webSocket.url)
+ this.emit('wsConnectionError', this.webSocket.url)
reject(this.webSocket.url)
}
}
@@ -183,7 +191,7 @@ export default class Signaling extends EventEmitter {
*
* @event Signaling#wsConnectionClose
*/
- this.emit(signalingEvents.connectionClose)
+ this.emit('wsConnectionClose')
}
})
}
diff --git a/packages/millicast-sdk/src/View.ts b/packages/millicast-sdk/src/Viewer.ts
similarity index 59%
rename from packages/millicast-sdk/src/View.ts
rename to packages/millicast-sdk/src/Viewer.ts
index 5feaf958..e6b42f3c 100644
--- a/packages/millicast-sdk/src/View.ts
+++ b/packages/millicast-sdk/src/Viewer.ts
@@ -1,9 +1,9 @@
import reemit from 're-emitter'
import jwtDecode from 'jwt-decode'
import Logger from './Logger'
-import BaseWebRTC from './utils/BaseWebRTC'
-import Signaling, { signalingEvents } from './Signaling'
-import PeerConnection, { webRTCEvents } from './PeerConnection'
+import { BaseWebRTC } from './utils/BaseWebRTC'
+import Signaling from './Signaling'
+import PeerConnection from './PeerConnection'
import { hexToUint8Array } from './utils/StringUtils'
import { swapPropertyValues } from './utils/ObjectUtils'
import FetchError from './utils/FetchError'
@@ -19,22 +19,21 @@ import TransformWorker from './workers/TransformWorker.worker.ts?worker&inline'
import SdpParser from './utils/SdpParser'
import { TokenGeneratorCallback } from './types/Director.types'
import {
- ViewConnectOptions,
+ ViewerConnectOptions,
LayerInfo,
ViewProjectSourceMapping,
DRMOptions,
- MetadataObject,
- SEIUserUnregisteredData,
- ViewerEvents,
-} from './types/View.types.js'
+ ViewerOptions,
+} from './types/Viewer.types.js'
import { DRMProfile } from './types/Director.types'
import { DecodedJWT, Media } from './types/BaseWebRTC.types'
import { VideoCodec } from './types/Codecs.types'
+import { Director } from './Director'
+import { ActiveEventPayload, InactiveEventPayload, MetadataEventPayload, SEIUserUnregisteredData, ViewerEvents } from './types/events'
+import TransactionManager from 'transaction-manager'
+import { isNotDefined } from './utils/Validators'
-const logger = Logger.get('View')
-logger.setLevel(Logger.DEBUG)
-
-const defaultConnectOptions: ViewConnectOptions = {
+const defaultConnectOptions: ViewerConnectOptions = {
metadata: false,
enableDRM: false,
disableVideo: false,
@@ -64,19 +63,67 @@ const defaultConnectOptions: ViewConnectOptions = {
// }
/**
- * @class View
- * @extends BaseWebRTC
- * @classdesc Manages connection with a secure WebSocket path to signal the Millicast server
- * and establishes a WebRTC connection to view a live stream.
+ * This object manages the connection to the platform to subscribe and receive streams.
+ *
+ * @example
+ * How to connect to a stream:
+ * ```typescript
+ * import { ViewerConnectOptions, Viewer, ViewerOptions } from '@millicast/sdk';
+ *
+ * const streamName = 'My Millicast Stream Name';
+ * const accountId = 'Millicast Publisher account Id';
+ *
+ * const options: ViewerOptions = {
+ * streamName,
+ * streamAccountId,
+ * };
+ *
+ * // Create a new viewer
+ * const viewer = new Viewer(options);
+ *
+ * // Listen to the track event to receive the streams from the publisher.
+ * viewer.on('track', (event) => {
+ * addStreamToYourVideoTag(event.streams[0]);
+ * });
+ *
+ * // Connect to the stream
+ * const connectOptions: ViewerConnectOptions = {};
+ * await viewer.connect(connectOptions);
+ * ```
+ *
+ * @example
+ * How to connect to a secure stream:
+ * ```typescript
+ * import { ViewerConnectOptions, Viewer, ViewerOptions } from '@millicast/sdk';
+ *
+ * const streamName = 'My Millicast Stream Name';
+ * const accountId = 'Millicast Publisher account Id';
+ * const subscriberToken = '176949b9e57de248d37edcff1689a84a047370ddc3f0dd960939ad1021e0b744';
+ *
+ * const options: ViewerOptions = {
+ * streamName,
+ * accountId,
+ * subscriberToken,
+ * };
+ *
+ * // Create a new viewer
+ * const viewer = new Viewer(options);
*
- * Before you can view an active broadcast, you will need:
+ * // Listen to the track event to receive the streams from the publisher.
+ * viewer.on('track', (event) => {
+ * addStreamToYourVideoTag(event.streams[0]);
+ * });
*
- * - A connection path that you can get from {@link Director} module or from your own implementation.
- * @constructor
- * @param {tokenGeneratorCallback} tokenGenerator - Callback function executed when a new token is needed.
- * @param {Boolean} [autoReconnect=true] - Enable auto reconnect to stream.
+ * // Connect to the stream
+ * const connectOptions: ViewerConnectOptions = {};
+ * await viewer.connect(connectOptions);
+ *
+ * @fires This class may fire the following events:
+ * * {@link ViewerEvents.track | track}
+ * * {@link ViewerEvents.active | active}
+ * * {@link ViewerEvents.inactive | inactive}
*/
-export default class View extends BaseWebRTC {
+export class Viewer extends BaseWebRTC {
// States what payload type is associated with each codec from the SDP answer.
private payloadTypeCodec: { [key: number]: string } = {}
// Follows the media id values of each transceiver's track from the 'track' events.
@@ -91,107 +138,74 @@ export default class View extends BaseWebRTC {
private eventQueue: RTCTrackEvent[] = []
private stopReemitingWebRTCPeerInstanceEvents: (() => void) | null = null
private stopReemitingSignalingInstanceEvents: (() => void) | null = null
- private events: { [K in keyof ViewerEvents]: Array<(payload: ViewerEvents[K]) => void> } = {}
- protected override options: ViewConnectOptions | null = null
- constructor(tokenGenerator: TokenGeneratorCallback, autoReconnect = true) {
- super(tokenGenerator, logger, autoReconnect)
- }
+ protected override options: ViewerConnectOptions | null = null
+
+ /**
+ * Creates a Viewer object.
+ *
+ * @param options Options for the viewer.
+ */
+ constructor(options: ViewerOptions) {
+ const logger = Logger.get('Viewer');
- override on(eventName: K, listener: (payload: ViewerEvents[K]) => void): this {
- if (!this.events[eventName]) {
- this.events[eventName] = []
+ if (isNotDefined(options.streamName)) {
+ logger.error('The Stream Name is missing.');
+ throw new Error('The Stream Name is missing.');
}
- this.events[eventName].push(listener)
- return this
- }
- override off(eventName: K, listener: (payload: ViewerEvents[K]) => void): this {
- const listeners = this.events[eventName]
- if (listeners) {
- const idx = listeners.indexOf(listener)
- if (idx >= 0) {
- listeners.splice(idx, 1)
- }
+ if (isNotDefined(options.streamAccountId)) {
+ logger.error('The Stream Name is missing.');
+ throw new Error('The Stream Account ID is missing.');
}
- return this
- }
- override emit(eventName: K, payload: ViewerEvents[K]): boolean {
- if (this.events[eventName]) {
- this.events[eventName].forEach((listener) => listener(payload))
- return true
- }
- return false
- }
+ const tokenGenerator: TokenGeneratorCallback = () => Director.getSubscriber({
+ streamName: options.streamName,
+ streamAccountId: options.streamAccountId,
+ subscriberToken: options.subscriberToken,
+ });
- /**
- * @typedef {Object} LayerInfo
- * @property {String} encodingId - rid value of the simulcast encoding of the track (default: automatic selection)
- * @property {Number} spatialLayerId - The spatial layer id to send to the outgoing stream (default: max layer available)
- * @property {Number} temporalLayerId - The temporaral layer id to send to the outgoing stream (default: max layer available)
- * @property {Number} maxSpatialLayerId - Max spatial layer id (default: unlimited)
- * @property {Number} maxTemporalLayerId - Max temporal layer id (default: unlimited)
- */
-
- /**
- * @typedef {RTCConfiguration} PeerConnectionConfig - RTC Peer Connection Configuration object. Extends `RTCConfiguration`.
- * @property {Boolean} [autoInitStats = true] - Whether stats collection should be auto initialized.
- * @property {Number} [statsIntervalMs = 1000] - The interval, in milliseconds, at which we poll stats.
- */
+ super(tokenGenerator, logger, options.autoReconnect ?? true);
+ }
/**
- * Connects to an active stream as subscriber.
+ * Connects to a stream as a subscriber.
*
* In the example, `addStreamToYourVideoTag` and `getYourSubscriberConnectionPath` is your own implementation.
- * @param {Object} [options] - General subscriber options.
- * @param {Boolean} [options.dtx = false] - True to modify SDP for supporting dtx in opus. Otherwise False.
- * @param {Boolean} [options.absCaptureTime = false] - True to modify SDP for supporting absolute capture time header extension. Otherwise False.
- * @param {Boolean} [options.metadata = false] - Enable metadata extraction if stream is compatible.
- * @param {Boolean} [options.drm = false] - Enable the DRM protected stream playback.
- * @param {Boolean} [options.disableVideo = false] - Disable the opportunity to receive video stream.
- * @param {Boolean} [options.disableAudio = false] - Disable the opportunity to receive audio stream.
- * @param {Number} [options.multiplexedAudioTracks] - Number of audio tracks to recieve VAD multiplexed audio for secondary sources.
- * @param {String} [options.pinnedSourceId] - Id of the main source that will be received by the default MediaStream.
- * @param {Array} [options.excludedSourceIds] - Do not receive media from the these source ids.
- * @param {Array} [options.events] - Override which events will be delivered by the server (any of "active" | "inactive" | "vad" | "layers" | "viewercount" | "updated").*
- * @param {PeerConnection} [options.peerConfig] - Options to configure the new RTCPeerConnection.
- * @param {LayerInfo} [options.layer] - Select the simulcast encoding layer and svc layers for the main video track, leave empty for automatic layer selection based on bandwidth estimation.
- * @param {Object} [options.forcePlayoutDelay] - Ask the server to use the playout delay header extension.
- * @param {Number} [options.forcePlayoutDelay.min] - Set minimum playout delay value.
- * @param {Number} [options.forcePlayoutDelay.max] - Set maximum playout delay value.
- * @param {Boolean} [options.enableDRM] - Enable DRM, default is false.
- * @returns {Promise} Promise object which resolves when the connection was successfully established.
- * @fires PeerConnection#track
- * @fires Signaling#broadcastEvent
- * @fires PeerConnection#connectionStateChange
- * @example await millicastView.connect(options)
+ *
+ * @param options General subscriber options.
+ *
+ * @returns Promise object which resolves when the connection was successfully established.
+ *
* @example
- * import View from '@millicast/sdk'
+ * import { Viewer, ViewerOptions } from '@millicast/sdk';
*
- * //Define callback for generate new token
- * const tokenGenerator = () => getYourSubscriberInformation(accountId, streamName)
+ * const streamName = "My Millicast Stream Name";
+ * const accountId = "Millicast Publisher account Id";
+ * const options: ViewerOptions = {
+ * streamName,
+ * streamAccountId,
+ * };
*
- * //Create a new instance
- * const streamName = "Millicast Stream Name where i want to connect"
- * const millicastView = new View(tokenGenerator)
+ * // Create a new viewer
+ * const viewer = new Viewer(options);
*
- * //Set track event handler to receive streams from Publisher.
- * millicastView.on('track', (event) => {
- * addStreamToYourVideoTag(event.streams[0])
- * })
+ * // Listen to the track event to receive the streams from the publisher.
+ * viewer.on('track', (event) => {
+ * addStreamToYourVideoTag(event.streams[0]);
+ * });
*
- * millicastView.on('error', (error) => {
- * console.error('Error from Millicast SDK', error)
- * })
+ * viewer.on('error', (error) => {
+ * console.error('Error from Millicast SDK', error);
+ * });
*
- * //Start connection to broadcast
* try {
- * await millicastView.connect()
+ * const options = {};
+ * await viewer.connect(options);
* } catch (e) {
- * console.log('Connection failed, handle error', e)
+ * console.error('Connection failed', e);
* }
*/
- override async connect(options: ViewConnectOptions = defaultConnectOptions): Promise {
+ override async connect(options: ViewerConnectOptions = defaultConnectOptions): Promise {
this.options = {
...defaultConnectOptions,
...options,
@@ -203,13 +217,13 @@ export default class View extends BaseWebRTC {
}
/**
- * Select the simulcast encoding layer and svc layers for the main video track
- * @param {LayerInfo} layer - leave empty for automatic layer selection based on bandwidth estimation.
+ * Selects the simulcast encoding layer and svc layers for the main video track
+ * @param layer leave empty for automatic layer selection based on bandwidth estimation.
*/
async select(layer?: LayerInfo): Promise {
- logger.debug('Viewer select layer values: ', layer)
- await this.signaling?.cmd('select', { layer })
- logger.info('Connected to streamName: ', this.streamName)
+ this.logger.debug('Viewer select layer values: ', layer);
+ await this.signaling?.cmd('select', { layer });
+ this.logger.info('Connected to streamName: ', this.streamName);
}
/**
@@ -219,7 +233,7 @@ export default class View extends BaseWebRTC {
* @return {Promise} Promise that will be resolved when the RTCRtpTransceiver is assigned an mid value.
*/
async addRemoteTrack(media: Media, streams: Array): Promise {
- logger.info('Viewer adding remote track', media)
+ this.logger.info('Viewer adding remote track', media)
const transceiver = await this.webRTCPeer.addRemoteTrack(media, streams)
for (const stream of streams) {
stream.addTrack(transceiver.receiver.track)
@@ -229,50 +243,44 @@ export default class View extends BaseWebRTC {
/**
* Start projecting source in selected media ids.
- * @param {String} sourceId - Selected source id.
- * @param {Array