diff --git a/doc/Getting_Started/Minimal_Player.md b/doc/Getting_Started/Minimal_Player.md index cb0b800a00..f1937daf62 100644 --- a/doc/Getting_Started/Minimal_Player.md +++ b/doc/Getting_Started/Minimal_Player.md @@ -8,33 +8,18 @@ Smooth streaming, VTT or SRT parsing. Because each implementation has its need, we permit multiple ways to import the player with limited features. -This principally leads to a smaller file size. -This customization can be done through two principal ways: +This customization can be done by importing the minimal version of the RxPlayer +and then adding only the features your want. +This allows to greatly reduce the final bundle size, if your bundler (esbuild, +webpack, rollup, vite...) support +[tree-shaking](https://en.wikipedia.org/wiki/Tree_shaking), like most do. -- by importing a minimal version and then adding only the features your want +## How it works -- by setting environment variables at build time - -The first solution is the most straightforward and should be used in most -usecases. The main disadvantages of this solution are that to reduce file size: - -- you will need to use a module-bundler or minifier which performs - [tree-shaking](https://en.wikipedia.org/wiki/Tree_shaking), like webpack's - production mode or rollup. - -- you will need to use the package published on npm (as opposed to the git - repository directly). - -The second solution will always work but needs you to build the bundle yourself -through our npm scripts. - -## Importing a minimal version - -### How it works - -If you imported the RxPlayer library through the npm package (like via the `npm install rx-player` command), you can import a minimal version of the player by -importing it from `"rx-player/minimal"`: +If you imported the RxPlayer library through the npm package (like via the +`npm install rx-player` command), you can import a minimal version of the player +by importing it from `"rx-player/minimal"`: ```js import MinimalRxPlayer from "rx-player/minimal"; @@ -56,8 +41,7 @@ import { DASH, SMOOTH } from "rx-player/features"; ``` At last you can add those features to the imported RxPlayer class by calling the -special `addFeatures` static method, which is only present on the minimal -version of the Player: +`addFeatures` static method: ```js // addFeatures takes an array of features as argument @@ -100,242 +84,6 @@ By using the minimal version, you will reduce the final bundle file **if tree-shaking is performed on the final code (like in webpack's production mode)**. -The key is just to know which feature does what. The next chapter will list -and explain the role of every one of them. - -### List of features - -Features, which are variables imported from the `"rx-player/features"` path, -are all objects declared in upper-case. - -Here is the anotated exhaustive list (notes are at the bottom of the table): - -| Feature | Description of the feature | -| ------------------------ | --------------------------------------------------------- | -| `SMOOTH` | Enable Smooth streaming (HSS) playback | -| `DASH` | Enable DASH playback using a JavaScript-based MPD parser | -| `DIRECTFILE` | Enable playback of "directfile" contents | -| `EME` | Enable playback of encrypted contents | -| `NATIVE_TEXT_BUFFER` [1] | Allow to display text tracks through \ elements | -| `HTML_TEXT_BUFFER` [1] | Allow to display richer text tracks through HTML elements | -| `IMAGE_BUFFER` [1] | Allow to display thumbnails through the image buffer | -| `NATIVE_SRT_PARSER` [2] | Parse SRT text tracks for the native text buffer | -| `NATIVE_VTT_PARSER` [2] | Parse VTT text tracks for the native text buffer | -| `NATIVE_TTML_PARSER` [2] | Parse TTML text tracks for the native text buffer | -| `NATIVE_SAMI_PARSER` [2] | Parse SAMI text tracks for the native text buffer | -| `HTML_SRT_PARSER` [3] | Parse SRT text tracks for the HTML text buffer | -| `HTML_VTT_PARSER` [3] | Parse VTT text tracks for the HTML text buffer | -| `HTML_TTML_PARSER` [3] | Parse TTML text tracks for the HTML text buffer | -| `HTML_SAMI_PARSER` [3] | Parse SAMI text tracks for the HTML text buffer | -| `BIF_PARSER` [4] | Parse BIF image tracks for the image buffer | -| `DASH_WASM` [5] [6] | Enable DASH playback using a WebAssembly-based MPD parser | -| `LOCAL_MANIFEST` [5] | Enable playback of "local" contents | -| `METAPLAYLIST` [5] | Enable playback of "metaplaylist" contents | -| `DEBUG_ELEMENT` [5] | Allows to use the `createDebugElement` RxPlayer method | - ---- - -**Notes**: - -**[1]**: You will need to also add at least one parser for this type of buffer -for those features to be useful. -(example: `NATIVE_SRT_PARSER` will parse srt subtitles for the -`NATIVE_TEXT_BUFFER`) - -**[2]**: Those features will only be used if `NATIVE_TEXT_BUFFER` is an added -feature. - -**[3]**: Those features will only be used if `HTML_TEXT_BUFFER` is an added -feature. - -**[4]**: This feature will only be used if `IMAGE_BUFFER` is an added feature. - -**[5]**: Those type of contents are experimental. They should be imported -from `rx-player/experimental/features`. - -**[6]**: In cases where both the `DASH` and `DASH_WASM` features are added -(which are both parsers for DASH contents), the RxPlayer will default using the -WebAssembly parser (provided by `DASH_WASM`) and fallback on the JavaScript -parser (provided by `DASH`) when it cannot do so. - ---- - -### Examples - -To help you choose your features, are some examples that represents common -usecases. - -#### unencrypted DASH contents with native webVTT subtitles - -```js -import RxPlayer from "rx-player/minimal"; -import { - DASH, - NATIVE_TEXT_BUFFER, - NATIVE_VTT_PARSER, -} from "rx-player/features"; - -RxPlayer.addFeatures([DASH, NATIVE_TEXT_BUFFER, NATIVE_VTT_PARSER]); -``` - -#### possibly-encrypted DASH contents with HMTL webVTT and TTML subtitles - -```js -import RxPlayer from "rx-player/minimal"; -import { - DASH, - EME, - HTML_TEXT_BUFFER, - HTML_VTT_PARSER, - HTML_HTML_PARSER, -} from "rx-player/features"; - -RxPlayer.addFeatures([ - DASH, - EME, - HTML_TEXT_BUFFER, - HTML_VTT_PARSER, - HTML_TTML_PARSER, -]); -``` - -#### Smooth contents with thumbnails (BIF) support - -```js -import RxPlayer from "rx-player/minimal"; -import { SMOOTH, IMAGE_BUFFER, BIF_PARSER } from "rx-player/features"; - -RxPlayer.addFeatures([SMOOTH, IMAGE_BUFFER, BIF_PARSER]); -``` - -## Building with environment variables - -### How it works - -You can also include only the features you need on the RxPlayer library by -building it while having specific environment variables. - -The code related to the unwanted features should be removed when the final code -is minified (as the corresponding code is made unreachable). - -To avoid any conflict with other environment variables, they all are named -`RXP_`. - -For example, the following will remove all code related to Microsoft Smooth -Streaming from the build: - -```sh -RXP_SMOOTH=false npm run build:min -``` - -### List of environment variables - -#### RXP_SMOOTH - -True by default. If set to "false", all code relative to HSS streaming will be -ignored during a build. - -#### RXP_DASH - -True by default. If set to "false", all code relative to DASH streaming will be -ignored during a build. - -#### RXP_DIRECTFILE - -True by default. If set to "false", all code relative to directfile streaming -will be ignored during a build. - -#### RXP_LOCAL_MANIFEST - -False by default. If set to "true", all code relative to the "local" transport -(to be able to play content offline for example) will be included during a -build. - -#### RXP_METAPLAYLIST - -False by default. If set to "true", all code relative to metaplaylist streaming -will be included during a build. - -#### RXP_DEBUG_ELEMENT - -False by default. If set to "true", the method RxPlayer's `createDebugElement` -method will be callable. - -#### RXP_EME - -True by default. If set to "false", all code relative to encrypted contents will -be ignored during a build. - -#### RXP_NATIVE_TTML - -True by default. If set to "false", all code relative to TTML parsing for native -text tracks will be ignored during a build. - -#### RXP_NATIVE_SAMI - -True by default. If set to "false", all code relative to SAMI parsing for native -text tracks will be ignored during a build. - -#### RXP_NATIVE_VTT - -True by default. If set to "false", all code relative to VTT parsing for native -text tracks will be ignored during a build. - -#### RXP_NATIVE_SRT - -True by default. If set to "false", all code relative to SRT parsing for native -text tracks will be ignored during a build. - -#### RXP_HTML_TTML - -True by default. If set to "false", all code relative to TTML parsing for html -text tracks [1] will be ignored during a build. - -#### RXP_HTML_SAMI - -True by default. If set to "false", all code relative to SAMI parsing for html -text tracks [1] will be ignored during a build. - -#### RXP_HTML_VTT - -True by default. If set to "false", all code relative to VTT parsing for html -text tracks [1] will be ignored during a build. - -#### RXP_HTML_SRT - -True by default. If set to "false", all code relative to SRT parsing for html -text tracks [1] will be ignored during a build. - -#### RXP_BIF_PARSER - -True by default. If set to "false", all code relative to BIF image parsing will -be ignored during a build. - -#### RXP_BAREBONE - -If set to true, no feature is activated by default and all other environment -variables are considered as false by default (unless set). - -For example, to only activate DASH, you could do: - -```sh -RXP_BAREBONE=true RXP_DASH=true npm run build:min -``` - -#### RXP_ENV - -Either "production" or "development". "production" as a default. -In the "development" case: - -- logs will be activated -- the code will be less tolerant towards unwanted behavior -- the code will be less optimized - ---- - -**Notes**: - -DOM element instead of a `` (the latter here being called "native") tag -for a richer formatting. - ---- +The key is just to know which feature does what. +You can refer to the [RxPlayer Features documentation page](../api/RxPlayer_Features.md) for +this. diff --git a/doc/api/.docConfig.json b/doc/api/.docConfig.json index d3a8299590..9c8f6dd568 100644 --- a/doc/api/.docConfig.json +++ b/doc/api/.docConfig.json @@ -8,6 +8,10 @@ "path": "./Creating_a_Player.md", "displayName": "Creating a Player" }, + { + "path": "./RxPlayer_Features.md", + "displayName": "Feature switching" + }, { "path": "./Loading_a_Content.md", "displayName": "Loading a Content" diff --git a/doc/api/Loading_a_Content.md b/doc/api/Loading_a_Content.md index da1d71db8a..85e57c5694 100644 --- a/doc/api/Loading_a_Content.md +++ b/doc/api/Loading_a_Content.md @@ -38,7 +38,8 @@ Can be either: player](../Getting_Started/Minimal_Player.md), you will need to add at least either one of the following features to be able to play DASH contents: - - the `DASH` feature (rely on a generally-sufficient JavaScript parser) + - the `DASH` [feature](./RxPlayer_Features.md) (rely on a generally-sufficient + JavaScript parser) - the `DASH_WASM` experimental feature (backed by a WebAssembly parser, more efficient when handling very large MPDs). @@ -50,8 +51,8 @@ Can be either: - **`"smooth"` - for Microsoft Smooth Streaming contents** If you're using the [minimal build of the player](../Getting_Started/Minimal_Player.md), you - will need to add at least the `SMOOTH` feature to be able to play Smooth - contents. + will need to add at least the `SMOOTH` [feature](./RxPlayer_Features.md) to be + able to play Smooth contents. - **`"directfile"` - for loading a video in _DirectFile_ mode, which allows to directly play media files** (example: `.mp4` or `.webm` files) without @@ -59,8 +60,8 @@ Can be either: contents on multiple browsers (mainly safari and iOS browsers). If you're using the [minimal build of the player](../Getting_Started/Minimal_Player.md), you - will need to add at least the `DIRECTFILE` feature to be able to play those - contents. + will need to add at least the `DIRECTFILE` [feature](./RxPlayer_Features.md) + to be able to play those contents.
In that mode, multiple APIs won't have any effect. @@ -71,17 +72,15 @@ Can be either: - `"metaplaylist"` for [MetaPlaylist](./Miscellaneous/MetaPlaylist.md) streams, which are a concatenation of multiple smooth and DASH contents - If you're using the [minimal build of the player](../Getting_Started/Minimal_Player.md), you - will need to add at least the `METAPLAYLIST` experimental feature to be able - to play those contents. + You will need to add at least the `METAPLAYLIST` experimental [feature](./RxPlayer_Features.md) + to be able to play those contents. - `"local"` for [local manifests](./Miscellaneous/Local_Contents.md), which allows to play downloaded DASH, Smooth or MetaPlaylist contents (when offline for example). - If you're using the [minimal build of the player](../Getting_Started/Minimal_Player.md), you - will need to add at least the `LOCAL_MANIFEST` experimental feature to be able - to play those contents. + You will need to add at least the `LOCAL_MANIFEST` experimental [feature](./RxPlayer_Features.md) + to be able to play those contents. Example: diff --git a/doc/api/Miscellaneous/DASH_WASM_Parser.md b/doc/api/Miscellaneous/DASH_WASM_Parser.md index 64a0ded5e3..c1a87e91e7 100644 --- a/doc/api/Miscellaneous/DASH_WASM_Parser.md +++ b/doc/api/Miscellaneous/DASH_WASM_Parser.md @@ -6,12 +6,11 @@ the "MPD": 1. A JavaScript parser. Provided in the default "bundled" builds and through the `DASH` feature in - the minimal build. + [the minimal build](../../Getting_Started/Minimal_Player.md). 2. A generally-faster WebAssembly parser. - Only provided through the `DASH_WASM` experimental feature in the minimal - build. + Only provided through the `DASH_WASM` experimental feature. This page is the API documentation page for the second parser. @@ -46,12 +45,12 @@ The "experimental" notion has more to do with the fact that its API can evolve without impacting too much RxPlayer's semantic versioning. For example, a new minor RxPlayer version could bring with it a complete API change regarding this feature. -Still, potential changes would be fully documented and at least a link will be -added both to that release's release note and changelog file. +Still, potential changes would be fully documented on that release's release +note and changelog file. The choice of labeling this feature as experimental has been made so we can have more freedom if we find ways to provide sensible improvements to it in the -future, in case they necessitate some incompatible API change. +future. ## How to use it? @@ -75,7 +74,8 @@ It might be a lot to grasp now, we will focus on what has been done here step by step in the next chapters. ```js -// Import the minimal RxPlayer +// Import the RxPlayer +// (here through the "minimal" build, though it doesn't change for other builds) import RxPlayer from "rx-player/minimal"; // Import the function allowing to create the DASH-WASM parser @@ -120,30 +120,12 @@ You can find it at any of the following places: loaded in your project, for example in the node_modules directory (most probably in `node_modules/rx-player/dist/mpd-parser.wasm` depending on your project). - ` Once you've retrieved the right WebAssembly file linked to your RxPlayer version, you will need to store it and give its URL to the RxPlayer so it will be able to load it. -### Step 2: using the minimal build of the RxPlayer - -The `DASH_WASM` feature is only available when using the "minimal" version of -the RxPlayer. That is, when the player is imported through the -`"rx-player/minimal"` path: - -```js -import RxPlayer from "rx-player/minimal"; -``` - -If you weren't using the minimal RxPlayer before, note that it necessitates that -you add the features you want to it. -More information about any of that can be found in the [minimal player documentation](../../Getting_Started/Minimal_Player.md). - -This documentation will especially dive into the `DASH_WASM` feature, which is -the WebAssembly parser for MPDs. - -### Step 3: importing the `DASH_WASM` feature +### Step 2: importing the `DASH_WASM` feature As indicated before, the `DASH-WASM` feature is an "experimental" feature. @@ -158,7 +140,7 @@ As any experimental features, it needs to be imported through the import { DASH_WASM } from "rx-player/experimental/features"; ``` -### Step 4: Initializing the feature +### Step 3: Initializing the feature -- @@ -201,7 +183,7 @@ In the case where initialization fails, the RxPlayer will try to use the regular `DASH` js parser instead, if that feature has been added. If it has not, an error will be thrown when playing DASH contents. -### Step 4bis: Adding the feature to the RxPlayer +### Step 3bis: Adding the feature to the RxPlayer -- @@ -211,7 +193,7 @@ _This step can be done before or after "initializing" the `DASH_WASM` feature -- To "link" the RxPlayer to the parser, you will need to call the `addFeatures` -static function on the minimal RxPlayer build, like every other features. +static function on the RxPlayer build, like any other feature. ```js import RxPlayer from "rx-player/minimal"; diff --git a/doc/api/Miscellaneous/Debug_Element.md b/doc/api/Miscellaneous/Debug_Element.md index 42699f0d32..34a89d5a15 100644 --- a/doc/api/Miscellaneous/Debug_Element.md +++ b/doc/api/Miscellaneous/Debug_Element.md @@ -27,13 +27,17 @@ Using one directly defined in the RxPlayer API instead allows to: This feature is not present in default builds to prevent adding unnecessary code to codebases that don't need it. -As such, to add it, you will need to rely on the [minimal](../../Getting_Started/Minimal_Player.md) -build of the RxPlayer and you will need to add the -`DEBUG_ELEMENT` experimental feature: +As such, to add it, you will need to add the `DEBUG_ELEMENT` experimental +feature: ```js +// Import the RxPlayer +// (here through the "minimal" build, though it doesn't change for other builds) import RxPlayer from "rx-player/minimal"; + +// Import the feature import { DEBUG_ELEMENT } from "rx-player/experimental/features"; +// Attach the feature to imported RxPlayer RxPlayer.addFeatures([DEBUG_ELEMENT]); ``` diff --git a/doc/api/Miscellaneous/Local_Contents.md b/doc/api/Miscellaneous/Local_Contents.md index f6bb5f4705..c3c739edf4 100644 --- a/doc/api/Miscellaneous/Local_Contents.md +++ b/doc/api/Miscellaneous/Local_Contents.md @@ -59,37 +59,20 @@ More infos on the `manifestLoader` can be found The `"LOCAL_MANIFEST"` feature is not included in the default RxPlayer build. -There's two way you can import it, depending on if you're relying on the minimal -version or if you prefer to make use of environment variables and build the -player manually. - -#### Through the minimal version of the RxPlayer - -If you're using the "minimal" version of the RxPlayer (through the -`"rx-player/minimal"` import), you will need to import the `LOCAL_MANIFEST` -experimental feature: - +You will need to import the `LOCAL_MANIFEST` experimental feature: ```js +// Import the RxPlayer +// (here through the "minimal" build, though it doesn't change for other builds) import RxPlayer from "rx-player/minimal"; + +// Import the `LOCAL_MANIFEST` feature import { LOCAL_MANIFEST } from "rx-player/experimental/features"; RxPlayer.addFeatures([LOCAL_MANIFEST]); ``` -#### Through environment variables - -If you don't want to go the minimal version's route and you have no problem with -building yourself a new version of the RxPlayer, you can make use of environment -variables to activate it. - -This can be done through the `RXP_LOCAL_MANIFEST` environment variable, which -you have to set to `true`: - -```sh -RXP_LOCAL_MANIFEST=true npm run build:min -``` - -More information about any of that can be found in the [minimal player documentation](../../Getting_Started/Minimal_Player.md). +More information on features [in the corresponding documentation +page](../RxPlayer_Features.md). ## The Manifest format diff --git a/doc/api/Miscellaneous/Local_Manifest_v0.1.md b/doc/api/Miscellaneous/Local_Manifest_v0.1.md index 4bc45c71eb..b4fba5344c 100644 --- a/doc/api/Miscellaneous/Local_Manifest_v0.1.md +++ b/doc/api/Miscellaneous/Local_Manifest_v0.1.md @@ -67,37 +67,20 @@ More infos on the `manifestLoader` can be found The `"LOCAL_MANIFEST"` feature is not included in the default RxPlayer build. -There's two way you can import it, depending on if you're relying on the minimal -version or if you prefer to make use of environment variables and build the -player manually. - -#### Through the minimal version of the RxPlayer - -If you're using the "minimal" version of the RxPlayer (through the -`"rx-player/minimal"` import), you will need to import the `LOCAL_MANIFEST` -experimental feature: - +You will need to import the `LOCAL_MANIFEST` experimental feature: ```js +// Import the RxPlayer +// (here through the "minimal" build, though it doesn't change for other builds) import RxPlayer from "rx-player/minimal"; + +// Import the `LOCAL_MANIFEST` feature import { LOCAL_MANIFEST } from "rx-player/experimental/features"; RxPlayer.addFeatures([LOCAL_MANIFEST]); ``` -#### Through environment variables - -If you don't want to go the minimal version's route and you have no problem with -building yourself a new version of the RxPlayer, you can make use of environment -variables to activate it. - -This can be done through the `RXP_LOCAL_MANIFEST` environment variable, which -you have to set to `true`: - -```sh -RXP_LOCAL_MANIFEST=true npm run build:min -``` - -More information about any of that can be found in the [minimal player documentation](../../Getting_Started/Minimal_Player.md). +More information on features [in the corresponding documentation +page](../RxPlayer_Features.md). ## The Manifest format diff --git a/doc/api/Miscellaneous/MetaPlaylist.md b/doc/api/Miscellaneous/MetaPlaylist.md index faabf968a1..6772cd8f31 100644 --- a/doc/api/Miscellaneous/MetaPlaylist.md +++ b/doc/api/Miscellaneous/MetaPlaylist.md @@ -225,44 +225,20 @@ should be the same value than the `startTime` of the following one). The `"METAPLAYLIST"` feature is not included in the default RxPlayer build. -There's two way you can import it, depending on if you're relying on the minimal -version or if you prefer to make use of environment variables and build the -player manually. - -#### Through the minimal version of the RxPlayer - -If you're using the "minimal" version of the RxPlayer (through the -`"rx-player/minimal"` import), you will need to import: - -- the `METAPLAYLIST` experimental feature -- every transport protocol you might want to use. - -For example if you need to use MetaPlaylist with both Smooth and DASH contents, -you have to import at least all three as such: - +You will need to import the `LOCAL_MANIFEST` experimental feature: ```js +// Import the RxPlayer +// (here through the "minimal" build, though it doesn't change for other builds) import RxPlayer from "rx-player/minimal"; -import { METAPLAYLIST } from "rx-player/experimental/features"; -import { DASH, SMOOTH } from "rx-player/features"; -RxPlayer.addFeatures([METAPLAYLIST, DASH, SMOOTH]); -``` - -#### Through environment variables - -If you don't want to go the minimal version's route and you have no problem with -building yourself a new version of the RxPlayer, you can make use of environment -variables to activate it. - -This can be done through the `RXP_METAPLAYLIST` environment variable, which you -have to set to `true`: +// Import the `METAPLAYLIST` feature +import { METAPLAYLIST } from "rx-player/experimental/features"; -```sh -RXP_METAPLAYLIST=true npm run build:min +RxPlayer.addFeatures([METAPLAYLIST]); ``` -More information about any of that can be found in the [minimal player -documentation](../../Getting_Started/Minimal_Player.md). +More information on features [in the corresponding documentation +page](../RxPlayer_Features.md). ### Loading a MetaPlaylist content diff --git a/doc/api/RxPlayer_Features.md b/doc/api/RxPlayer_Features.md new file mode 100644 index 0000000000..098eedbe7a --- /dev/null +++ b/doc/api/RxPlayer_Features.md @@ -0,0 +1,285 @@ +# RxPlayer Features + +## Overview + +The RxPlayer has this concept of "features" which are functionalities which may +or may not be included to your build. + +This allows to reduce bundle size by not including features you don't use, like +parsers for subtitles formats you don't depend on. + +Which features you will need to import will depend on what RxPlayer's build you +rely on; + +- If you import the default RxPlayer build (e.g. through an + `import RxPlayer from "rx-player` import), you will obtain an RxPlayer with most + features, which should be sufficient for most use-cases. It already includes the + following features (description of each available in the next chapter): + + - `SMOOTH` + - `DASH` + - `DIRECTFILE` + - `EME` + - `NATIVE_SRT_PARSER` + - `NATIVE_VTT_PARSER` + - `NATIVE_TTML_PARSER` + - `NATIVE_SAMI_PARSER` + - `HTML_SRT_PARSER` + - `HTML_VTT_PARSER` + - `HTML_TTML_PARSER` + - `HTML_SAMI_PARSER` + +- If you import the [RxPlayer's minimal + build](../Getting_Started/Minimal_Player.md) however (e.g. through an + `import RxPlayer from "rx-player/minimal` import), you will + obtain an RxPlayer with no feature by default. + In that case, you will probably need to add the features you want. + +## `addFeatures` static method + +New features can be added by calling the [`addFeatures` static +method](../api/RxPlayer_Features.md): +```js +import RxPlayer from "rx-player/minimal"; +import { DASH } from "rx-player/features"; + +RxPlayer.addFeatures([DASH]); +``` + +## Features list + +Features, which are variables imported from the `"rx-player/features"` path, +are all objects declared in upper-case. + +Here is the anotated exhaustive list (notes are at the bottom of the table): + +| Feature | Description of the feature | +| --------------------------- | --------------------------------------------------------- | +| `SMOOTH` | Enable Smooth streaming (HSS) playback | +| `DASH` [1] | Enable DASH playback using a JavaScript-based MPD parser | +| `DIRECTFILE` | Enable playback of "directfile" contents | +| `EME` | Enable playback of encrypted contents | +| `NATIVE_SRT_PARSER` [2] | Parse SRT text tracks for the `"native"` `textTrackMode` | +| `NATIVE_VTT_PARSER` [2] | Parse VTT text tracks for the `"native"` `textTrackMode` | +| `NATIVE_TTML_PARSER` [2] | Parse TTML text tracks for the `"native"` `textTrackMode` | +| `NATIVE_SAMI_PARSER` [2] | Parse SAMI text tracks for the `"native"` `textTrackMode` | +| `HTML_SRT_PARSER` [2] | Parse SRT text tracks for the `"html"` `textTrackMode` | +| `HTML_VTT_PARSER` [2] | Parse VTT text tracks for the `"html"` `textTrackMode` | +| `HTML_TTML_PARSER` [2] | Parse TTML text tracks for the `"html"` `textTrackMode` | +| `HTML_SAMI_PARSER` [2] | Parse SAMI text tracks for the `"html"` `textTrackMode` | +| `DEBUG_ELEMENT` [3] | Allows to use the `createDebugElement` RxPlayer method | +| `DASH_WASM` [1] [4] | Enable DASH playback using a WebAssembly-based MPD parser | +| `LOCAL_MANIFEST` [4] | Enable playback of "local" contents | +| `METAPLAYLIST` [4] | Enable playback of "metaplaylist" contents | +| `NATIVE_TEXT_BUFFER` [5] | (Deprecated) Base for the `"native"` `textTrackMode`. | +| `HTML_TEXT_BUFFER` [5] | (Deprecated) Base for the `"html"` `textTrackMode`. | + +--- + +**Notes**: + +**[1]**: In cases where both the `DASH` and `DASH_WASM` features are added +(which are both parsers for DASH contents), the RxPlayer will default using the +WebAssembly parser (provided by `DASH_WASM`) and fallback on the JavaScript +parser (provided by `DASH`) when it cannot do so. + +**[2]**: The `"native"` and `"html"` `textTrackMode` are options set when +loading a new content through the [`loadVideo` method](../api/Loading_a_Content.md). +To help you choose between those two: + - The `"native"` mode relies on HTMLTrackElement (`` tags) to display + subtitles. + This does not need any setup but may lead to poorly stylized subtitles. + You may rely on this if you don't need advanced subtitles stylization. + - The `"html"` mode relies on regular HTMLElement (like `
` and such) to + display subtitles. + It allows more powerful stylization but will need a parent + `textTrackElement` to also be provided on that same `loadVideo` call (as + documented [in the corresponding API documentation + page](../api/Loading_a_Content.md). + + +**[3]**: Those features are experimental. They should be imported from +`rx-player/experimental/features`. + +**[4]**: The `DASH_WASM` feature has its own setup, detailed in the +[corresponding documentation page](../api/Miscellaneous/DASH_WASM_Parser.md). + +**[5]**: Both the `NATIVE_TEXT_BUFFER` and `HTML_TEXT_BUFFER` features are +deprecated. They are already implicitly imported when parsing any of the +corresponding text parsers. + +--- + +## Examples + +To help you choose your features, are some examples that represents common +usecases. + +### unencrypted DASH contents with native webVTT subtitles + +```js +import RxPlayer from "rx-player/minimal"; +import { + DASH, + NATIVE_VTT_PARSER, +} from "rx-player/features"; + +RxPlayer.addFeatures([DASH, NATIVE_VTT_PARSER]); +``` + +## possibly-encrypted DASH contents with HMTL webVTT and TTML subtitles + +```js +import RxPlayer from "rx-player/minimal"; +import { + DASH, + EME, + HTML_VTT_PARSER, + HTML_HTML_PARSER, +} from "rx-player/features"; + +RxPlayer.addFeatures([ + DASH, + EME, + HTML_VTT_PARSER, + HTML_TTML_PARSER, +]); +``` +## Building with environment variables (not recommended) + +### How it works + +If you don't want to or can't rely on tree shaking for your use-case but still +would like to remove features you don't want, you can also build yourself an +RxPlayer while only enabling specific features through environment variables. +The code related to the unwanted features should be removed when the final code +is minified (as the corresponding code is made unreachable). + +To be able to do this, you will need to: + 1. pull the RxPlayer's repository (for example, through a `git clone`) + 2. install its dependencies (for example by calling `npm install` in that + repository), + 3. run its bundling script (`npm run build:min`) with the right environment + variables. + +To avoid any conflict with other environment variables, they all are named +`RXP_`. + +For example, the following will remove all code related to Microsoft Smooth +Streaming from the build: + +```sh +RXP_SMOOTH=false npm run build:min +``` + +### List of environment variables + +#### RXP_SMOOTH + +True by default. If set to "false", all code relative to HSS streaming will be +ignored during a build. + +#### RXP_DASH + +True by default. If set to "false", all code relative to DASH streaming will be +ignored during a build. + +#### RXP_DIRECTFILE + +True by default. If set to "false", all code relative to directfile streaming +will be ignored during a build. + +#### RXP_LOCAL_MANIFEST + +False by default. If set to "true", all code relative to the "local" transport +(to be able to play content offline for example) will be included during a +build. + +#### RXP_METAPLAYLIST + +False by default. If set to "true", all code relative to metaplaylist streaming +will be included during a build. + +#### RXP_DEBUG_ELEMENT + +False by default. If set to "true", the method RxPlayer's `createDebugElement` +method will be callable. + +#### RXP_EME + +True by default. If set to "false", all code relative to encrypted contents will +be ignored during a build. + +#### RXP_NATIVE_TTML + +True by default. If set to "false", all code relative to TTML parsing for native +text tracks will be ignored during a build. + +#### RXP_NATIVE_SAMI + +True by default. If set to "false", all code relative to SAMI parsing for native +text tracks will be ignored during a build. + +#### RXP_NATIVE_VTT + +True by default. If set to "false", all code relative to VTT parsing for native +text tracks will be ignored during a build. + +#### RXP_NATIVE_SRT + +True by default. If set to "false", all code relative to SRT parsing for native +text tracks will be ignored during a build. + +#### RXP_HTML_TTML + +True by default. If set to "false", all code relative to TTML parsing for html +text tracks [1] will be ignored during a build. + +#### RXP_HTML_SAMI + +True by default. If set to "false", all code relative to SAMI parsing for html +text tracks [1] will be ignored during a build. + +#### RXP_HTML_VTT + +True by default. If set to "false", all code relative to VTT parsing for html +text tracks [1] will be ignored during a build. + +#### RXP_HTML_SRT + +True by default. If set to "false", all code relative to SRT parsing for html +text tracks [1] will be ignored during a build. + +#### RXP_BIF_PARSER + +True by default. If set to "false", all code relative to BIF image parsing will +be ignored during a build. + +#### RXP_BAREBONE + +If set to true, no feature is activated by default and all other environment +variables are considered as false by default (unless set). + +For example, to only activate DASH, you could do: + +```sh +RXP_BAREBONE=true RXP_DASH=true npm run build:min +``` + +#### RXP_ENV + +Either "production" or "development". "production" as a default. +In the "development" case: + +- logs will be activated +- the code will be less tolerant towards unwanted behavior +- the code will be less optimized + +--- + +**Notes**: + +DOM element instead of a `` (the latter here being called "native") tag +for a richer formatting. + +--- diff --git a/src/core/api/public_api.ts b/src/core/api/public_api.ts index 2f02c60e98..8599fc2e85 100644 --- a/src/core/api/public_api.ts +++ b/src/core/api/public_api.ts @@ -37,7 +37,10 @@ import { IErrorType, MediaError, } from "../../errors"; -import features from "../../features"; +import features, { + addFeatures, + IFeature, +} from "../../features"; import log from "../../log"; import Manifest, { Adaptation, @@ -101,7 +104,6 @@ import { getCurrentKeySystem, } from "../decrypt"; import { ContentInitializer } from "../init"; -import MediaSourceContentInitializer from "../init/media_source_content_initializer"; import SegmentBuffersStore, { IBufferedChunk, IBufferType, @@ -341,6 +343,14 @@ class Player extends EventEmitter { log.setLevel(logLevel); } + /** + * Add feature(s) to the RxPlayer. + * @param {Array.} featureList - Features wanted. + */ + static addFeatures(featureList : IFeature[]) : void { + addFeatures(featureList); + } + /** * @constructor * @param {Object} options @@ -673,6 +683,10 @@ class Player extends EventEmitter { throw new Error(`transport "${transport}" not supported`); } + if (features.mediaSourceInit === null) { + throw new Error("MediaSource streaming not supported"); + } + const transportPipelines = transportFn(transportOptions); const { offlineRetry, @@ -762,7 +776,7 @@ class Player extends EventEmitter { requestTimeout: segmentRequestTimeout, maxRetryOffline: offlineRetry }; - initializer = new MediaSourceContentInitializer({ + initializer = new features.mediaSourceInit({ adaptiveOptions, autoPlay, bufferOptions, diff --git a/src/core/init/index.ts b/src/core/init/index.ts index 33479d4ac7..e44665cee5 100644 --- a/src/core/init/index.ts +++ b/src/core/init/index.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import MediaSourceContentInitializer, { - IInitializeArguments, -} from "./media_source_content_initializer"; -export * from "./types"; - -export default MediaSourceContentInitializer; -export { IInitializeArguments }; +export { + ContentInitializer, + IContentInitializerEvents, + IAdaptationChangeEventPayload, + IStallingSituation, +} from "./types"; diff --git a/src/experimental/features/__tests__/dash_wasm.test.ts b/src/experimental/features/__tests__/dash_wasm.test.ts index 7122b14899..c4ebe73517 100644 --- a/src/experimental/features/__tests__/dash_wasm.test.ts +++ b/src/experimental/features/__tests__/dash_wasm.test.ts @@ -14,18 +14,11 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - +import { IFeaturesObject } from "../../../features/types"; import DashWasmParser from "../../../parsers/manifest/dash/wasm-parser"; import DASHFeature from "../../../transports/dash"; import dashWasmFeature from "../dash_wasm"; -jest.mock("../../../transports/dash", () => ({ - __esModule: true as const, - default: jest.fn(), -})); - describe("Features list - DASH WASM Parser", () => { it("should add DASH WASM parser in the current features", () => { const mockInitialize = jest.spyOn(DashWasmParser.prototype, "initialize") @@ -40,10 +33,9 @@ describe("Features list - DASH WASM Parser", () => { expect(mockInitialize).toHaveBeenCalledTimes(1); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = { transports: {}, - dashParsers: { js: null, - wasm: null } }; + const featureObject = { transports: {}, + dashParsers: { js: null, + wasm: null } } as unknown as IFeaturesObject; DASH_WASM._addFeature(featureObject); expect(featureObject.transports).toEqual({ dash: DASHFeature }); expect(featureObject.dashParsers.js).toEqual(null); diff --git a/src/experimental/features/__tests__/debug_element.test.ts b/src/experimental/features/__tests__/debug_element.test.ts index b1b8d53084..20f5f5f4c4 100644 --- a/src/experimental/features/__tests__/debug_element.test.ts +++ b/src/experimental/features/__tests__/debug_element.test.ts @@ -1,26 +1,12 @@ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-var-requires */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ +import createDebugElement from "../../../core/api/debug"; +import { IFeaturesObject } from "../../../features/types"; +import addDebugElementFeature from "../debug_element"; describe("Features list - DEBUG_ELEMENT", () => { - beforeEach(() => { - jest.resetModules(); - }); - it("should add DEBUG_ELEMENT in the current features", () => { - const feat = {}; - jest.mock("../../../core/api/debug", () => ({ __esModule: true as const, - default: feat })); - const addFeature = jest.requireActual("../debug_element").default; - - const featureObject : { - createDebugElement? : unknown; - } = {}; - addFeature(featureObject); - expect(featureObject).toEqual({ createDebugElement: {} }); - expect(featureObject.createDebugElement).toBe(feat); + const featureObject = {} as unknown as IFeaturesObject; + addDebugElementFeature(featureObject); + expect(featureObject).toEqual({ createDebugElement }); + expect(featureObject.createDebugElement).toBe(createDebugElement); }); }); diff --git a/src/experimental/features/__tests__/local.test.ts b/src/experimental/features/__tests__/local.test.ts index 2a7858aa49..3fadbc70b2 100644 --- a/src/experimental/features/__tests__/local.test.ts +++ b/src/experimental/features/__tests__/local.test.ts @@ -14,31 +14,22 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-var-requires */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable-next-line max-len */ +import MediaSourceContentInitializer from "../../../core/init/media_source_content_initializer"; +import { IFeaturesObject } from "../../../features/types"; +import local from "../../../transports/local"; +import addLocalManifestFeature from "../local"; describe("Features list - LOCAL_MANIFEST", () => { - beforeEach(() => { - jest.resetModules(); - }); - it("should add LOCAL_MANIFEST in the current features", () => { - const feat = {}; - jest.mock("../../../transports/local", () => ({ __esModule: true as const, - default: feat })); - const addDASHFeature = jest.requireActual("../local").default; - - const featureObject : { - transports : { [featureName : string] : unknown }; - } = { transports: {} }; - - addDASHFeature(featureObject); - - expect(featureObject).toEqual({ transports: { local: {} } }); - expect(featureObject.transports.local).toBe(feat); + const featureObject = { transports: {} } as unknown as IFeaturesObject; + addLocalManifestFeature(featureObject); + expect(featureObject).toEqual({ + transports: { local }, + mediaSourceInit: MediaSourceContentInitializer, + }); + expect(featureObject.transports.local).toBe(local); + expect(featureObject.mediaSourceInit) + .toBe(MediaSourceContentInitializer); }); }); diff --git a/src/experimental/features/__tests__/metaplaylist.test.ts b/src/experimental/features/__tests__/metaplaylist.test.ts index 847dc8e11a..582faace17 100644 --- a/src/experimental/features/__tests__/metaplaylist.test.ts +++ b/src/experimental/features/__tests__/metaplaylist.test.ts @@ -14,29 +14,22 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-var-requires */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable-next-line max-len */ +import MediaSourceContentInitializer from "../../../core/init/media_source_content_initializer"; +import { IFeaturesObject } from "../../../features/types"; +import metaplaylist from "../../../transports/metaplaylist"; +import addLocalManifestFeature from "../metaplaylist"; describe("Features list - METAPLAYLIST", () => { - beforeEach(() => { - jest.resetModules(); - }); - it("should add METAPLAYLIST in the current features", () => { - const feat = {}; - jest.mock("../../../transports/metaplaylist", () => ({ __esModule: true as const, - default: feat })); - const addDASHFeature = jest.requireActual("../metaplaylist").default; - - const featureObject : { - transports : { [featureName : string] : unknown }; - } = { transports: {} }; - addDASHFeature(featureObject); - expect(featureObject).toEqual({ transports: { metaplaylist: {} } }); - expect(featureObject.transports.metaplaylist).toBe(feat); + const featureObject = { transports: {} } as unknown as IFeaturesObject; + addLocalManifestFeature(featureObject); + expect(featureObject).toEqual({ + transports: { metaplaylist }, + mediaSourceInit: MediaSourceContentInitializer, + }); + expect(featureObject.transports.metaplaylist).toBe(metaplaylist); + expect(featureObject.mediaSourceInit) + .toBe(MediaSourceContentInitializer); }); }); diff --git a/src/experimental/features/dash_wasm.ts b/src/experimental/features/dash_wasm.ts index 1a13c0206e..df1fc344ae 100644 --- a/src/experimental/features/dash_wasm.ts +++ b/src/experimental/features/dash_wasm.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +// eslint-disable-next-line max-len +import MediaSourceContentInitializer from "../../core/init/media_source_content_initializer"; import { IFeaturesObject } from "../../features/types"; import DashWasmParser, { IDashWasmParserOptions, @@ -27,6 +29,7 @@ const dashWasmFeature = { features.transports.dash = dash; } features.dashParsers.wasm = dashWasmParser; + features.mediaSourceInit = MediaSourceContentInitializer; }, initialize(opts : IDashWasmParserOptions) : Promise { diff --git a/src/experimental/features/index.ts b/src/experimental/features/index.ts index c13f264cbd..d7faf13db5 100644 --- a/src/experimental/features/index.ts +++ b/src/experimental/features/index.ts @@ -16,5 +16,4 @@ export { DASH_WASM } from "./dash_wasm"; export { DEBUG_ELEMENT } from "./debug_element"; -export { LOCAL_MANIFEST } from "./local"; export { METAPLAYLIST } from "./metaplaylist"; diff --git a/src/experimental/features/local.ts b/src/experimental/features/local.ts index 532660b6a0..b52287608e 100644 --- a/src/experimental/features/local.ts +++ b/src/experimental/features/local.ts @@ -14,11 +14,14 @@ * limitations under the License. */ +// eslint-disable-next-line max-len +import MediaSourceContentInitializer from "../../core/init/media_source_content_initializer"; import { IFeaturesObject } from "../../features/types"; import local from "../../transports/local"; function addLocalManifestFeature(features: IFeaturesObject) : void { features.transports.local = local; + features.mediaSourceInit = MediaSourceContentInitializer; } export { addLocalManifestFeature as LOCAL_MANIFEST }; diff --git a/src/experimental/features/metaplaylist.ts b/src/experimental/features/metaplaylist.ts index 60181afc75..bea2ef8f66 100644 --- a/src/experimental/features/metaplaylist.ts +++ b/src/experimental/features/metaplaylist.ts @@ -14,11 +14,14 @@ * limitations under the License. */ +// eslint-disable-next-line max-len +import MediaSourceContentInitializer from "../../core/init/media_source_content_initializer"; import { IFeaturesObject } from "../../features/types"; import metaplaylist from "../../transports/metaplaylist"; function addMetaPlaylistFeature(features: IFeaturesObject) : void { features.transports.metaplaylist = metaplaylist; + features.mediaSourceInit = MediaSourceContentInitializer; } export { addMetaPlaylistFeature as METAPLAYLIST }; diff --git a/src/features/__tests__/initialize_features.test.ts b/src/features/__tests__/initialize_features.test.ts index 80ba481f27..f9a650d7b9 100644 --- a/src/features/__tests__/initialize_features.test.ts +++ b/src/features/__tests__/initialize_features.test.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { IFeaturesObject } from "../types"; + /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-var-requires */ @@ -86,8 +88,9 @@ describe("Features - initializeFeaturesObject", () => { NATIVE_VTT: 1, SMOOTH: 1, }; - const feat = { + const feat : IFeaturesObject = { transports: {}, + mediaSourceInit: null, dashParsers: { js: null, wasm: null }, imageBuffer: null, imageParser: null, @@ -97,6 +100,7 @@ describe("Features - initializeFeaturesObject", () => { htmlTextTracksParsers: {}, decrypt: null, directfile: null, + createDebugElement: null, }; jest.mock("../features_object", () => ({ __esModule: true as const, @@ -116,6 +120,8 @@ describe("Features - initializeFeaturesObject", () => { wasm: null, }, decrypt: jest.requireActual("../../core/decrypt/index").default, + mediaSourceInit: jest.requireActual("../../core/init/media_source_content_initializer") + .default, createDebugElement: jest.requireActual("../../core/api/debug").default, directfile: { initDirectFile: jest.requireActual("../../core/init/directfile_content_initializer").default, @@ -149,6 +155,179 @@ describe("Features - initializeFeaturesObject", () => { delete win.__FEATURES__; }); + it("should add MediaSource-specific features if DASH is added", () => { + win.__FEATURES__ = { + IS_DISABLED: 0, + IS_ENABLED: 1, + + BIF_PARSER: 0, + DASH: 1, + DIRECTFILE: 0, + EME: 0, + HTML_SAMI: 0, + HTML_SRT: 0, + HTML_TTML: 0, + HTML_VTT: 0, + LOCAL_MANIFEST: 0, + METAPLAYLIST: 0, + DEBUG_ELEMENT: 0, + NATIVE_SAMI: 0, + NATIVE_SRT: 0, + NATIVE_TTML: 0, + NATIVE_VTT: 0, + SMOOTH: 0, + }; + const feat = { + transports: {}, + dashParsers: { js: null, wasm: null }, + }; + jest.mock("../features_object", () => ({ + __esModule: true as const, + default: feat, + })); + const initializeFeaturesObject = jest.requireActual("../initialize_features").default; + initializeFeaturesObject(); + expect(feat).toEqual({ + mediaSourceInit: jest.requireActual("../../core/init/media_source_content_initializer") + .default, + transports: { + dash: jest.requireActual("../../transports/dash/index").default, + }, + dashParsers: { + js: jest.requireActual("../../parsers/manifest/dash/js-parser").default, + wasm: null, + }, + }); + + delete win.__FEATURES__; + }); + + it("should add MediaSource-specific features if SMOOTH is added", () => { + win.__FEATURES__ = { + IS_DISABLED: 0, + IS_ENABLED: 1, + + BIF_PARSER: 0, + DASH: 0, + DIRECTFILE: 0, + EME: 0, + HTML_SAMI: 0, + HTML_SRT: 0, + HTML_TTML: 0, + HTML_VTT: 0, + LOCAL_MANIFEST: 0, + METAPLAYLIST: 0, + DEBUG_ELEMENT: 0, + NATIVE_SAMI: 0, + NATIVE_SRT: 0, + NATIVE_TTML: 0, + NATIVE_VTT: 0, + SMOOTH: 1, + }; + const feat = { + transports: {}, + }; + jest.mock("../features_object", () => ({ + __esModule: true as const, + default: feat, + })); + const initializeFeaturesObject = jest.requireActual("../initialize_features").default; + initializeFeaturesObject(); + expect(feat).toEqual({ + mediaSourceInit: jest.requireActual("../../core/init/media_source_content_initializer") + .default, + transports: { + smooth: jest.requireActual("../../transports/smooth/index").default, + }, + }); + + delete win.__FEATURES__; + }); + + it("should add MediaSource-specific features if LOCAL_MANIFEST is added", () => { + win.__FEATURES__ = { + IS_DISABLED: 0, + IS_ENABLED: 1, + + BIF_PARSER: 0, + DASH: 0, + DIRECTFILE: 0, + EME: 0, + HTML_SAMI: 0, + HTML_SRT: 0, + HTML_TTML: 0, + HTML_VTT: 0, + LOCAL_MANIFEST: 1, + METAPLAYLIST: 0, + DEBUG_ELEMENT: 0, + NATIVE_SAMI: 0, + NATIVE_SRT: 0, + NATIVE_TTML: 0, + NATIVE_VTT: 0, + SMOOTH: 0, + }; + const feat = { + transports: {}, + }; + jest.mock("../features_object", () => ({ + __esModule: true as const, + default: feat, + })); + const initializeFeaturesObject = jest.requireActual("../initialize_features").default; + initializeFeaturesObject(); + expect(feat).toEqual({ + mediaSourceInit: jest.requireActual("../../core/init/media_source_content_initializer") + .default, + transports: { + local: jest.requireActual("../../transports/local/index").default, + }, + }); + + delete win.__FEATURES__; + }); + + it("should add MediaSource-specific features if METAPLAYLIST is added", () => { + win.__FEATURES__ = { + IS_DISABLED: 0, + IS_ENABLED: 1, + + BIF_PARSER: 0, + DASH: 0, + DIRECTFILE: 0, + EME: 0, + HTML_SAMI: 0, + HTML_SRT: 0, + HTML_TTML: 0, + HTML_VTT: 0, + LOCAL_MANIFEST: 0, + METAPLAYLIST: 1, + DEBUG_ELEMENT: 0, + NATIVE_SAMI: 0, + NATIVE_SRT: 0, + NATIVE_TTML: 0, + NATIVE_VTT: 0, + SMOOTH: 0, + }; + const feat = { + transports: {}, + }; + jest.mock("../features_object", () => ({ + __esModule: true as const, + default: feat, + })); + const initializeFeaturesObject = jest.requireActual("../initialize_features").default; + initializeFeaturesObject(); + expect(feat).toEqual({ + mediaSourceInit: jest.requireActual("../../core/init/media_source_content_initializer") + .default, + transports: { + metaplaylist: jest.requireActual("../../transports/metaplaylist/index").default, + }, + }); + + delete win.__FEATURES__; + }); + it("should add the html text buffer if the html vtt parser is added", () => { win.__FEATURES__ = { IS_DISABLED: 0, diff --git a/src/features/features_object.ts b/src/features/features_object.ts index 59a228a8a4..6730e5cfc5 100644 --- a/src/features/features_object.ts +++ b/src/features/features_object.ts @@ -29,6 +29,7 @@ const features : IFeaturesObject = { dashParsers: { wasm: null, htmlTextTracksParsers: {}, imageBuffer: null, imageParser: null, + mediaSourceInit: null, nativeTextTracksBuffer: null, nativeTextTracksParsers: {}, transports: {} }; diff --git a/src/features/initialize_features.ts b/src/features/initialize_features.ts index ca6f86e743..ee5de4964c 100644 --- a/src/features/initialize_features.ts +++ b/src/features/initialize_features.ts @@ -21,9 +21,18 @@ import features from "./features_object"; /** - * Selects the features to include based on environment variables. + * Selects the features to include. */ export default function initializeFeaturesObject() : void { + const HAS_MEDIA_SOURCE = + __FEATURES__.SMOOTH as number === __FEATURES__.IS_ENABLED as number || + __FEATURES__.DASH as number === __FEATURES__.IS_ENABLED as number || + __FEATURES__.LOCAL_MANIFEST as number === __FEATURES__.IS_ENABLED as number || + __FEATURES__.METAPLAYLIST as number === __FEATURES__.IS_ENABLED as number; + if (HAS_MEDIA_SOURCE) { + features.mediaSourceInit = require("../core/init/media_source_content_initializer.ts") + .default; + } if (__FEATURES__.EME as number === __FEATURES__.IS_ENABLED as number) { features.decrypt = require("../core/decrypt/index.ts").default; } diff --git a/src/features/list/__tests__/bif_parser.test.ts b/src/features/list/__tests__/bif_parser.test.ts index e80170a45b..33b7179686 100644 --- a/src/features/list/__tests__/bif_parser.test.ts +++ b/src/features/list/__tests__/bif_parser.test.ts @@ -14,21 +14,13 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - import bifParser from "../../../parsers/images/bif"; +import { IFeaturesObject } from "../../types"; import addBIFParserFeature from "../bif_parser"; -jest.mock("../../../parsers/images/bif", () => ({ - __esModule: true as const, - default: jest.fn(), -})); - describe("Features list - BIF Parser", () => { it("should add the BIF Parser in the current features", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = {}; + const featureObject = {} as unknown as IFeaturesObject; addBIFParserFeature(featureObject); expect(featureObject).toEqual({ imageParser: bifParser }); expect(featureObject.imageParser).toBe(bifParser); diff --git a/src/features/list/__tests__/dash.test.ts b/src/features/list/__tests__/dash.test.ts index 80e313ddd0..2bc7b5b8b0 100644 --- a/src/features/list/__tests__/dash.test.ts +++ b/src/features/list/__tests__/dash.test.ts @@ -14,28 +14,28 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - +/* eslint-disable-next-line max-len */ +import MediaSourceContentInitializer from "../../../core/init/media_source_content_initializer"; import dashJsParser from "../../../parsers/manifest/dash/js-parser"; import DASHFeature from "../../../transports/dash"; +import { IFeaturesObject } from "../../types"; import addDASHFeature from "../dash"; -jest.mock("../../../transports/dash", () => ({ - __esModule: true as const, - default: jest.fn(), -})); - describe("Features list - DASH", () => { it("should add DASH in the current features", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = { transports: {}, - dashParsers: { js: null, - wasm: null } }; + const featureObject = { + transports: {}, + dashParsers: { js: null, wasm: null }, + mediaSourceInit: null, + } as unknown as IFeaturesObject; addDASHFeature(featureObject); - expect(featureObject).toEqual({ transports: { dash: DASHFeature }, - dashParsers: { js: dashJsParser, - wasm: null } }); + expect(featureObject).toEqual({ + transports: { dash: DASHFeature }, + dashParsers: { js: dashJsParser, wasm: null }, + mediaSourceInit: MediaSourceContentInitializer, + }); expect(featureObject.transports.dash).toBe(DASHFeature); + expect(featureObject.mediaSourceInit) + .toBe(MediaSourceContentInitializer); }); }); diff --git a/src/features/list/__tests__/directfile.test.ts b/src/features/list/__tests__/directfile.test.ts index a8305a6afb..e96dec1fbf 100644 --- a/src/features/list/__tests__/directfile.test.ts +++ b/src/features/list/__tests__/directfile.test.ts @@ -14,31 +14,22 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - // eslint-disable-next-line max-len -import mediaElementTrackChoiceManager from "../../../core/api/tracks_management/media_element_track_choice_manager"; +import MediaElementTrackChoiceManager from "../../../core/api/tracks_management/media_element_track_choice_manager"; import initDirectFile from "../../../core/init/directfile_content_initializer"; +import { IFeaturesObject } from "../../types"; import addDirectfileFeature from "../directfile"; -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -jest.mock("../../../core/init/directfile_content_initializer", () => ({ - __esModule: true as const, - default: jest.fn(), -})); - describe("Features list - Directfile", () => { it("should add Directfile in the current features", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = {}; + const featureObject = {} as unknown as IFeaturesObject; addDirectfileFeature(featureObject); expect(featureObject).toEqual({ directfile: { initDirectFile, - mediaElementTrackChoiceManager }, + mediaElementTrackChoiceManager: MediaElementTrackChoiceManager }, }); - expect(featureObject.directfile.initDirectFile).toEqual(initDirectFile); - expect(featureObject.directfile.mediaElementTrackChoiceManager) - .toEqual(mediaElementTrackChoiceManager); + expect(featureObject.directfile?.initDirectFile).toEqual(initDirectFile); + expect(featureObject.directfile?.mediaElementTrackChoiceManager) + .toEqual(MediaElementTrackChoiceManager); }); }); diff --git a/src/features/list/__tests__/eme.test.ts b/src/features/list/__tests__/eme.test.ts index 258feefa91..84dc220e56 100644 --- a/src/features/list/__tests__/eme.test.ts +++ b/src/features/list/__tests__/eme.test.ts @@ -14,21 +14,13 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - import ContentDecryptor from "../../../core/decrypt"; +import { IFeaturesObject } from "../../types"; import addEMEFeature from "../eme"; -jest.mock("../../../core/decrypt", () => ({ - __esModule: true as const, - default: jest.fn(), -})); - describe("Features list - EME", () => { it("should add the ContentDecryptor in the current features", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = {}; + const featureObject = {} as unknown as IFeaturesObject; addEMEFeature(featureObject); expect(featureObject).toEqual({ decrypt: ContentDecryptor }); expect(featureObject.decrypt).toBe(ContentDecryptor); diff --git a/src/features/list/__tests__/html_sami_parser.test.ts b/src/features/list/__tests__/html_sami_parser.test.ts index a3532c77f3..6aae2d87a1 100644 --- a/src/features/list/__tests__/html_sami_parser.test.ts +++ b/src/features/list/__tests__/html_sami_parser.test.ts @@ -14,24 +14,19 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - +// eslint-disable-next-line max-len +import HTMLTextSegmentBuffer from "../../../core/segment_buffers/implementations/text/html"; import samiParser from "../../../parsers/texttracks/sami/html"; -import addHTMLSAMIFeature from "../html_sami_parser"; - -jest.mock("../../../parsers/texttracks/sami/html", () => ({ - __esModule: true as const, - default: jest.fn(), -})); +import { IFeaturesObject } from "../../types"; +import addHTMLsamiFeature from "../html_sami_parser"; -describe("Features list - HTML SAMI Parser", () => { - it("should add an HTML SAMI Parser in the current features", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = { htmlTextTracksParsers: {} }; - addHTMLSAMIFeature(featureObject); +describe("Features list - HTML sami Parser", () => { + it("should add an HTML sami Parser in the current features", () => { + const featureObject = { htmlTextTracksParsers: {} } as unknown as IFeaturesObject; + addHTMLsamiFeature(featureObject); expect(featureObject).toEqual({ htmlTextTracksParsers: { sami: samiParser }, + htmlTextTracksBuffer: HTMLTextSegmentBuffer, }); expect(featureObject.htmlTextTracksParsers.sami).toBe(samiParser); }); diff --git a/src/features/list/__tests__/html_srt_parser.test.ts b/src/features/list/__tests__/html_srt_parser.test.ts index 1015760765..862c476cfc 100644 --- a/src/features/list/__tests__/html_srt_parser.test.ts +++ b/src/features/list/__tests__/html_srt_parser.test.ts @@ -14,24 +14,19 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - +// eslint-disable-next-line max-len +import HTMLTextSegmentBuffer from "../../../core/segment_buffers/implementations/text/html"; import srtParser from "../../../parsers/texttracks/srt/html"; +import { IFeaturesObject } from "../../types"; import addHTMLsrtFeature from "../html_srt_parser"; -jest.mock("../../../parsers/texttracks/srt/html", () => ({ - __esModule: true as const, - default: jest.fn(), -})); - describe("Features list - HTML srt Parser", () => { it("should add an HTML srt Parser in the current features", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = { htmlTextTracksParsers: {} }; + const featureObject = { htmlTextTracksParsers: {} } as unknown as IFeaturesObject; addHTMLsrtFeature(featureObject); expect(featureObject).toEqual({ htmlTextTracksParsers: { srt: srtParser }, + htmlTextTracksBuffer: HTMLTextSegmentBuffer, }); expect(featureObject.htmlTextTracksParsers.srt).toBe(srtParser); }); diff --git a/src/features/list/__tests__/html_text_buffer.test.ts b/src/features/list/__tests__/html_text_buffer.test.ts index 9794614e66..4ac36c95ca 100644 --- a/src/features/list/__tests__/html_text_buffer.test.ts +++ b/src/features/list/__tests__/html_text_buffer.test.ts @@ -14,25 +14,16 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ +// eslint-disable-next-line max-len +import HtmlTextSegmentBuffer from "../../../core/segment_buffers/implementations/text/native"; +import { IFeaturesObject } from "../../types"; +import addHtmlTextBuffer from "../native_text_buffer"; -/* eslint-disable max-len */ -import htmlTextTracksBuffer from "../../../core/segment_buffers/implementations/text/html"; -/* eslint-enable max-len */ -import addHTMLTextBuffer from "../html_text_buffer"; - -jest.mock("../../../core/segment_buffers/implementations/text/html", () => ({ - __esModule: true as const, - default: jest.fn(), -})); - -describe("Features list - HTML Text Buffer", () => { - it("should add an HTML Text Buffer in the current features", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = {}; - addHTMLTextBuffer(featureObject); - expect(featureObject).toEqual({ htmlTextTracksBuffer }); - expect(featureObject.htmlTextTracksBuffer).toBe(htmlTextTracksBuffer); +describe("Features list - native Text Buffer", () => { + it("should add an native Text Buffer in the current features", () => { + const featureObject = {} as unknown as IFeaturesObject; + addHtmlTextBuffer(featureObject); + expect(featureObject).toEqual({ nativeTextTracksBuffer: HtmlTextSegmentBuffer }); + expect(featureObject.nativeTextTracksBuffer).toBe(HtmlTextSegmentBuffer); }); }); diff --git a/src/features/list/__tests__/html_ttml_parser.test.ts b/src/features/list/__tests__/html_ttml_parser.test.ts index b5d2bc187f..e0d8f4d052 100644 --- a/src/features/list/__tests__/html_ttml_parser.test.ts +++ b/src/features/list/__tests__/html_ttml_parser.test.ts @@ -14,24 +14,19 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - +// eslint-disable-next-line max-len +import HTMLTextSegmentBuffer from "../../../core/segment_buffers/implementations/text/html"; import ttmlParser from "../../../parsers/texttracks/ttml/html"; +import { IFeaturesObject } from "../../types"; import addHTMLttmlFeature from "../html_ttml_parser"; -jest.mock("../../../parsers/texttracks/ttml/html", () => ({ - __esModule: true as const, - default: jest.fn(), -})); - describe("Features list - HTML ttml Parser", () => { it("should add an HTML ttml Parser in the current features", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = { htmlTextTracksParsers: {} }; + const featureObject = { htmlTextTracksParsers: {} } as unknown as IFeaturesObject; addHTMLttmlFeature(featureObject); expect(featureObject).toEqual({ htmlTextTracksParsers: { ttml: ttmlParser }, + htmlTextTracksBuffer: HTMLTextSegmentBuffer, }); expect(featureObject.htmlTextTracksParsers.ttml).toBe(ttmlParser); }); diff --git a/src/features/list/__tests__/html_vtt_parser.test.ts b/src/features/list/__tests__/html_vtt_parser.test.ts index 0a42f852e9..ab6ed70b59 100644 --- a/src/features/list/__tests__/html_vtt_parser.test.ts +++ b/src/features/list/__tests__/html_vtt_parser.test.ts @@ -14,24 +14,19 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - +// eslint-disable-next-line max-len +import HTMLTextSegmentBuffer from "../../../core/segment_buffers/implementations/text/html"; import vttParser from "../../../parsers/texttracks/webvtt/html"; +import { IFeaturesObject } from "../../types"; import addHTMLVTTFeature from "../html_vtt_parser"; -jest.mock("../../../parsers/texttracks/webvtt/html", () => ({ - __esModule: true as const, - default: jest.fn(), -})); - describe("Features list - HTML VTT Parser", () => { it("should add an HTML VTT Parser in the current features", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = { htmlTextTracksParsers: {} }; + const featureObject = { htmlTextTracksParsers: {} } as unknown as IFeaturesObject; addHTMLVTTFeature(featureObject); expect(featureObject).toEqual({ htmlTextTracksParsers: { vtt: vttParser }, + htmlTextTracksBuffer: HTMLTextSegmentBuffer, }); expect(featureObject.htmlTextTracksParsers.vtt).toBe(vttParser); }); diff --git a/src/features/list/__tests__/image_buffer.test.ts b/src/features/list/__tests__/image_buffer.test.ts index 0fe1fd2fd9..8f922a6910 100644 --- a/src/features/list/__tests__/image_buffer.test.ts +++ b/src/features/list/__tests__/image_buffer.test.ts @@ -14,20 +14,13 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - import imageBuffer from "../../../core/segment_buffers/implementations/image"; +import { IFeaturesObject } from "../../types"; import addImageBufferFeature from "../image_buffer"; describe("Features list - HTML Text Buffer", () => { - beforeEach(() => { - jest.resetModules(); - }); - it("should add an Image Buffer in the current features", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = {}; + const featureObject = {} as unknown as IFeaturesObject; addImageBufferFeature(featureObject); expect(featureObject).toEqual({ imageBuffer }); expect(featureObject.imageBuffer).toBe(imageBuffer); diff --git a/src/features/list/__tests__/native_sami_parser.test.ts b/src/features/list/__tests__/native_sami_parser.test.ts index bfc11eab93..bdf12346af 100644 --- a/src/features/list/__tests__/native_sami_parser.test.ts +++ b/src/features/list/__tests__/native_sami_parser.test.ts @@ -14,24 +14,19 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - +// eslint-disable-next-line max-len +import NativeTextSegmentBuffer from "../../../core/segment_buffers/implementations/text/native"; import samiParser from "../../../parsers/texttracks/sami/native"; -import addNativeSAMIFeature from "../native_sami_parser"; - -jest.mock("../../../parsers/texttracks/sami/native", () => ({ - __esModule: true as const, - default: jest.fn(), -})); +import { IFeaturesObject } from "../../types"; +import addNativesamiFeature from "../native_sami_parser"; -describe("Features list - native SAMI Parser", () => { - it("should add an native SAMI Parser in the current features", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = { nativeTextTracksParsers: {} }; - addNativeSAMIFeature(featureObject); +describe("Features list - native sami Parser", () => { + it("should add an native sami Parser in the current features", () => { + const featureObject = { nativeTextTracksParsers: {} } as unknown as IFeaturesObject; + addNativesamiFeature(featureObject); expect(featureObject).toEqual({ nativeTextTracksParsers: { sami: samiParser }, + nativeTextTracksBuffer: NativeTextSegmentBuffer, }); expect(featureObject.nativeTextTracksParsers.sami).toBe(samiParser); }); diff --git a/src/features/list/__tests__/native_srt_parser.test.ts b/src/features/list/__tests__/native_srt_parser.test.ts index 540d0cec4c..96cb4c65e9 100644 --- a/src/features/list/__tests__/native_srt_parser.test.ts +++ b/src/features/list/__tests__/native_srt_parser.test.ts @@ -14,24 +14,19 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - +// eslint-disable-next-line max-len +import NativeTextSegmentBuffer from "../../../core/segment_buffers/implementations/text/native"; import srtParser from "../../../parsers/texttracks/srt/native"; +import { IFeaturesObject } from "../../types"; import addNativesrtFeature from "../native_srt_parser"; -jest.mock("../../../parsers/texttracks/srt/native", () => ({ - __esModule: true as const, - default: jest.fn(), -})); - describe("Features list - native srt Parser", () => { it("should add an native srt Parser in the current features", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = { nativeTextTracksParsers: {} }; + const featureObject = { nativeTextTracksParsers: {} } as unknown as IFeaturesObject; addNativesrtFeature(featureObject); expect(featureObject).toEqual({ nativeTextTracksParsers: { srt: srtParser }, + nativeTextTracksBuffer: NativeTextSegmentBuffer, }); expect(featureObject.nativeTextTracksParsers.srt).toBe(srtParser); }); diff --git a/src/features/list/__tests__/native_text_buffer.test.ts b/src/features/list/__tests__/native_text_buffer.test.ts index 3f6b4968a1..efda6f72c6 100644 --- a/src/features/list/__tests__/native_text_buffer.test.ts +++ b/src/features/list/__tests__/native_text_buffer.test.ts @@ -14,24 +14,16 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - // eslint-disable-next-line max-len -import nativeTextTracksBuffer from "../../../core/segment_buffers/implementations/text/native"; +import NativeTextSegmentBuffer from "../../../core/segment_buffers/implementations/text/native"; +import { IFeaturesObject } from "../../types"; import addNativeTextBuffer from "../native_text_buffer"; -jest.mock("../../../core/segment_buffers/implementations/text/native", () => ({ - __esModule: true as const, - default: jest.fn(), -})); - describe("Features list - native Text Buffer", () => { it("should add an native Text Buffer in the current features", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = {}; + const featureObject = {} as unknown as IFeaturesObject; addNativeTextBuffer(featureObject); - expect(featureObject).toEqual({ nativeTextTracksBuffer }); - expect(featureObject.nativeTextTracksBuffer).toBe(nativeTextTracksBuffer); + expect(featureObject).toEqual({ nativeTextTracksBuffer: NativeTextSegmentBuffer }); + expect(featureObject.nativeTextTracksBuffer).toBe(NativeTextSegmentBuffer); }); }); diff --git a/src/features/list/__tests__/native_ttml_parser.test.ts b/src/features/list/__tests__/native_ttml_parser.test.ts index 9ce1279f29..2cb71c6109 100644 --- a/src/features/list/__tests__/native_ttml_parser.test.ts +++ b/src/features/list/__tests__/native_ttml_parser.test.ts @@ -14,24 +14,19 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - +// eslint-disable-next-line max-len +import NativeTextSegmentBuffer from "../../../core/segment_buffers/implementations/text/native"; import ttmlParser from "../../../parsers/texttracks/ttml/native"; +import { IFeaturesObject } from "../../types"; import addNativettmlFeature from "../native_ttml_parser"; -jest.mock("../../../parsers/texttracks/ttml/native", () => ({ - __esModule: true as const, - default: jest.fn(), -})); - describe("Features list - native ttml Parser", () => { it("should add an native ttml Parser in the current features", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = { nativeTextTracksParsers: {} }; + const featureObject = { nativeTextTracksParsers: {} } as unknown as IFeaturesObject; addNativettmlFeature(featureObject); expect(featureObject).toEqual({ nativeTextTracksParsers: { ttml: ttmlParser }, + nativeTextTracksBuffer: NativeTextSegmentBuffer, }); expect(featureObject.nativeTextTracksParsers.ttml).toBe(ttmlParser); }); diff --git a/src/features/list/__tests__/native_vtt_parser.test.ts b/src/features/list/__tests__/native_vtt_parser.test.ts index ba8c8281b3..f3204cf046 100644 --- a/src/features/list/__tests__/native_vtt_parser.test.ts +++ b/src/features/list/__tests__/native_vtt_parser.test.ts @@ -14,24 +14,19 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - +// eslint-disable-next-line max-len +import NativeTextSegmentBuffer from "../../../core/segment_buffers/implementations/text/native"; import vttParser from "../../../parsers/texttracks/webvtt/native"; +import { IFeaturesObject } from "../../types"; import addNativevttFeature from "../native_vtt_parser"; -jest.mock("../../../parsers/texttracks/webvtt/native", () => ({ - __esModule: true as const, - default: jest.fn(), -})); - describe("Features list - native vtt Parser", () => { it("should add an native vtt Parser in the current features", () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = { nativeTextTracksParsers: {} }; + const featureObject = { nativeTextTracksParsers: {} } as unknown as IFeaturesObject; addNativevttFeature(featureObject); expect(featureObject).toEqual({ nativeTextTracksParsers: { vtt: vttParser }, + nativeTextTracksBuffer: NativeTextSegmentBuffer, }); expect(featureObject.nativeTextTracksParsers.vtt).toBe(vttParser); }); diff --git a/src/features/list/__tests__/smooth.test.ts b/src/features/list/__tests__/smooth.test.ts index ec094126e6..c89a786b2d 100644 --- a/src/features/list/__tests__/smooth.test.ts +++ b/src/features/list/__tests__/smooth.test.ts @@ -14,23 +14,23 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - +/* eslint-disable-next-line max-len */ +import MediaSourceContentInitializer from "../../../core/init/media_source_content_initializer"; import SmoothFeature from "../../../transports/smooth"; +import { IFeaturesObject } from "../../types"; import addSmoothFeature from "../smooth"; -jest.mock("../../../transports/smooth", () => ({ - __esModule: true as const, - default: jest.fn(), -})); - describe("Features list - Smooth", () => { it("should add Smooth in the current features", () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any - const featureObject : any = { transports: {} }; + const featureObject = { transports: {} } as unknown as IFeaturesObject; addSmoothFeature(featureObject); - expect(featureObject).toEqual({ transports: { smooth: SmoothFeature } }); + expect(featureObject).toEqual({ + transports: { smooth: SmoothFeature }, + mediaSourceInit: MediaSourceContentInitializer, + }); expect(featureObject.transports.smooth).toBe(SmoothFeature); + expect(featureObject.mediaSourceInit) + .toBe(MediaSourceContentInitializer); }); }); diff --git a/src/features/list/dash.ts b/src/features/list/dash.ts index 87e73fc09b..4fd4fc45ba 100644 --- a/src/features/list/dash.ts +++ b/src/features/list/dash.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +// eslint-disable-next-line max-len +import MediaSourceContentInitializer from "../../core/init/media_source_content_initializer"; import dashJsParser from "../../parsers/manifest/dash/js-parser"; import dash from "../../transports/dash"; import { IFeaturesObject } from "../types"; @@ -27,6 +29,7 @@ function addDASHFeature(features : IFeaturesObject) : void { features.transports.dash = dash; } features.dashParsers.js = dashJsParser; + features.mediaSourceInit = MediaSourceContentInitializer; } export { addDASHFeature as DASH }; diff --git a/src/features/list/directfile.ts b/src/features/list/directfile.ts index 2ae2adc4c6..25e15f2a97 100644 --- a/src/features/list/directfile.ts +++ b/src/features/list/directfile.ts @@ -15,7 +15,7 @@ */ // eslint-disable-next-line max-len -import mediaElementTrackChoiceManager from "../../core/api/tracks_management/media_element_track_choice_manager"; +import MediaElementTrackChoiceManager from "../../core/api/tracks_management/media_element_track_choice_manager"; import directfile from "../../core/init/directfile_content_initializer"; import { IFeaturesObject } from "../types"; @@ -25,8 +25,10 @@ import { IFeaturesObject } from "../types"; * @param {Object} features */ function addDirectfileFeature(features : IFeaturesObject) : void { - features.directfile = { initDirectFile: directfile, - mediaElementTrackChoiceManager }; + features.directfile = { + initDirectFile: directfile, + mediaElementTrackChoiceManager: MediaElementTrackChoiceManager, + }; } export { addDirectfileFeature as DIRECTFILE }; diff --git a/src/features/list/html_sami_parser.ts b/src/features/list/html_sami_parser.ts index 6cbcf1a267..2f16ada8a5 100644 --- a/src/features/list/html_sami_parser.ts +++ b/src/features/list/html_sami_parser.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import HTMLTextSegmentBuffer from "../../core/segment_buffers/implementations/text/html"; import samiParser from "../../parsers/texttracks/sami/html"; import { IFeaturesObject } from "../types"; @@ -23,6 +24,7 @@ import { IFeaturesObject } from "../types"; */ function addHTMLSAMIFeature(features : IFeaturesObject) : void { features.htmlTextTracksParsers.sami = samiParser; + features.htmlTextTracksBuffer = HTMLTextSegmentBuffer; } export { addHTMLSAMIFeature as HTML_SAMI_PARSER }; diff --git a/src/features/list/html_srt_parser.ts b/src/features/list/html_srt_parser.ts index 5d5ab7ce98..ae1f4cba60 100644 --- a/src/features/list/html_srt_parser.ts +++ b/src/features/list/html_srt_parser.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import HTMLTextSegmentBuffer from "../../core/segment_buffers/implementations/text/html"; import srtParser from "../../parsers/texttracks/srt/html"; import { IFeaturesObject } from "../types"; @@ -23,6 +24,7 @@ import { IFeaturesObject } from "../types"; */ function addHTMLSRTFeature(features : IFeaturesObject) : void { features.htmlTextTracksParsers.srt = srtParser; + features.htmlTextTracksBuffer = HTMLTextSegmentBuffer; } export { addHTMLSRTFeature as HTML_SRT_PARSER }; diff --git a/src/features/list/html_text_buffer.ts b/src/features/list/html_text_buffer.ts index a723d02a0b..caa0d34422 100644 --- a/src/features/list/html_text_buffer.ts +++ b/src/features/list/html_text_buffer.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import htmlTextBuffer from "../../core/segment_buffers/implementations/text/html"; +import HTMLTextSegmentBuffer from "../../core/segment_buffers/implementations/text/html"; import { IFeaturesObject } from "../types"; /** @@ -22,7 +22,7 @@ import { IFeaturesObject } from "../types"; * @param {Object} features */ function addHTMLTextBuffer(features : IFeaturesObject) : void { - features.htmlTextTracksBuffer = htmlTextBuffer; + features.htmlTextTracksBuffer = HTMLTextSegmentBuffer; } export { addHTMLTextBuffer as HTML_TEXT_BUFFER }; diff --git a/src/features/list/html_ttml_parser.ts b/src/features/list/html_ttml_parser.ts index aacb97d4a8..8014fe4287 100644 --- a/src/features/list/html_ttml_parser.ts +++ b/src/features/list/html_ttml_parser.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import HTMLTextSegmentBuffer from "../../core/segment_buffers/implementations/text/html"; import ttmlParser from "../../parsers/texttracks/ttml/html"; import { IFeaturesObject } from "../types"; @@ -23,6 +24,7 @@ import { IFeaturesObject } from "../types"; */ function addHTMLTTMLFeature(features : IFeaturesObject) : void { features.htmlTextTracksParsers.ttml = ttmlParser; + features.htmlTextTracksBuffer = HTMLTextSegmentBuffer; } export { addHTMLTTMLFeature as HTML_TTML_PARSER }; diff --git a/src/features/list/html_vtt_parser.ts b/src/features/list/html_vtt_parser.ts index dcfdeeb83b..6289377a9f 100644 --- a/src/features/list/html_vtt_parser.ts +++ b/src/features/list/html_vtt_parser.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import HTMLTextSegmentBuffer from "../../core/segment_buffers/implementations/text/html"; import vttParser from "../../parsers/texttracks/webvtt/html"; import { IFeaturesObject } from "../types"; @@ -23,6 +24,7 @@ import { IFeaturesObject } from "../types"; */ function addHTMLVTTFeature(features : IFeaturesObject) : void { features.htmlTextTracksParsers.vtt = vttParser; + features.htmlTextTracksBuffer = HTMLTextSegmentBuffer; } export { addHTMLVTTFeature as HTML_VTT_PARSER }; diff --git a/src/features/list/native_sami_parser.ts b/src/features/list/native_sami_parser.ts index a9441e82b4..885b024d6b 100644 --- a/src/features/list/native_sami_parser.ts +++ b/src/features/list/native_sami_parser.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +// eslint-disable-next-line max-len +import NativeTextSegmentBuffer from "../../core/segment_buffers/implementations/text/native"; import samiParser from "../../parsers/texttracks/sami/native"; import { IFeaturesObject } from "../types"; @@ -23,6 +25,7 @@ import { IFeaturesObject } from "../types"; */ function addNativeSAMIFeature(features : IFeaturesObject) : void { features.nativeTextTracksParsers.sami = samiParser; + features.nativeTextTracksBuffer = NativeTextSegmentBuffer; } export { addNativeSAMIFeature as NATIVE_SAMI_PARSER }; diff --git a/src/features/list/native_srt_parser.ts b/src/features/list/native_srt_parser.ts index 274f57aeda..95a636f1bf 100644 --- a/src/features/list/native_srt_parser.ts +++ b/src/features/list/native_srt_parser.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +// eslint-disable-next-line max-len +import NativeTextSegmentBuffer from "../../core/segment_buffers/implementations/text/native"; import srtParser from "../../parsers/texttracks/srt/native"; import { IFeaturesObject } from "../types"; @@ -23,6 +25,7 @@ import { IFeaturesObject } from "../types"; */ function addNativeSRTFeature(features : IFeaturesObject) : void { features.nativeTextTracksParsers.srt = srtParser; + features.nativeTextTracksBuffer = NativeTextSegmentBuffer; } export { addNativeSRTFeature as NATIVE_SRT_PARSER }; diff --git a/src/features/list/native_text_buffer.ts b/src/features/list/native_text_buffer.ts index 8b3a719d2e..a94375a265 100644 --- a/src/features/list/native_text_buffer.ts +++ b/src/features/list/native_text_buffer.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -import nativeTextBuffer from "../../core/segment_buffers/implementations/text/native"; +// eslint-disable-next-line max-len +import NativeTextSegmentBuffer from "../../core/segment_buffers/implementations/text/native"; import { IFeaturesObject } from "../types"; /** @@ -22,7 +23,7 @@ import { IFeaturesObject } from "../types"; * @param {Object} features */ function addNativeTextBuffer(features : IFeaturesObject) : void { - features.nativeTextTracksBuffer = nativeTextBuffer; + features.nativeTextTracksBuffer = NativeTextSegmentBuffer; } export { addNativeTextBuffer as NATIVE_TEXT_BUFFER }; diff --git a/src/features/list/native_ttml_parser.ts b/src/features/list/native_ttml_parser.ts index e80db859d0..ef41950804 100644 --- a/src/features/list/native_ttml_parser.ts +++ b/src/features/list/native_ttml_parser.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +// eslint-disable-next-line max-len +import NativeTextSegmentBuffer from "../../core/segment_buffers/implementations/text/native"; import ttmlParser from "../../parsers/texttracks/ttml/native"; import { IFeaturesObject } from "../types"; @@ -23,6 +25,7 @@ import { IFeaturesObject } from "../types"; */ function addNativeTTMLFeature(features : IFeaturesObject) : void { features.nativeTextTracksParsers.ttml = ttmlParser; + features.nativeTextTracksBuffer = NativeTextSegmentBuffer; } export { addNativeTTMLFeature as NATIVE_TTML_PARSER }; diff --git a/src/features/list/native_vtt_parser.ts b/src/features/list/native_vtt_parser.ts index d34a2ce8b0..5147684832 100644 --- a/src/features/list/native_vtt_parser.ts +++ b/src/features/list/native_vtt_parser.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +// eslint-disable-next-line max-len +import NativeTextSegmentBuffer from "../../core/segment_buffers/implementations/text/native"; import vttParser from "../../parsers/texttracks/webvtt/native"; import { IFeaturesObject } from "../types"; @@ -23,6 +25,7 @@ import { IFeaturesObject } from "../types"; */ function addNativeVTTFeature(features : IFeaturesObject) : void { features.nativeTextTracksParsers.vtt = vttParser; + features.nativeTextTracksBuffer = NativeTextSegmentBuffer; } export { addNativeVTTFeature as NATIVE_VTT_PARSER }; diff --git a/src/features/list/smooth.ts b/src/features/list/smooth.ts index b83830100d..c428fd43a7 100644 --- a/src/features/list/smooth.ts +++ b/src/features/list/smooth.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +// eslint-disable-next-line max-len +import MediaSourceContentInitializer from "../../core/init/media_source_content_initializer"; import smooth from "../../transports/smooth"; import { IFeaturesObject } from "../types"; @@ -23,6 +25,7 @@ import { IFeaturesObject } from "../types"; */ function addSmoothFeature(features : IFeaturesObject) : void { features.transports.smooth = smooth; + features.mediaSourceInit = MediaSourceContentInitializer; } export { addSmoothFeature as SMOOTH }; diff --git a/src/features/types.ts b/src/features/types.ts index bcc647f7af..91e1371c93 100644 --- a/src/features/types.ts +++ b/src/features/types.ts @@ -19,6 +19,7 @@ import RxPlayer from "../core/api"; import MediaElementTrackChoiceManager from "../core/api/tracks_management/media_element_track_choice_manager"; import type ContentDecryptor from "../core/decrypt"; import DirectFileContentInitializer from "../core/init/directfile_content_initializer"; +import MediaSourceContentInitializer from "../core/init/media_source_content_initializer"; import { SegmentBuffer } from "../core/segment_buffers"; import { IDashParserResponse, @@ -32,14 +33,29 @@ import { import { ITransportFunction } from "../transports"; import { CancellationSignal } from "../utils/task_canceller"; -export type IDirectFileInit = typeof DirectFileContentInitializer; - -export type IContentDecryptorClass = typeof ContentDecryptor; - +/** + * Function allowing to implement a text track rendered by displaying them + * through "regular" (e.g. div, span etc.) HTML elements. + * @param {HTMLMediaElement} mediaElement - The `HTMLMediaElement` the text + * tracks should be synced to. + * @param {HTMLElement} textTrackElement - The parent `HTMLElement` where all + * text tracks-related `HTMLElement` should be put. + * @returns {Object} - `SegmentBuffer` implementation. + */ export type IHTMLTextTracksBuffer = new(mediaElement : HTMLMediaElement, textTrackElement : HTMLElement) => SegmentBuffer; +/** + * Function allowing to implement a text track rendered by displaying them + * through a native `` `HTMLElement` associated to the given + * `mediaElement`. + * @param {HTMLMediaElement} mediaElement - The `HTMLMediaElement` the text + * tracks should be synced to. The `` `HTMLElement` on which the text + * tracks will be displayed will also be linked to this `HTMLMediaElement`. + * @param {boolean} hideNativeSubtitle + * @returns {Object} - `SegmentBuffer` implementation. + */ export type INativeTextTracksBuffer = new(mediaElement : HTMLMediaElement, hideNativeSubtitle : boolean) => SegmentBuffer; @@ -73,38 +89,95 @@ export type IDashJsParser = ( args : IMPDParserArguments ) => IDashParserResponse; -// interface of the global `features` object through which features are -// accessed. +/** + * Function implementing the optional RxPlayer debug UI element. + * @param {HTMLElement} parentElt - `HTMLElement` in which the debug UI + * element will be displayed. + * @param {Object} RxPlayer - RxPlayer instance concerned + * @param {Object} cancelSignal - CancellationSignal allowing to free + * up the resources taken to keep the debug UI element up-to-date. + */ +export type IDebugElementFn = ( + parentElt : HTMLElement, + instance : RxPlayer, + cancelSignal : CancellationSignal +) => void; + +/** + * Interface of the global `features` object through which features are + * accessed. + * + * Allows for feature-switching with the goal of reducing the bundle size for + * an application. + */ export interface IFeaturesObject { - directfile : { initDirectFile: IDirectFileInit; + /** + * Feature allowing to load so-called "directfile" contents, which are + * contents natively decodable by the browser. + */ + directfile : { initDirectFile: typeof DirectFileContentInitializer; mediaElementTrackChoiceManager : IMediaElementTrackChoiceManager; } | null; - decrypt : IContentDecryptorClass | null; - createDebugElement : ( - ( - parentElt : HTMLElement, - instance : RxPlayer, - cancelSignal : CancellationSignal - ) => void - ) | null; + /** Handle content decryption. */ + decrypt : typeof ContentDecryptor | null; + /** Optional debug element function (@see `IDebugElementFn`) */ + createDebugElement : IDebugElementFn | null; + /** Implement text track rendering in the DOM. */ htmlTextTracksBuffer : IHTMLTextTracksBuffer|null; + /** + * Parsers for various text track formats, by their name as set by the + * RxPlayer. + * Those parsers are specifically destined to be displayed in DOM elements. + */ htmlTextTracksParsers : Partial>; imageBuffer : IImageBuffer|null; imageParser : IImageParser|null; + /** Feature allowing to load contents through MediaSource API. */ + mediaSourceInit: typeof MediaSourceContentInitializer | null; + /** + * Function for loading and parsing contents through various protocols, by + * their name as set by the RxPlayer. + */ transports : Partial>; + /** + * Manifest parsers specific to the "DASH" transport. + */ dashParsers : { + /** + * WebAssembly-based Manifest DASH parser. + */ wasm : DashWasmParser | null; + /** + * JavaScript-based Manifest DASH parser. + */ js : IDashJsParser | null; }; nativeTextTracksBuffer : INativeTextTracksBuffer|null; + /** + * Parsers for various text track formats, by their name as set by the + * RxPlayer. + * Those parsers are specifically destined to be displayed in `` HTML + * elements. + */ nativeTextTracksParsers : Partial>; } +/** + * Variant of an add-able feature (as exported by the RxPlayer) when in an + * Object format. + */ export interface IFeatureObject { _addFeature(features : IFeaturesObject) : void; } +/** + * Variant of an add-able feature (as exported by the RxPlayer) when in an + * Function format. + */ export type IFeatureFunction = (features : IFeaturesObject) => void; +/** + * How features are actually exported by the RxPlayer. + */ export type IFeature = IFeatureObject | IFeatureFunction; diff --git a/src/minimal.ts b/src/minimal.ts index 13890ba55f..c9349de7bc 100644 --- a/src/minimal.ts +++ b/src/minimal.ts @@ -22,10 +22,6 @@ */ import Player from "./core/api"; -import { - addFeatures, - IFeature, -} from "./features"; import logger from "./log"; if (typeof __RX_PLAYER_DEBUG_MODE__ === "boolean" && __RX_PLAYER_DEBUG_MODE__) { @@ -34,15 +30,4 @@ if (typeof __RX_PLAYER_DEBUG_MODE__ === "boolean" && __RX_PLAYER_DEBUG_MODE__) { logger.setLevel(__LOGGER_LEVEL__.CURRENT_LEVEL); } -/** - * Minimal Player for which you can features at will: - * - start with no features - * - Allow to only load features wanted - * - * @class MinimalPlayer - */ -export default class MinimalPlayer extends Player { - static addFeatures(featureList : IFeature[]) : void { - addFeatures(featureList); - } -} +export default Player;