Skip to content

v3.15.0

Compare
Choose a tag to compare
@peaBerberian peaBerberian released this 24 Jul 17:00
c00eed1

Release v3.15.0 (2019-07-24)

Overview

The v3.15.0 brings multiple new features. Among them:

  • we improved our adaptive streaming logic. Among other things we now better consider networks with high latencies
  • the license-fetching behavior becomes much more configurable. You can now decide when the request should be retried, how much time maximum it needs to be, after how much time the request should "timeout" and a configurable error message on failure.
  • we profited from an error management refactoring to fix several error-related issues (see the changelog at the bottom of this note)
  • on our demo page, we added the possibility to save a custom content's information to local storage, to be able to retrieve it later
  • our build scripts are now compatible with macOS. A minor difference between GNU's sed utility and the BSD one led to some errors when the latter was used (it's the default sed implementation on macOS).

Adaptive improvements

Since the end of last year, we worked a lot on our adaptive bitrate algorithms, which choose the best possible quality according to the current streaming conditions.

One of the problem with our previous logic was how it behaved in unconventional networks. For example, we had some issues in regions with a very high network latency, where we would display a quality lower than what people there should expect.

Another problem is that we often stayed on a low quality to avoid as much as possible buffering, even when we had a lot of buffer in advance.

Our previous logic was only based on the calculated network bandwidth. We found that we could fix both of those problems by taking the current buffer size into account as well.

After some research, we decided to implement the BOLA algorithm - or more precizely a version of it adapted to our needs - in our adaptive logic. That algorithm basically decide which quality should be chosen depending on the current size of the buffer. The more filled the buffer is, the more it is considered as "healthy", and the more the player chooses a better quality.

We now use both a network-based approach and - when the buffers has grown enough - a hybrid network and BOLA-based algorithm.

We have already been doing that since the beginning of 2019 in a version specially released internally for specific regions. We now consider that the algorithm can be used everywhere - which is why we release it now for everybody.

A basic explanation of our adaptive algorithms can be found in the ABRManager architecture documentation.

getLicense configuration

We improved the control you can have over the getLicense callback, which is used to fetch a license.

Previously, when the callback returned a rejected promise, we retried to call it three other times before failing on error. Moreover, a timeout of 10 seconds was applied on that callback. After those 10 seconds, that getLicense invocation was automatically considered rejected.

This was however not ideal:

  • some applications could want to retry the underlying request less or more than 3 times (even never or infinitely)
  • some applications might not want to have a 10 seconds timeout (often either a higher timeout or no timeout at all)
  • some getLicense errors could mean that the content is not decipherable and as such, retrying the call should be unnecessary

To allow a greater control over how we're supposed to handle that callback, we decided to add the getLicenseConfig property to keySystems - at the same place getLicense is defined.

This property is an object which can contain two values:

  • retry (number|undefined): Number of times the getLicense call should be retried on rejection. 0 means no retry, Infinity means infinite retry. 3 by default
  • timeout (number|undefined): amount of time in milliseconds after which the call should be considered rejected and potentially retried. Set it to -1 to disable any timeout. 10000 by default.

Moreover, we even added the possibility to communicate through getLicense errors.

When getLicense rejects, you can now set the rejected value to be an Object (or an Error) with two properties:

  • noRetry (boolean|undefined): if set to true, we won't retry to call getLicense, stop the current content and emit immediately the corresponding KEY_LOAD_ERROR through an error event
  • message (string|undefined): if set to a string (note: it should be automatically equal to an Error's message for an Error instance), the corresponding warning (if getLicense is retried) or error event (if it is not) will have a KEY_LOAD_ERROR payload with that message.

All of this is documented in the keySystems documentation

Error refactoring

We refactored our error management, to use TypeScript for ensuring that our error API was respected.

When doing that, we found multiple incoherence which have since been fixed:

  • an undocumented PIPELINE_RESOLVE_ERROR code could be thrown (in some very specific undocumented cases that I guess are only considered internally) instead of the documented PIPELINE_LOAD_ERROR code.
  • the PIPELINE_PARSING_ERROR code could be thrown instead of the documented PIPELINE_PARSE_ERROR code
  • the ErrorCodes static property missed three error codes: NONE, INVALID_KEY_SYSTEM and INVALID_ENCRYPTED_EVENT

Content saving in the demo

You can now save your custom contents on our demo page. You will then have them stored and be able to play them again with the same configuration later on.

We make use of the local storage to allow retrieval of those contents even when the page is loaded again. To test it just go into our demo page, choose "Custom content" and the rest should - I hope - be straightforward.

Changelog

Features

  • eme: add getLicenseConfig property to the keySystems loadVideo option, to be able to have much more control over getLicense's behavior
  • eme: add noRetry to getLicense errors to abort retries when the licence request fails
  • eme: add message to getLicense and onKeyStatusesChange errors to allow custom errors when the license request fails
  • eme: add a new ENCRYPTED_MEDIA_ERROR with the code CREATE_MEDIA_KEYS_ERROR for when we cannot create a MediaKeys instance (seen on some Android devices).

Bug fixes

  • api: avoid sending {audio,video...}BitrateChange with a -1 value when starting to play a content
  • api/abr: a call to setAudioBitrate or setVideoBitrate could be ignored for a content if it was still loading. This is now fixed.
  • api/abr: a call to setMaxAutoBitrate or setMaxVideoBitrate could be ignored for a content if it was still loading. This is now fixed.
  • dash: fix maximum position calculation when refreshing a live MPD with a UTCTiming element and no SegmentTimeline.
  • dash/smooth: a MPD/Manifest request failing could still be retried when loading another content
  • eme/compat: on Safari, depend on WebKitMediaKeys even if MediaKeys is defined because of differences of implementations
  • pipelines: always send PIPELINE_LOAD_ERROR warnings when a segment request or a Manifest request is retried
  • errors: replace undocumented PIPELINE_RESOLVE_ERROR code into the proper documented PIPELINE_LOAD_ERROR code
  • errors: replace undocumented PIPELINE_PARSING_ERROR code into the proper documented PIPELINE_PARSE_ERROR code
  • errors: add to the ErrorCodes static property the previously forgotten NONE, INVALID_KEY_SYSTEM and INVALID_ENCRYPTED_EVENT codes.

Other improvements

  • abr: make use of another adaptive algorithm, buffer-based, when enough buffer has been built.
  • demo: allow the user to save custom contents to local storage to be able to reuse them when the page is refreshed
  • eme: throw a better error in onKeyStatusesChange if the Promise is rejected without an Error
  • errors: refactore error management to better correlate the fatal boolean to a playback stop and to better ensure a documented error is always thrown
  • scripts: make our build script compatible with MacOS (handle BSD sed)