Skip to content

Releases: canalplus/rx-player

v4.1.0

08 Jul 17:23
74b603a
Compare
Choose a tag to compare

Release v4.1.0 (2024-07-08)

Quick Links:
📖 API documentation - Demo - 🎓 Migration guide from v3

🔍 Overview

We're now releasing the v4.1.0.
This release adds multiple fixes and improvements:

  • it improves our MULTI_THREAD experimental feature allowing to run most of the RxPlayer logic in another thread - which we're now using on the great majority of devices at Canal+.

  • This release also adds support for DASH Content Protection References, which can greatly reduce the size and thus improve parsing time of Multi-Period Manifest with complex DRM configurations.

  • After an issue report, we noticed that our DASH URL resolution algorithm did not handle all cases. We thus rewrote it so it completely respect the corresponding standard (the RFC 3986).

  • For the Edge browser, after having multiple PlayReady-specific issues, we now perform much more checks before validating the fact that PlayReady SL3000/SL2000 is available on the device. This helped to fix multiple Edge issues we were having.

  • Many other smaller fixes, including on the maxVideoBufferSize option which was not always relying on good estimates, on better handling contents with mixed encryption and multiple fixes of minor compatibility issues (mainly on the PlayStation 4 and 5, and on Safari)

📑 Changelog

