Skip to content

v4.2.0

Latest
Compare
Choose a tag to compare
@peaBerberian peaBerberian released this 17 Oct 13:17
· 48 commits to dev since this release
419d66a

Release v4.2.0 (2024-10-17)

Quick Links:
πŸ“– API documentation - ⏯ Demo - πŸŽ“ Migration guide from v3

πŸ” Overview

The v4.2.0 is out, with both new features and multiple fixes:

  • "cmcd" (for "common media client data") v1 is now (fully) supported. It is a standardized system to allow the communication of current playback conditions through http(s) requests.

  • When checking which media codec is supported on the device, we now also consider encryption as a factor.

    This is following new Google Chrome releases supporting HEVC only when unencrypted.

  • We added a filterPlayableRepresentations option to our audio and video tracks getters.

    This lets the application know about which media has been filtered out (e.g. 4k content due to it not being decipherable, or hevc content for not being decodable).

  • We added a contentProtections property to Representations returned by the API to let applications know which Representations are encrypted and what their key id are.

  • We added the checkManifestIntegrity option, allowing to retry Manifest requests in cases where the CDN returned corrupted data.

    This was added after such behaviors was actually seen, in the name of resilience even when the issue is in another component of the media streaming process.

  • We worked around a Safari bug leading to infinite loading when playing encrypted HLS contents (through the directfile transport) and having a system language different than the playlist's default language.

  • We added the LogFormat static property to produce more informative logs.

  • Many other fixes, including some for the experimental MULTI_THREAD feature, some for the DASH_WASM feature, for a short-lived firefox issue, for legacy bundles...

Changelog

