mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-26 17:46:26 +03:00
7091275cbf
This replaces almost every instance of indexOf on both String and Array. There are very few places where we really wanted an index. Mostly, indexOf was used to check for inclusion. Change-Id: I08e299768b6ffdb4bfc30b39b5d82a058c6d1b56
472 lines
13 KiB
Markdown
472 lines
13 KiB
Markdown
# Shaka Upgrade Guide, v2.1 => v2.4
|
|
|
|
This is a detailed guide for upgrading from Shaka Player v2.1 to v2.4.
|
|
Feel free to skim or to search for the class and method names you are using in
|
|
your application.
|
|
|
|
|
|
#### What's New in v2.4?
|
|
|
|
Shaka v2.4 introduces several improvements over v2.1, including:
|
|
- Allowing applications to render their own text tracks
|
|
- Allowing applications to define their own retry logic after streaming
|
|
failures
|
|
- Making the default ABR manager more configurable
|
|
- Adding channel count and bandwidth info to variant tracks
|
|
- Xlink support in DASH
|
|
- Stricter runtime type-checking of EME cert configuration
|
|
- New option for offline protected content without persistent licensing
|
|
- Support for HLS live streams
|
|
- Support for HLS VOD streams that do not start at t=0
|
|
- MPEG-2 TS content can be transmuxed to MP4 for playback on all browsers
|
|
- Captions are not streamed until they are shown
|
|
- Use NetworkInformation API to get initial bandwidth estimate
|
|
- The demo app is now a Progressive Web App (PWA) and can be used offline
|
|
- Support for CEA captions in TS content
|
|
- Support for TTML and VTT regions
|
|
- A video element is no longer required when `Player` is constructed
|
|
- New `attach()` and `detach()` methods have been added to `Player` to manage
|
|
attachment to video elements
|
|
- Fetch is now preferred over XHR when available
|
|
- Network requests are now abortable
|
|
- Live stream playback can begin at a negative offset from the live edge
|
|
|
|
|
|
#### New "text" namespace
|
|
|
|
In Shaka v2.1, `TextEngine` was part of the `shaka.media` namespace. In v2.2,
|
|
this was moved to the new `shaka.text` namespace. Text-parsing plugins should
|
|
now be registered with {@link shaka.text.TextEngine.registerParser}.
|
|
|
|
|
|
#### Customizing subtitle display
|
|
|
|
Shaka v2 gave applications an opportunity to have a custom text parser, but
|
|
all the displaying was handled by the browser. Shaka v2.2 added the
|
|
possibility to have custom logic for displaying text. By default the
|
|
rendering will still be done by the {@linksource shaka.text.SimpleTextDisplayer}
|
|
class.
|
|
|
|
A custom text display factory can be specified by calling player.configure().
|
|
|
|
```js
|
|
player.configure({
|
|
textDisplayFactory: customTextDisplayerClass
|
|
});
|
|
```
|
|
|
|
See {@linksource shaka.extern.TextDisplayer} for details.
|
|
|
|
|
|
#### Text parser API changes
|
|
|
|
The text-parsing plugin API has changed. Plugins now return `shaka.text.Cue`
|
|
objects instead of `VTTCue` or `TextTrackCue` objects like in v2.1. The plugin
|
|
API has also changed to take a `Uint8Array` instead of an `ArrayBuffer`.
|
|
|
|
```js
|
|
// v2.1
|
|
/**
|
|
* @param {!ArrayBuffer} data
|
|
* @param {shakaExtern.TextParser.TimeContext} timeContext
|
|
* @return {!Array.<!TextTrackCue>}
|
|
*/
|
|
MyTextParser.prototype.parseMedia = function(data, timeContext) {
|
|
var cues = [];
|
|
var parserState = new MyInternalParser(data);
|
|
while (parserState.more()) {
|
|
cues.push(new VTTCue(...));
|
|
}
|
|
return cues;
|
|
};
|
|
|
|
// v2.4
|
|
/**
|
|
* @param {!Uint8Array} data
|
|
* @param {shakaExtern.TextParser.TimeContext} timeContext
|
|
* @return {!Array.<!shaka.text.Cue>}
|
|
*/
|
|
MyTextParser.prototype.parseMedia = function(data, timeContext) {
|
|
var cues = [];
|
|
var parserState = new MyInternalParser(data);
|
|
while (parserState.more()) {
|
|
cues.push(new shaka.text.Cue(...));
|
|
}
|
|
return cues;
|
|
};
|
|
```
|
|
|
|
Additionally, the `segmentStart` attribute of `timeContext` is now
|
|
nullable. Your plugin will receive a `segmentStart` of `null` if the
|
|
information is not available, as is the case in HLS.
|
|
|
|
All application-specific text-parsing plugins MUST to be updated.
|
|
v2.4 does not have backward compatibility on this!
|
|
|
|
Shaka.text.Cue class contains the same information about a text cue as
|
|
VTTCue class plus extra information about text style.
|
|
|
|
See {@link shaka.text.Cue} for details.
|
|
|
|
|
|
#### Setting and configuring ABR manager
|
|
|
|
In Shaka v2.1, a custom ABR manager could be set through:
|
|
|
|
```js
|
|
player.configure({
|
|
abr.manager: customAbrManager
|
|
});
|
|
```
|
|
|
|
In v2.4, it's done through:
|
|
|
|
```js
|
|
player.configure({
|
|
abrFactory: customAbrManager
|
|
});
|
|
```
|
|
|
|
The API for AbrManager also changed.
|
|
|
|
In v2.1, default bandwidth estimate and restrictions were set through
|
|
`setDefaultEstimate()` and `setRestrictions()` methods.
|
|
|
|
In v2.4, they are set through `configure()` method which accepts a
|
|
{@link shaka.extern.AbrConfiguration} structure. The new method is more general,
|
|
and allows for the configuration of bandwidth upgrade and downgrade targets
|
|
as well.
|
|
|
|
```js
|
|
// v2.1:
|
|
abrManager.setDefaultEstimate(defaultBandwidthEstimate);
|
|
abrManager.setRestrictions(restrictions);
|
|
|
|
// v2.4:
|
|
abrManager.configure(abrConfigurations);
|
|
```
|
|
|
|
In v2.1, AbrManager had a `chooseStreams()` method for the player to prompt for
|
|
a stream selection, and a `switch()` callback to send unsolicited changes from
|
|
AbrManager to player. In v2.4, `chooseStreams()` has been replaced with
|
|
`chooseVariant()`, and the `switch()` callback takes a variant instead of a map
|
|
of streams.
|
|
|
|
```js
|
|
// v2.1:
|
|
var map = abrManager.chooseStreams(['audio', 'video']);
|
|
console.log(map['video'], map['audio']);
|
|
|
|
MyAbrManager.prototype.makeDecision_ = function() {
|
|
var video = this.computeBestVideo_(this.bandwidth_);
|
|
var audio = this.computeBestAudio_(this.bandwidth_);
|
|
var map = {
|
|
'audio': audio,
|
|
'video': video
|
|
};
|
|
this.switch_(map);
|
|
};
|
|
|
|
// v2.4:
|
|
var variant = abrManager.chooseVariant();
|
|
console.log(variant, variant.video, variant.audio);
|
|
|
|
MyAbrManager.prototype.makeDecision_ = function() {
|
|
var variant = this.computeBestVariant_(this.bandwidth_);
|
|
this.switch_(variant);
|
|
};
|
|
```
|
|
|
|
The v2.1 interfaces were deprecated in v2.2 and removed in v2.3. All custom
|
|
AbrManager plugins MUST be updated.
|
|
|
|
|
|
#### Switch history changes
|
|
|
|
In v2.1, `shakaExtern.Stats` had a member `shakaExtern.StreamChoice` structure
|
|
named switchHistory that had a type field containing the changed stream's
|
|
type ('audio', 'video' or 'text').
|
|
|
|
In v2.2, shakaExtern.StreamChoice was renamed shakaExtern.TrackChoice to
|
|
reflect that it contains information about the changed track rather than
|
|
stream. The type field now represents the changed track's type:
|
|
'variant' or 'text'. It also now contains track's bandwidth. Similarly, the
|
|
id field is now a track id instead of stream id.
|
|
|
|
```js
|
|
// v2.1:
|
|
/*
|
|
* @typedef {{
|
|
* timestamp: number,
|
|
* id: number, // stream id
|
|
* type: string, // 'audio'/'video'/'text'
|
|
* fromAdaptation: boolean
|
|
* }}
|
|
*/
|
|
shakaExtern.StreamChoice;
|
|
|
|
// v2.4:
|
|
/*
|
|
* @typedef {{
|
|
* timestamp: number,
|
|
* id: number, // track id
|
|
* type: string, // 'variant'/'text'
|
|
* fromAdaptation: boolean,
|
|
* bandwidth: ?number
|
|
* }}
|
|
*/
|
|
shakaExtern.TrackChoice;
|
|
```
|
|
|
|
|
|
#### Retry after streaming failure
|
|
|
|
In v2.0, after a network error and all network retries were exhausted, streaming
|
|
would continue to retry those requests. The only way to stop this process was
|
|
to `unload()` or `destroy()` the Player.
|
|
|
|
In v2.1.3, we introduced a new config called
|
|
`streaming.infiniteRetriesForLiveStreams` to control retry behavior for live
|
|
streams. In v2.2, we added a more flexible callback mechanism to specify retry
|
|
behavior for all kinds of streams.
|
|
|
|
```js
|
|
// v2.1
|
|
player.configure({
|
|
streaming: {
|
|
infiniteRetriesForLiveStreams: true // the default
|
|
}
|
|
});
|
|
|
|
// v2.4
|
|
player.configure({
|
|
streaming: {
|
|
failureCallback: function(error) {
|
|
// Always retry live streams:
|
|
if (player.isLive()) player.retryStreaming();
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
// v2.1
|
|
player.configure({
|
|
streaming: {
|
|
infiniteRetriesForLiveStreams: false // do not retry live
|
|
}
|
|
});
|
|
|
|
// v2.4
|
|
player.configure({
|
|
streaming: {
|
|
failureCallback: function(error) {
|
|
// Do nothing, and we will stop trying to stream the content.
|
|
}
|
|
}
|
|
});
|
|
```
|
|
|
|
The `streaming.infiniteRetriesForLiveStreams` config was deprecated in v2.2 and
|
|
removed in v2.3.
|
|
|
|
The new `player.retryStreaming()` method can be used to retry after a failure.
|
|
You can base the decision on `player.isLive()`, `error.code`, or anything else.
|
|
Because you can call `retryStreaming()` at any time, you can also delay the
|
|
decision until you get feedback from the user, the browser is back online, etc.
|
|
|
|
A few more examples of possible failure callbacks:
|
|
|
|
```js
|
|
function neverRetryCallback(error) {}
|
|
|
|
function alwaysRetryCallback(error) {
|
|
player.retryStreaming();
|
|
}
|
|
|
|
function retryLiveOnFailureCallback(error) {
|
|
if (player.isLive()) {
|
|
player.retryStreaming();
|
|
}
|
|
}
|
|
|
|
function retryOnSpecificHttpErrorsCallback(error) {
|
|
if (error.code == shaka.util.Error.Code.BAD_HTTP_STATUS) {
|
|
var statusCode = error.data[1];
|
|
var retryCodes = [ 502, 503, 504, 520 ];
|
|
if (retryCodes.includes(statusCode)) {
|
|
player.retryStreaming();
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
If you choose to react to `error` events instead of the failure callback, you
|
|
can use `event.preventDefault()` to avoid the callback completely:
|
|
|
|
```js
|
|
player.addEventListener('error', function(event) {
|
|
// Custom logic for error events
|
|
if (player.isLive() &&
|
|
event.error.code == shaka.util.Error.Code.BAD_HTTP_STATUS) {
|
|
player.retryStreaming();
|
|
}
|
|
|
|
// Do not invoke the failure callback for this event
|
|
event.preventDefault();
|
|
});
|
|
```
|
|
|
|
|
|
#### HLS start time configuration
|
|
|
|
For VOD HLS content which does not start at t=0, v2.1 had a configuration called
|
|
`manifest.hls.defaultTimeOffset` which applications could use to inform us of
|
|
the correct start time for content.
|
|
|
|
This has been removed in v2.4. The start time of HLS content can now be
|
|
automatically extracted from the segments themselves. No configuration is
|
|
necessary.
|
|
|
|
|
|
#### Offline storage API changes
|
|
|
|
In v2.1, the `remove()` method on `shaka.offline.Storage` took an instance of
|
|
`StoredContent` as an argument. Now, in v2.4, it takes a the `offlineUri` field
|
|
from `StoredContent` as an argument.
|
|
|
|
All applications which use offline storage MUST update to the new API.
|
|
The old argument was deprecated in v2.3 and has been removed in v2.4.
|
|
|
|
```js
|
|
// v2.1:
|
|
storage.list().then(function(storedContentList) {
|
|
var someContent = storedContentList[someIndex];
|
|
storage.remove(someContent);
|
|
});
|
|
|
|
// v2.4:
|
|
storage.list().then(function(storedContentList) {
|
|
var someContent = storedContentList[someIndex];
|
|
storage.remove(someContent.offlineUri);
|
|
});
|
|
```
|
|
|
|
|
|
#### Language and role selection
|
|
|
|
In addition to the language methods introduced in v2.1, v2.4 adds additional
|
|
methods for dealing with roles: `getAudioLanguagesAndRoles()` and
|
|
`getTextLanguagesAndRoles()`. These return language/role combinations in an
|
|
object. You can specify a role in an optional second argument to the language
|
|
selection methods.
|
|
|
|
```js
|
|
// v2.4:
|
|
var languagesAndRoles = player.getAudioLanguagesAndRoles();
|
|
|
|
for (var i = 0; i < languagesAndRoles.length; ++i) {
|
|
var combo = languagesAndRoles[i];
|
|
if (someSelector(combo)) {
|
|
player.selectAudioLanguage(combo.language, combo.role);
|
|
break;
|
|
}
|
|
}
|
|
```
|
|
|
|
|
|
#### NetworkingEngine API changes
|
|
|
|
In v2.1, the `request()` method on `shaka.net.NetworkingEngine` returned a
|
|
Promise. Now, in v2.4, it returns an instance of
|
|
`shakaExtern.IAbortableOperation`, which contains a Promise.
|
|
|
|
All applications which make application-level requests via `NetworkingEngine`
|
|
SHOULD update to the new API. Support for the old API will be removed in v2.5.
|
|
|
|
```js
|
|
// v2.1:
|
|
player.getNetworkingEngine().request(type, request).then((response) => {
|
|
// ...
|
|
});
|
|
|
|
// v2.4:
|
|
let operation = player.getNetworkingEngine().request(type, request);
|
|
// Use operation.promise to get the response.
|
|
operation.promise.then((response) => {
|
|
// ...
|
|
});
|
|
// The operation can also be aborted on some condition.
|
|
onSomeOtherCondition(() => {
|
|
operation.abort();
|
|
});
|
|
```
|
|
|
|
Backward compatibility is provided in the v2.4 releases by adding `.then` and
|
|
`.catch` methods to the return value from `request()`.
|
|
|
|
|
|
#### Network scheme plugin API changes
|
|
|
|
In v2.4, we changed the API for network scheme plugins.
|
|
|
|
These plugins now return an instance of `shakaExtern.IAbortableOperation`.
|
|
We suggest using the utility `shaka.util.AbortableOperation` for convenience.
|
|
|
|
We also introduced an additional parameter for network scheme plugins to
|
|
identify the request type.
|
|
|
|
All applications which have application-level network scheme plugins SHOULD
|
|
update to the new API. Support for the old API will be removed in v2.5.
|
|
|
|
```js
|
|
// v2.1
|
|
function fooPlugin(uri, request) {
|
|
return new Promise((resolve, reject) => {
|
|
// ...
|
|
});
|
|
}
|
|
shaka.net.NetworkingEngine.registerScheme('foo', fooPlugin);
|
|
|
|
// v2.4
|
|
function fooPlugin(uri, request, requestType) {
|
|
let rejectCallback = null;
|
|
|
|
const promise = new Promise((resolve, reject) => {
|
|
rejectCallback = reject;
|
|
|
|
// Use this if you have a need for it. Ignore it otherwise.
|
|
if (requestType == shaka.net.NetworkingEngine.RequestType.MANIFEST) {
|
|
// ...
|
|
} else {
|
|
// ...
|
|
}
|
|
|
|
// ...
|
|
});
|
|
|
|
const abort = () => {
|
|
// Abort the operation.
|
|
// ...
|
|
|
|
// Reject the Promise.
|
|
rejectCallback(new shaka.util.Error(
|
|
shaka.util.Error.Severity.RECOVERABLE,
|
|
shaka.util.Error.Category.NETWORK,
|
|
shaka.util.Error.Code.OPERATION_ABORTED));
|
|
};
|
|
|
|
return new shaka.util.AbortableOperation(promise, abort);
|
|
}
|
|
shaka.net.NetworkingEngine.registerScheme('foo', fooPlugin);
|
|
```
|
|
|
|
|
|
#### Manifest parser plugin API changes
|
|
|
|
The API for `shaka.media.PresentationTimeline` has changed. `ManifestParser`
|
|
plugins that use these methods MUST be updated:
|
|
|
|
- `setAvailabilityStart()` was renamed to `setUserSeekStart()`.
|
|
- `notifySegments()` now takes a reference array and a boolean called
|
|
`isFirstPeriod`, instead of a period start time and a reference array.
|