Features

  • DASH: Implement ContentProtection references [#1439]

Bug fixes

  • DASH: support absolute path in URL resolution with RFC 3986 implementation [#1443, #1440]
  • DASH: fix cases of blinking subtitles [#1416, #1424]
  • Fix precision issues of the maxVideoBufferSize API [#1421]
  • DASH: Prevent multiple loading of the same segment for some DASH low-latency contents [#1422]
  • DRM/Compat: on Edge test comprehensively KeySystems before considering them as usable [#1434]
  • DRM/DASH: Ignore 0x0 key id found in DASH initialization segments are they are often linked to unencrypted data. [#1466, #1458]
  • DRM/Compat: On the PlayStation 5, reload directly when a decryption key become unusable to prevent fatal errors [#1399]
  • MULTI_THREAD: Perform several actions so that our MULTI_THREAD experimental feature now works on older browser and on the Playstation 4 [#1401, #1402]
  • Directfile/Compat: On safari on iOS no longer stay stuck in buffering when autoPlay is set to false or not set and the video element has the attribute "playsinline" [#1408, #1390]
  • Directfile/compat: On safari mobile in directfile mode, do not stay in an infinite LOADING state if the duration is set to NaN (rare issue in a normally-unsupported multiple RxPlayer-per-media-element scenario) [#1393]
  • Fix RxPlay error messages not properly displaying in Chrome's inspector since Chrome 126 [#1474]

Other improvements

  • Signal an error if multiple active RxPlayer are linked to the same media element [#1394]
  • Undetermined audio and text track language now have a normalized property equal to "und" for better ISO 639-3 compatibility [#1428]
  • MULTI_THREAD: The experimental MULTI_THREAD feature does not need a dashWasmUrl anymore nor compatibility to WebAssembly [#1384]
  • MULTI_THREAD: The DEBUG_ELEMENT feature now allows to display all debug information even under the "multithreading" mode [#1438]
  • Generate TypeScript declaration maps [#1412]
  • Do not rely on the performance.now API if not available [#1402]
  • DRM: Refactor MediaKeys attachment logic to simplify device support updates [#1357]
  • tests: use exponential backoff to speed up integration tests [#1389]
  • code: Rely on the TypeScript type keyword at type imports to be sure they have no code impact on our final build [#1365]
  • code: Reorganize core RxPlayer code into a src/main_thread and src/core respectively for main thread and worker code in a "multithread" mode [#1365]
  • code: Rely on the prettier and rustfmt formatting tools in the codebase [#1387]
  • build: remove dependency to webpack [#1435, #1425, #1420]
  • tests: migrate all tests to the vitest framework to simplify and unify test-related dependencies and test writing [#1444, #1445]

DASH ContentProtection References

ContentProtection metadata leading to huge MPD

DASH MPD can get quite huge on complex contents with multiple Period elements and various decryption keys depending on the Period and Representation.

One of the bigger part of the MPD in those scenario is the <ContentProtection> element, which contains metadata related to content decryption. This element can get very big as it contains Base64-encoded binary data for various client-side key systems.

protscreen1
Screenshot: For encrypted contents, we can see on this screenshot that encryption-related metadata (in <ContentProtection> elements) - especially base64-encoded data - are one of the main culprit for an MPD large size.
Moreover, note that this example only advertise metadata for PlayReady and Widevine. So this example is even lighter than most actual encrypted contents we play in production.

Each DASH AdaptationSet or Representation linked to that metadata is then supposed to have this element, contributing to the MPD's size. And when the same encryption metadata repeats, for example in another Period, that same huge element has to be repeated there - leading to a very large MPD.

Thankfully, newer iterations of the DASH specification provide a solution to greatly reduce the size of those kind of MPD: ContentProtection references.

ContentProtection references

With ContentProtection referecences we can only declare once (in the MPD) encryption metadata linked to multiple AdaptationSet or Representation and then refer to it through an identifier each time it is needed.

protscreen2
Screenshot: The same MPD than in the first screenshot, but this time making use of ContentProtection references. Here the actual metadata could be defined on top of the MPD, and only refered to through a ref attribute as pictured. You can see that the exact same information would take less space here.

This allows to greatly reduce the size of multi-Period MPD with encrypted media whose encryption key repeats multiple times in the stream - which happens often.

This feature is directly enabled, with nothing to do on the application-side.

MULTI_THREAD feature improvements

The MULTI_THREAD feature

In the v4.0.0, we added the MULTI_THREAD feature which allows to run most of the RxPlayer's logic in a Worker, and thus in another thread.

Doing this has multiple advantages, performance-related ones, yet this isolation also has a considerable effect on the quality of our adaptive algorithms: on some low-end devices where we before observed either a lower quality or frequent transitions between multiple qualities, we're now able to better maintain a higher quality.

Removing the need to add our WebAssembly parser

The main issue with adding the MULTI_THREAD mode was its complex setup, among which the need to add our WebAssembly MPD parser, which implies WebAssembly support and thus preventing its usage on many "old" (year ~2019 and less) devices.

We've since noticed some work done on efficient JavaScript-only XML parsing whose performance was impressive. As the need for optimal XML parsing in a Worker environment was the main reason why we relied on our WebAssembly parser, we wondered if we couldn't take inspiration from this work to much simplify the MULTI_THREAD setup and increase support.

This is now done and performance has been impressive enough that we now consider that this can be the default MPD parser directly included in the worker file provided to the RxPlayer's attachWorker method.

Without this supplementary step, the feature becomes much simpler to profit from:

import RxPlayer from "rx-player/minimal";
import { MULTI_THREAD } from "rx-player/experimental/features";

// To simplify this example, we'll directly import an "embedded" version of the
// supplementary code loaded by the `MULTI_THREAD` feature.
// We could also load it on demand through an URL
import { EMBEDDED_WORKER } from "rx-player/experimental/features/embeds";

RxPlayer.addFeatures([MULTI_THREAD]);
const player = new RxPlayer(/* your usual op...
Read more

v3.33.3

08 Jul 17:02
Compare
Choose a tag to compare

Release v3.33.3 (2024-07-08)

Quick Links:
📖 API documentation - Demo

🔍 Overview

The v3.33.3 is a "legacy" release (now that the v4 is the current major version) mostly containing some of the bug fixes and improvements initially made for the upcoming v4.1.0 release that should be done just after this one.

📑 Changelog

Bug fixes

  • DASH: support absolute path in URL resolution with RFC 3986 implementation [#1446]
  • DASH: fix cases of blinking subtitles [#1447]
  • Fix precision issues of the maxVideoBufferSize API [#1448]
  • DASH: Prevent multiple loading of the same segment for some DASH low-latency contents [#1449]
  • Await some delay before re-attempting to push a segment following an error [#1411]
  • DRM/Compat: on Edge test comprehensively KeySystems before considering them as usable [#1450]
  • DRM/DASH: Ignore 0x0 key id found in DASH initialization segments are they are often linked to unencrypted data. [#1466, #1458]
  • DRM/Compat: On the PlayStation 5, reload directly when a decryption key become unusable to prevent fatal errors [#1451]
  • Directfile/Compat: On safari on iOS no longer stay stuck in buffering when autoPlay is set to false or not set and the video element has the attribute "playsinline" [#1406, #1404, #1390]
  • Directfile/compat: On safari mobile in directfile mode, do not stay in an infinite LOADING state if the duration is set to NaN (rare issue in a normally-unsupported multiple RxPlayer-per-media-element scenario) [#1452]
  • Fix RxPlay error messages not properly displaying in Chrome's inspector since Chrome 126 [#1474]

Other improvements

  • Signal an error if multiple active RxPlayer are linked to the same media element [#1453]
  • Undetermined audio and text track language now have a normalized property equal to "und" for better ISO 639-3 compatibility [#1454]

v4.0.0

21 Feb 15:47
Compare
Choose a tag to compare

Release v4.0.0 (2024-02-21)

Quick Links:
📖 API documentation - Demo - 🎓 Migration guide from v3

🔍 Overview

It's finally time for the official v4.0.0 release with the v4 now becoming our default focus and the default major version when installing the RxPlayer through package managers relying on the npm registry (npm / yarn / pnpm etc.).

If you relied on the 4.0.0-rc.2 before, this release is a quasi-exact copy of that version, with only a minor fix for the representationListUpdate event - which was previously never triggered.

Because previous v4 beta and release candidate release notes already listed the new features available in v4 in comparison to v3, this release note will only summarize v4 features we consider to be the most important. They already all have been presented in one of the previous release notes.

To migrate from a v3 RxPlayer to a v4 one, you can rely on our migration guide, which lists every API that changed in that major version.

📑 Changelog

We decided to compile the full v4 changelog into one (instead of splitting and associating it to the various beta and release candidates they have been initially available in).

This lead to an enormous changelog for the v4. To avoid polluting this release note we will just redirect you to our CHANGELOG.md file, here.

About the v3

We will mainly only add bug fixes and small improvements from now on to the now legacy v3.x.x versions so it stays stable and usable for people not having time yet to do the switch to the v4.

As such, it should still work as expected, but new features probably won't be added to it, unless you provide the contribution and test cases for it yourself through pull requests.

However, we do recommend you to switch to v4 instead, and not hesitate to open an issue if you find an API change to be unclear or undesirable for your usage.

A more flexible track API

Note: this feature was already presented in the v4.0.0-beta.0 release note.

One of the focus of this new major release was to improve the RxPlayer API on DASH multi-Period contents - which are contents with various set of AdaptationSets (tracks) and Representations (qualities) depending on the time period.

The RxPlayer's previous track API (e.g. setAudioTrack and getAvailableAudioTracks) only allowed to get the list and update the track for the currently-playing Period.

// Example setting the first english audio track for the current Period if found
const availableAudioTracks = rxPlayer.getAvailableAudioTracks();
const englishAudioTrack = availableAudioTracks.find((track) => {
  return track.language === "eng";
});

if (englishAudioTrack !== undefined) {
  rxPlayer.setAudioTrack(englishAudioTrack.id);
}

Now, using the track API this way still works with the same result, but it is also possible to get and set the available tracks for any Period on the content.

// Get the list of Periods currently considered by the RxPlayer:
const availablePeriods = rxPlayer.getAvailablePeriods();

// Get the list of available audio tracks for a given period
const tracks = rxPlayer.getAvailableAudioTracks(availablePeriods[0].id);

// Set an audio track for that Period
rxPlayer.setAudioTrack({
  trackId: tracks[0].id,
  periodId: availablePeriods[0].id,
});

The new tracks API also let you to choose a behavior when switching from an old to any new track (e.g.: reloading, switching in place with a potential rebuffering or seamlessly) through a new switchingMode property and also allow to rewind a little (and let you set by how much) in cases where you want to give back some context (for example when switching the audio track to another language).

Last but not least, it is also possible to restrict the Representations (a.k.a. qualities) played under that new track, this will be described in the next chapter.

Some of those features have been described in our "Selecting a Track" tutorial. To have complete informations, you can also refer to our API documentation

Improved Representation selection

Note: this feature was already presented in the v4.0.0-beta.0 release note.

Previous RxPlayer versions only allowed to specify allowed Representation(s) (i.e. qualities) by using bitrate-oriented API.
For example you could call setVideoBitrate, setMaxVideoBitrate and setMinVideoBitrate to either choose a Representation (the first one) or to reduce the ranges of Representations to choose from (the latter two).

In real-life, you might instead want to select Representation(s) based on other criterias. In some more complex use cases, you might only want to allow Representations with a specific codec property. Both of those were not always possible with the previous API.

We chose to remediate to those issues in the v4 by providing a new API for Representation selection: the "Representation locking" family of API.
For example, the lockVideoRepresentations method allows to select which Representation for the current video track are allowed to play, the regular RxPlayer's adaptive logic then picking its choice between them, as usual. To lock a single Representation in place, you can just communicate a single Representation's id to that method:

// Example only playing the Representation with the lowest height in the
// current video track

const videoTrack = rxPlayer.getVideoTrack();
if (videoTrack !== null && videoTrack !== undefined) {
  const lowestHeight = videoTrack.representations.sort((a, b) => {
    // Put `undefined` heights at the end of the resulting array
    if (a.height === undefined) {
          return 1; // Put `a` after `b`
    } else if (b.height === undefined) {
      return -1; // Put `b` after `a`
    }
    // Sort ascending
    return a.height - b.height; // Put the higher height after
  })[0]; // Select the lowest one
  if (lowestHeight !== undefined) {
    // Only play the lowest anounced height
    rxPlayer.lockVideoRepresentations([lowestHeight.id]);
  }
}

There is a lot more to know on this API, see the lockVideoRepresentations / lockAudioRepresentations documentation page to see all that is can do.

We rely on this new API to display a better quality selection in our demo page for example:

new-bitrate-choice
Screenshot: our new demo page now allows a user to select a video quality based on its height and/or the wanted bitrate, thanks to this new API.

We also chose to remove the previous bitrate-related API to simplify the general API of the RxPlayer, considering that its behavior can be completely replaced by the new "Representation locking" methods.

Information on how to make the switch is present in its own page in our migration guide

The new MULTI_THREAD experimental feature

Note: this feature was already presented in the v4.0.0-rc.1 release note.

This major release also brings the possibility of running most of the RxPlayer main logic in a WebWorker, letting your application to run concurrently with it. This has potentially large positive impacts on performance and adaptive streaming stability (e.g. keeping a stable high video quality).

This new behavior is totally optional and has to be enabled through specific APIs.
The RxPlayer is also able to automatically detect when multithreading is not possible (very old devices), to go back in the regular monothreading mode instead.

Running the RxPlayer without a WebWorker (the default):

+-------------------------------------------------------------------------------+
| Main thread (also running the UI)                                             |
|                                ...
Read more

v3.33.2

21 Feb 15:33
Compare
Choose a tag to compare

Release v3.33.2 (2024-02-21)

Quick Links:
📖 API documentation - Demo

NOTE: we skipped the v3.33.1 release due to a minor TypeScript typing issue seen when testing that release. This is now fixed.

🔍 Overview

This release only brings minor bug fixes on top of the v3.33.0, none being regressions (those issues have been here since the corresponding features have been introduced).

This reassure us that the v3 is stable enough for it to be reliable for people not having the time yet to make the switch to a v4, as we plan to release the official v4.0.0 just after this release.

The v3 major releases should still be maintained and receive bug fixes for some time if we find them, but our main focus will now go to the v4 releases. Note that all future v3 releases will have the legacy-v3 tag on npm.

📑 Changelog

Bug fixes

  • dash: Don't unnecessarily reload external <UTCTiming> resources at each refresh if it failed for the first request of the Manifest [#1370]
  • dash: The DASH_WASM feature do not rely on WebAssembly's sign-extension operators anymore as that is poorly supported on older Samsung and LG TVs [#1372]

Other improvements

  • build: automatically install Rust and WASM toolchain locally if unavailable when building the RxPlayer WebAssembly file
  • doc: Update our documentation generator and fix all invalid anchors in it
  • npm: prevent the publishing of unnecessary files on the npm registry [#1377, #1378]

v4.0.0-rc.2

07 Feb 17:44
Compare
Choose a tag to compare
v4.0.0-rc.2 Pre-release
Pre-release

Release v4.0.0-rc.2 (2024-02-07)

Quick Links:
📖 API documentation - Demo - 🎓 Migration guide from v3

Overview

This new release candidate mainly fixes issues we've seen with the WebAssembly parser for DASH MPD, that is used for both the DASH_WASM feature (which lost its "experimental" label at v4.0.0-rc.1) and the MULTI_THREAD experimental feature.

Another minor fix is on the handling of the <UTCTiming> element in a DASH MPD. If it pointed to an URL and if the resource behind it could not be fetched when first loading the MPD due to issues with the request(s) (there may be several attempts), then the RxPlayer would keep re-loading the resource each time the MPD was refreshed, instead of just stopping doing it once it loaded successfully once - which is what the RxPlayer does now.

None of these issues are regressions, and thus some also concern the v3.33.0 (the DASH_WASM and <UTCTiming> ones). As those all are very minor issues (DASH_WASM being still experimental in v3.33.0 - with an error triggering a fallback on the JS-based parser anyway - and the <UTCTiming> issue being rare and not preventing smooth playback) they will only be released as a future v3.33.1 release once the 4.0.0 is released.

Changelog

Features

  • MULTI_THREAD: attachWorker now returns a Promise to indicate when WebWorker attachment failed [#1374]

Bug fixes

  • dash: Don't unnecessarily reload external <UTCTiming> resources at each refresh if it failed for the first request of the Manifest [#1370]
  • dash: The DASH_WASM feature do not rely on WebAssembly's sign-extension operators anymore as that is poorly supported on older Samsung and LG TVs [#1372]
  • MULTI_THREAD: properly categorize forced subtitles in multithread scenarios

Other improvements

  • build: automatically install Rust and WASM toolchain locally if unavailable when building the RxPlayer [#1373]
  • doc: Update our documentation generator and fix all invalid anchors in it
  • npm: prevent the publishing of unnecessary files on the npm registry [#1377, #1378]

DASH_WASM and MULTI_THREAD fix

After testing the MULTI_THREAD feature on a large array of smart TVs, we noticed that some old Samsung and LG TVs had issues instantiating our WebAssembly MPD parser (on which both the MULTI_THREAD and DASH_WASM features rely).
It turned out that those TVs had support for WebAssembly (if they did not, the RxPlayer would automatically have disabled "multithread" mode), yet to a very old version of it which did not have some of its early features present in the WebAssembly file produced by the Rust compiler (the compiler we're using) by default.

This was not known to us as we always assumed that the compiler targeted by default the earliest available version of WebAssembly.

We ended up doing supplementary transformations on our WebAssembly file to remove the reliance on those newer features. The new mpd-parser.wasm file delivered with this version (as well as exported through "rx-player/experimental/features/embeds") should now be compatible with those devices.

attachWorker now returns a Promise

The aforementioned DASH_WASM and MULTI_THREAD issue put a light into some scenarios we were not enough prepared for: how to handle cases where the WebWorker and/or WebAssembly module relied on when using the MULTI_THREAD feature fail to initialize.
This should hopefully be very rare now, yet may still happen if e.g. any of those resources are behind an URL that is not accessible or if browser security settings prevents the RxPlayer from creating or relying on a WebWorker.

To better handle those cases for now, we decided that the attachWorker method now returns a Promise. That promise will either resolve if the Worker was initialized with success and reject if it did not.

Like before, you may still call loadVideo synchronously after the attachWorker call has been made (you don't have to await this Promise) but it is now advised to await that Promise in scenarios where you're both relying on the MULTI_THREAD feature and on one of the corresponding monothreaded feature (either DASH or DASH_WASM) - in which case it is the role of the RxPlayer to choose between one or the other.

For example: the following code:

import RxPlayer from "rx-player/minimal";
import { DASH } from "rx-player/features";
import { MULTI_THREAD } from "rx-player/experimental/features";
import {
    EMBEDDED_WORKER,
    EMBEDDED_DASH_WASM,
} from "rx-player/experimental/features/embeds";

RxPlayer.addFeatures([
  // Will allow to play DASH contents in main thread
  DASH,

  // Will allow to play DASH contents in multithread scenarios
  MULTI_THREAD,
]);

const player = new RxPlayer(/* your usual RxPlayer options */);

try {
  await player.attachWorker({
    workerUrl: EMBEDDED_WORKER,
    dashWasmUrl: EMBEDDED_DASH_WASM,
  })
  console.log("Worker succesfully attached!");
} catch (err) {
  console.warn("An error arised while initializing the Worker", err);
}

player.loadVideo({ /* your usual loadVideo options */ });

Will only load the content in "multithread" mode if all of the following are true:

  1. Your browser supports the feature (which is already checked synchronously when attachWorker is called)
  2. Your content is compatible with multithread mode
  3. The Worker initialization went without issue (this is the case where awaiting attachWorker has an effect)

And in other cases, it will load in monothreaded mode, as the DASH feature is also added.

If you do not await attachWorker before calling loadVideo here and the Worker initialization fails, the RxPlayer might have already begun to load the content in "multithread" mode. In that case it might fail to do so and trigger an error for that content (we're also currently exploring ways of making the RxPlayer automatically reload in monothreaded mode in this exact last scenario but it isn't done for now).

Also note that if Worker initialization fails, the RxPlayer won't try to rely on it anymore for the next loadVideo and reload calls. If you want to retry Worker initialization in that unlikely scenario, you could call attachWorker again.

Project repository updates

As we're now very confident of the stability of the v4 pre-releases, we began making changes to the RxPlayer repository:

  1. The default branch seen on GitHub and choosen as a default target branch for Pull Requests is now dev, which corresponds to the latest merged developments on the v4. Note that it is currently further than the v4.0.0-rc.2 as we're already merging improvements for future v4 releases.

    Another branch, stable corresponds to the last released v4 version (so here v4.0.0-rc.2) plus optional hotfixes. dev is based on stable.

    The old master branch keeps refering to the v3 but has been renamed to legacy-v3. next does not exist anymore, any new developments for the v3 now targets legacy-v3.

  2. The default demo page exposed both by the GitHub link and in our README.md file now leads to the v4.0.0-rc.2 demo.

    The last v3.33.0 demo page can still be accessed here and the list of demo pages per version can be found here.

  3. Likewise, the default documentation pages exposed in our README.md file now leads to the v4.0.0-rc.2 documentation.

    The last v3.33.0 documentation page can still be accessed here and the list of documentation pages per version can be found here.

  4. We filtered files that were actually published on npm when we published a new version. For example, you now shouldn't be pulling the RxPlayer source files anymore when doing so.

v4.0.0-rc.1

24 Jan 16:54
Compare
Choose a tag to compare
v4.0.0-rc.1 Pre-release
Pre-release

Release v4.0.0-rc.1 (2024-01-24)

Quick Links:
📖 API documentation - Demo - 🎓 Migration guide from v3

🔍 Overview

After more than three years since its early drafts and one year of open beta releases, it is finally time for the first release candidate of the v4.0.0 of the RxPlayer.

The main ideas behind this new v4 major version are:

  • To provide a more flexible and powerful track and quality selection API, especially more adapted to multi-Period DASH contents.

    For example, it is now not only possible to set a particular quality on a content, you can also allow a subset of multiple qualities from which the RxPlayer will adaptively choose from, based on any of their characteristics exposed by the API.

    You can also indicate what to do if the buffer already contains media data in another quality (reload? Keep it in the buffer? Remove it?).

    Likewise, track switching becomes very configurable, allowing you to directly switch a track of any Period, again with a strategy if another track was previously present in the buffer. The RxPlayer also allow to rewind a little (and let you set by how much), in cases where you want to give back some context (for example when switching the audio track to another language).

    The main API documentation about quality selection can be found here.
    For track switching, you can refer to the API documentation of the concerned API, see for example the setAudioTrack API documentation.

  • To allow a more sane default behavior and more resilience in the RxPlayer.

    For example, we are now automatically reloading if something has been detected to have gone horribly wrong, such as when encountering some exceptional device-related decryption issues or when obtaining a completely different Manifest after updating it.

    Moreover, if the chosen track is linked to Representations (qualities) which are all impossible to decrypt, the RxPlayer will now automatically fallback to a supported track instead (after sending events to indicate that it does so).

    We were previously limited on how we could do those things to stay compatible to old APIs.

  • To facilitate the implementation of ambitious improvements.

    For example the v4.0.0-rc.1 brings the new MULTI_THREAD experimental feature, allowing to run the RxPlayer's main logic in a WebWorker for better adaptive streaming stability and performances.
    This is a huge work we're right now using on a multitude of devices at Canal+, intended to improve the quality of experience, especially on devices with limited resources.

Depending on return we have on our large-scale tests (basically, if no important issue is found with it), this release candidate may become an official v4.0.0 relatively fastly (in the coming weeks).

If you're still relying on a v3.x.x release, we recommend looking up our migration guide to make the switch more easily.

📑 Changelog

We decided to compile the full v4.0.0 changelog for this release (instead of comparing it to our latest beta release), which makes it too big for this release note!
So we're only linking you to it here: https://github.com/canalplus/rx-player/blob/bf79b9164f8d530a94e338725f795ec5a5c7b278/CHANGELOG.md

What about the v3?

The v3.33.0 release of the RxPlayer, which was published just before this one, is planned to be our final default release on npm in the v3 major version (unless there is a major issue with it).

Once the official v4.0.0 stable release is published, v4 releases will take its place as a default when installing the package through package managers such as yarn and npm.

Moreover, most incoming features and improvements will be planned for v4.x.x releases first from now on.

v3.x.x releases will still be maintained for some time (we were for example talking about providing at least 1 year of support), but it will mostly be only bug fixes and improvements simple enough to be ported to it. Of course, outside contributions are welcomed if you want to provide improvements on it yourself.

If you want to make the switch but you're afraid of relying on a release candidate right now, we recommend maintaining a branch which will depend on this
v4.0.0-rc.1 release in your project and putting it in production once the v4.0.0 is actually released.

v4 summary

The v4.0.0-rc.1 inherits from both the v4.0.0-beta.3 (and consequently any prior v4 release) and from the just-released v3.33.0 (and consequently all previous v3 releases).

The rest of this release note is going to focus ONLY on features brought in this particular release (which means we're not relisting features already announced in previous v4 and v3 release notes).

You can look at the v4 beta release notes for more information on some earlier v4 features:

And on the the v3.33.0 release note for the just-released features which are also in this one.

The new MULTI_THREAD experimental feature

This release brings the possibility of running most of the RxPlayer main logic in a WebWorker, letting your application to run concurrently with it. This has potentially large positive impacts on performance and adaptive streaming stability (e.g. keeping a stable high video quality).

This new behavior is totally optional and has to be enabled through specific APIs.
The RxPlayer is also able to automatically detect when multithreading is not possible (very old devices), to go back in the regular monothreading mode instead.

Running the RxPlayer without a WebWorker (the default):

+-------------------------------------------------------------------------------+
| Main thread (also running the UI)                                             |
|                                                                               |
| +------------------+     +----------------------+    +----------------------+ |
| |    Application   | --> |  RxPlayer Main [1]   | -> |   RxPlayer Core [2]  | |
| +------------------+     +----------------------+    +----------------------+ |
+-------------------------------------------------------------------------------+

Running with a WebWorker:

+----------------------------------------------------+
| Main thread (also running the UI)                  |
|                                                    |
| +------------------+      +----------------------+ |
| |    Application   | ---> |  RxPlayer Main [1]   | |
| +------------------+      +----------------------+ |
+--------------------------------------|-------------+
                                       | (messages)
+--------------------------------------|-------------+
| WebWorker                            V             |
|                           +----------------------+ |
|                           |  RxPlayer Core [2]   | |
|                           +----------------------+ |
+--------------...
Read more

v3.33.0

24 Jan 16:39
Compare
Choose a tag to compare

Release v3.33.0 (2024-01-24)

🔍 Overview

The v3.33.0 is now available on npm.

It is planned to be the last main v3 release now that the official v4.0.0 is around the corner and became our main focus (a v4.0.0-rc1 will be published just after this one), yet is still contains its share of improvements and bug fixes:

  • DASH: To better support retro-compatible Dolby Vision content, the scte214:supplementalCodecs is now handled. Concerned contents will be advertised under a Dolby Vision codec for compatible devices, or the retro-compatible codec for those who aren't
  • A new getLivePosition method and fromLivePosition startAt option have been added, mainly for advanced ad-switching usages.
  • subtitles: the tts:lineHeight TTML attribute was not properly applied, it is now fixed
  • subtitles: A rare occurence of blinking subtitles could arise, especially on low-latency contents. This also has been fixed.
  • Add the possibility of setting another keySystems option on the reload API.
  • Several fixes on issues that could arise when doing API calls after reaching the last playable position of a content.
  • DEBUG_ELEMENT: Undecipherable and unsupported codecs are now announced in the debug element
  • Multiple other minor fixes and improvements linked to ad-switching, checking of codec support, and low-memory handling.

📑 Changelog

Features

  • Add getLivePosition RxPlayer method [#1300]
  • Add startAt.fromLivePosition loadVideo option [#1300]
  • Add the possibility to set a new keySystems option on the reload API [#1308]

Bug fixes

  • Fix subtitles "blinking" in some specific conditions, especially with some DASH low-latency contents [#1314]
  • DASH: Fix Period overlap resolution logic for when the first Period is removed [#1311]
  • TTML: Fix handling of the tts:lineHeight attribute [#1320]
  • Fix import of the LOCAL_MANIFEST experimental feature
  • Avoid very rarely skipping segments which initially were too big to be pushed due to memory limitations [#1323]
  • Fix issue arising when using track APIs at the exact last possible position of a Period with no consecutive Period [#1337]
  • Starting at the end (through a startAt loadVideo option) or reloading at the end led to the restart of the content [#1338]
  • DRM/Safari: also perform Safari DRM work-arounds when the page is launched from the dock [#1351, #1356]

Other improvements

  • DASH: rely on SCTE214 supplementalCodecs instead of codecs if it's supported to better support backward compatible Dolby Vision contents [#1307]
  • DASH: Provide better support of the availabilityTimeOffset attribute [#1300]
  • DEBUG_ELEMENT: Add unsupported and undecipherable bitrates to the debug element [#1321]
  • DEBUG_ELEMENT: update buffer graph maximum size so it becomes more readable for lengthy contents [#1316]
  • DEBUG_ELEMENT: always synchronize inventory of segments before rendering it [#1317]
  • Remove remaining RxPlayer dependency removing possibility of some application-side bundling errors [#1312]
  • Add exception to text Garbage collection logic to avoid unnecessarily reload text segments frequently [#1325]
  • Avoid logging too much the buffer's content when our debugging UI or the demo is used [#1341]
  • Demo: Fix reporting of live position in demo page [#1313]

About it being the last "main v3 release"

As we've reached a point where we plan to release the first official v4.0.0 release, we also plan to make v4 releases our main focus when new features and improvements are added. As such, a v4.0.0-rc1 release should be released just after this release. If our large-scale tests go well, it will become the first v4.0.0 release.

This do not mean that the v3 will become unsupported. It should still receive bug fixes yet:

  1. It will not be the version installed by default through npm / yarn, which will be the v4 instead once the official v4.0.0 version is released.
    The idea will be to set the npm legacy-v3 tag for newer v3 releases, so an rx-player v3 may be installed through something like: npm install rx-player@legacy-v3.

  2. When planning new improvements, we now will implement it on the v4 first, and only backport it to the v3 if it is simple enough with few risks to break.

  3. As more and more applications will rely on the v4 (we already "convinced" many at Canal+ to do so), we will progressively become more aware of issues when they concern the v4 and less about v3 issues.

DASH supplementalCodecs handling

We recently had some issues trying to play Dolby Vision content on LG TVs where the device would not play at all, due to a discrepancy between the video codec announced by the RxPlayer (which did not make mention of Dolby Vision), and the Dolby Vision data actually pushed to the video buffer.

This was because the media stream we've tested make usage of a smart trick: as the Dolby Vision video data was backward-compatible to regular HDR for devices not supporting Dolby Vision, two codecs were actually announced in the content's MPD (the DASH's Manifest file, which list available tracks and qualities):

  • The much more compatible HDR codec, as a codecs attribute (e.g. in a <Representation> or <AdaptationSet> element in the MPD) like expected
  • The Dolby Vision codec, as a scte214:supplementalCodecs property, that we did not process until now

repsupcodec
Screenshot: Content of a DASH MPD with both a codecs property and a supplementalCodecs property in the <Representation> element

The RxPlayer previously only relied on the codecs property (so here not the Dolby Vision video codec) when interacting with lower-level media API.
Though the HDR codec was compatible to the video data, it was actually expected by some Dolby Vision-capable device that the Dolby Vision codec should have been relied on when creating video buffers.

However, if we did rely on the Dolby Vision codec instead through those API, devices which do not handle Dolby Vision video content would not have been able to play the content as just "regular" HDR video data, for them it would have been Dolby Vision, which they do not know how to decode.

So we chose to put a little more intelligence in the RxPlayer, when there is a scte214:supplementalCodecs property (let's call the corresponding codec property the "supplemental codec"):

  • If the supplemental codec is supported by the current device (we can know that through the MediaSource.isTypeSupported API, we consider it to be the actual "codec" of the corresponding video data.
  • If it is not supported, we rely on the codecs instead, just like we did before

suppcodec
Flowchart: How the RxPlayer will decide whether to rely on a scte214:supplementalCodecs or a codecs attribute in a DASH MPD.

This also means that API communicating about video codecs, like the getVideoTrack method, may now actually indicate the "supplemental codec" through their codec property, where it always corresponded in DASH to the corresponding codecs attribute instead).
This should in most case not lead to any change in your application as this is mainly a lower-level detail about a Representation (a.k.a. media quality).

getLivePosition method and startAt.fromLivePosition option

Some applications at Canal+ relying on the RxPlayer make use of "ad-switching" technologies.
Basically, the idea is to replace ads present in a source stream by targeted ads.

There are multiple techniques to implement this, yet for DASH they generally rely on its concept of Periods.
In the MPD (DASH's Manifest file), each of those ads would be defined in a different <Period> element, which is a time-delimited division of the content with its own media tracks and qualities.

multiperiods
Schema: Exemple of a schema representing a DASH multi-Period live content, with an ad break where each Period corresponds to a single Ad.

Another effect of ad-switching is that the server may know in advance which ad should be served to a user.

Let's for example consider a user which plays a live content. That user now encounters an ad-switched ad break at 11:04 AM, which will end 5 minutes later, at 11:09 AM.
Though it is still 11:04, the server already knows which ads it's going to serve to that user from 11:04 to 11:09 (those ads are targeted and already scheduled), so it may want to already announce them in the MPD even though most of those ads are m...

Read more

v4.0.0-beta.3

19 Oct 18:15
c9dd85f
Compare
Choose a tag to compare
v4.0.0-beta.3 Pre-release
Pre-release

Release v4.0.0-beta.3 (2023-10-19)

Quick Links:
📖 API documentation - Demo - 🎓 Migration guide from v3

🔍 Overview

The v4.0.0-beta.3 release is now here. As usual, it is based on the last official v3 release (here the just released v3.32.1) as well as previous v4 beta releases.

The v4.0.0-beta.3 release should be the last v4 "beta" release, meaning that the next v4-linked release will probably be our first release candidate for a first official v4.0.0 release.

We already tested the code behind this beta.3 release extensively in production conditions on most environments we target at Canal+ (which helped us detect and fix an adaptive-linked issue only seen on older Edge browser versions), so we're becoming confident that this version will work on every supported devices and for a large panel of usages.

As we wanted to ensure that the v4 API is final (or very close to final), we reviewed every RxPlayer v4 API on current usages as well as future planned usages to ensure that API stability is easy to guarantee. This led to some changes, described in this release note.

📑 Changelog

Changes

  • The MediaError's trackInfo property is now an array renamed as tracksInfo and similar MediaError are grouped in one [#1264]
  • The manifestUpdateUrl loadVideo option has been removed as it was unused [#1276]
  • The /dist directory in the project has been removed [#1270]

Bug fixes

  • Fix adaptive logic on some legacy Edge browsers [#1302]

Other improvements

  • newAvailablePeriods is now sent lazily at the time new Periods are considered to improve performance [#1265]
  • Implement better error messages by not repeating the Error Type in it [#1290]
  • All import path to the RxPlayer now depend on the same RxPlayer modular build (and not just the minimal, as before) [#1301]

newAvailablePeriods event now sent lazily

The newAvailablePeriods event is a new RxPlayer event central to the v4 API indicating that new "Periods" from the current content begin to be considered by the RxPlayer.
As each Period brings with it its own set of audio/text/video tracks and qualities, it is the main event to listen to when you want to choose an initial track or quality.

hierarmpd
Screenshot: screenshot describing the Period, AdaptationSet and Representation elements of an MPD, which are advertised in the v4 API beginning with a newAvailablePeriods event.

In previous beta and alpha releases, the RxPlayer sent this event just after parsing the content's Manifest (and after refreshing it), by communicating directly about all Periods seen in that Manifest.

We became afraid that on very large Manifest with a large amount of Periods and track choices, the current design for this event could lead to performance issues: as soon as the Manifest was parsed (and before the content started to play), the RxPlayer would send a newAvailablePeriods event - perhaps for the hundreds of Periods seen in that Manifest.
The application (the software using the RxPlayer library) would then iterate through all of those Periods, as well as its inner tracks and qualities, to make its initial choice - and all that before the content is finally able to play.

supergraph
Graph: Timeline of situations leading to the newAvailablePeriods event and corresponding player actions. It then continues as the setting of the audio, video and text tracks by the application has to be done for all Periods advertised through the newAvailablePeriods event.

This seems risky performance-wise as well as unnecessary. When the content starts to play, the only track and quality choices we probably want to set are just the one linked to the Period we're initially playing. For live contents for example, we don't need to set the audio track for the program that was aired 15 minutes ago.
The only time where we might want to set it, is if the user ever seeks back to that program (a situation which might never occur).

The RxPlayer now "lazily" sends newAvailablePeriods events, meaning that it will only communicate about "Period(s)" that are either playing or will be played soon by the RxPlayer. For example when playing a live content, it will probably only send this event for the currently-playing program, not the one playing before or after it.

supergraph2
Graph: Updated timeline now that newAvailablePeriods only transports information on the Period(s) that matter for now. Here we can see that the application for example only set the tracks for a single Period.

If the user seeks to another Period or if playback position reaches a new Period, a new newAvailablePeriods will then be sent for it.

Normally, this doesn't break the previous v4 API so you shouldn't need to change anything if you relied on a previous v4 version. Still, as it is a considerable change, you could need to check if this doesn't break assumptions you previously had on your side.

Changes concerning Errors

Error message changes

Historically, the message property of RxPlayer errors had the peculiar following format:

<Error Type> (<Error Code>) <Error Message>

For example, for an EncryptedMediaError with an INCOMPATIBLE_KEYSYSTEMS code, we could have:

EncryptedMediaError (INCOMPATIBLE_KEYSYSTEMS) Some description message

Packing so much information into the message was unconventional, repeated information already available elsewhere and led to an ugly reporting in debuggging tools.
For example, error logged in most inspectors and debuggers are already prepended by the Error Type, leading in the previous example to the following log:

EncryptedMediaError: EncryptedMediaError (INCOMPATIBLE_KEYSYSTEMS) Some description message

Although error messages are not part of our API (so we could have changed its format at any time) we were still reluctant to do so as applications might have relied on that format to extract information programatically. Now that the official v4 is around the corner, we finally updated its format to a more legible:

<Error Code>: <Error Message>

As such the previous error message would be:

INCOMPATIBLE_KEYSYSTEMS: Some description message

And it would be logged by inspectors as:

EncryptedMediaError: INCOMPATIBLE_KEYSYSTEMS: Some description message

trackInfo renamed as tracksInfo

We made another small change to RxPlayer errors, this time on the recently-added trackInfo property that could be set on some MediaError, to add precizion on the particular track concerned.

We noticed that many of them were sent in bulk, for example when the Manifest is found to contain multiple tracks in unsupported codecs, we would send a warning event dispatching a MediaError with an MANIFEST_INCOMPATIBLE_CODECS_ERROR for each of the unsupported track (and in multi-Period contents, there could be hundreds of them).

Now we decided to group such errors together when they are happening at the same time, and to allow the setting of multiple tracks' information in a tracksInfo array property (with an s, instead of the previous trackInfo). The MediaError documentation has been updated.

Changes concerning the builds

In previous RxPlayer versions, we exposed several builds of the RxPlayer in the npm repository:

  1. The "legacy" build, which is a bundled single JS file, which was used when importing the RxPlayer "normally" through an import RxPlayer from "rx-player" line in ES6-style (or const RxPlayer = require("rx-player") ni CommonJS style).

    We relied on the Webpack bundler to produce that build.

  2. The "modular" build, targeted by most other imports (such as the minimal build: import RxPlayer from "rx-player/minimal") which uses multiple files, allowing for "tree-shaking" on the application-side.

    Here we mostly rely on TypeScript and on our own scripts.

Having this double way of exporting the RxPlayer led to some complexity on our side and we weren't too comfortable of having too much complexity in such an important area for a library.

We'r...

Read more

v3.32.1

19 Oct 17:19
Compare
Choose a tag to compare

Release v3.32.1 (2023-10-19)

NOTE: This is the v3.32.1 and not a v3.32.0 as you could have expected due to a small mistake when publishing our TypeScript types to npm for a v3.32.0. We detected it and fixed it immediately with a new release, the v3.32.1.

🔍 Overview

The v3.32.1 mainly brings stability improvements over the v3.31.0, as we start to focus more and more on the future v4.0.0 release.

On that matter we'll probably soon release the first v4.0.0 release candidate (paving the way for the first official v4.0.0 release), after a long period of alpha and beta releases (the next beta release should come just after this one) where we were still figuring out some API details.

Note that we're however still commited to maintain the v3.x.x releases for some time, at least in terms of providing bug fixes, as we know doing the switch to the v4 may not be in your agenda for now.
As such, even when the official v4.0.0 will be released, we will continue publishing some v3.x.x releases, only with a special npm tag (e.g. rx-player@v3).

📑 Changelog

Features

  • DASH: add optional isSpatialAudio boolean property to Representation returned by getAvailableAudioTracks, getAudioTrack, corresponding events, and trackInfo optional property of MediaError objects to signal Dolby Atmos techology [#1275]
  • LOCAL: add isSpatialAudio property to Representation of the experiment "local" transport (used for offline playback) [#1275]
  • addFeatures static method is now available on all RxPlayer builds. It was previously only in the minimal (rx-player/minimal import path) [#1287]
  • The NATIVE_TEXT_BUFFER, HTML_TEXT_BUFFER and IMAGE_BUFFER features are now totally optional [#1287, #1293]

Bug fixes

  • Fix setVideoBitrate and setAudioBitrate API which may have led to a higher quality than wanted in the default "seamless" manualBitrateSwitchingMode if our buffer-based adaptive logic decided to [#1267, #1271]
  • On the PlayStation 5, only switch to the "LOADED" state once the HTMLMediaElement's readyState of 4 has been reached, as it seems to switch to 3 too soon there [#1257]
  • DASH: Fix potential track duplication if more than two AdaptationSet have an adaptation-set-switching <SupplementalProperty> between one another [#1279]
  • DASH-WASM: availabilityTimeOffset is actually a floating number [#1278]

Other improvements

  • Do not load the last text segment if the current position goes after it as it is unnecessary [#1256]
  • Implement better NetworkError messages [#1274]
  • Set a better error message for when no keySystems option is set when playing an encrypted content
  • Fix very small memory leak when reloading a content [#1286]
  • Re-check for segments to load immediately after the manifest has been refreshed [#1282]
  • When "fallbacking" an undecipherable Representation, now empty the whole buffer if we can't make out where content was in the buffer [#1283]
  • Improve segment start detection in buffer when there's unknown data buffered before it [#1284]
  • DRM: Selection of alternative EME API like those used on IE11 or Safari has been refactored to facilitate future developments [#1261]

Deprecated

  • Deprecate the manifestUpdateUrl loadVideo option as it doesn't seem used anymore [#1288]
  • Deprecate the NATIVE_TEXT_BUFFER, HTML_TEXT_BUFFER and IMAGE_BUFFER features as they are now unneeded [#1287, #1293]

New isSpatialAudio property

This v3.32.1 release brings the new isSpatialAudio property to audio tracks on the following API:

This property is for now only set to true when an audio track relies on Dolby Atmos under the "Dolby Digital Plus Joint Object Coding" (or JOC) technology, which allows to distribute Dolby Atmos audio content in a format compatible with Dolby Digital Plus audio (most probably under the "ec-3" codec), which is Dolby's recommended way of distributing DASH contents with Dolby Atmos audio.

So in short, for now isSpatialAudio is only set to true when an audio track relies on Dolby Atmos technology. For any other cases for now, it is not defined (a value of false would semantically mean that we're sure that the audio track is not spatial audio, which is a guess we prefer not to make for now).

Due to what's allowed in DASH, the isSpatialAudio property is set on "representations" (a.k.a. qualities), not on the track itself:

function hasSpatialAudio(audioTrack) {
    if (!audioTrack) {
        return false;
    }
    return audioTrack.representations
        .some(representation => representation.isSpatialAudio === true);
}

if (hasSpatialAudio(player.getAudioTrack()) {
    console.log("We're currently playing an audio track with spatial audio");
}

The majority of the development on this feature has been provided by an external contributor, @klatoszewski-oke, which we thank again.

addFeatures now globally available

On previous RxPlayer releases you were forced to rely on the minimal RxPlayer build to use any of its experimental features like DASH_WASM (WebAssembly-based DASH MPD parser), LOCAL_MANIFEST (playback of offline contents), DEBUG_ELEMENT (debugging UI) or METAPLAYLIST (client-side content generation).

If instead you used the default RxPlayer build, for example through a simple import RxPlayer from "rx-player"; import in your files, you were just left with the default set of features.

Now any build of the RxPlayer can directly call the addFeatures static method to add any of those optional features. For example to add the DEBUG_ELEMENT feature (and thus be able to call the createDebugElement method), you can write:

// 1. Add `DEBUG_ELEMENT` feature
import RxPlayer from "rx-player";
import { DEBUG_ELEMENT } from "rx-player/experimental/features";

RxPlayer.addFeatures([DEBUG_ELEMENT]);

// 2. Create RxPlayer instance and call method
const player = new RxPlayer({ /* ... */ });
player.createDebugElement(myElement);

Consequently, the features documentation has been moved from the "Getting started" part to our regular "API" documentation.

Deprecation of the NATIVE_TEXT_BUFFER and HTML_TEXT_BUFFER features

Both the NATIVE_TEXT_BUFFER feature and the HTML_TEXT_BUFFER features, which are the arguments of the addFeatures static method, have been deprecated as they are now unneeded.

They're basically optional now that importing a text parser for the corresponding type of buffer is going to implicitely add the feature anyway.

This means that if you were previously doing:

import RxPlayerMinimal from "rx-player/minimal";
import { HTML_TEXT_BUFFER, HTML_TTML_PARSER } from "rx-player/features";
RxPlayerMinimal.addFeatures([HTML_TEXT_BUFFER, HTML_TTML_PARSER]);

You can now just omit the HTML_TEXT_BUFFER feature:

import RxPlayerMinimal from "rx-player/minimal";
import { HTML_TTML_PARSER } from "rx-player/features";
RxPlayerMinimal.addFeatures([HTML_TTML_PARSER]);

As you have no reason to import one of those features without at least one parser, making it optional and implicit will generally just simplify your code.

Many small fixes

This v3.32.1 brings a lot of small fixes and improvements, that you can see on the changelog on top of this release note.

A good chunk of them were found as we were extensively testing both the future v4.0.0 as well as our proof-of-concept of trying to run the RxPlayer's internal logic in a WebWorker (more details on this hopefully soon).

We also reinforced our debugging capabilities by continuing our work on RxPaired, our remote debugger specialized for the RxPlayer that we're using internally at Canal+.
This helps a lot when debugging the RxPlayer on devices such as smart TVs, chromecast and game consoles which often have their own issues.
It helped us ...

Read more

v4.0.0-beta.2

27 Jun 15:06
ab78c0f
Compare
Choose a tag to compare
v4.0.0-beta.2 Pre-release
Pre-release

Release v4.0.0-beta.2 (2023-06-27)

Quick Links:
📖 API documentation - Demo - 🎓 Migration guide from v3

🔍 Overview

The new v4 beta release, based on the v3.31.0, is here.
It contains all improvements from previous v4 alpha and beta releases, as well as some further improvements mostly related to DRM, all described in this release note.

About v4 beta releases

As a reminder, beta v4 versions are RxPlayer pre-releases (as some minor API changes are still done, see changelog) for the future official v4 release, a successor to the current v3 releases of the RxPlayer.

We're currently testing it on several applications. As we're doing it, our team as well as people porting it can propose some small API improvements, which may then be added to the next beta releases. After enough people have made the switch and are satisfied with the new API, the first official v4 release will be published (we're also in the process to have some applications running it in production to ensure its stability with a large enough population).

We will still continue maintaining and providing improvements to the v3 for at least as long as the v4 is in beta (and we will probably continue to provide bug fixes for the v3 for some time after the official v4.0.0 is released).
This process is long on purpose to be sure that we're providing a useful v4 API for applications and also to avoid alienating application developers, as the migration from the v3 might take time.

📑 Changelog

Changes

  • If all Representations from the current track become undecipherable, automatically switch to another track (also send a trackUpdate event) instead of stopping on error [#1234]
  • Only send MediaError errors with the NO_PLAYABLE_REPRESENTATION error code when no Representation from all tracks of a given type can be played [#1234]

Features

  • Add representationListUpdate event for when the list of available Representation for a current track changes [#1240]
  • Add "no-playable-representation" as a reason for trackUpdate events when the track switch is due to encrypted Representations [#1234]

Other improvements

  • DRM: Reload when playback is unexpectedly frozen with encrypted but only decipherable data in the buffer to work-around rare encryption-related issues [#1236]

NO_PLAYABLE_REPRESENTATION behavior change

In the v3 and previous v4 beta releases, if you could not play any Representation (i.e. quality) from your chosen audio or video track due to encryption matters, you would obtain a MediaError error with the NO_PLAYABLE_REPRESENTATION error code.

Stopping on error when no quality of the chosen track can be played seemed logical at the time, but we're now encountering use cases where it would be better if the RxPlayer automatically took the decision to change the current track instead, to one that perhaps has decipherable Representation(s).
The main example we encountered was cases where we had separate video tracks, each linked to another dynamic range (e.g. an HDR and a SDR track) and with different security policies (tracks with a high dynamic range would have more drastic security policies for example).
Here, I would guess that an application would prefer that by default we switch to the SDR video track if no Representation in the HDR one is decipherable, instead of just stopping playback with a NO_PLAYABLE_REPRESENTATION error.

Before:
-------

+----------------+
|    Selected    |  Not decipherable
|   Video Track  |  --------------------> NO_PLAYABLE_REPRESENTATION
| (example: HDR) |                        Error
+----------------+

Now:
----

+----------------+                        +---------------------+
|    Selected    |  Not decipherable      |      Automatic      |
|   Video Track  |  --------------------> |     fallback to     |
| (example: HDR) |                        | another video Track |
+----------------+                        |   (example: SDR)    |
                                          +---------------------+

Note that the NO_PLAYABLE_REPRESENTATION error might still be thrown, only now it is when no Representation of all tracks for the given type are decipherable.

New trackUpdate reason

Because an application might still want to be notified or even stop playback by itself when the initially-chosen track has no playable Representation, we also brought added the "no-playable-representation" reason to the trackUpdate event, which indicates that the current track for any Period of the current content was updated due to this situation.

player.addEventListener("trackUpdate", (payload) => {
  if (payload.reason === "no-playable-representation") {
    console.warn(
      `A ${payload.trackType} track was just changed ` +
      "because it had no playable Representation"
    );
  }
});

New representationListUpdate event

This new beta version of the v4 also brings a new event: representationListUpdate.

The problem without this event

Let's consider for example an application storing information on the currently available qualities (a.k.a. Representation) for the chosen video track of the currently-playing Period (said another way: being played right now).
With the v4 that application can simply get the initial list of Representation when that Period begins to be played through the periodChange event and update this list any time the video track changes, by listening to the trackUpdate event:

let currentVideoRepresentations = null;

function updateVideoRepresentations() {
  const videoTrack = player.getVideoTrack();
  if (videoTrack === undefined || videoTrack === null) {
    currentVideoRepresentations = null;
  } else {
    currentVideoRepresentations = videoTrack.representations;
  }
}

// Set it when the Period is initially played
player.addEventListener("periodChange", () => {
  updateVideoRepresentations();
});

// Set it when the video track is changed
player.addEventListener("trackUpdate", (t) => {
  // We only want to consider the currently-playing Period
  const currentPeriodId = player.getCurrentPeriod()?.id;
  if (t.trackType === "video" && t.period.id === currentPeriodId) {
    updateVideoRepresentations();
  }
});

// Remove it when no content is loaded
player.addEventListener("playerStateChange", () => {
  if (!player.isContentLoaded()) {
    currentVideoRepresentations = null;
  }
});

This seems sufficient at first.

But now let's consider that we're playing encrypted contents, and that one of the Representation of those current video tracks became un-decipherable at some point (e.g. after its license has been fetched and communicated to your browser's Content Decryption Module).
Here, an application won't be able to select that Representation anymore, so it generally will want to remove it from its internal state. However, there was no event to indicate that the list of available Representations had changed when neither the video track itself nor the Period has changed

The new event

We thus decided to add the representationListUpdate event. Exactly like the trackUpdate event, it is only triggered when the Representation list changes, i.e. not initially, when the track is chosen.

So taking into consideration that point, the previous code can be written:

let currentVideoRepresentations = null;

function updateVideoRepresentations() {
  const videoTrack = player.getVideoTrack();
  if (videoTrack === undefined || videoTrack === null) {
    currentVideoRepresentations = null;
  } else {
    currentVideoRepresentations = videoTrack.representations;
  }
}

// Set it when the Period is initially played
player.addEventListener("periodChange", () => {
  updateVideoRepresentations();
});

// Set it when the video track is changed
player.addEventListener("trackUpdate", (t) => {
  // We only want to consider the currently-playing Period
  const currentPeriodId = player.getCurrentPeriod()?.id;
  if (t.trackType === "video" && t.period.id === currentPeriodId) {
    updateVideoRepresentations();
  }
});

// Remove it when no content is loaded
player.addEventListener("playerStateChange", () => {
  if (!player.isContentLoaded()) {
    currentVideoRepresentations = null;
  }
});

// What's new:
...
Read more