diff --git a/.github/workflows/github-release.yml b/.github/workflows/release.yml
similarity index 84%
rename from .github/workflows/github-release.yml
rename to .github/workflows/release.yml
index 76c9d94c3..8e457c629 100644
--- a/.github/workflows/github-release.yml
+++ b/.github/workflows/release.yml
@@ -1,4 +1,4 @@
-name: github-release
+name: release
on:
push:
tags:
@@ -7,7 +7,7 @@ on:
# match semver pre-releases
- "v[0-9]+.[0-9]+.[0-9]+-*"
jobs:
- github-release:
+ release:
env:
NETLIFY_BASE: 'videojs-http-streaming.netlify.app'
runs-on: ubuntu-latest
@@ -29,12 +29,17 @@ jobs:
with:
node-version: '${{steps.nvm.outputs.NVMRC}}'
cache: npm
+ # this line is required for the setup-node action to be able to run the npm publish below.
+ registry-url: 'https://registry.npmjs.org'
- name: npm install
run: npm i --prefer-offline --no-audit
- - name: build
- run: npm run build-prod --if-present
+ # publish runs build for us via a prepublishOnly script
+ - name: npm release
+ run: npm publish --tag next
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Check if this is a pre-release
run: echo ::set-output name=IS_PRE_RELEASE::$(npx -p not-prerelease is-prerelease && echo "true" || echo "false")
@@ -67,3 +72,5 @@ jobs:
files: |
dist/**/*.js
dist/**/*.css
+ discussion_category_name: Releases
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e49d3dd1c..38da60ee3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,9 +1,33 @@
+
+# [3.1.0](https://github.com/videojs/http-streaming/compare/v3.0.2...v3.1.0) (2023-03-07)
+
+### Features
+
+* add fmp4 emsg ID3 support ([#1370](https://github.com/videojs/http-streaming/issues/1370)) ([906f29e](https://github.com/videojs/http-streaming/commit/906f29e))
+
+### Chores
+
+* npm publish for release workflow ([#1376](https://github.com/videojs/http-streaming/issues/1376)) ([e5b4bf6](https://github.com/videojs/http-streaming/commit/e5b4bf6))
+
+
+## [3.0.2](https://github.com/videojs/http-streaming/compare/v3.0.1...v3.0.2) (2023-02-27)
+
+### Bug Fixes
+
+* CMAF HLS. Source buffer change type is called with wrong codecs sometimes when append segment without init data because of a race condition. ([#1375](https://github.com/videojs/http-streaming/issues/1375)) ([7c3e08e](https://github.com/videojs/http-streaming/commit/7c3e08e))
+
+### Chores
+
+* **changelog:** add missing bug fix ([#1362](https://github.com/videojs/http-streaming/issues/1362)) ([343f682](https://github.com/videojs/http-streaming/commit/343f682))
+* update mux.js ([#1372](https://github.com/videojs/http-streaming/issues/1372)) ([1bd22c9](https://github.com/videojs/http-streaming/commit/1bd22c9))
+
## [3.0.1](https://github.com/videojs/http-streaming/compare/v3.0.0...v3.0.1) (2023-01-24)
### Bug Fixes
* Linear DASH multiperiod label issue ([#1352](https://github.com/videojs/http-streaming/issues/1352)) ([d7e8713](https://github.com/videojs/http-streaming/commit/d7e8713))
+* In-manifest VTT iOS MSE issue ([#1360](https://github.com/videojs/http-streaming/issues/1360)) ([6ba70e0](https://github.com/videojs/http-streaming/commit/6ba70e0))
# [3.0.0](https://github.com/videojs/http-streaming/compare/v2.14.2...v3.0.0) (2022-11-21)
diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md
index 3fc89ddf9..4aa46470e 100644
--- a/COLLABORATOR_GUIDE.md
+++ b/COLLABORATOR_GUIDE.md
@@ -59,7 +59,7 @@ Install dependencies for the project.
npm install
```
-Then, it's mostly a standard npm package release process with running `npm version`, followed by an `npm publish`.
+Update version.
```sh
npm version {major|minor|patch}
@@ -71,17 +71,16 @@ See [deciding what type of version release section](#deciding-what-type-of-versi
Optionally, you can run `git show` now to verify that the version update and CHANGELOG automation worked as expected.
Afterwards, you want to push the commit and the tag to the repo.
-It's necessary to do this before running `npm publish` because our GitHub release automation relies on the commit being available on GitHub.
```sh
git push --follow-tags origin main
```
-Publish to npm.
+After the tag was pushed, GitHub actions will trigger the `release` workflow, which will do the following:
-```sh
-npm publish
-```
+* Publish to npm with `next` or `next-{n}` depending on your current major version.
+* Create GitHub release with changelog and Netlify preview.
+* Create a GitHub `releases` discussion linked to the GitHub release.
If it's a large enough release, consider writing a blog post as well.
diff --git a/package-lock.json b/package-lock.json
index 4682c7c5c..dcd85fad9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@videojs/http-streaming",
- "version": "3.0.1",
+ "version": "3.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -14,6 +14,47 @@
"@jridgewell/trace-mapping": "^0.3.9"
}
},
+ "@babel/cli": {
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.21.0.tgz",
+ "integrity": "sha512-xi7CxyS8XjSyiwUGCfwf+brtJxjW1/ZTcBUkP10xawIEXLX5HzLn+3aXkgxozcP2UhRhtKTmQurw9Uaes7jZrA==",
+ "dev": true,
+ "requires": {
+ "@jridgewell/trace-mapping": "^0.3.17",
+ "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3",
+ "chokidar": "^3.4.0",
+ "commander": "^4.0.1",
+ "convert-source-map": "^1.1.0",
+ "fs-readdir-recursive": "^1.1.0",
+ "glob": "^7.2.0",
+ "make-dir": "^2.1.0",
+ "slash": "^2.0.0"
+ },
+ "dependencies": {
+ "@jridgewell/trace-mapping": {
+ "version": "0.3.17",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
+ "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
+ "dev": true,
+ "requires": {
+ "@jridgewell/resolve-uri": "3.1.0",
+ "@jridgewell/sourcemap-codec": "1.4.14"
+ }
+ },
+ "commander": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+ "dev": true
+ },
+ "slash": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
+ "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
+ "dev": true
+ }
+ }
+ },
"@babel/code-frame": {
"version": "7.15.8",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz",
@@ -1449,6 +1490,19 @@
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
+ "@nicolo-ribaudo/chokidar-2": {
+ "version": "2.1.8-no-fsevents.3",
+ "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz",
+ "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@popperjs/core": {
+ "version": "2.11.7",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz",
+ "integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==",
+ "dev": true
+ },
"@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -1610,10 +1664,13 @@
"dev": true
},
"@types/cors": {
- "version": "2.8.12",
- "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz",
- "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==",
- "dev": true
+ "version": "2.8.13",
+ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz",
+ "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
},
"@types/estree": {
"version": "0.0.39",
@@ -1722,68 +1779,27 @@
}
},
"@videojs/http-streaming": {
- "version": "2.10.2",
- "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.10.2.tgz",
- "integrity": "sha512-JTAlAUHzj0sTsge2WBh4DWKM2I5BDFEZYOvzxmsK/ySILmI0GRyjAHx9uid68ZECQ2qbEAIRmZW5lWp0R5PeNA==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-3.0.0.tgz",
+ "integrity": "sha512-AdKmY/W2dyeJP0uALgMRmhLa4pbHMvE4OMlg6yQvufnqsz6jDFo1DYnZRv2ENDYrmVdnPH58Ehgu59053+OIhQ==",
"requires": {
"@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "3.0.3",
- "aes-decrypter": "3.1.2",
+ "@videojs/vhs-utils": "4.0.0",
+ "aes-decrypter": "4.0.1",
"global": "^4.4.0",
- "m3u8-parser": "4.7.0",
- "mpd-parser": "0.19.0",
- "mux.js": "5.13.0",
- "video.js": "^6 || ^7"
+ "m3u8-parser": "^6.0.0",
+ "mpd-parser": "^1.0.1",
+ "mux.js": "6.2.0",
+ "video.js": "^7 || ^8"
},
"dependencies": {
- "@videojs/vhs-utils": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.3.tgz",
- "integrity": "sha512-bU7daxDHhzcTDbmty1cXjzsTYvx2cBGbA8hG5H2Gvpuk4sdfuvkZtMCwtCqL59p6dsleMPspyaNS+7tWXx2Y0A==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "global": "^4.4.0",
- "url-toolkit": "^2.2.1"
- }
- },
- "aes-decrypter": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.2.tgz",
- "integrity": "sha512-42nRwfQuPRj9R1zqZBdoxnaAmnIFyDi0MNyTVhjdFOd8fifXKKRfwIHIZ6AMn1or4x5WONzjwRTbTWcsIQ0O4A==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "^3.0.0",
- "global": "^4.4.0",
- "pkcs7": "^1.0.4"
- }
- },
- "m3u8-parser": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.7.0.tgz",
- "integrity": "sha512-48l/OwRyjBm+QhNNigEEcRcgbRvnUjL7rxs597HmW9QSNbyNvt+RcZ9T/d9vxi9A9z7EZrB1POtZYhdRlwYQkQ==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "^3.0.0",
- "global": "^4.4.0"
- }
- },
- "mpd-parser": {
- "version": "0.19.0",
- "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.19.0.tgz",
- "integrity": "sha512-FDLIXtZMZs99fv5iXNFg94quNFT26tobo0NUgHu7L3XgZvEq1NBarf5yxDFFJ1zzfbcmtj+NRaml6nYIxoPWvw==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "^3.0.2",
- "@xmldom/xmldom": "^0.7.2",
- "global": "^4.4.0"
- }
- },
"mux.js": {
- "version": "5.13.0",
- "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.13.0.tgz",
- "integrity": "sha512-PkmnzHcTQjUBEHp3KRPQAFoNkJtKlpCEvsYtXDfDrC+/WqbMuxHvoYfmAbHVAH7Sa/KliPVU0dT1ureO8wilog==",
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-6.2.0.tgz",
+ "integrity": "sha512-SKuxIcbmK/aJoz78aQNuoXY8R/uEPm1gQMqWTXL6DNl7oF8UPjdt/AunXGkPQpBouGWKDgL/TzSl2VV5NuboRg==",
"requires": {
- "@babel/runtime": "^7.11.2"
+ "@babel/runtime": "^7.11.2",
+ "global": "^4.4.0"
}
}
}
@@ -1824,9 +1840,10 @@
}
},
"@xmldom/xmldom": {
- "version": "0.7.5",
- "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.5.tgz",
- "integrity": "sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A=="
+ "version": "0.8.7",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.7.tgz",
+ "integrity": "sha512-sI1Ly2cODlWStkINzqGrZ8K6n+MTSbAeQnAipGyL+KZCXuHaRlj2gyyy8B/9MvsFFqN7XHryQnB2QwhzvJXovg==",
+ "dev": true
},
"JSONStream": {
"version": "1.3.5",
@@ -2551,7 +2568,7 @@
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
- "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "integrity": "sha512-wFUFA5bg5dviipbQQ32yOQhl6gcJaJXiHE7dvR8VYPG97+J/GNC5FKGepKdEDUFeXRzDxPF1X/Btc8L+v7oqIQ==",
"dev": true
},
"is-fullwidth-code-point": {
@@ -2684,7 +2701,7 @@
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
"concat-stream": {
@@ -3511,9 +3528,9 @@
"dev": true
},
"engine.io": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz",
- "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz",
+ "integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==",
"dev": true,
"requires": {
"@types/cookie": "^0.4.1",
@@ -3537,9 +3554,9 @@
}
},
"engine.io-parser": {
- "version": "5.0.4",
- "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
- "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==",
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz",
+ "integrity": "sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==",
"dev": true
},
"enquirer": {
@@ -4247,6 +4264,12 @@
"universalify": "^0.1.0"
}
},
+ "fs-readdir-recursive": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz",
+ "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==",
+ "dev": true
+ },
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -5499,9 +5522,9 @@
"dev": true
},
"json5": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
- "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"jsonfile": {
@@ -5892,7 +5915,7 @@
"keycode": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz",
- "integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ="
+ "integrity": "sha512-ps3I9jAdNtRpJrbBvQjpzyFbss/skHqzS+eu4RxKLaEAtFqkjZaB6TZMSivPbLxf4K7VI4SjR0P5mRCX5+Q25A=="
},
"kind-of": {
"version": "6.0.3",
@@ -6284,6 +6307,30 @@
"sourcemap-codec": "^1.4.4"
}
},
+ "make-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+ "dev": true,
+ "requires": {
+ "pify": "^4.0.1",
+ "semver": "^5.6.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+ "dev": true
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ }
+ }
+ },
"map-obj": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
@@ -6797,9 +6844,9 @@
"dev": true
},
"minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
@@ -6835,9 +6882,9 @@
"dev": true
},
"mpd-parser": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-1.0.1.tgz",
- "integrity": "sha512-3CmVq7af3tcLqpx9SLBSweVnxS0SlpkKr+YBLC7O/wO1bv2L9tsCY350wziPWuMEjE5+x46i898sI4YIY3cmJA==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-1.1.1.tgz",
+ "integrity": "sha512-uZ/db5wQdlQn1L+OD49YXBhPI9UGeK1SeQE4D5EoaJIhf0WM9X3HDj8d+9PjoG06CgCvGZw3YW/wsHku+CH3yA==",
"requires": {
"@babel/runtime": "^7.12.5",
"@videojs/vhs-utils": "^3.0.5",
@@ -6856,9 +6903,9 @@
}
},
"@xmldom/xmldom": {
- "version": "0.8.3",
- "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.3.tgz",
- "integrity": "sha512-Lv2vySXypg4nfa51LY1nU8yDAGo/5YwF+EY/rUZgIbfvwVARcd67ttCM8SMsTeJy51YhHYavEq+FS6R0hW9PFQ=="
+ "version": "0.8.6",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.6.tgz",
+ "integrity": "sha512-uRjjusqpoqfmRkTaNuLJ2VohVr67Q5YwDATW3VU7PfzTj6IRaihGrYI7zckGZjxQPBIp63nfvJbM+Yu5ICh0Bg=="
}
}
},
@@ -6875,9 +6922,9 @@
"dev": true
},
"mux.js": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-6.2.0.tgz",
- "integrity": "sha512-SKuxIcbmK/aJoz78aQNuoXY8R/uEPm1gQMqWTXL6DNl7oF8UPjdt/AunXGkPQpBouGWKDgL/TzSl2VV5NuboRg==",
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-6.3.0.tgz",
+ "integrity": "sha512-/QTkbSAP2+w1nxV+qTcumSDN5PA98P0tjrADijIzQHe85oBK3Akhy9AHlH0ne/GombLMz1rLyvVsmrgRxoPDrQ==",
"requires": {
"@babel/runtime": "^7.11.2",
"global": "^4.4.0"
@@ -8980,9 +9027,9 @@
"dev": true
},
"ua-parser-js": {
- "version": "0.7.31",
- "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz",
- "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==",
+ "version": "0.7.34",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.34.tgz",
+ "integrity": "sha512-cJMeh/eOILyGu0ejgTKB95yKT3zOenSe9UGE3vj6WfiOwgGYnmATUsnDixMFvdU+rNMvWih83hrUP8VwhF9yXQ==",
"dev": true
},
"uc.micro": {
@@ -9176,74 +9223,33 @@
"dev": true
},
"video.js": {
- "version": "7.15.4",
- "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.15.4.tgz",
- "integrity": "sha512-hghxkgptLUvfkpktB4wxcIVF3VpY/hVsMkrjHSv0jpj1bW9Jplzdt8IgpTm9YhlB1KYAp07syVQeZcBFUBwhkw==",
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/video.js/-/video.js-8.0.4.tgz",
+ "integrity": "sha512-fvvWauPanrKDps1HQGGL+9CIAK8G0YVwlNme0hvY0k3moXQryaRcJSLHIlPKV2j9ZFTHl32VbN43jL3TaUllfg==",
"requires": {
"@babel/runtime": "^7.12.5",
- "@videojs/http-streaming": "2.10.2",
- "@videojs/vhs-utils": "^3.0.3",
+ "@videojs/http-streaming": "3.0.0",
+ "@videojs/vhs-utils": "^4.0.0",
"@videojs/xhr": "2.6.0",
- "aes-decrypter": "3.1.2",
- "global": "^4.4.0",
- "keycode": "^2.2.0",
- "m3u8-parser": "4.7.0",
- "mpd-parser": "0.19.0",
- "mux.js": "5.13.0",
+ "aes-decrypter": "^4.0.1",
+ "global": "4.4.0",
+ "keycode": "2.2.0",
+ "m3u8-parser": "^6.0.0",
+ "mpd-parser": "^1.0.1",
+ "mux.js": "^6.2.0",
"safe-json-parse": "4.0.0",
+ "videojs-contrib-quality-levels": "3.0.0",
"videojs-font": "3.2.0",
- "videojs-vtt.js": "^0.15.3"
+ "videojs-vtt.js": "0.15.4"
},
"dependencies": {
- "@videojs/vhs-utils": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz",
- "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "global": "^4.4.0",
- "url-toolkit": "^2.2.1"
- }
- },
- "aes-decrypter": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.2.tgz",
- "integrity": "sha512-42nRwfQuPRj9R1zqZBdoxnaAmnIFyDi0MNyTVhjdFOd8fifXKKRfwIHIZ6AMn1or4x5WONzjwRTbTWcsIQ0O4A==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "^3.0.0",
- "global": "^4.4.0",
- "pkcs7": "^1.0.4"
- }
- },
- "m3u8-parser": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.7.0.tgz",
- "integrity": "sha512-48l/OwRyjBm+QhNNigEEcRcgbRvnUjL7rxs597HmW9QSNbyNvt+RcZ9T/d9vxi9A9z7EZrB1POtZYhdRlwYQkQ==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "^3.0.0",
- "global": "^4.4.0"
- }
- },
- "mpd-parser": {
- "version": "0.19.0",
- "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.19.0.tgz",
- "integrity": "sha512-FDLIXtZMZs99fv5iXNFg94quNFT26tobo0NUgHu7L3XgZvEq1NBarf5yxDFFJ1zzfbcmtj+NRaml6nYIxoPWvw==",
+ "videojs-contrib-quality-levels": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/videojs-contrib-quality-levels/-/videojs-contrib-quality-levels-3.0.0.tgz",
+ "integrity": "sha512-sNx38EYUx+Q+gmup1gVTv9P9/sPs28rM7gZOx1sedaHoKxEdYB+ysOGfHj6MSELBMNGMj6ZspdrpSiWguGvGxA==",
"requires": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "^3.0.2",
- "@xmldom/xmldom": "^0.7.2",
"global": "^4.4.0"
}
- },
- "mux.js": {
- "version": "5.13.0",
- "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.13.0.tgz",
- "integrity": "sha512-PkmnzHcTQjUBEHp3KRPQAFoNkJtKlpCEvsYtXDfDrC+/WqbMuxHvoYfmAbHVAH7Sa/KliPVU0dT1ureO8wilog==",
- "requires": {
- "@babel/runtime": "^7.11.2"
- }
}
}
},
@@ -9258,13 +9264,12 @@
}
},
"videojs-contrib-quality-levels": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/videojs-contrib-quality-levels/-/videojs-contrib-quality-levels-2.1.0.tgz",
- "integrity": "sha512-dqGQGbL9AFhucxki7Zh0c3kIhH0PAPcHEh6jUdRyaFCVeOuqnJrOYs/3wNtsokDdBdRf2Du2annpu4Z2XaSZRg==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/videojs-contrib-quality-levels/-/videojs-contrib-quality-levels-4.0.0.tgz",
+ "integrity": "sha512-u5rmd8BjLwANp7XwuQ0Q/me34bMe6zg9PQdHfTS7aXgiVRbNTb4djcmfG7aeSrkpZjg+XCLezFNenlJaCjBHKw==",
"dev": true,
"requires": {
- "global": "^4.3.2",
- "video.js": "^6 || ^7"
+ "global": "^4.4.0"
}
},
"videojs-font": {
@@ -9347,6 +9352,111 @@
"global": "^4.3.2",
"video.js": "^7.0.0",
"videojs-contrib-quality-levels": "^2.0.4"
+ },
+ "dependencies": {
+ "@videojs/http-streaming": {
+ "version": "2.16.2",
+ "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.16.2.tgz",
+ "integrity": "sha512-etPTUdCFu7gUWc+1XcbiPr+lrhOcBu3rV5OL1M+3PDW89zskScAkkcdqYzP4pFodBPye/ydamQoTDScOnElw5A==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.12.5",
+ "@videojs/vhs-utils": "3.0.5",
+ "aes-decrypter": "3.1.3",
+ "global": "^4.4.0",
+ "m3u8-parser": "4.8.0",
+ "mpd-parser": "^0.22.1",
+ "mux.js": "6.0.1",
+ "video.js": "^6 || ^7"
+ }
+ },
+ "@videojs/vhs-utils": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz",
+ "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.12.5",
+ "global": "^4.4.0",
+ "url-toolkit": "^2.2.1"
+ }
+ },
+ "aes-decrypter": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.3.tgz",
+ "integrity": "sha512-VkG9g4BbhMBy+N5/XodDeV6F02chEk9IpgRTq/0bS80y4dzy79VH2Gtms02VXomf3HmyRe3yyJYkJ990ns+d6A==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.12.5",
+ "@videojs/vhs-utils": "^3.0.5",
+ "global": "^4.4.0",
+ "pkcs7": "^1.0.4"
+ }
+ },
+ "m3u8-parser": {
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.8.0.tgz",
+ "integrity": "sha512-UqA2a/Pw3liR6Df3gwxrqghCP17OpPlQj6RBPLYygf/ZSQ4MoSgvdvhvt35qV+3NaaA0FSZx93Ix+2brT1U7cA==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.12.5",
+ "@videojs/vhs-utils": "^3.0.5",
+ "global": "^4.4.0"
+ }
+ },
+ "mpd-parser": {
+ "version": "0.22.1",
+ "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.22.1.tgz",
+ "integrity": "sha512-fwBebvpyPUU8bOzvhX0VQZgSohncbgYwUyJJoTSNpmy7ccD2ryiCvM7oRkn/xQH5cv73/xU7rJSNCLjdGFor0Q==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.12.5",
+ "@videojs/vhs-utils": "^3.0.5",
+ "@xmldom/xmldom": "^0.8.3",
+ "global": "^4.4.0"
+ }
+ },
+ "mux.js": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-6.0.1.tgz",
+ "integrity": "sha512-22CHb59rH8pWGcPGW5Og7JngJ9s+z4XuSlYvnxhLuc58cA1WqGDQPzuG8I+sPm1/p0CdgpzVTaKW408k5DNn8w==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.11.2",
+ "global": "^4.4.0"
+ }
+ },
+ "video.js": {
+ "version": "7.21.4",
+ "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.21.4.tgz",
+ "integrity": "sha512-R5e57M/5uqxQMQpFpybNbd8GtiRwFJPqkHjrhv0QTJ2tqnesbjETbck5kU5dhFr1FevsJRFhjBG4hAnvRGnXbw==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.12.5",
+ "@videojs/http-streaming": "2.16.2",
+ "@videojs/vhs-utils": "^3.0.4",
+ "@videojs/xhr": "2.6.0",
+ "aes-decrypter": "3.1.3",
+ "global": "^4.4.0",
+ "keycode": "^2.2.0",
+ "m3u8-parser": "4.8.0",
+ "mpd-parser": "0.22.1",
+ "mux.js": "6.0.1",
+ "safe-json-parse": "4.0.0",
+ "videojs-font": "3.2.0",
+ "videojs-vtt.js": "^0.15.4"
+ }
+ },
+ "videojs-contrib-quality-levels": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/videojs-contrib-quality-levels/-/videojs-contrib-quality-levels-2.2.1.tgz",
+ "integrity": "sha512-cnF6OGGgoC/2nUrbdz54nzPm3BpEZQzMTpyekiX6AXs8imATX2sHbrUz97xXVSHITldk/+d7ZAUrdQYJJTyuug==",
+ "dev": true,
+ "requires": {
+ "global": "^4.3.2",
+ "video.js": "^6 || ^7 || ^8"
+ }
+ }
}
},
"videojs-standard": {
@@ -9374,9 +9484,9 @@
}
},
"videojs-vtt.js": {
- "version": "0.15.3",
- "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.15.3.tgz",
- "integrity": "sha512-5FvVsICuMRx6Hd7H/Y9s9GDeEtYcXQWzGMS+sl4UX3t/zoHp3y+isSfIPRochnTH7h+Bh1ILyC639xy9Z6kPag==",
+ "version": "0.15.4",
+ "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.15.4.tgz",
+ "integrity": "sha512-r6IhM325fcLb1D6pgsMkTQT1PpFdUdYZa1iqk7wJEu+QlibBwATPfPc9Bg8Jiym0GE5yP1AG2rMLu+QMVWkYtA==",
"requires": {
"global": "^4.3.1"
}
diff --git a/package.json b/package.json
index afdd37a67..e3becbca8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@videojs/http-streaming",
- "version": "3.0.1",
+ "version": "3.1.0",
"description": "Play back HLS and DASH with Video.js, even where it's not natively supported",
"main": "dist/videojs-http-streaming.cjs.js",
"module": "dist/videojs-http-streaming.es.js",
@@ -62,14 +62,16 @@
"aes-decrypter": "4.0.1",
"global": "^4.4.0",
"m3u8-parser": "^6.0.0",
- "mpd-parser": "^1.0.1",
- "mux.js": "6.2.0",
+ "mpd-parser": "^1.1.1",
+ "mux.js": "6.3.0",
"video.js": "^7 || ^8"
},
"peerDependencies": {
"video.js": "^7 || ^8"
},
"devDependencies": {
+ "@babel/cli": "^7.21.0",
+ "@popperjs/core": "^2.11.7",
"@rollup/plugin-replace": "^2.3.4",
"@rollup/plugin-strip": "^2.0.1",
"@videojs/generator-helpers": "~3.1.0",
@@ -86,7 +88,7 @@
"sinon": "^8.1.1",
"url-toolkit": "^2.2.1",
"videojs-contrib-eme": "^5.0.1",
- "videojs-contrib-quality-levels": "^2.0.4",
+ "videojs-contrib-quality-levels": "^4.0.0",
"videojs-generate-karma-config": "^8.0.1",
"videojs-generate-rollup-config": "^7.0.0",
"videojs-generator-verify": "~3.0.1",
diff --git a/src/media-segment-request.js b/src/media-segment-request.js
index 0a88b63ce..086f0fe48 100644
--- a/src/media-segment-request.js
+++ b/src/media-segment-request.js
@@ -462,7 +462,7 @@ const handleSegmentBytes = ({
// Note that the start time returned by the probe reflects the baseMediaDecodeTime, as
// that is the true start of the segment (where the playback engine should begin
// decoding).
- const finishLoading = (captions) => {
+ const finishLoading = (captions, id3Frames) => {
// if the track still has audio at this point it is only possible
// for it to be audio only. See `tracks.video && tracks.audio` if statement
// above.
@@ -471,6 +471,9 @@ const handleSegmentBytes = ({
data: bytesAsUint8Array,
type: trackInfo.hasAudio && !trackInfo.isMuxed ? 'audio' : 'video'
});
+ if (id3Frames && id3Frames.length) {
+ id3Fn(segment, id3Frames);
+ }
if (captions && captions.length) {
captionsFn(segment, captions);
}
@@ -494,29 +497,40 @@ const handleSegmentBytes = ({
if (trackInfo.hasVideo) {
timingInfoFn(segment, 'video', 'start', startTime);
}
-
- // Run through the CaptionParser in case there are captions.
- // Initialize CaptionParser if it hasn't been yet
- if (!tracks.video || !data.byteLength || !segment.transmuxer) {
- finishLoading();
- return;
- }
-
workerCallback({
- action: 'pushMp4Captions',
- endAction: 'mp4Captions',
- transmuxer: segment.transmuxer,
+ action: 'probeEmsgID3',
data: bytesAsUint8Array,
- timescales: segment.map.timescales,
- trackIds: [tracks.video.id],
- callback: (message) => {
+ transmuxer: segment.transmuxer,
+ offset: startTime,
+ callback: ({emsgData, id3Frames}) => {
// transfer bytes back to us
- bytes = message.data.buffer;
- segment.bytes = bytesAsUint8Array = message.data;
- message.logs.forEach(function(log) {
- onTransmuxerLog(merge(log, {stream: 'mp4CaptionParser'}));
+ bytes = emsgData.buffer;
+ segment.bytes = bytesAsUint8Array = emsgData;
+
+ // Run through the CaptionParser in case there are captions.
+ // Initialize CaptionParser if it hasn't been yet
+ if (!tracks.video || !data.byteLength || !segment.transmuxer) {
+ finishLoading(undefined, id3Frames);
+ return;
+ }
+
+ workerCallback({
+ action: 'pushMp4Captions',
+ endAction: 'mp4Captions',
+ transmuxer: segment.transmuxer,
+ data: bytesAsUint8Array,
+ timescales: segment.map.timescales,
+ trackIds: [tracks.video.id],
+ callback: (message) => {
+ // transfer bytes back to us
+ bytes = message.data.buffer;
+ segment.bytes = bytesAsUint8Array = message.data;
+ message.logs.forEach(function(log) {
+ onTransmuxerLog(merge(log, {stream: 'mp4CaptionParser'}));
+ });
+ finishLoading(message.captions, id3Frames);
+ }
});
- finishLoading(message.captions);
}
});
}
diff --git a/src/playlist-controller.js b/src/playlist-controller.js
index aed3786a7..79f0da771 100644
--- a/src/playlist-controller.js
+++ b/src/playlist-controller.js
@@ -933,18 +933,12 @@ export class PlaylistController extends videojs.EventTarget {
// Delete all buffered data to allow an immediate quality switch, then seek to give
// the browser a kick to remove any cached frames from the previous rendtion (.04 seconds
- // ahead is roughly the minimum that will accomplish this across a variety of content
+ // ahead was roughly the minimum that will accomplish this across a variety of content
// in IE and Edge, but seeking in place is sufficient on all other browsers)
// Edge/IE bug: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/14600375/
// Chrome bug: https://bugs.chromium.org/p/chromium/issues/detail?id=651904
this.mainSegmentLoader_.resetEverything(() => {
- // Since this is not a typical seek, we avoid the seekTo method which can cause segments
- // from the previously enabled rendition to load before the new playlist has finished loading
- if (videojs.browser.IE_VERSION || videojs.browser.IS_EDGE) {
- this.tech_.setCurrentTime(this.tech_.currentTime() + 0.04);
- } else {
- this.tech_.setCurrentTime(this.tech_.currentTime());
- }
+ this.tech_.setCurrentTime(this.tech_.currentTime());
});
// don't need to reset audio as it is reset when media changes
@@ -1003,19 +997,6 @@ export class PlaylistController extends videojs.EventTarget {
return false;
}
- if (videojs.browser.IE_VERSION &&
- this.tech_.readyState() === 0) {
- // IE11 throws an InvalidStateError if you try to set currentTime while the
- // readyState is 0, so it must be delayed until the tech fires loadedmetadata.
- this.tech_.one('loadedmetadata', () => {
- this.trigger('firstplay');
- this.tech_.setCurrentTime(seekable.end(0));
- this.hasPlayed_ = true;
- });
-
- return false;
- }
-
// trigger firstplay to inform the source handler to ignore the next seek event
this.trigger('firstplay');
// seek to the live point
@@ -1715,9 +1696,11 @@ export class PlaylistController extends videojs.EventTarget {
audio: this.audioSegmentLoader_.getCurrentMediaInfo_() || {}
};
+ const playlist = this.mainSegmentLoader_.getPendingSegmentPlaylist() || this.media();
+
// set "main" media equal to video
media.video = media.main;
- const playlistCodecs = codecsForPlaylist(this.main(), this.media());
+ const playlistCodecs = codecsForPlaylist(this.main(), playlist);
const codecs = {};
const usingAudioLoader = !!this.mediaTypes_.AUDIO.activePlaylistLoader;
@@ -1738,7 +1721,7 @@ export class PlaylistController extends videojs.EventTarget {
// no codecs, no playback.
if (!codecs.audio && !codecs.video) {
this.excludePlaylist({
- playlistToExclude: this.media(),
+ playlistToExclude: playlist,
error: { message: 'Could not determine codecs for playlist.' },
playlistExclusionDuration: Infinity
});
@@ -1763,13 +1746,13 @@ export class PlaylistController extends videojs.EventTarget {
}
});
- if (usingAudioLoader && unsupportedAudio && this.media().attributes.AUDIO) {
- const audioGroup = this.media().attributes.AUDIO;
+ if (usingAudioLoader && unsupportedAudio && playlist.attributes.AUDIO) {
+ const audioGroup = playlist.attributes.AUDIO;
this.main().playlists.forEach(variant => {
const variantAudioGroup = variant.attributes && variant.attributes.AUDIO;
- if (variantAudioGroup === audioGroup && variant !== this.media()) {
+ if (variantAudioGroup === audioGroup && variant !== playlist) {
variant.excludeUntil = Infinity;
}
});
@@ -1790,7 +1773,7 @@ export class PlaylistController extends videojs.EventTarget {
}, '') + '.';
this.excludePlaylist({
- playlistToExclude: this.media(),
+ playlistToExclude: playlist,
error: {
internal: true,
message
@@ -1817,7 +1800,7 @@ export class PlaylistController extends videojs.EventTarget {
if (switchMessages.length) {
this.excludePlaylist({
- playlistToExclude: this.media(),
+ playlistToExclude: playlist,
error: {
message: `Codec switching not supported: ${switchMessages.join(', ')}.`,
internal: true
diff --git a/src/segment-loader.js b/src/segment-loader.js
index 3b26a2f04..5428a8347 100644
--- a/src/segment-loader.js
+++ b/src/segment-loader.js
@@ -576,7 +576,7 @@ export default class SegmentLoader extends videojs.EventTarget {
// TODO possibly move gopBuffer and timeMapping info to a separate controller
this.gopBuffer_ = [];
this.timeMapping_ = 0;
- this.safeAppend_ = videojs.browser.IE_VERSION >= 11;
+ this.safeAppend_ = false;
this.appendInitSegment_ = {
audio: true,
video: true
@@ -1163,6 +1163,7 @@ export default class SegmentLoader extends videojs.EventTarget {
*/
resetEverything(done) {
this.ended_ = false;
+ this.activeInitSegmentId_ = null;
this.appendInitSegment_ = {
audio: true,
video: true
@@ -1983,6 +1984,10 @@ export default class SegmentLoader extends videojs.EventTarget {
return this.getCurrentMediaInfo_(segmentInfo) || this.startingMediaInfo_;
}
+ getPendingSegmentPlaylist() {
+ return this.pendingSegment_ ? this.pendingSegment_.playlist : null;
+ }
+
hasEnoughInfoToAppend_() {
if (!this.sourceUpdater_.ready()) {
return false;
diff --git a/src/source-updater.js b/src/source-updater.js
index 5b4f541b7..a7f3f11da 100644
--- a/src/source-updater.js
+++ b/src/source-updater.js
@@ -468,11 +468,9 @@ export default class SourceUpdater extends videojs.EventTarget {
* if removeSourceBuffer can be called.
*/
canRemoveSourceBuffer() {
- // IE reports that it supports removeSourceBuffer, but often throws
- // errors when attempting to use the function. So we report that it
- // does not support removeSourceBuffer. As of Firefox 83 removeSourceBuffer
- // throws errors, so we report that it does not support this as well.
- return !videojs.browser.IE_VERSION && !videojs.browser.IS_FIREFOX && window.MediaSource &&
+ // As of Firefox 83 removeSourceBuffer
+ // throws errors, so we report that it does not support this.
+ return !videojs.browser.IS_FIREFOX && window.MediaSource &&
window.MediaSource.prototype &&
typeof window.MediaSource.prototype.removeSourceBuffer === 'function';
}
diff --git a/src/transmuxer-worker.js b/src/transmuxer-worker.js
index d8f9e7e3f..049e221ba 100644
--- a/src/transmuxer-worker.js
+++ b/src/transmuxer-worker.js
@@ -227,6 +227,24 @@ class MessageHandlers {
}, [data.buffer]);
}
+ /**
+ * Probes an mp4 segment for EMSG boxes containing ID3 data.
+ * https://aomediacodec.github.io/id3-emsg/
+ *
+ * @param {Uint8Array} data segment data
+ * @param {number} offset segment start time
+ * @return {Object[]} an array of ID3 frames
+ */
+ probeEmsgID3({data, offset}) {
+ const id3Frames = mp4probe.getEmsgID3(data, offset);
+
+ this.self.postMessage({
+ action: 'probeEmsgID3',
+ id3Frames,
+ emsgData: data
+ }, [data.buffer]);
+ }
+
/**
* Probe an mpeg2-ts segment to determine the start time of the segment in it's
* internal "media time," as well as whether it contains video and/or audio.
diff --git a/src/util/text-tracks.js b/src/util/text-tracks.js
index 1f9562b25..699c26d1c 100644
--- a/src/util/text-tracks.js
+++ b/src/util/text-tracks.js
@@ -159,6 +159,11 @@ export const addMetadata = ({
return;
}
+ // If we have no frames, we can't create a cue.
+ if (!metadata.frames || !metadata.frames.length) {
+ return;
+ }
+
metadata.frames.forEach((frame) => {
const cue = new Cue(
time,
@@ -285,26 +290,16 @@ export const removeDuplicateCuesFromTrack = function(track) {
return;
}
- for (let i = 0; i < cues.length; i++) {
- const duplicates = [];
- let occurrences = 0;
-
- for (let j = 0; j < cues.length; j++) {
- if (
- cues[i].startTime === cues[j].startTime &&
- cues[i].endTime === cues[j].endTime &&
- cues[i].text === cues[j].text
- ) {
- occurrences++;
-
- if (occurrences > 1) {
- duplicates.push(cues[j]);
- }
- }
- }
+ const uniqueCues = {};
+
+ for (let i = cues.length - 1; i >= 0; i--) {
+ const cue = cues[i];
+ const cueKey = `${cue.startTime}-${cue.endTime}-${cue.text}`;
- if (duplicates.length) {
- duplicates.forEach(dupe => track.removeCue(dupe));
+ if (uniqueCues[cueKey]) {
+ track.removeCue(cue);
+ } else {
+ uniqueCues[cueKey] = cue;
}
}
};
diff --git a/src/videojs-http-streaming.js b/src/videojs-http-streaming.js
index 1869a9b0b..e7833d285 100644
--- a/src/videojs-http-streaming.js
+++ b/src/videojs-http-streaming.js
@@ -287,8 +287,8 @@ export const waitForKeySessionCreation = ({
const keySessionCreatedPromises = [];
// Since PSSH values are interpreted as initData, EME will dedupe any duplicates. The
- // only place where it should not be deduped is for ms-prefixed APIs, but the early
- // return for IE11 above, and the existence of modern EME APIs in addition to
+ // only place where it should not be deduped is for ms-prefixed APIs, but
+ // the existence of modern EME APIs in addition to
// ms-prefixed APIs on Edge should prevent this from being a concern.
// initializeMediaKeys also won't use the webkit-prefixed APIs.
keySystemsOptionsArr.forEach((keySystemsOptions) => {
@@ -1060,9 +1060,7 @@ class VhsHandler extends Component {
this.handleWaitingForKey_ = this.handleWaitingForKey_.bind(this);
this.player_.tech_.on('waitingforkey', this.handleWaitingForKey_);
- // In IE11 this is too early to initialize media keys, and IE11 does not support
- // promises.
- if (videojs.browser.IE_VERSION === 11 || !didSetupEmeOptions) {
+ if (!didSetupEmeOptions) {
// If EME options were not set up, we've done all we could to initialize EME.
this.playlistController_.sourceUpdater_.initializedEme();
return;
diff --git a/test/loader-common.js b/test/loader-common.js
index 6681c6094..0016b114d 100644
--- a/test/loader-common.js
+++ b/test/loader-common.js
@@ -1,5 +1,4 @@
import QUnit from 'qunit';
-import videojs from 'video.js';
import xhrFactory from '../src/xhr';
import Config from '../src/config';
import document from 'global/document';
@@ -941,16 +940,7 @@ export const LoaderCommonFactory = ({
// only main/fmp4 segment loaders use async appends and parts/partIndex
if (usesAsyncAppends) {
- let testFn = 'test';
-
- if (videojs.browser.IE_VERSION) {
- testFn = 'skip';
- }
-
- // this test has a race condition on ie 11 that causes it to fail some of the time.
- // Since IE 11 isn't really a priority and it only fails some of the time we decided to
- // skip this on IE 11.
- QUnit[testFn]('playlist change before any appends does not error', function(assert) {
+ QUnit.test('playlist change before any appends does not error', function(assert) {
return this.setupMediaSource(loader.mediaSource_, loader.sourceUpdater_).then(() => {
loader.playlist(playlistWithDuration(50, {
uri: 'bar-720.m3u8',
diff --git a/test/media-segment-request.test.js b/test/media-segment-request.test.js
index 4ca5c1a81..bfb89843e 100644
--- a/test/media-segment-request.test.js
+++ b/test/media-segment-request.test.js
@@ -15,6 +15,8 @@ import {
ac3WithoutId3 as ac3WithoutId3Segment,
video as videoSegment,
audio as audioSegment,
+ mp4Audio,
+ mp4AudioInit,
mp4Video,
mp4VideoInit,
muxed as muxedSegment,
@@ -1357,6 +1359,17 @@ QUnit.test('non-TS segment will get parsed for captions', function(assert) {
}
});
}
+
+ if (event.action === 'probeEmsgID3') {
+ transmuxer.trigger({
+ type: 'message',
+ data: {
+ action: 'probeEmsgID3',
+ emsgData: event.data,
+ id3Frames: []
+ }
+ });
+ }
};
mediaSegmentRequest({
@@ -1498,6 +1511,17 @@ QUnit.test('non-TS segment will get parsed for captions on next segment request
}
});
}
+
+ if (event.action === 'probeEmsgID3') {
+ transmuxer.trigger({
+ type: 'message',
+ data: {
+ action: 'probeEmsgID3',
+ emsgData: event.data,
+ id3Frames: []
+ }
+ });
+ }
};
mediaSegmentRequest({
@@ -1553,3 +1577,263 @@ QUnit.test('non-TS segment will get parsed for captions on next segment request
// Simulate receiving the init segment after the media
this.standardXHRResponse(initReq, mp4VideoInit());
});
+
+QUnit.test('can get emsg ID3 frames from fmp4 video segment', function(assert) {
+ const done = assert.async();
+ let gotEmsgId3 = 0;
+ let gotData = 0;
+ // expected frame data
+ const id3Frames = [{
+ cueTime: 1,
+ duration: 0,
+ frames: [{
+ id: 'TXXX',
+ description: 'foo bar',
+ data: { key: 'value' }
+ },
+ {
+ id: 'PRIV',
+ owner: 'priv-owner@foo.bar',
+ // 'foo'
+ data: new Uint8Array([0x66, 0x6F, 0x6F])
+ }]
+ },
+ {
+ cueTime: 3,
+ duration: 0,
+ frames: [{
+ id: 'PRIV',
+ owner: 'priv-owner@foo.bar',
+ // 'bar'
+ data: new Uint8Array([0x62, 0x61, 0x72])
+ },
+ {
+ id: 'TXXX',
+ description: 'bar foo',
+ data: { key: 'value' }
+ }]
+ }];
+ const transmuxer = new videojs.EventTarget();
+
+ transmuxer.postMessage = (event) => {
+ if (event.action === 'pushMp4Captions') {
+ transmuxer.trigger({
+ type: 'message',
+ data: {
+ action: 'mp4Captions',
+ data: event.data,
+ captions: 'foo bar',
+ logs: []
+ }
+ });
+ }
+
+ if (event.action === 'probeMp4StartTime') {
+ transmuxer.trigger({
+ type: 'message',
+ data: {
+ action: 'probeMp4StartTime',
+ data: event.data,
+ timingInfo: {}
+ }
+ });
+ }
+
+ if (event.action === 'probeMp4Tracks') {
+ transmuxer.trigger({
+ type: 'message',
+ data: {
+ action: 'probeMp4Tracks',
+ data: event.data,
+ tracks: [{type: 'video', codec: 'avc1.4d400d'}]
+ }
+ });
+ }
+
+ if (event.action === 'probeEmsgID3') {
+ transmuxer.trigger({
+ type: 'message',
+ data: {
+ action: 'probeEmsgID3',
+ emsgData: event.data,
+ id3Frames
+ }
+ });
+ }
+ };
+
+ mediaSegmentRequest({
+ xhr: this.xhr,
+ xhrOptions: this.xhrOptions,
+ decryptionWorker: this.mockDecrypter,
+ segment: {
+ transmuxer,
+ resolvedUri: 'mp4Video.mp4',
+ map: {
+ resolvedUri: 'mp4VideoInit.mp4'
+ }
+ },
+ progressFn: this.noop,
+ trackInfoFn: this.noop,
+ timingInfoFn: this.noop,
+ id3Fn: (segment, _id3Frames) => {
+ gotEmsgId3++;
+ assert.deepEqual(_id3Frames, id3Frames, 'got expected emsg id3 data.');
+ },
+ captionsFn: this.noop,
+ dataFn: (segment, segmentData) => {
+ gotData++;
+ assert.ok(segmentData, 'init segment bytes in map');
+ assert.ok(segment.map.tracks, 'added tracks');
+ assert.ok(segment.map.tracks.video, 'added video track');
+ },
+ doneFn: () => {
+ assert.equal(gotEmsgId3, 1, 'received emsg ID3 event');
+ assert.equal(gotData, 1, 'received data event');
+ transmuxer.off();
+ done();
+ }
+ });
+ assert.equal(this.requests.length, 2, 'there are two requests');
+
+ const initReq = this.requests.shift();
+ const segmentReq = this.requests.shift();
+
+ assert.equal(initReq.uri, 'mp4VideoInit.mp4', 'the first request is for the init segment');
+ assert.equal(segmentReq.uri, 'mp4Video.mp4', 'the second request is for a segment');
+
+ // Simulate receiving the media first
+ this.standardXHRResponse(segmentReq, mp4Video());
+ // Simulate receiving the init segment after the media
+ this.standardXHRResponse(initReq, mp4VideoInit());
+});
+
+QUnit.test('can get emsg ID3 frames from fmp4 audio segment', function(assert) {
+ const done = assert.async();
+ let gotEmsgId3 = 0;
+ let gotData = 0;
+ // expected frame data
+ const id3Frames = [{
+ cueTime: 1,
+ duration: 0,
+ frames: [{
+ id: 'TXXX',
+ description: 'foo bar',
+ data: { key: 'value' }
+ },
+ {
+ id: 'PRIV',
+ owner: 'priv-owner@foo.bar',
+ // 'foo'
+ data: new Uint8Array([0x66, 0x6F, 0x6F])
+ }]
+ },
+ {
+ cueTime: 3,
+ duration: 0,
+ frames: [{
+ id: 'PRIV',
+ owner: 'priv-owner@foo.bar',
+ // 'bar'
+ data: new Uint8Array([0x62, 0x61, 0x72])
+ },
+ {
+ id: 'TXXX',
+ description: 'bar foo',
+ data: { key: 'value' }
+ }]
+ }];
+ const transmuxer = new videojs.EventTarget();
+
+ transmuxer.postMessage = (event) => {
+ if (event.action === 'pushMp4Captions') {
+ transmuxer.trigger({
+ type: 'message',
+ data: {
+ action: 'mp4Captions',
+ data: event.data,
+ captions: 'foo bar',
+ logs: []
+ }
+ });
+ }
+
+ if (event.action === 'probeMp4StartTime') {
+ transmuxer.trigger({
+ type: 'message',
+ data: {
+ action: 'probeMp4StartTime',
+ data: event.data,
+ timingInfo: {}
+ }
+ });
+ }
+
+ if (event.action === 'probeMp4Tracks') {
+ transmuxer.trigger({
+ type: 'message',
+ data: {
+ action: 'probeMp4Tracks',
+ data: event.data,
+ tracks: [{type: 'audio', codec: 'mp4a.40.2'}]
+ }
+ });
+ }
+
+ if (event.action === 'probeEmsgID3') {
+ transmuxer.trigger({
+ type: 'message',
+ data: {
+ action: 'probeEmsgID3',
+ emsgData: event.data,
+ id3Frames
+ }
+ });
+ }
+ };
+
+ mediaSegmentRequest({
+ xhr: this.xhr,
+ xhrOptions: this.xhrOptions,
+ decryptionWorker: this.mockDecrypter,
+ segment: {
+ transmuxer,
+ resolvedUri: 'mp4Audio.mp4',
+ map: {
+ resolvedUri: 'mp4AudioInit.mp4'
+ }
+ },
+ progressFn: this.noop,
+ trackInfoFn: this.noop,
+ timingInfoFn: this.noop,
+ id3Fn: (segment, _id3Frames) => {
+ gotEmsgId3++;
+ assert.deepEqual(_id3Frames, id3Frames, 'got expected emsg id3 data.');
+ },
+ captionsFn: this.noop,
+ dataFn: (segment, segmentData) => {
+ gotData++;
+ assert.ok(segmentData, 'init segment bytes in map');
+ assert.ok(segment.map.tracks, 'added tracks');
+ assert.ok(segment.map.tracks.audio, 'added audio track');
+ },
+ doneFn: () => {
+ assert.equal(gotEmsgId3, 1, 'received emsg ID3 event');
+ assert.equal(gotData, 1, 'received data event');
+ transmuxer.off();
+ done();
+ }
+ });
+ assert.equal(this.requests.length, 2, 'there are two requests');
+
+ const initReq = this.requests.shift();
+ const segmentReq = this.requests.shift();
+
+ assert.equal(initReq.uri, 'mp4AudioInit.mp4', 'the first request is for the init segment');
+ assert.equal(segmentReq.uri, 'mp4Audio.mp4', 'the second request is for a segment');
+
+ // Simulate receiving the media first
+ this.standardXHRResponse(segmentReq, mp4Audio());
+ // Simulate receiving the init segment after the media
+ this.standardXHRResponse(initReq, mp4AudioInit());
+});
diff --git a/test/playback.test.js b/test/playback.test.js
index 25d658278..07a7215eb 100644
--- a/test/playback.test.js
+++ b/test/playback.test.js
@@ -34,13 +34,6 @@ const playFor = function(player, time, cb) {
checkPlayerTime();
};
-let testFn = 'test';
-
-// TODO: get these tests working, right now we just one the one basic test
-if (videojs.browser.IE_VERSION || videojs.browser.IS_EDGE) {
- testFn = 'skip';
-}
-
QUnit.module('Playback', {
beforeEach(assert) {
assert.timeout(50000);
@@ -117,7 +110,7 @@ QUnit.test('Advanced Bip Bop', function(assert) {
});
});
-QUnit[testFn]('replay', function(assert) {
+QUnit.test('replay', function(assert) {
const done = assert.async();
assert.expect(2);
@@ -145,7 +138,7 @@ QUnit[testFn]('replay', function(assert) {
});
});
-QUnit[testFn]('playlist with fmp4 segments', function(assert) {
+QUnit.test('playlist with fmp4 segments', function(assert) {
const done = assert.async();
assert.expect(2);
@@ -164,7 +157,7 @@ QUnit[testFn]('playlist with fmp4 segments', function(assert) {
});
});
-QUnit[testFn]('playlist with fmp4 and ts segments', function(assert) {
+QUnit.test('playlist with fmp4 and ts segments', function(assert) {
const done = assert.async();
assert.expect(2);
@@ -183,7 +176,7 @@ QUnit[testFn]('playlist with fmp4 and ts segments', function(assert) {
});
});
-QUnit[testFn]('Advanced Bip Bop preload=none', function(assert) {
+QUnit.test('Advanced Bip Bop preload=none', function(assert) {
const done = assert.async();
assert.expect(2);
@@ -204,7 +197,7 @@ QUnit[testFn]('Advanced Bip Bop preload=none', function(assert) {
});
});
-QUnit[testFn]('Big Buck Bunny', function(assert) {
+QUnit.test('Big Buck Bunny', function(assert) {
const done = assert.async();
assert.expect(2);
@@ -223,7 +216,7 @@ QUnit[testFn]('Big Buck Bunny', function(assert) {
});
});
-QUnit[testFn]('Live DASH', function(assert) {
+QUnit.test('Live DASH', function(assert) {
const done = assert.async();
const player = this.player;
@@ -257,7 +250,7 @@ QUnit[testFn]('Live DASH', function(assert) {
player.play();
});
-QUnit[testFn]('Multiperiod dash works and can end', function(assert) {
+QUnit.test('Multiperiod dash works and can end', function(assert) {
const done = assert.async();
assert.expect(2);
@@ -287,7 +280,7 @@ QUnit[testFn]('Multiperiod dash works and can end', function(assert) {
// firefox has lower performance or more aggressive throttling than chrome
// which causes a variety of issues.
if (!videojs.browser.IS_FIREFOX) {
- QUnit[testFn]('Big Buck Bunny audio only, groups & renditions same uri', function(assert) {
+ QUnit.test('Big Buck Bunny audio only, groups & renditions same uri', function(assert) {
const done = assert.async();
assert.expect(2);
@@ -306,7 +299,7 @@ if (!videojs.browser.IS_FIREFOX) {
});
});
- QUnit[testFn]('Big Buck Bunny Demuxed av, audio only rendition same as group', function(assert) {
+ QUnit.test('Big Buck Bunny Demuxed av, audio only rendition same as group', function(assert) {
const done = assert.async();
assert.expect(2);
@@ -325,7 +318,7 @@ if (!videojs.browser.IS_FIREFOX) {
});
});
- QUnit[testFn]('DASH sidx', function(assert) {
+ QUnit.test('DASH sidx', function(assert) {
const done = assert.async();
const player = this.player;
@@ -349,7 +342,7 @@ if (!videojs.browser.IS_FIREFOX) {
});
});
- QUnit[testFn]('DASH sidx with alt audio should end', function(assert) {
+ QUnit.test('DASH sidx with alt audio should end', function(assert) {
const done = assert.async();
const player = this.player;
@@ -376,7 +369,7 @@ if (!videojs.browser.IS_FIREFOX) {
});
});
- QUnit[testFn]('DRM Dash', function(assert) {
+ QUnit.test('DRM Dash', function(assert) {
const done = assert.async();
const player = this.player;
@@ -419,7 +412,7 @@ if (!videojs.browser.IS_FIREFOX) {
// TODO: why does this make the next test
// throw an "The operation was aborted." on firefox
- QUnit[testFn]('loops', function(assert) {
+ QUnit.test('loops', function(assert) {
const done = assert.async();
const player = this.player;
@@ -444,7 +437,7 @@ if (!videojs.browser.IS_FIREFOX) {
});
}
-QUnit[testFn]('zero-length id3 segment', function(assert) {
+QUnit.test('zero-length id3 segment', function(assert) {
const done = assert.async();
const player = this.player;
@@ -465,7 +458,7 @@ QUnit[testFn]('zero-length id3 segment', function(assert) {
const hlsDataUri = 'data:application/x-mpegurl;charset=utf-8,%23EXTM3U%0D%0A%0D%0A%23EXT-X-MEDIA%3ATYPE%3DAUDIO%2CGROUP-ID%3D%22bipbop_audio%22%2CLANGUAGE%3D%22eng%22%2CNAME%3D%22BipBop%20Audio%201%22%2CAUTOSELECT%3DYES%2CDEFAULT%3DYES%0D%0A%23EXT-X-MEDIA%3ATYPE%3DAUDIO%2CGROUP-ID%3D%22bipbop_audio%22%2CLANGUAGE%3D%22eng%22%2CNAME%3D%22BipBop%20Audio%202%22%2CAUTOSELECT%3DNO%2CDEFAULT%3DNO%2CURI%3D%22https%3A%2F%2Fd2zihajmogu5jn.cloudfront.net%2Fbipbop-advanced%2Falternate_audio_aac_sinewave%2Fprog_index.m3u8%22%0D%0A%0D%0A%0D%0A%23EXT-X-MEDIA%3ATYPE%3DSUBTITLES%2CGROUP-ID%3D%22subs%22%2CNAME%3D%22English%22%2CDEFAULT%3DYES%2CAUTOSELECT%3DYES%2CFORCED%3DNO%2CLANGUAGE%3D%22en%22%2CCHARACTERISTICS%3D%22public.accessibility.transcribes-spoken-dialog%2C%20public.accessibility.describes-music-and-sound%22%2CURI%3D%22https%3A%2F%2Fd2zihajmogu5jn.cloudfront.net%2Fbipbop-advanced%2Fsubtitles%2Feng%2Fprog_index.m3u8%22%0D%0A%23EXT-X-MEDIA%3ATYPE%3DSUBTITLES%2CGROUP-ID%3D%22subs%22%2CNAME%3D%22English%20%28Forced%29%22%2CDEFAULT%3DNO%2CAUTOSELECT%3DNO%2CFORCED%3DYES%2CLANGUAGE%3D%22en%22%2CURI%3D%22https%3A%2F%2Fd2zihajmogu5jn.cloudfront.net%2Fbipbop-advanced%2Fsubtitles%2Feng_forced%2Fprog_index.m3u8%22%0D%0A%23EXT-X-MEDIA%3ATYPE%3DSUBTITLES%2CGROUP-ID%3D%22subs%22%2CNAME%3D%22Fran%C3%83%C2%A7ais%22%2CDEFAULT%3DNO%2CAUTOSELECT%3DYES%2CFORCED%3DNO%2CLANGUAGE%3D%22fr%22%2CCHARACTERISTICS%3D%22public.accessibility.transcribes-spoken-dialog%2C%20public.accessibility.describes-music-and-sound%22%2CURI%3D%22https%3A%2F%2Fd2zihajmogu5jn.cloudfront.net%2Fbipbop-advanced%2Fsubtitles%2Ffra%2Fprog_index.m3u8%22%0D%0A%23EXT-X-MEDIA%3ATYPE%3DSUBTITLES%2CGROUP-ID%3D%22subs%22%2CNAME%3D%22Fran%C3%83%C2%A7ais%20%28Forced%29%22%2CDEFAULT%3DNO%2CAUTOSELECT%3DNO%2CFORCED%3DYES%2CLANGUAGE%3D%22fr%22%2CURI%3D%22https%3A%2F%2Fd2zihajmogu5jn.cloudfront.net%2Fbipbop-advanced%2Fsubtitles%2Ffra_forced%2Fprog_index.m3u8%22%0D%0A%23EXT-X-MEDIA%3ATYPE%3DSUBTITLES%2CGROUP-ID%3D%22subs%22%2CNAME%3D%22Espa%C3%83%C2%B1ol%22%2CDEFAULT%3DNO%2CAUTOSELECT%3DYES%2CFORCED%3DNO%2CLANGUAGE%3D%22es%22%2CCHARACTERISTICS%3D%22public.accessibility.transcribes-spoken-dialog%2C%20public.accessibility.describes-music-and-sound%22%2CURI%3D%22https%3A%2F%2Fd2zihajmogu5jn.cloudfront.net%2Fbipbop-advanced%2Fsubtitles%2Fspa%2Fprog_index.m3u8%22%0D%0A%23EXT-X-MEDIA%3ATYPE%3DSUBTITLES%2CGROUP-ID%3D%22subs%22%2CNAME%3D%22Espa%C3%83%C2%B1ol%20%28Forced%29%22%2CDEFAULT%3DNO%2CAUTOSELECT%3DNO%2CFORCED%3DYES%2CLANGUAGE%3D%22es%22%2CURI%3D%22https%3A%2F%2Fd2zihajmogu5jn.cloudfront.net%2Fbipbop-advanced%2Fsubtitles%2Fspa_forced%2Fprog_index.m3u8%22%0D%0A%23EXT-X-MEDIA%3ATYPE%3DSUBTITLES%2CGROUP-ID%3D%22subs%22%2CNAME%3D%22%C3%A6%C2%97%C2%A5%C3%A6%C2%9C%C2%AC%C3%A8%C2%AA%C2%9E%22%2CDEFAULT%3DNO%2CAUTOSELECT%3DYES%2CFORCED%3DNO%2CLANGUAGE%3D%22ja%22%2CCHARACTERISTICS%3D%22public.accessibility.transcribes-spoken-dialog%2C%20public.accessibility.describes-music-and-sound%22%2CURI%3D%22https%3A%2F%2Fd2zihajmogu5jn.cloudfront.net%2Fbipbop-advanced%2Fsubtitles%2Fjpn%2Fprog_index.m3u8%22%0D%0A%23EXT-X-MEDIA%3ATYPE%3DSUBTITLES%2CGROUP-ID%3D%22subs%22%2CNAME%3D%22%C3%A6%C2%97%C2%A5%C3%A6%C2%9C%C2%AC%C3%A8%C2%AA%C2%9E%20%28Forced%29%22%2CDEFAULT%3DNO%2CAUTOSELECT%3DNO%2CFORCED%3DYES%2CLANGUAGE%3D%22ja%22%2CURI%3D%22https%3A%2F%2Fd2zihajmogu5jn.cloudfront.net%2Fbipbop-advanced%2Fsubtitles%2Fjpn_forced%2Fprog_index.m3u8%22%0D%0A%0D%0A%0D%0A%23EXT-X-STREAM-INF%3ABANDWIDTH%3D263851%2CCODECS%3D%22mp4a.40.2%2C%20avc1.4d400d%22%2CRESOLUTION%3D416x234%2CAUDIO%3D%22bipbop_audio%22%2CSUBTITLES%3D%22subs%22%0D%0Ahttps%3A%2F%2Fd2zihajmogu5jn.cloudfront.net%2Fbipbop-advanced%2Fgear1%2Fprog_index.m3u8%0D%0A%0D%0A%23EXT-X-STREAM-INF%3ABANDWIDTH%3D577610%2CCODECS%3D%22mp4a.40.2%2C%20avc1.4d401e%22%2CRESOLUTION%3D640x360%2CAUDIO%3D%22bipbop_audio%22%2CSUBTITLES%3D%22subs%22%0D%0Ahttps%3A%2F%2Fd2zihajmogu5jn.cloudfront.net%2Fbipbop-advanced%2Fgear2%2Fprog_index.m3u8%0D%0A%0D%0A%23EXT-X-STREAM-INF%3ABANDWIDTH%3D915905%2CCODECS%3D%22mp4a.40.2%2C%20avc1.4d401f%22%2CRESOLUTION%3D960x540%2CAUDIO%3D%22bipbop_audio%22%2CSUBTITLES%3D%22subs%22%0D%0Ahttps%3A%2F%2Fd2zihajmogu5jn.cloudfront.net%2Fbipbop-advanced%2Fgear3%2Fprog_index.m3u8%0D%0A%0D%0A%23EXT-X-STREAM-INF%3ABANDWIDTH%3D1030138%2CCODECS%3D%22mp4a.40.2%2C%20avc1.4d401f%22%2CRESOLUTION%3D1280x720%2CAUDIO%3D%22bipbop_audio%22%2CSUBTITLES%3D%22subs%22%0D%0Ahttps%3A%2F%2Fd2zihajmogu5jn.cloudfront.net%2Fbipbop-advanced%2Fgear4%2Fprog_index.m3u8%0D%0A%0D%0A%23EXT-X-STREAM-INF%3ABANDWIDTH%3D1924009%2CCODECS%3D%22mp4a.40.2%2C%20avc1.4d401f%22%2CRESOLUTION%3D1920x1080%2CAUDIO%3D%22bipbop_audio%22%2CSUBTITLES%3D%22subs%22%0D%0Ahttps%3A%2F%2Fd2zihajmogu5jn.cloudfront.net%2Fbipbop-advanced%2Fgear5%2Fprog_index.m3u8%0D%0A%0D%0A%23EXT-X-STREAM-INF%3ABANDWIDTH%3D41457%2CCODECS%3D%22mp4a.40.2%22%2CAUDIO%3D%22bipbop_audio%22%2CSUBTITLES%3D%22subs%22%0D%0Ahttps%3A%2F%2Fd2zihajmogu5jn.cloudfront.net%2Fbipbop-advanced%2Fgear0%2Fprog_index.m3u8';
-QUnit[testFn]('hls data uri', function(assert) {
+QUnit.test('hls data uri', function(assert) {
const done = assert.async();
const player = this.player;
@@ -488,7 +481,7 @@ QUnit[testFn]('hls data uri', function(assert) {
const dashDataUri = 'data:application/dash+xml;charset=utf-8,%3CMPD%20mediaPresentationDuration=%22PT634.566S%22%20minBufferTime=%22PT2.00S%22%20profiles=%22urn:hbbtv:dash:profile:isoff-live:2012,urn:mpeg:dash:profile:isoff-live:2011%22%20type=%22static%22%20xmlns=%22urn:mpeg:dash:schema:mpd:2011%22%20xmlns:xsi=%22http://www.w3.org/2001/XMLSchema-instance%22%20xsi:schemaLocation=%22urn:mpeg:DASH:schema:MPD:2011%20DASH-MPD.xsd%22%3E%20%3CBaseURL%3Ehttps://dash.akamaized.net/akamai/bbb_30fps/%3C/BaseURL%3E%20%3CPeriod%3E%20%20%3CAdaptationSet%20mimeType=%22video/mp4%22%20contentType=%22video%22%20subsegmentAlignment=%22true%22%20subsegmentStartsWithSAP=%221%22%20par=%2216:9%22%3E%20%20%20%3CSegmentTemplate%20duration=%22120%22%20timescale=%2230%22%20media=%22$RepresentationID$/$RepresentationID$_$Number$.m4v%22%20startNumber=%221%22%20initialization=%22$RepresentationID$/$RepresentationID$_0.m4v%22/%3E%20%20%20%3CRepresentation%20id=%22bbb_30fps_1024x576_2500k%22%20codecs=%22avc1.64001f%22%20bandwidth=%223134488%22%20width=%221024%22%20height=%22576%22%20frameRate=%2230%22%20sar=%221:1%22%20scanType=%22progressive%22/%3E%20%20%20%3CRepresentation%20id=%22bbb_30fps_1280x720_4000k%22%20codecs=%22avc1.64001f%22%20bandwidth=%224952892%22%20width=%221280%22%20height=%22720%22%20frameRate=%2230%22%20sar=%221:1%22%20scanType=%22progressive%22/%3E%20%20%20%3CRepresentation%20id=%22bbb_30fps_1920x1080_8000k%22%20codecs=%22avc1.640028%22%20bandwidth=%229914554%22%20width=%221920%22%20height=%221080%22%20frameRate=%2230%22%20sar=%221:1%22%20scanType=%22progressive%22/%3E%20%20%20%3CRepresentation%20id=%22bbb_30fps_320x180_200k%22%20codecs=%22avc1.64000d%22%20bandwidth=%22254320%22%20width=%22320%22%20height=%22180%22%20frameRate=%2230%22%20sar=%221:1%22%20scanType=%22progressive%22/%3E%20%20%20%3CRepresentation%20id=%22bbb_30fps_320x180_400k%22%20codecs=%22avc1.64000d%22%20bandwidth=%22507246%22%20width=%22320%22%20height=%22180%22%20frameRate=%2230%22%20sar=%221:1%22%20scanType=%22progressive%22/%3E%20%20%20%3CRepresentation%20id=%22bbb_30fps_480x270_600k%22%20codecs=%22avc1.640015%22%20bandwidth=%22759798%22%20width=%22480%22%20height=%22270%22%20frameRate=%2230%22%20sar=%221:1%22%20scanType=%22progressive%22/%3E%20%20%20%3CRepresentation%20id=%22bbb_30fps_640x360_1000k%22%20codecs=%22avc1.64001e%22%20bandwidth=%221254758%22%20width=%22640%22%20height=%22360%22%20frameRate=%2230%22%20sar=%221:1%22%20scanType=%22progressive%22/%3E%20%20%20%3CRepresentation%20id=%22bbb_30fps_640x360_800k%22%20codecs=%22avc1.64001e%22%20bandwidth=%221013310%22%20width=%22640%22%20height=%22360%22%20frameRate=%2230%22%20sar=%221:1%22%20scanType=%22progressive%22/%3E%20%20%20%3CRepresentation%20id=%22bbb_30fps_768x432_1500k%22%20codecs=%22avc1.64001e%22%20bandwidth=%221883700%22%20width=%22768%22%20height=%22432%22%20frameRate=%2230%22%20sar=%221:1%22%20scanType=%22progressive%22/%3E%20%20%20%3CRepresentation%20id=%22bbb_30fps_3840x2160_12000k%22%20codecs=%22avc1.640033%22%20bandwidth=%2214931538%22%20width=%223840%22%20height=%222160%22%20frameRate=%2230%22%20sar=%221:1%22%20scanType=%22progressive%22/%3E%20%20%3C/AdaptationSet%3E%20%20%3CAdaptationSet%20mimeType=%22audio/mp4%22%20contentType=%22audio%22%20subsegmentAlignment=%22true%22%20subsegmentStartsWithSAP=%221%22%3E%20%20%20%3CAccessibility%20schemeIdUri=%22urn:tva:metadata:cs:AudioPurposeCS:2007%22%20value=%226%22/%3E%20%20%20%3CRole%20schemeIdUri=%22urn:mpeg:dash:role:2011%22%20value=%22main%22/%3E%20%20%20%3CSegmentTemplate%20duration=%22192512%22%20timescale=%2248000%22%20media=%22$RepresentationID$/$RepresentationID$_$Number$.m4a%22%20startNumber=%221%22%20initialization=%22$RepresentationID$/$RepresentationID$_0.m4a%22/%3E%20%20%20%3CRepresentation%20id=%22bbb_a64k%22%20codecs=%22mp4a.40.5%22%20bandwidth=%2267071%22%20audioSamplingRate=%2248000%22%3E%20%20%20%20%3CAudioChannelConfiguration%20schemeIdUri=%22urn:mpeg:dash:23003:3:audio_channel_configuration:2011%22%20value=%222%22/%3E%20%20%20%3C/Representation%3E%20%20%3C/AdaptationSet%3E%20%3C/Period%3E%3C/MPD%3E';
-QUnit[testFn]('dash data uri', function(assert) {
+QUnit.test('dash data uri', function(assert) {
const done = assert.async();
const player = this.player;
@@ -504,7 +497,7 @@ QUnit[testFn]('dash data uri', function(assert) {
});
});
-QUnit[testFn]('dash manifest object', function(assert) {
+QUnit.test('dash manifest object', function(assert) {
const done = assert.async();
const player = this.player;
@@ -519,7 +512,7 @@ QUnit[testFn]('dash manifest object', function(assert) {
});
});
-QUnit[testFn]('hls manifest object', function(assert) {
+QUnit.test('hls manifest object', function(assert) {
const done = assert.async();
const player = this.player;
diff --git a/test/playlist-controller.test.js b/test/playlist-controller.test.js
index 48e138c5a..b70a0828d 100644
--- a/test/playlist-controller.test.js
+++ b/test/playlist-controller.test.js
@@ -59,10 +59,8 @@ const sharedHooks = {
this.requests = this.env.requests;
this.mse = useFakeMediaSource();
- if (!videojs.browser.IE_VERSION) {
- this.oldDevicePixelRatio = window.devicePixelRatio;
- window.devicePixelRatio = 1;
- }
+ this.oldDevicePixelRatio = window.devicePixelRatio;
+ window.devicePixelRatio = 1;
// force the HLS tech to run
this.origSupportsNativeHls = videojs.Vhs.supportsNativeHls;
@@ -638,7 +636,7 @@ QUnit.test('seeks in place for fast quality switch on non-IE/Edge browsers', fun
seeks++;
});
- let timeBeforeSwitch = this.player.currentTime();
+ const timeBeforeSwitch = this.player.currentTime();
// mock buffered values so removes are processed
segmentLoader.sourceUpdater_.audioBuffer.buffered = createTimeRanges([[0, 10]]);
@@ -650,10 +648,6 @@ QUnit.test('seeks in place for fast quality switch on non-IE/Edge browsers', fun
segmentLoader.sourceUpdater_.videoBuffer.trigger('updateend');
this.clock.tick(1);
- // we seek an additional 0.04s on edge and ie
- if (videojs.browser.IS_EDGE || videojs.browser.IE_VERSION) {
- timeBeforeSwitch += 0.04;
- }
assert.equal(
this.player.currentTime(),
timeBeforeSwitch,
@@ -836,120 +830,6 @@ QUnit.test('demuxed timeToLoadedData, mediaAppends, appendsToLoadedData stats',
});
});
-QUnit.test('seeks forward 0.04 sec for fast quality switch on Edge', function(assert) {
- const oldIEVersion = videojs.browser.IE_VERSION;
- const oldIsEdge = videojs.browser.IS_EDGE;
- let seeks = 0;
-
- this.playlistController.mediaSource.trigger('sourceopen');
- // main
- this.standardXHRResponse(this.requests.shift());
- // media
- this.standardXHRResponse(this.requests.shift());
-
- const segmentLoader = this.playlistController.mainSegmentLoader_;
-
- return requestAndAppendSegment({
- request: this.requests.shift(),
- segmentLoader,
- clock: this.clock
- }).then(() => {
- // media is changed
- this.playlistController.selectPlaylist = () => {
- const playlists = this.playlistController.main().playlists;
- const currentPlaylist = this.playlistController.media();
-
- return playlists.find((playlist) => playlist !== currentPlaylist);
- };
-
- this.player.tech_.on('seeking', function() {
- seeks++;
- });
-
- const timeBeforeSwitch = this.player.currentTime();
-
- videojs.browser.IE_VERSION = null;
- videojs.browser.IS_EDGE = true;
-
- // mock buffered values so removes are processed
- segmentLoader.sourceUpdater_.audioBuffer.buffered = createTimeRanges([[0, 10]]);
- segmentLoader.sourceUpdater_.videoBuffer.buffered = createTimeRanges([[0, 10]]);
-
- this.playlistController.fastQualityChange_();
- // trigger updateend to indicate the end of the remove operation
- segmentLoader.sourceUpdater_.audioBuffer.trigger('updateend');
- segmentLoader.sourceUpdater_.videoBuffer.trigger('updateend');
- this.clock.tick(1);
-
- assert.equal(
- this.player.currentTime(),
- timeBeforeSwitch + 0.04,
- 'seeks forward on fast quality switch'
- );
- assert.equal(seeks, 1, 'seek event occurs on fast quality switch');
-
- videojs.browser.IE_VERSION = oldIEVersion;
- videojs.browser.IS_EDGE = oldIsEdge;
- });
-});
-
-QUnit.test('seeks forward 0.04 sec for fast quality switch on IE', function(assert) {
- const oldIEVersion = videojs.browser.IE_VERSION;
- const oldIsEdge = videojs.browser.IS_EDGE;
- let seeks = 0;
-
- this.playlistController.mediaSource.trigger('sourceopen');
- // main
- this.standardXHRResponse(this.requests.shift());
- // media
- this.standardXHRResponse(this.requests.shift());
-
- const segmentLoader = this.playlistController.mainSegmentLoader_;
-
- return requestAndAppendSegment({
- request: this.requests.shift(),
- segmentLoader,
- clock: this.clock
- }).then(() => {
- // media is changed
- this.playlistController.selectPlaylist = () => {
- const playlists = this.playlistController.main().playlists;
- const currentPlaylist = this.playlistController.media();
-
- return playlists.find((playlist) => playlist !== currentPlaylist);
- };
-
- this.player.tech_.on('seeking', function() {
- seeks++;
- });
-
- const timeBeforeSwitch = this.player.currentTime();
-
- videojs.browser.IE_VERSION = 11;
- videojs.browser.IS_EDGE = false;
-
- // mock buffered values so removes are processed
- segmentLoader.sourceUpdater_.audioBuffer.buffered = createTimeRanges([[0, 10]]);
- segmentLoader.sourceUpdater_.videoBuffer.buffered = createTimeRanges([[0, 10]]);
-
- this.playlistController.fastQualityChange_();
- // trigger updateend to indicate the end of the remove operation
- segmentLoader.sourceUpdater_.audioBuffer.trigger('updateend');
- segmentLoader.sourceUpdater_.videoBuffer.trigger('updateend');
- this.clock.tick(1);
-
- assert.equal(
- this.player.currentTime(),
- timeBeforeSwitch + 0.04,
- 'seeks forward on fast quality switch'
- );
- assert.equal(seeks, 1, 'seek event occurs on fast quality switch');
-
- videojs.browser.IE_VERSION = oldIEVersion;
- videojs.browser.IS_EDGE = oldIsEdge;
- });
-});
-
QUnit.test('audio segment loader is reset on audio track change', function(assert) {
this.requests.length = 0;
this.player.dispose();
@@ -5040,6 +4920,25 @@ QUnit.test('playlist codecs take priority over others', function(assert) {
assert.deepEqual(codecs, {video: 'avc1.4b400d', audio: 'mp4a.40.20'}, 'codecs returned');
});
+QUnit.test('Current pending segment\'s playlist codecs take priority over others', function(assert) {
+ this.contentSetup({
+ mainStartingMedia: {videoCodec: 'avc1.4c400d', hasVideo: true, hasAudio: false},
+ audioStartingMedia: {audioCodec: 'mp4a.40.5', hasVideo: false, hasAudio: true},
+ mainPlaylist: {attributes: {CODECS: 'avc1.4b400d', AUDIO: 'low-quality'}},
+ audioPlaylist: {attributes: {CODECS: 'mp4a.40.20'}}
+ });
+
+ const originalGetPendingSegmentPlaylist = this.pc.mainSegmentLoader_.getPendingSegmentPlaylist.bind(this.pc.mainSegmentLoader_);
+
+ this.pc.mainSegmentLoader_.getPendingSegmentPlaylist = () => ({attributes: {CODECS: 'avc1.64001f', AUDIO: 'low-quality'}});
+
+ const codecs = this.pc.getCodecsOrExclude_();
+
+ assert.deepEqual(this.exclusionList, [], 'did not blacklist anything');
+ assert.deepEqual(codecs, {video: 'avc1.64001f', audio: 'mp4a.40.20'}, 'codecs returned');
+ this.pc.mainSegmentLoader_.getPendingSegmentPlaylist = originalGetPendingSegmentPlaylist;
+});
+
QUnit.test('uses default codecs if no codecs are found', function(assert) {
this.contentSetup({
mainStartingMedia: {hasVideo: true, hasAudio: false},
@@ -5071,6 +4970,27 @@ QUnit.test('excludes playlist without detected audio/video', function(assert) {
assert.deepEqual(codecs, void 0, 'no codecs returned');
});
+QUnit.test('excludes current pending segment\'s playlist without detected audio/video', function(assert) {
+ this.contentSetup({
+ mainStartingMedia: {},
+ audioStartingMedia: {},
+ mainPlaylist: {attributes: {}}
+ });
+
+ const originalGetPendingSegmentPlaylist = this.pc.mainSegmentLoader_.getPendingSegmentPlaylist.bind(this.pc.mainSegmentLoader_);
+
+ this.pc.mainSegmentLoader_.getPendingSegmentPlaylist = () => ({attributes: {CODECS: ''}});
+ const codecs = this.pc.getCodecsOrExclude_();
+
+ assert.deepEqual(this.exclusionList, [{
+ playlistExclusionDuration: Infinity,
+ playlistToExclude: {attributes: {CODECS: ''}},
+ error: { message: 'Could not determine codecs for playlist.' }
+ }], 'excluded playlist');
+ assert.deepEqual(codecs, void 0, 'no codecs returned');
+ this.pc.mainSegmentLoader_.getPendingSegmentPlaylist = originalGetPendingSegmentPlaylist;
+});
+
QUnit.test('excludes unsupported muxer codecs for ts', function(assert) {
this.contentSetup({
mainStartingMedia: {
diff --git a/test/playlist-loader.test.js b/test/playlist-loader.test.js
index 96f67a801..c642db048 100644
--- a/test/playlist-loader.test.js
+++ b/test/playlist-loader.test.js
@@ -1,5 +1,4 @@
import QUnit from 'qunit';
-import videojs from 'video.js';
import {
default as PlaylistLoader,
updateSegments,
@@ -2422,435 +2421,433 @@ QUnit.module('Playlist Loader', function(hooks) {
assert.equal(this.requests.length, 1, 'playlist re-requested');
});
- if (!videojs.browser.IE_VERSION) {
- QUnit.module('llhls', {
- beforeEach() {
- this.fakeVhs.options_ = {llhls: true};
- this.loader = new PlaylistLoader('http://example.com/media.m3u8', this.fakeVhs);
+ QUnit.module('llhls', {
+ beforeEach() {
+ this.fakeVhs.options_ = {llhls: true};
+ this.loader = new PlaylistLoader('http://example.com/media.m3u8', this.fakeVhs);
- this.loader.load();
-
- },
- afterEach() {
- this.loader.dispose();
- }
- });
-
- QUnit.test('#EXT-X-SKIP does not add initial empty segments', function(assert) {
- this.requests.shift().respond(
- 200, null,
- '#EXTM3U\n' +
- '#EXT-X-MEDIA-SEQUENCE:0\n' +
- '#EXT-X-SKIP:SKIPPED-SEGMENTS=10\n' +
- '#EXTINF:2\n' +
- 'low-1.ts\n'
- );
- assert.equal(this.loader.media().segments.length, 1, 'only 1 segment');
- });
-
- QUnit.test('#EXT-X-SKIP merges skipped segments', function(assert) {
- let playlist =
- '#EXTM3U\n' +
- '#EXT-X-MEDIA-SEQUENCE:0\n';
-
- for (let i = 0; i < 10; i++) {
- playlist += '#EXTINF:2\n';
- playlist += `segment-${i}.ts\n`;
- }
-
- this.requests.shift().respond(200, null, playlist);
- assert.equal(this.loader.media().segments.length, 10, '10 segments');
-
- this.loader.trigger('mediaupdatetimeout');
-
- const skippedPlaylist =
- '#EXTM3U\n' +
- '#EXT-X-MEDIA-SEQUENCE:0\n' +
- '#EXT-X-SKIP:SKIPPED-SEGMENTS=10\n' +
- '#EXTINF:2\n' +
- 'segment-10.ts\n';
-
- this.requests.shift().respond(200, null, skippedPlaylist);
-
- assert.equal(this.loader.media().segments.length, 11, '11 segments');
-
- this.loader.media().segments.forEach(function(s, i) {
- if (i < 10) {
- assert.ok(s.hasOwnProperty('skipped'), 'has skipped property');
- assert.false(s.skipped, 'skipped property is false');
- }
-
- assert.equal(s.uri, `segment-${i}.ts`, 'segment uri as expected');
- });
-
- this.loader.trigger('mediaupdatetimeout');
-
- const skippedPlaylist2 =
- '#EXTM3U\n' +
- '#EXT-X-MEDIA-SEQUENCE:1\n' +
- '#EXT-X-SKIP:SKIPPED-SEGMENTS=10\n' +
- '#EXTINF:2\n' +
- 'segment-11.ts\n';
-
- this.requests.shift().respond(200, null, skippedPlaylist2);
+ this.loader.load();
- this.loader.media().segments.forEach(function(s, i) {
- if (i < 10) {
- assert.ok(s.hasOwnProperty('skipped'), 'has skipped property');
- assert.false(s.skipped, 'skipped property is false');
- }
+ },
+ afterEach() {
+ this.loader.dispose();
+ }
+ });
- assert.equal(s.uri, `segment-${i + 1}.ts`, 'segment uri as expected');
- });
- });
+ QUnit.test('#EXT-X-SKIP does not add initial empty segments', function(assert) {
+ this.requests.shift().respond(
+ 200, null,
+ '#EXTM3U\n' +
+ '#EXT-X-MEDIA-SEQUENCE:0\n' +
+ '#EXT-X-SKIP:SKIPPED-SEGMENTS=10\n' +
+ '#EXTINF:2\n' +
+ 'low-1.ts\n'
+ );
+ assert.equal(this.loader.media().segments.length, 1, 'only 1 segment');
+ });
- QUnit.test('#EXT-X-PRELOAD with parts to added to segment list', function(assert) {
- this.requests.shift().respond(
- 200, null,
- '#EXTM3U\n' +
- '#EXT-X-PART-INF:PART-TARGET=1\n' +
- '#EXT-X-MEDIA-SEQUENCE:0\n' +
- '#EXTINF:2\n' +
- 'low-1.ts\n' +
- '#EXT-X-PART:URI="part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="part2.ts",DURATION=1\n'
- );
- const media = this.loader.media();
+ QUnit.test('#EXT-X-SKIP merges skipped segments', function(assert) {
+ let playlist =
+ '#EXTM3U\n' +
+ '#EXT-X-MEDIA-SEQUENCE:0\n';
- assert.equal(media.segments.length, 2, '2 segments');
- assert.deepEqual(
- media.preloadSegment,
- media.segments[media.segments.length - 1],
- 'last segment is preloadSegment'
- );
- });
+ for (let i = 0; i < 10; i++) {
+ playlist += '#EXTINF:2\n';
+ playlist += `segment-${i}.ts\n`;
+ }
- QUnit.test('#EXT-X-PRELOAD without parts not added to segment list', function(assert) {
- this.requests.shift().respond(
- 200, null,
- '#EXTM3U\n' +
- '#EXT-X-PART-INF:PART-TARGET=1\n' +
- '#EXT-X-MEDIA-SEQUENCE:0\n' +
- '#EXTINF:2\n' +
- 'low-1.ts\n' +
- '#EXT-X-PRELOAD-HINT:TYPE="PART",URI="part1.ts"\n'
- );
- const media = this.loader.media();
+ this.requests.shift().respond(200, null, playlist);
+ assert.equal(this.loader.media().segments.length, 10, '10 segments');
- assert.equal(media.segments.length, 1, '1 segment');
- assert.notDeepEqual(
- media.preloadSegment,
- media.segments[media.segments.length - 1],
- 'last segment is not preloadSegment'
- );
- });
+ this.loader.trigger('mediaupdatetimeout');
- QUnit.test('#EXT-X-PART added to segments', function(assert) {
- this.requests.shift().respond(
- 200, null,
- '#EXTM3U\n' +
- '#EXT-X-PART-INF:PART-TARGET=1\n' +
- '#EXT-X-MEDIA-SEQUENCE:0\n' +
- '#EXTINF:2\n' +
- 'segment0.ts\n' +
- '#EXT-X-PART:URI="segment1-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment1-part2.ts",DURATION=1\n' +
- 'segment1.ts\n' +
- '#EXT-X-PART:URI="segment2-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment2-part2.ts",DURATION=1\n' +
- 'segment2.ts\n' +
- '#EXT-X-PART:URI="segment3-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment3-part2.ts",DURATION=1\n' +
- 'segment3.ts\n'
- );
- const segments = this.loader.media().segments;
+ const skippedPlaylist =
+ '#EXTM3U\n' +
+ '#EXT-X-MEDIA-SEQUENCE:0\n' +
+ '#EXT-X-SKIP:SKIPPED-SEGMENTS=10\n' +
+ '#EXTINF:2\n' +
+ 'segment-10.ts\n';
- assert.equal(segments.length, 4, '4 segments');
- assert.notOk(segments[0].parts, 'no parts for first segment');
- assert.equal(segments[1].parts.length, 2, 'parts for second segment');
- assert.equal(segments[2].parts.length, 2, 'parts for third segment');
- assert.equal(segments[3].parts.length, 2, 'parts for forth segment');
- });
+ this.requests.shift().respond(200, null, skippedPlaylist);
- QUnit.test('Adds _HLS_skip=YES to url when CAN-SKIP-UNTIL is set', function(assert) {
- this.requests.shift().respond(
- 200, null,
- '#EXTM3U\n' +
- '#EXT-X-PART-INF:PART-TARGET=1\n' +
- '#EXT-X-MEDIA-SEQUENCE:0\n' +
- '#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=3\n' +
- '#EXTINF:2\n' +
- 'segment0.ts\n' +
- '#EXTINF:2\n' +
- 'segment1.ts\n' +
- '#EXTINF:2\n' +
- 'segment2.ts\n' +
- '#EXTINF:2\n' +
- 'segment3.ts\n' +
- '#EXTINF:2\n' +
- 'segment4.ts\n' +
- '#EXTINF:2\n' +
- 'segment5.ts\n' +
- '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
- 'segment6.ts\n' +
- '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
- 'segment7.ts\n' +
- '#EXT-X-PART:URI="segment8-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment8-part2.ts",DURATION=1\n' +
- 'segment8.ts\n'
- );
+ assert.equal(this.loader.media().segments.length, 11, '11 segments');
- this.loader.trigger('mediaupdatetimeout');
+ this.loader.media().segments.forEach(function(s, i) {
+ if (i < 10) {
+ assert.ok(s.hasOwnProperty('skipped'), 'has skipped property');
+ assert.false(s.skipped, 'skipped property is false');
+ }
- assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?_HLS_skip=YES');
+ assert.equal(s.uri, `segment-${i}.ts`, 'segment uri as expected');
});
- QUnit.test('Adds _HLS_skip=v2 to url when CAN-SKIP-UNTIL/CAN-SKIP-DATERANGES is set', function(assert) {
- this.requests.shift().respond(
- 200, null,
- '#EXTM3U\n' +
- '#EXT-X-PART-INF:PART-TARGET=1\n' +
- '#EXT-X-MEDIA-SEQUENCE:0\n' +
- '#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=3,CAN-SKIP-DATERANGES=YES\n' +
- '#EXTINF:2\n' +
- 'segment0.ts\n' +
- '#EXTINF:2\n' +
- 'segment1.ts\n' +
- '#EXTINF:2\n' +
- 'segment2.ts\n' +
- '#EXTINF:2\n' +
- 'segment3.ts\n' +
- '#EXTINF:2\n' +
- 'segment4.ts\n' +
- '#EXTINF:2\n' +
- 'segment5.ts\n' +
- '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
- 'segment6.ts\n' +
- '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
- 'segment7.ts\n' +
- '#EXT-X-PART:URI="segment8-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment8-part2.ts",DURATION=1\n' +
- 'segment8.ts\n'
- );
-
- this.loader.trigger('mediaupdatetimeout');
+ this.loader.trigger('mediaupdatetimeout');
- assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?_HLS_skip=v2');
- });
+ const skippedPlaylist2 =
+ '#EXTM3U\n' +
+ '#EXT-X-MEDIA-SEQUENCE:1\n' +
+ '#EXT-X-SKIP:SKIPPED-SEGMENTS=10\n' +
+ '#EXTINF:2\n' +
+ 'segment-11.ts\n';
- QUnit.test('Adds _HLS_part= and _HLS_msn= when we have a part preload hints and parts', function(assert) {
- this.requests.shift().respond(
- 200, null,
- '#EXTM3U\n' +
- '#EXT-X-PART-INF:PART-TARGET=1\n' +
- '#EXT-X-MEDIA-SEQUENCE:0\n' +
- '#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES\n' +
- '#EXTINF:2\n' +
- 'segment0.ts\n' +
- '#EXTINF:2\n' +
- 'segment1.ts\n' +
- '#EXTINF:2\n' +
- 'segment2.ts\n' +
- '#EXTINF:2\n' +
- 'segment3.ts\n' +
- '#EXTINF:2\n' +
- 'segment4.ts\n' +
- '#EXTINF:2\n' +
- 'segment5.ts\n' +
- '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
- 'segment6.ts\n' +
- '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
- 'segment7.ts\n' +
- '#EXT-X-PART:URI="segment8-part1.ts",DURATION=1\n' +
- '#EXT-X-PRELOAD-HINT:TYPE="PART",URI="segment8-part2.ts"\n'
- );
+ this.requests.shift().respond(200, null, skippedPlaylist2);
- this.loader.trigger('mediaupdatetimeout');
+ this.loader.media().segments.forEach(function(s, i) {
+ if (i < 10) {
+ assert.ok(s.hasOwnProperty('skipped'), 'has skipped property');
+ assert.false(s.skipped, 'skipped property is false');
+ }
- assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?_HLS_msn=8&_HLS_part=1');
+ assert.equal(s.uri, `segment-${i + 1}.ts`, 'segment uri as expected');
});
+ });
- QUnit.test('Adds _HLS_part= and _HLS_msn= when we have only a part preload hint', function(assert) {
- this.requests.shift().respond(
- 200, null,
- '#EXTM3U\n' +
- '#EXT-X-PART-INF:PART-TARGET=1\n' +
- '#EXT-X-MEDIA-SEQUENCE:0\n' +
- '#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES\n' +
- '#EXTINF:2\n' +
- 'segment0.ts\n' +
- '#EXTINF:2\n' +
- 'segment1.ts\n' +
- '#EXTINF:2\n' +
- 'segment2.ts\n' +
- '#EXTINF:2\n' +
- 'segment3.ts\n' +
- '#EXTINF:2\n' +
- 'segment4.ts\n' +
- '#EXTINF:2\n' +
- 'segment5.ts\n' +
- '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
- 'segment6.ts\n' +
- '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
- 'segment7.ts\n' +
- '#EXT-X-PRELOAD-HINT:TYPE="PART",URI="segment8-part1.ts"\n'
- );
-
- this.loader.trigger('mediaupdatetimeout');
-
- assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?_HLS_msn=7&_HLS_part=0');
- });
+ QUnit.test('#EXT-X-PRELOAD with parts to added to segment list', function(assert) {
+ this.requests.shift().respond(
+ 200, null,
+ '#EXTM3U\n' +
+ '#EXT-X-PART-INF:PART-TARGET=1\n' +
+ '#EXT-X-MEDIA-SEQUENCE:0\n' +
+ '#EXTINF:2\n' +
+ 'low-1.ts\n' +
+ '#EXT-X-PART:URI="part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="part2.ts",DURATION=1\n'
+ );
+ const media = this.loader.media();
- QUnit.test('does not add _HLS_part= when we have only a preload parts without preload hints', function(assert) {
- this.requests.shift().respond(
- 200, null,
- '#EXTM3U\n' +
- '#EXT-X-PART-INF:PART-TARGET=1\n' +
- '#EXT-X-MEDIA-SEQUENCE:0\n' +
- '#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES\n' +
- '#EXTINF:2\n' +
- 'segment0.ts\n' +
- '#EXTINF:2\n' +
- 'segment1.ts\n' +
- '#EXTINF:2\n' +
- 'segment2.ts\n' +
- '#EXTINF:2\n' +
- 'segment3.ts\n' +
- '#EXTINF:2\n' +
- 'segment4.ts\n' +
- '#EXTINF:2\n' +
- 'segment5.ts\n' +
- '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
- 'segment6.ts\n' +
- '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
- 'segment7.ts\n' +
- '#EXT-X-PART:URI="segment8-part1.ts",DURATION=1\n'
- );
+ assert.equal(media.segments.length, 2, '2 segments');
+ assert.deepEqual(
+ media.preloadSegment,
+ media.segments[media.segments.length - 1],
+ 'last segment is preloadSegment'
+ );
+ });
- this.loader.trigger('mediaupdatetimeout');
+ QUnit.test('#EXT-X-PRELOAD without parts not added to segment list', function(assert) {
+ this.requests.shift().respond(
+ 200, null,
+ '#EXTM3U\n' +
+ '#EXT-X-PART-INF:PART-TARGET=1\n' +
+ '#EXT-X-MEDIA-SEQUENCE:0\n' +
+ '#EXTINF:2\n' +
+ 'low-1.ts\n' +
+ '#EXT-X-PRELOAD-HINT:TYPE="PART",URI="part1.ts"\n'
+ );
+ const media = this.loader.media();
- assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?_HLS_msn=8');
- });
+ assert.equal(media.segments.length, 1, '1 segment');
+ assert.notDeepEqual(
+ media.preloadSegment,
+ media.segments[media.segments.length - 1],
+ 'last segment is not preloadSegment'
+ );
+ });
- QUnit.test('Adds only _HLS_msn= when we have segment info', function(assert) {
- this.requests.shift().respond(
- 200, null,
- '#EXTM3U\n' +
- '#EXT-X-PART-INF:PART-TARGET=1\n' +
- '#EXT-X-MEDIA-SEQUENCE:0\n' +
- '#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES\n' +
- '#EXTINF:2\n' +
- 'segment0.ts\n' +
- '#EXTINF:2\n' +
- 'segment1.ts\n' +
- '#EXTINF:2\n' +
- 'segment2.ts\n' +
- '#EXTINF:2\n' +
- 'segment3.ts\n' +
- '#EXTINF:2\n' +
- 'segment4.ts\n' +
- '#EXTINF:2\n' +
- 'segment5.ts\n' +
- '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
- 'segment6.ts\n' +
- '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
- 'segment7.ts\n' +
- '#EXT-X-PART:URI="segment8-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment8-part2.ts",DURATION=1\n' +
- 'segment8.ts\n'
- );
+ QUnit.test('#EXT-X-PART added to segments', function(assert) {
+ this.requests.shift().respond(
+ 200, null,
+ '#EXTM3U\n' +
+ '#EXT-X-PART-INF:PART-TARGET=1\n' +
+ '#EXT-X-MEDIA-SEQUENCE:0\n' +
+ '#EXTINF:2\n' +
+ 'segment0.ts\n' +
+ '#EXT-X-PART:URI="segment1-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment1-part2.ts",DURATION=1\n' +
+ 'segment1.ts\n' +
+ '#EXT-X-PART:URI="segment2-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment2-part2.ts",DURATION=1\n' +
+ 'segment2.ts\n' +
+ '#EXT-X-PART:URI="segment3-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment3-part2.ts",DURATION=1\n' +
+ 'segment3.ts\n'
+ );
+ const segments = this.loader.media().segments;
+
+ assert.equal(segments.length, 4, '4 segments');
+ assert.notOk(segments[0].parts, 'no parts for first segment');
+ assert.equal(segments[1].parts.length, 2, 'parts for second segment');
+ assert.equal(segments[2].parts.length, 2, 'parts for third segment');
+ assert.equal(segments[3].parts.length, 2, 'parts for forth segment');
+ });
- this.loader.trigger('mediaupdatetimeout');
+ QUnit.test('Adds _HLS_skip=YES to url when CAN-SKIP-UNTIL is set', function(assert) {
+ this.requests.shift().respond(
+ 200, null,
+ '#EXTM3U\n' +
+ '#EXT-X-PART-INF:PART-TARGET=1\n' +
+ '#EXT-X-MEDIA-SEQUENCE:0\n' +
+ '#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=3\n' +
+ '#EXTINF:2\n' +
+ 'segment0.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment1.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment2.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment3.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment4.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment5.ts\n' +
+ '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
+ 'segment6.ts\n' +
+ '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
+ 'segment7.ts\n' +
+ '#EXT-X-PART:URI="segment8-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment8-part2.ts",DURATION=1\n' +
+ 'segment8.ts\n'
+ );
+
+ this.loader.trigger('mediaupdatetimeout');
+
+ assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?_HLS_skip=YES');
+ });
- assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?_HLS_msn=9');
- });
+ QUnit.test('Adds _HLS_skip=v2 to url when CAN-SKIP-UNTIL/CAN-SKIP-DATERANGES is set', function(assert) {
+ this.requests.shift().respond(
+ 200, null,
+ '#EXTM3U\n' +
+ '#EXT-X-PART-INF:PART-TARGET=1\n' +
+ '#EXT-X-MEDIA-SEQUENCE:0\n' +
+ '#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=3,CAN-SKIP-DATERANGES=YES\n' +
+ '#EXTINF:2\n' +
+ 'segment0.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment1.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment2.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment3.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment4.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment5.ts\n' +
+ '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
+ 'segment6.ts\n' +
+ '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
+ 'segment7.ts\n' +
+ '#EXT-X-PART:URI="segment8-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment8-part2.ts",DURATION=1\n' +
+ 'segment8.ts\n'
+ );
+
+ this.loader.trigger('mediaupdatetimeout');
+
+ assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?_HLS_skip=v2');
+ });
- QUnit.test('can add all query directives', function(assert) {
- this.requests.shift().respond(
- 200, null,
- '#EXTM3U\n' +
- '#EXT-X-PART-INF:PART-TARGET=1\n' +
- '#EXT-X-MEDIA-SEQUENCE:0\n' +
- '#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,CAN-SKIP-UNTIL=3\n' +
- '#EXTINF:2\n' +
- 'segment0.ts\n' +
- '#EXTINF:2\n' +
- 'segment1.ts\n' +
- '#EXTINF:2\n' +
- 'segment2.ts\n' +
- '#EXTINF:2\n' +
- 'segment3.ts\n' +
- '#EXTINF:2\n' +
- 'segment4.ts\n' +
- '#EXTINF:2\n' +
- 'segment5.ts\n' +
- '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
- 'segment6.ts\n' +
- '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
- 'segment7.ts\n' +
- '#EXT-X-PART:URI="segment8-part1.ts",DURATION=1\n' +
- '#EXT-X-PRELOAD-HINT:TYPE="PART",URI="segment8-part2.ts"\n'
- );
+ QUnit.test('Adds _HLS_part= and _HLS_msn= when we have a part preload hints and parts', function(assert) {
+ this.requests.shift().respond(
+ 200, null,
+ '#EXTM3U\n' +
+ '#EXT-X-PART-INF:PART-TARGET=1\n' +
+ '#EXT-X-MEDIA-SEQUENCE:0\n' +
+ '#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES\n' +
+ '#EXTINF:2\n' +
+ 'segment0.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment1.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment2.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment3.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment4.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment5.ts\n' +
+ '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
+ 'segment6.ts\n' +
+ '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
+ 'segment7.ts\n' +
+ '#EXT-X-PART:URI="segment8-part1.ts",DURATION=1\n' +
+ '#EXT-X-PRELOAD-HINT:TYPE="PART",URI="segment8-part2.ts"\n'
+ );
+
+ this.loader.trigger('mediaupdatetimeout');
+
+ assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?_HLS_msn=8&_HLS_part=1');
+ });
- this.loader.trigger('mediaupdatetimeout');
+ QUnit.test('Adds _HLS_part= and _HLS_msn= when we have only a part preload hint', function(assert) {
+ this.requests.shift().respond(
+ 200, null,
+ '#EXTM3U\n' +
+ '#EXT-X-PART-INF:PART-TARGET=1\n' +
+ '#EXT-X-MEDIA-SEQUENCE:0\n' +
+ '#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES\n' +
+ '#EXTINF:2\n' +
+ 'segment0.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment1.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment2.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment3.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment4.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment5.ts\n' +
+ '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
+ 'segment6.ts\n' +
+ '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
+ 'segment7.ts\n' +
+ '#EXT-X-PRELOAD-HINT:TYPE="PART",URI="segment8-part1.ts"\n'
+ );
+
+ this.loader.trigger('mediaupdatetimeout');
+
+ assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?_HLS_msn=7&_HLS_part=0');
+ });
- assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?_HLS_skip=YES&_HLS_msn=8&_HLS_part=1');
- });
+ QUnit.test('does not add _HLS_part= when we have only a preload parts without preload hints', function(assert) {
+ this.requests.shift().respond(
+ 200, null,
+ '#EXTM3U\n' +
+ '#EXT-X-PART-INF:PART-TARGET=1\n' +
+ '#EXT-X-MEDIA-SEQUENCE:0\n' +
+ '#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES\n' +
+ '#EXTINF:2\n' +
+ 'segment0.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment1.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment2.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment3.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment4.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment5.ts\n' +
+ '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
+ 'segment6.ts\n' +
+ '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
+ 'segment7.ts\n' +
+ '#EXT-X-PART:URI="segment8-part1.ts",DURATION=1\n'
+ );
+
+ this.loader.trigger('mediaupdatetimeout');
+
+ assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?_HLS_msn=8');
+ });
- QUnit.test('works with existing query directives', function(assert) {
- // clear existing requests
- this.requests.length = 0;
+ QUnit.test('Adds only _HLS_msn= when we have segment info', function(assert) {
+ this.requests.shift().respond(
+ 200, null,
+ '#EXTM3U\n' +
+ '#EXT-X-PART-INF:PART-TARGET=1\n' +
+ '#EXT-X-MEDIA-SEQUENCE:0\n' +
+ '#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES\n' +
+ '#EXTINF:2\n' +
+ 'segment0.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment1.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment2.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment3.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment4.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment5.ts\n' +
+ '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
+ 'segment6.ts\n' +
+ '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
+ 'segment7.ts\n' +
+ '#EXT-X-PART:URI="segment8-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment8-part2.ts",DURATION=1\n' +
+ 'segment8.ts\n'
+ );
+
+ this.loader.trigger('mediaupdatetimeout');
+
+ assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?_HLS_msn=9');
+ });
- this.loader.dispose();
- this.loader = new PlaylistLoader('http://example.com/media.m3u8?foo=test', this.fakeVhs);
+ QUnit.test('can add all query directives', function(assert) {
+ this.requests.shift().respond(
+ 200, null,
+ '#EXTM3U\n' +
+ '#EXT-X-PART-INF:PART-TARGET=1\n' +
+ '#EXT-X-MEDIA-SEQUENCE:0\n' +
+ '#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,CAN-SKIP-UNTIL=3\n' +
+ '#EXTINF:2\n' +
+ 'segment0.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment1.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment2.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment3.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment4.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment5.ts\n' +
+ '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
+ 'segment6.ts\n' +
+ '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
+ 'segment7.ts\n' +
+ '#EXT-X-PART:URI="segment8-part1.ts",DURATION=1\n' +
+ '#EXT-X-PRELOAD-HINT:TYPE="PART",URI="segment8-part2.ts"\n'
+ );
+
+ this.loader.trigger('mediaupdatetimeout');
+
+ assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?_HLS_skip=YES&_HLS_msn=8&_HLS_part=1');
+ });
- this.loader.load();
+ QUnit.test('works with existing query directives', function(assert) {
+ // clear existing requests
+ this.requests.length = 0;
- this.requests.shift().respond(
- 200, null,
- '#EXTM3U\n' +
- '#EXT-X-PART-INF:PART-TARGET=1\n' +
- '#EXT-X-MEDIA-SEQUENCE:0\n' +
- '#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,CAN-SKIP-UNTIL=3\n' +
- '#EXTINF:2\n' +
- 'segment0.ts\n' +
- '#EXTINF:2\n' +
- 'segment1.ts\n' +
- '#EXTINF:2\n' +
- 'segment2.ts\n' +
- '#EXTINF:2\n' +
- 'segment3.ts\n' +
- '#EXTINF:2\n' +
- 'segment4.ts\n' +
- '#EXTINF:2\n' +
- 'segment5.ts\n' +
- '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
- 'segment6.ts\n' +
- '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
- 'segment7.ts\n' +
- '#EXT-X-PART:URI="segment8-part1.ts",DURATION=1\n' +
- '#EXT-X-PRELOAD-HINT:TYPE="PART",URI="segment8-part2.ts"\n'
- );
+ this.loader.dispose();
+ this.loader = new PlaylistLoader('http://example.com/media.m3u8?foo=test', this.fakeVhs);
- this.loader.trigger('mediaupdatetimeout');
+ this.loader.load();
- assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?foo=test&_HLS_skip=YES&_HLS_msn=8&_HLS_part=1');
- });
- }
+ this.requests.shift().respond(
+ 200, null,
+ '#EXTM3U\n' +
+ '#EXT-X-PART-INF:PART-TARGET=1\n' +
+ '#EXT-X-MEDIA-SEQUENCE:0\n' +
+ '#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,CAN-SKIP-UNTIL=3\n' +
+ '#EXTINF:2\n' +
+ 'segment0.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment1.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment2.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment3.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment4.ts\n' +
+ '#EXTINF:2\n' +
+ 'segment5.ts\n' +
+ '#EXT-X-PART:URI="segment6-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment6-part2.ts",DURATION=1\n' +
+ 'segment6.ts\n' +
+ '#EXT-X-PART:URI="segment7-part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="segment7-part2.ts",DURATION=1\n' +
+ 'segment7.ts\n' +
+ '#EXT-X-PART:URI="segment8-part1.ts",DURATION=1\n' +
+ '#EXT-X-PRELOAD-HINT:TYPE="PART",URI="segment8-part2.ts"\n'
+ );
+
+ this.loader.trigger('mediaupdatetimeout');
+
+ assert.equal(this.requests[0].uri, 'http://example.com/media.m3u8?foo=test&_HLS_skip=YES&_HLS_msn=8&_HLS_part=1');
+ });
});
diff --git a/test/playlist.test.js b/test/playlist.test.js
index 9e6f2c6d6..a02c4f9cd 100644
--- a/test/playlist.test.js
+++ b/test/playlist.test.js
@@ -2,7 +2,6 @@ import Playlist from '../src/playlist';
import PlaylistLoader from '../src/playlist-loader';
import QUnit from 'qunit';
import xhrFactory from '../src/xhr';
-import videojs from 'video.js';
import { useFakeEnvironment } from './test-helpers';
// needed for plugin registration
import '../src/videojs-http-streaming';
@@ -1463,56 +1462,54 @@ QUnit.module('Playlist', function() {
}
);
- if (!videojs.browser.IE_VERSION) {
- QUnit.test('can return a partIndex', function(assert) {
- this.fakeVhs.options_ = {llhls: true};
- const loader = new PlaylistLoader('media.m3u8', this.fakeVhs);
+ QUnit.test('can return a partIndex', function(assert) {
+ this.fakeVhs.options_ = {llhls: true};
+ const loader = new PlaylistLoader('media.m3u8', this.fakeVhs);
- loader.load();
+ loader.load();
- this.requests.shift().respond(
- 200, null,
- '#EXTM3U\n' +
- '#EXT-X-MEDIA-SEQUENCE:1001\n' +
- '#EXTINF:4,\n' +
- '1001.ts\n' +
- '#EXTINF:5,\n' +
- '1002.ts\n' +
- '#EXT-X-PART:URI="1003.part1.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="1003.part2.ts",DURATION=1\n' +
- '#EXT-X-PART:URI="1003.part3.ts",DURATION=1\n' +
- '#EXT-X-PRELOAD-HINT:TYPE="PART",URI="1003.part4.ts"\n'
- );
+ this.requests.shift().respond(
+ 200, null,
+ '#EXTM3U\n' +
+ '#EXT-X-MEDIA-SEQUENCE:1001\n' +
+ '#EXTINF:4,\n' +
+ '1001.ts\n' +
+ '#EXTINF:5,\n' +
+ '1002.ts\n' +
+ '#EXT-X-PART:URI="1003.part1.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="1003.part2.ts",DURATION=1\n' +
+ '#EXT-X-PART:URI="1003.part3.ts",DURATION=1\n' +
+ '#EXT-X-PRELOAD-HINT:TYPE="PART",URI="1003.part4.ts"\n'
+ );
- const media = loader.media();
+ const media = loader.media();
- this.defaults = {
- playlist: media,
- currentTime: 0,
- startingSegmentIndex: 0,
- startingPartIndex: null,
- startTime: 0
- };
+ this.defaults = {
+ playlist: media,
+ currentTime: 0,
+ startingSegmentIndex: 0,
+ startingPartIndex: null,
+ startTime: 0
+ };
- assert.deepEqual(
- this.getMediaInfoForTime({currentTime: 10, startTime: 0}),
- {segmentIndex: 2, startTime: 9, partIndex: 0},
- 'returns expected part/segment'
- );
+ assert.deepEqual(
+ this.getMediaInfoForTime({currentTime: 10, startTime: 0}),
+ {segmentIndex: 2, startTime: 9, partIndex: 0},
+ 'returns expected part/segment'
+ );
- assert.deepEqual(
- this.getMediaInfoForTime({currentTime: 11, startTime: 0}),
- {segmentIndex: 2, startTime: 10, partIndex: 1},
- 'returns expected part/segment'
- );
+ assert.deepEqual(
+ this.getMediaInfoForTime({currentTime: 11, startTime: 0}),
+ {segmentIndex: 2, startTime: 10, partIndex: 1},
+ 'returns expected part/segment'
+ );
- assert.deepEqual(
- this.getMediaInfoForTime({currentTime: 11, segmentIndex: -15}),
- {segmentIndex: 2, startTime: 10, partIndex: 1},
- 'returns expected part/segment'
- );
- });
- }
+ assert.deepEqual(
+ this.getMediaInfoForTime({currentTime: 11, segmentIndex: -15}),
+ {segmentIndex: 2, startTime: 10, partIndex: 1},
+ 'returns expected part/segment'
+ );
+ });
QUnit.test('liveEdgeDelay works as expected', function(assert) {
const media = {
diff --git a/test/sanity.test.js b/test/sanity.test.js
index 0f8e29c18..d45cb98e8 100644
--- a/test/sanity.test.js
+++ b/test/sanity.test.js
@@ -11,11 +11,7 @@ QUnit.test('the environment is sane', function(assert) {
assert.strictEqual(typeof sinon, 'object', 'sinon exists');
assert.strictEqual(typeof videojs, 'function', 'videojs exists');
assert.strictEqual(typeof window.MediaSource, 'function', 'MediaSource is a function');
- if (videojs.browser.IE_VERSION) {
- assert.strictEqual(typeof window.URL, 'object', 'URL is an object');
- } else {
- assert.strictEqual(typeof window.URL, 'function', 'URL is a function');
- }
+ assert.strictEqual(typeof window.URL, 'function', 'URL is a function');
assert.strictEqual(typeof videojs.Vhs, 'object', 'Vhs is an object');
assert.strictEqual(
typeof videojs.VhsSourceHandler,
diff --git a/test/source-updater.test.js b/test/source-updater.test.js
index d3c042328..4ca5d57f2 100644
--- a/test/source-updater.test.js
+++ b/test/source-updater.test.js
@@ -9,21 +9,9 @@ import { QUOTA_EXCEEDED_ERR } from '../src/error-codes';
import {createTimeRanges} from '../src/util/vjs-compat';
const checkInitialDuration = function({duration}) {
- // ie sometimes sets duration to infinity earlier then expected
- if (videojs.browser.IS_EDGE || videojs.browser.IE_VERSION) {
- QUnit.assert.ok(Number.isNaN(duration) || !Number.isFinite(duration), 'starting duration as expected');
- } else {
- QUnit.assert.ok(Number.isNaN(duration), 'starting duration as expected');
- }
+ QUnit.assert.ok(Number.isNaN(duration), 'starting duration as expected');
};
-let testOrSkip = 'test';
-
-// some tests just don't work reliably on ie11 or edge
-if (videojs.browser.IS_EDGE || videojs.browser.IE_VERSION) {
- testOrSkip = 'skip';
-}
-
const concatSegments = (...segments) => {
let byteLength = segments.reduce((acc, cv) => {
acc += cv.byteLength;
@@ -962,7 +950,7 @@ QUnit.test(
}
);
-QUnit[testOrSkip]('setDuration waits for audio buffer to finish updating', function(assert) {
+QUnit.test('setDuration waits for audio buffer to finish updating', function(assert) {
const done = assert.async();
assert.expect(5);
@@ -1013,50 +1001,48 @@ QUnit.test('setDuration waits for video buffer to finish updating', function(ass
assert.ok(this.sourceUpdater.updating(), 'updating during appends');
});
-if (!videojs.browser.IS_EDGE) {
- QUnit.test(
- 'setDuration waits for both audio and video buffers to finish updating',
- function(assert) {
- const done = assert.async();
- let appendsFinished = 0;
+QUnit.test(
+ 'setDuration waits for both audio and video buffers to finish updating',
+ function(assert) {
+ const done = assert.async();
+ let appendsFinished = 0;
- assert.expect(7);
+ assert.expect(7);
- this.sourceUpdater.createSourceBuffers({
- audio: 'mp4a.40.2',
- video: 'avc1.4D001E'
- });
+ this.sourceUpdater.createSourceBuffers({
+ audio: 'mp4a.40.2',
+ video: 'avc1.4D001E'
+ });
- assert.notOk(this.sourceUpdater.updating(), 'not updating by default');
+ assert.notOk(this.sourceUpdater.updating(), 'not updating by default');
- const checkDuration = () => {
- // duration is set to infinity if content is appended before an explicit duration is
- // set https://w3c.github.io/media-source/#sourcebuffer-init-segment-received
- assert.equal(this.mediaSource.duration, Infinity, 'duration not set on media source');
+ const checkDuration = () => {
+ // duration is set to infinity if content is appended before an explicit duration is
+ // set https://w3c.github.io/media-source/#sourcebuffer-init-segment-received
+ assert.equal(this.mediaSource.duration, Infinity, 'duration not set on media source');
- if (appendsFinished === 0) {
- // try to set the duration while one of the buffers is still updating, this should
- // happen after the other setDuration call
- this.sourceUpdater.setDuration(12, () => {
- assert.equal(this.mediaSource.duration, 12, 'set duration on media source');
- done();
- });
- }
+ if (appendsFinished === 0) {
+ // try to set the duration while one of the buffers is still updating, this should
+ // happen after the other setDuration call
+ this.sourceUpdater.setDuration(12, () => {
+ assert.equal(this.mediaSource.duration, 12, 'set duration on media source');
+ done();
+ });
+ }
- appendsFinished++;
- };
+ appendsFinished++;
+ };
- this.sourceUpdater.appendBuffer({type: 'video', bytes: mp4VideoTotal()}, checkDuration);
- this.sourceUpdater.appendBuffer({type: 'audio', bytes: mp4AudioTotal()}, checkDuration);
- this.sourceUpdater.setDuration(11, () => {
- assert.equal(this.mediaSource.duration, 11, 'set duration on media source');
- });
+ this.sourceUpdater.appendBuffer({type: 'video', bytes: mp4VideoTotal()}, checkDuration);
+ this.sourceUpdater.appendBuffer({type: 'audio', bytes: mp4AudioTotal()}, checkDuration);
+ this.sourceUpdater.setDuration(11, () => {
+ assert.equal(this.mediaSource.duration, 11, 'set duration on media source');
+ });
- checkInitialDuration(this.mediaSource);
- assert.ok(this.sourceUpdater.updating(), 'updating during appends');
- }
- );
-}
+ checkInitialDuration(this.mediaSource);
+ assert.ok(this.sourceUpdater.updating(), 'updating during appends');
+ }
+);
QUnit.test(
'setDuration blocks audio and video queue entries until it finishes',
@@ -1318,7 +1304,7 @@ QUnit.test('dispose removes sourceopen listener', function(assert) {
});
});
-QUnit[testOrSkip]('audio appends are delayed until video append for the first append', function(assert) {
+QUnit.test('audio appends are delayed until video append for the first append', function(assert) {
const done = assert.async();
let audioAppend = false;
let videoAppend = false;
diff --git a/test/util/text-tracks.test.js b/test/util/text-tracks.test.js
index 60ae1be51..8951e8ab2 100644
--- a/test/util/text-tracks.test.js
+++ b/test/util/text-tracks.test.js
@@ -123,3 +123,38 @@ test('creates cues for timed metadata', function(assert) {
'added one metadata cues'
);
});
+
+test('does nothing if frames are undefined', function(assert) {
+ addMetadata({
+ inbandTextTracks: this.inbandTextTracks,
+ timestampOffset: this.timestampOffset,
+ videoDuration: 1,
+ metadataArray: [{
+ cueTime: 1
+ }]
+ });
+
+ assert.strictEqual(
+ this.inbandTextTracks.metadataTrack_.cues.length,
+ 0,
+ 'added no metadata cues'
+ );
+});
+
+test('does nothing if frames.length is 0', function(assert) {
+ addMetadata({
+ inbandTextTracks: this.inbandTextTracks,
+ timestampOffset: this.timestampOffset,
+ videoDuration: 1,
+ metadataArray: [{
+ cueTime: 1,
+ frames: []
+ }]
+ });
+
+ assert.strictEqual(
+ this.inbandTextTracks.metadataTrack_.cues.length,
+ 0,
+ 'added no metadata cues'
+ );
+});
diff --git a/test/videojs-http-streaming.test.js b/test/videojs-http-streaming.test.js
index 5c06bb993..13cf4e8a5 100644
--- a/test/videojs-http-streaming.test.js
+++ b/test/videojs-http-streaming.test.js
@@ -53,13 +53,6 @@ import {version as mpdVersion} from 'mpd-parser/package.json';
import {version as m3u8Version} from 'm3u8-parser/package.json';
import {version as aesVersion} from 'aes-decrypter/package.json';
-let testOrSkip = 'test';
-
-// some tests just don't work reliably on ie11 or edge
-if (videojs.browser.IS_EDGE || videojs.browser.IE_VERSION) {
- testOrSkip = 'skip';
-}
-
const ogVhsHandlerSetupQualityLevels = videojs.VhsHandler.prototype.setupQualityLevels_;
// do a shallow copy of the properties of source onto the target object
@@ -78,10 +71,9 @@ QUnit.module('VHS', {
this.mse = useFakeMediaSource();
this.clock = this.env.clock;
this.old = {};
- if (!videojs.browser.IE_VERSION) {
- this.old.devicePixelRatio = window.devicePixelRatio;
- window.devicePixelRatio = 1;
- }
+ this.old.devicePixelRatio = window.devicePixelRatio;
+ window.devicePixelRatio = 1;
+
// store functionality that some tests need to mock
this.old.GlobalOptions = merge(videojs.options);
@@ -404,37 +396,6 @@ QUnit.test('autoplay seeks to the live point after media source open', function(
assert.notEqual(currentTime, 0, 'seeked on autoplay');
});
-QUnit.test(
- 'autoplay seeks to the live point after tech fires loadedmetadata in ie11',
- function(assert) {
- videojs.browser.IE_VERSION = 11;
- let currentTime = 0;
-
- this.player.autoplay(true);
- this.player.on('seeking', () => {
- currentTime = this.player.currentTime();
- });
- this.player.src({
- src: 'liveStart30sBefore.m3u8',
- type: 'application/vnd.apple.mpegurl'
- });
-
- this.clock.tick(1);
-
- openMediaSource(this.player, this.clock);
- this.player.tech_.trigger('play');
- this.standardXHRResponse(this.requests.shift());
- this.clock.tick(1);
-
- assert.equal(currentTime, 0, 'have not played yet');
-
- this.player.tech_.trigger('loadedmetadata');
- this.clock.tick(1);
-
- assert.notEqual(currentTime, 0, 'seeked after tech is ready');
- }
-);
-
QUnit.test(
'duration is set when the source opens after the playlist is loaded',
function(assert) {
@@ -950,7 +911,7 @@ QUnit.module('NetworkInformationApi', hooks => {
window.navigator = this.ogNavigator;
});
- QUnit[testOrSkip](
+ QUnit.test(
'bandwidth returns networkInformation.downlink when useNetworkInformationApi option is enabled',
function(assert) {
this.resetNavigatorConnection({
@@ -973,7 +934,7 @@ QUnit.module('NetworkInformationApi', hooks => {
}
);
- QUnit[testOrSkip](
+ QUnit.test(
'bandwidth uses player-estimated bandwidth when its value is greater than networkInformation.downLink and both values are >= 10 Mbps',
function(assert) {
this.resetNavigatorConnection({
@@ -997,7 +958,7 @@ QUnit.module('NetworkInformationApi', hooks => {
}
);
- QUnit[testOrSkip](
+ QUnit.test(
'bandwidth uses network-information-api bandwidth when its value is less than the player bandwidth and 10 Mbps',
function(assert) {
this.resetNavigatorConnection({
@@ -1021,7 +982,7 @@ QUnit.module('NetworkInformationApi', hooks => {
}
);
- QUnit[testOrSkip](
+ QUnit.test(
'bandwidth uses player-estimated bandwidth when networkInformation is not supported',
function(assert) {
// Nullify the `connection` property on Navigator
@@ -4447,21 +4408,11 @@ QUnit.test('eme waitingforkey event triggers another setup', function(assert) {
vhs.playlistController_.sourceUpdater_.trigger('createdsourcebuffers');
- // Since IE11 doesn't initialize media keys early, in this test IE11 will always have
- // one less call than in other browsers.
- if (videojs.browser.IE_VERSION === 11) {
- assert.equal(createKeySessionCalls, 0, 'did not call createKeySessions_ yet');
- } else {
- assert.equal(createKeySessionCalls, 1, 'called createKeySessions_ once');
- }
+ assert.equal(createKeySessionCalls, 1, 'called createKeySessions_ once');
this.player.tech_.trigger({type: 'waitingforkey', status: 'usable'});
- if (videojs.browser.IE_VERSION === 11) {
- assert.equal(createKeySessionCalls, 1, 'called createKeySessions_ once');
- } else {
- assert.equal(createKeySessionCalls, 2, 'called createKeySessions_ again');
- }
+ assert.equal(createKeySessionCalls, 2, 'called createKeySessions_ again');
});
QUnit.test('integration: configures eme for DASH on source buffer creation', function(assert) {
@@ -4604,13 +4555,8 @@ QUnit.test('integration: updates source updater after eme init', function(assert
sourceUpdater.on(
'createdsourcebuffers',
() => {
- let expected = false;
+ const expected = false;
- // IE initializes eme syncronously directly after source buffer
- // creation
- if (videojs.browser.IE_VERSION) {
- expected = true;
- }
assert.equal(sourceUpdater.hasInitializedAnyEme(), expected, 'correct eme state');
}
);
@@ -4632,7 +4578,7 @@ QUnit.test('integration: updates source updater after eme init', function(assert
this.standardXHRResponse(this.requests.shift(), audioSegment());
});
-QUnit[testOrSkip]('player error when key session creation rejects promise', function(assert) {
+QUnit.test('player error when key session creation rejects promise', function(assert) {
const done = assert.async();
this.player.error = (errorObject) => {
@@ -4741,7 +4687,7 @@ QUnit.test(
}
);
-QUnit[testOrSkip](
+QUnit.test(
'stores bandwidth and throughput in localStorage when global option is true',
function(assert) {
videojs.options.vhs = {
@@ -4770,7 +4716,7 @@ QUnit[testOrSkip](
}
);
-QUnit[testOrSkip](
+QUnit.test(
'stores bandwidth and throughput in localStorage when player option is true',
function(assert) {
this.player.dispose();
@@ -4805,7 +4751,7 @@ QUnit[testOrSkip](
}
);
-QUnit[testOrSkip](
+QUnit.test(
'stores bandwidth and throughput in localStorage when source option is true',
function(assert) {
this.player.dispose();
@@ -4835,7 +4781,7 @@ QUnit[testOrSkip](
}
);
-QUnit[testOrSkip](
+QUnit.test(
'source localStorage option takes priority over player option',
function(assert) {
this.player.dispose();
@@ -4871,7 +4817,7 @@ QUnit[testOrSkip](
}
);
-QUnit[testOrSkip](
+QUnit.test(
'does not store bandwidth and throughput in localStorage by default',
function(assert) {
this.player.dispose();
@@ -4897,7 +4843,7 @@ QUnit[testOrSkip](
}
);
-QUnit[testOrSkip]('retrieves bandwidth and throughput from localStorage', function(assert) {
+QUnit.test('retrieves bandwidth and throughput from localStorage', function(assert) {
window.localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify({
bandwidth: 33,
throughput: 44
@@ -4959,7 +4905,7 @@ QUnit[testOrSkip]('retrieves bandwidth and throughput from localStorage', functi
videojs.options.vhs = origVhsOptions;
});
-QUnit[testOrSkip](
+QUnit.test(
'does not retrieve bandwidth and throughput from localStorage when stored value is not as expected',
function(assert) {
// bad value