Release v4.2.0 (2024-10-17)
Quick Links:
π API documentation
-
β― Demo
-
π Migration guide from v3
- π Overview
- π Changelog
- CMCD v1 support
- DRM: Detection of codecs unsupported when encrypted
- DRM: More information on Representations in the API
keySystems[].reuseMediaKeys
optionLogFormat
static propertycheckManifestIntegrity
option- Safari/DRM: Fix for the DRM+language issue
- Note 1: Facilitating tests of RxPlayer pending developments
- Note 2: Work-around for a Firefox 129 issue
π 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 theDASH_WASM
feature, for a short-lived firefox issue, for legacy bundles...
Changelog
Features
- Add
cmcd
object toloadVideo
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 therepresentations
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 theRxPlayer
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
and1912238
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
whenQuotaExceededError
mitigations afterappendBuffer
MSE calls don't work #1546 - Fix issues when handling a
QuotaExceededError
after anappendBuffer
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
andSourceBuffer.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 andhvc1
codecs as part of the same family of codecs when trying to check for compatibility between the two [#1499] - Better handle
QuotaExceededError
issue afterappendBuffer
MSE calls whenwantedBufferAhead
is set toInfinity
[#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.
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.
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:
getAvailableVideoTracks
getAvailableAudioTracks
getVideoTrack
getAudioTrack
- the
availableVideoTracksChange
event - the
availableAudioTracksChange
event - the
videoTracksChange
event - the
audioTracksChange
event
And directly as a property of the objects returned by the following methods and events:
getVideoRepresentation
getAudioRepresentation
- the
videoRepresentationChange
event - the
audioRepresentationChange
event
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.
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.
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).
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):
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).