Features

  • Add cmcd object to loadVideo options to enable CMCD (Common Media Client Data) [#1461, #1518]
  • Add checkManifestIntegrity loadVideo option as a temporary work-around when you suspect your packager or CDN to sometimes deliver corrupted data [#1471]
  • Add contentProtections to the representations of the tracks API to know if they're considered encrypted [#1505]
  • Add filterPlayableRepresentations property to audio and video tracks API to get information on ALL representations, even those that won't be played [#1501]
  • Add LogFormat static property to the RxPlayer to try improving on bug reports [#1469]
  • Experimentally re-export config in v4 (only intended for debugging matters) [#1510]

Bug fixes

  • Detect cases where an encrypted media's codec is not supported specifically when the media is encrypted and prevent the playback of such contents [#1484]
  • Work-around the "hulu issue" seen on firefox 129 and 130 (1911283 and 1912238 on bugzilla) which also impacted the RxPlayer [#1495, #1498]
  • Fix rare cases where the active Period would not be advertised by the RxPlayer [#1502]
  • Actually trigger a BUFFER_FULL_ERROR when QuotaExceededError mitigations after appendBuffer MSE calls don't work #1546
  • Fix issues when handling a QuotaExceededError after an appendBuffer MSE call [#1546, #1559]
  • Directfile/Compat: Fix startAt.fromLastPosition handling on Safari when playing directfile contents [#1548]
  • DRM/Compat: Re-create MediaKeys for each content on Philips' NETTV, and KSTB40XX set-top boxes [#1515]
  • DRM/Compat: fix content not starting on Safari because key are never considered usable for a track [#1479, #1512]
  • DASH_WASM: fix Label element never being parsed [#1541, #1540]
  • Fix RxPlayer not being exposed in release bundles [#1542]
  • Consider stpp.ttml codec for text format [#1557]
  • Prevent very rare cases of infinite rebuffering after getting errors from calling the SourceBuffer.prototype.appendBuffer and SourceBuffer.prototype.remove MSE API [#1560, #1561]
  • MULTI_THREAD: Fix rare CancellationError error happening when reloading while a reload is pending. [#1528]
  • MULTI_THREAD: fix wrong Period considered as current in multi-Period DASH contents with the multi-thread feature [#1527]
  • MULTI_THREAD: Fix rare occurrences of infinite loading on constrained devices [#1556]

Other improvements

  • DASH: provide a more precize calculation for the timeshift buffer depth [#1483]
  • Handle hev1 codec and hvc1 codecs as part of the same family of codecs when trying to check for compatibility between the two [#1499]
  • Better handle QuotaExceededError issue after appendBuffer MSE calls when wantedBufferAhead is set to Infinity [#1546]
  • Code: Forbid the direct usage of MSE and HTML5 media TypeScript type in profit of our own compatible ones to facilitate testing and the addition of platform-specific differences [#1397].
  • Demo: Remove standalone demo as we never relied on it [#1473]
  • Scripts: Automatize official releases and CHANGELOG.md updating through a script [#1524]

CMCD v1 support

CMCD, for "Common Media Client Data", is a standard allowing to communicate various playback-related metrics to the CDN when requesting resources.

The idea is that a back-end may then be able to exploit those metrics with the goal of improving both the streaming experience (e.g. by putting more bandwidth to customers that need it the most or by preparing segments that will be requested in the future) and the monitoring aspect (by being notified about buffer-related information, following the user's QoE).

The information CMCD v1 relies on can be here communicated either through HTTP(S) request headers or a query string in the URL and is opt-in: it is only enabled if the new cmcd loadVideo option is communicated.

cmcd
Screenshot: request for an initialization segment with CMCD enabled as query string parameters.

Many players and CDN support CMCD today but the RxPlayer did not until now - mainly because we prioritized other work in the past.
We've now added a CMCD implementation so that application that wants to rely on it are now able to do so.

DRM: Detection of codecs unsupported when encrypted

Recently Google Chrome added support for HEVC (also known as "H.265"), though only if it was either unencrypted or if the current device had what we call "hardware DRM" available (which most desktop PCs do not have).

This was problematic because when considering what the RxPlayer was able to play it only checked if the codec was supported. It did not also take into consideration DRM matters.

We've now worked to not only consider whether a codec should theoretically be supported by a device but also consider, when the corresponding content is encrypted, if it is also supported when encrypted.
This improvement most notably now lead to the RxPlayer correctly avoiding encrypted H.265 video content on devices where hardware DRM is not available.

DRM: More information on Representations in the API

We sometimes work closely with applications using the RxPlayer, at least those at Canal+, to understand what API they might miss.

We noticed that our audio and video tracks API missed some key information that the application may find useful.

1. New filterPlayableRepresentations option

Previously, we filtered non-"playable" Representations (qualities) from our audio video tracks methods (getVideoTrack, getAvailableVideoTracks...) and events (videoTrackChange, availableVideoTracksChange...).

What this means is that video and audio qualities that were either in an unsupported codec or that were non-decipherable would not be communicated by those API, as they cannot be played anyway.

However, an application may want to know which qualities were present in the content yet are not supported, for example for monitoring and debugging use cases.

To allow this usage, the RxPlayer can now optionally take a filterPlayableRepresentations property through those following API:

When adding this option, those methods will also return information on "Representation" which cannot be played by the RxPlayer. You will now whether the limitations are due to an unsupported codec, because it is not decipherable, or both, respectively by checking their isCodecSupported and decipherable properties.

filter
Screenshot: First call is to rxPlayer.getVideoTrack() (on top) and we can see the 6 representations that seems to be available (from bitrate 190000 to bitrate 2100000).
Next call is to rxPlayer.getVideoTrack({ filterPlayableRepresentations: false }), we can now see the actual 8 representations linked to that track (adding bitrates 3400000 and 4500000), with those top two being undecipherable (decipherable is set to false) so will not be played (which is why they weren't included on top).

2. Adding DRM-related information to Representation

We found out that an application had no practical way of knowing which Representation (quality) was encrypted when calling video and audio track APIs.

Because this is an important information that may be useful to applications, we added an optional contentProtections property to elements of the representations array property returned by the following methods and events:

And directly as a property of the objects returned by the following methods and events:

When that contentProtections is set to an object, it indicates that the corresponding Representation is encrypted. The contentProtections can itself contain a keyIds property, which is an array of Uint8Array corresponding to the key id(s) linked to that Representation.

keyid
Screenshot: There's now a new contentProtections.keyIds on the object describing a Representation

keySystems[].reuseMediaKeys option

An important issues is encountered at Canal+ when broadcasting live events, usually sports game: many customers load the channel at once, leading to a time-localized huge server load.

Usually CDN serving Manifest and segments can handle the load just fine, as they are very frequently requested anyway as people continue to watch the content.
However the fetching of the license to decrypt the content happens much less frequently, and thus servers are less prepared for those huge pikes.

To lower this load, we have added many features to the RxPlayer, the singleLicensePer option, persistent licenses support, and "MediaKeySession caching" which we will talk about now.

MediaKeySession caching is a concept in the RxPlayer where we keep around encryption keys that are not used anymore, just because they might be needed again in a short time.
For example, when switching between two live channels, or when different programs are encrypted with different keys yet keys may come back in a future program, keeping the old key around allows to prevent a license request.

cache
Schema: general idea behind our cache. Here we're switching back to the previously-played "content 1". As its keys have already been loaded previously, we avoid a license request.

MediaKeySession caching is enabled by default, though we noticed that implementation bugs on many devices (seen on LG TVs, Panasonic TVs, Philips TVs and some set-top boxes) causes playback issues when that cache is enabled.

Until now, our strategy has been to implicitly disable caching on the devices where we detected issues. However as we continue to see more devices with implementation issues, we now added the new keySystems[].reuseMediaKeys loadVideo option.

It is today by default set to true - which means that caching is enabled - but can be set to false to disable caching if issues are seen on the current device when playing multiple encrypted contents. The long term idea would be to have it set to false by default on a future major version (which should not happen before a long time though) so only applications who needs caching would enable it, and others would profit from a theoretical better compatibility by default.

LogFormat static property

A large amount of time spent when maintaining the RxPlayer is actually spent on debugging device-specific issues. Media streaming is complex and has many opportunities to break or be implemented subtly differently on some platform.

To help us in that debugging task, we beefed-up our debugging capabilities: the RxPlayer can output a LOT of logs, we developed our own specialized remote
debugger
so we can be monitoring low-end devices for a long amount of time with very low memory usage (unlike chromium's or webkit's debugger), added the DEBUG_ELEMENT feature and developed some reverse-engineering tools.

Now that we have many tools at our disposition, it's our "regular logs" (those that can e.g. be produced by calling RxPlayer.LogLevel = "DEBUG") that are lacking. Incidentally, that's how most applications report issues to us initially.

To improve on those logs, we introduce the new LogFormat static property:

import RxPlayer from "rx-player":

RxPlayer.LogFormat = "full";

By setting it to "full", you will enable richer logs. Those include timestamps as well as the log's severity at the beginning of each logged message.

It also adds some logs which allows us to import those logs in our debugging tools to better understand what happened, especially on long-lived tests (our "RxPaired" debugger has a "time-travel" feature, allowing to check playback conditions at particular timestamps, relying on those).

logformat
Screenshot: Difference between regular "standard" logs and the "full" format. We can see that the "full" format includes a timestamp between other things.

As such, when applications report bugs, we may now ask them to set the "full" LogFormat to have more debugging capabilities.

You may also want to enable it directly, we chose to keep the current "standard" LogFormat by default so the logs applications are currently used to don't drastically change.

checkManifestIntegrity option

While investigating an issue encountered by an application at Canal+, we noticed that their CDN sometimes returned corrupted / incomplete Manifest files.

This should never happen and is most likely a back-end issue, but as sometimes such issues happen,we decided to better handle that risk by adding the checkManifestIntegrity loadVideo option.

When setting it to true, the RxPlayer will perform some (minor) checks after a Manifest request (though for now only for DASH) to check if it appears coherent/complete. If it does not, the request will be retried under the same retry rules that a failing request (see requestConfig loadVideo option to configure those retry rules).

checkManifestIntegrity is disabled by default, as enabling it should not be needed by most applications and may hide a back-end issue that should be fixed.

Safari/DRM: Fix for the DRM+language issue

Multiple applications are able to play HLS contents with the RxPlayer on Apple devices by relying on the directfile transport, as Safari is able to handle HLS natively as well as all IOS browsers.

However, we often encounter issues with that configuration. One that was especially annoying was that encrypted content with multiple audio languages sometimes were not able to load, if the OS' default language was not the content's default language. After investigations, it seems to be a race condition inside Safari's way to handle DRM-related APIs.

Succeeding to report and get Safari issue fixes is hard, so we tried for a long time to find a way to work-around that bug inside the RxPlayer.
We finally found a working work-around for that particular issue: if we call several time some EME API (the group of web API related to DRM) instead of a single time in some conditions, the issue is fixed.

We added that work-around to the v4.2.0.

Note 1: Facilitating tests of RxPlayer pending developments

When developing bug fixes and new features, we often needs to see if it corresponds to an application's needs before actually adding to the RxPlayer.

Until now, we handled this by having read (and sometime write) access to applications at Canal+ relying on the RxPlayer, to test our ongoing development on them, and in occasions where we could not do the test ourselves, we would try to find a way to communicate a temporary release of the RxPlayer to application developers.

However doing such temporary releases wasn't a convincing solution:

  • we could for example push a pre-release to the npm registry, yet we cannot remove those once they're not needed anymore, meaning we'll clutter space we prefer to use for real releases
  • We could use git, and GitHub, to store temporarily build artifacts and rely on those, but this was also at a higher maintenance cost than what we would have liked and we felt it played a little with implicit rules of version control systems and forges.

A solution we finally found was to rely on GitHub's releases, which can have attached files and which can be removed at any times: We added a script which optionally creates an RxPlayer release with a linked archive that can be installed through most node package managers (npm, yarn, pnpm etc.) when a Pull Request is opened on GitHub.

Because we didn't want to clutter our release in this repository, we for now awkwardly only allow forks to perform such releases: RxPlayer forks now will be optionally able to produce a release on each GitHub Pull Request opened that does not target this official repository. A message will be added to that Pull Request to indicate what has to be done (which for now is only to add a particular "tag" to that Pull Request):

releasenote1releases
Screenshot: Example of messages indicating to developers how to rely on those temporary releases

The idea is that we, RxPlayer maintainers, will be the main users of that feature. Yet it will help us greatly in providing bug fixes and features to application developers, also allowing us to easily make application developers test a fix.

NOTE 2: Work-around for a Firefox 129 issue

For a few days after the release of Firefox 129, most applications relying on the RxPlayer were unable to play encrypted contents on Firefox.

This issue, which also touched other streaming platforms (we know that the popular "hulu" platform was also concerned) was due to a temporary issue in that Firefox release.

However, we saw that multiple other streaming platforms could play encrypted contents on Firefox just fine. This launched an attempt on our side to improve our reliability in that regard.
Our DRM setup logic is now better aligned with other big streaming platforms that weren't impacted by the issue, this should not change anything for an application beside improve our reliability in cases of browser bugs (which actually often happen on DRM-related code).