shaka-player 2.5.1 → 2.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.csslintrc +13 -0
- package/AUTHORS +3 -0
- package/CHANGELOG.md +156 -0
- package/CONTRIBUTORS +3 -0
- package/README.md +3 -0
- package/build/README.md +5 -5
- package/build/apps.py +3 -1
- package/build/build.py +5 -2
- package/build/check.py +17 -0
- package/build/compiler.py +49 -0
- package/build/conformance.textproto +1 -0
- package/build/docs.py +0 -6
- package/build/generateExterns.js +72 -20
- package/build/install-linux-prereqs.sh +4 -4
- package/build/shakaBuildHelpers.py +7 -8
- package/build/test.py +21 -9
- package/build/types/core +1 -0
- package/build/types/ui +6 -1
- package/demo/asset_card.js +129 -41
- package/demo/cast_receiver/receiver_app.css +27 -13
- package/demo/close_button.js +10 -15
- package/demo/common/asset.js +6 -6
- package/demo/common/assets.js +72 -14
- package/demo/config.js +28 -25
- package/demo/custom.js +20 -16
- package/demo/demo.less +107 -16
- package/demo/demo_uncompiled.js +33 -0
- package/demo/demo_utils.js +4 -3
- package/demo/front.js +12 -8
- package/demo/index.html +14 -17
- package/demo/input.js +30 -23
- package/demo/input_container.js +15 -11
- package/demo/load.js +5 -7
- package/demo/main.js +138 -49
- package/demo/search.js +40 -36
- package/demo/service_worker.js +1 -1
- package/demo/tooltip.js +16 -24
- package/dist/.csslintstamp +0 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +165 -152
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +165 -152
- package/dist/demo.compiled.map +4 -4
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/deps.js +28 -11
- package/dist/receiver.compiled.debug.js +11 -11
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +11 -11
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.debug.externs.js +232 -102
- package/dist/shaka-player.compiled.debug.js +189 -165
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +232 -102
- package/dist/shaka-player.compiled.js +567 -553
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.debug.externs.js +338 -113
- package/dist/shaka-player.ui.debug.js +296 -276
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +338 -113
- package/dist/shaka-player.ui.js +685 -671
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/drm-config.md +1 -0
- package/docs/tutorials/fairplay.md +77 -0
- package/docs/tutorials/index.json +1 -0
- package/docs/tutorials/manifest-parser.md +1 -1
- package/docs/tutorials/ui-customization.md +5 -2
- package/docs/tutorials/ui.md +10 -4
- package/docs/tutorials/welcome.md +2 -2
- package/externs/mediasession.js +16 -1
- package/externs/shaka/net.js +14 -4
- package/externs/shaka/player.js +136 -90
- package/externs/tippy.js +30 -0
- package/externs/webkitmediakeys.js +4 -0
- package/karma.conf.js +30 -24
- package/lib/cast/cast_proxy.js +94 -23
- package/lib/cast/cast_receiver.js +8 -1
- package/lib/dash/content_protection.js +33 -1
- package/lib/dash/dash_parser.js +13 -5
- package/lib/hls/hls_parser.js +20 -4
- package/lib/media/drm_engine.js +29 -2
- package/lib/media/media_source_engine.js +9 -6
- package/lib/media/play_rate_controller.js +14 -3
- package/lib/media/playhead.js +8 -3
- package/lib/media/streaming_engine.js +68 -20
- package/lib/media/transmuxer.js +2 -2
- package/lib/media/video_wrapper.js +8 -3
- package/lib/net/data_uri_plugin.js +5 -2
- package/lib/net/http_fetch_plugin.js +3 -3
- package/lib/net/http_plugin_utils.js +2 -4
- package/lib/net/http_xhr_plugin.js +2 -2
- package/lib/net/networking_engine.js +1 -0
- package/lib/offline/offline_scheme.js +7 -2
- package/lib/player.js +18 -8
- package/lib/polyfill/input_event.js +7 -11
- package/lib/polyfill/mediasource.js +1 -1
- package/lib/polyfill/patchedmediakeys_apple.js +2 -72
- package/lib/text/cue.js +1 -1
- package/lib/text/ttml_text_parser.js +1 -1
- package/lib/util/config_utils.js +1 -0
- package/lib/util/error.js +45 -11
- package/lib/util/event_manager.js +211 -100
- package/lib/util/fairplay_utils.js +122 -0
- package/lib/util/i_releasable.js +1 -0
- package/lib/util/player_configuration.js +7 -0
- package/lib/util/pssh.js +41 -0
- package/lib/util/string_utils.js +42 -6
- package/lib/util/timer.js +1 -1
- package/package.json +33 -33
- package/roadmap.md +96 -0
- package/shaka-player.uncompiled.js +5 -1
- package/test/dash/dash_parser_content_protection_unit.js +35 -1
- package/test/dash/dash_parser_manifest_unit.js +60 -0
- package/test/hls/hls_live_unit.js +7 -1
- package/test/hls/hls_parser_unit.js +50 -0
- package/test/media/drm_engine_unit.js +10 -4
- package/test/media/media_source_engine_integration.js +12 -0
- package/test/media/media_source_engine_unit.js +3 -1
- package/test/media/playhead_unit.js +7 -5
- package/test/media/streaming_engine_unit.js +46 -1
- package/test/media/transmuxer_integration.js +13 -0
- package/test/net/data_uri_plugin_unit.js +13 -2
- package/test/net/http_plugin_unit.js +17 -12
- package/test/net/networking_engine_unit.js +17 -8
- package/test/offline/offline_scheme_unit.js +18 -8
- package/test/player_external.js +3 -2
- package/test/player_integration.js +94 -3
- package/test/player_src_equals_integration.js +2 -2
- package/test/player_unit.js +21 -8
- package/test/test/boot.js +20 -5
- package/test/test/externs/jasmine.js +48 -0
- package/test/test/util/expect_async_polyfill.js +145 -0
- package/test/test/util/fake_networking_engine.js +1 -0
- package/test/test/util/manifest_generator.js +2 -1
- package/test/test/util/test_scheme.js +34 -2
- package/test/test/util/ui_utils.js +41 -0
- package/test/test/util/util.js +16 -8
- package/test/ui/ui_unit.js +130 -4
- package/ui/audio_language_selection.js +17 -96
- package/ui/big_play_button.js +61 -0
- package/ui/controls.js +226 -335
- package/ui/controls.less +3 -5
- package/ui/element.js +24 -6
- package/ui/externs/ui.js +62 -9
- package/ui/fullscreen_button.js +2 -52
- package/ui/less/buttons.less +10 -16
- package/ui/less/containers.less +75 -20
- package/ui/less/general.less +18 -2
- package/ui/less/other_elements.less +2 -1
- package/ui/less/overflow_menu.less +11 -10
- package/ui/less/range_elements.less +12 -10
- package/ui/less/spinner.less +2 -0
- package/ui/overflow_menu.js +1 -1
- package/ui/pip_button.js +1 -1
- package/ui/{play_pause_button.js → play_button.js} +17 -47
- package/ui/presentation_time.js +17 -12
- package/ui/range_element.js +176 -0
- package/ui/resolution_selection.js +43 -106
- package/ui/seek_bar.js +204 -0
- package/ui/settings_menu.js +113 -0
- package/ui/small_play_button.js +73 -0
- package/ui/text_displayer.js +17 -14
- package/ui/text_selection.js +42 -107
- package/ui/ui.js +17 -40
- package/ui/volume_bar.js +40 -68
package/lib/util/error.js
CHANGED
|
@@ -84,17 +84,20 @@ shaka.util.Error = function(severity, category, code, ...varArgs) {
|
|
|
84
84
|
*/
|
|
85
85
|
this.message = 'Shaka Error ' + categoryName + '.' + codeName +
|
|
86
86
|
' (' + this.data.toString() + ')';
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
87
|
+
|
|
88
|
+
if (shaka.util.Error.createStack) {
|
|
89
|
+
try {
|
|
90
|
+
throw new Error(this.message);
|
|
91
|
+
} catch (e) {
|
|
92
|
+
/**
|
|
93
|
+
* A stack-trace showing where the error occurred.
|
|
94
|
+
* <i>(Only available in uncompiled mode.)</i>
|
|
95
|
+
*
|
|
96
|
+
* @const {string}
|
|
97
|
+
* @exportDoc
|
|
98
|
+
*/
|
|
99
|
+
this.stack = e.stack;
|
|
100
|
+
}
|
|
98
101
|
}
|
|
99
102
|
}
|
|
100
103
|
};
|
|
@@ -109,6 +112,19 @@ shaka.util.Error.prototype.toString = function() {
|
|
|
109
112
|
};
|
|
110
113
|
|
|
111
114
|
|
|
115
|
+
if (goog.DEBUG) {
|
|
116
|
+
/**
|
|
117
|
+
* If true, create a stack trace in Error objects.
|
|
118
|
+
*
|
|
119
|
+
* Only available in uncompiled mode, and disabled in tests to avoid issues
|
|
120
|
+
* with karma-jasmine. See comments in test/test/boot.js for details.
|
|
121
|
+
*
|
|
122
|
+
* @type {boolean}
|
|
123
|
+
*/
|
|
124
|
+
shaka.util.Error.createStack = true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
112
128
|
/**
|
|
113
129
|
* @enum {number}
|
|
114
130
|
* @export
|
|
@@ -717,6 +733,18 @@ shaka.util.Error.Code = {
|
|
|
717
733
|
*/
|
|
718
734
|
'EXPIRED': 6014,
|
|
719
735
|
|
|
736
|
+
/**
|
|
737
|
+
* A server certificate wasn't given when it is required. FairPlay requires
|
|
738
|
+
* setting an explicit server certificate in the configuration.
|
|
739
|
+
*/
|
|
740
|
+
'SERVER_CERTIFICATE_REQUIRED': 6015,
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* An error was thrown while executing the init data transformation.
|
|
744
|
+
* <br> error.data[0] is the original error.
|
|
745
|
+
*/
|
|
746
|
+
'INIT_DATA_TRANSFORM_ERROR': 6016,
|
|
747
|
+
|
|
720
748
|
|
|
721
749
|
/**
|
|
722
750
|
* The call to Player.load() was interrupted by a call to Player.unload()
|
|
@@ -783,6 +811,12 @@ shaka.util.Error.Code = {
|
|
|
783
811
|
'CAST_RECEIVER_APP_UNAVAILABLE': 8006,
|
|
784
812
|
|
|
785
813
|
|
|
814
|
+
/**
|
|
815
|
+
* No receiver app id has been provided, making casting impossible.
|
|
816
|
+
*/
|
|
817
|
+
'CAST_RECEIVER_APP_ID_MISSING': 8007,
|
|
818
|
+
|
|
819
|
+
|
|
786
820
|
/**
|
|
787
821
|
* Offline storage is not supported on this browser; it is required for
|
|
788
822
|
* offline support.
|
|
@@ -23,143 +23,254 @@ goog.require('shaka.util.MultiMap');
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
26
|
+
* @summary
|
|
27
|
+
* An EventManager maintains a collection of "event
|
|
27
28
|
* bindings" between event targets and event listeners.
|
|
28
29
|
*
|
|
29
|
-
* @struct
|
|
30
|
-
* @constructor
|
|
31
30
|
* @implements {shaka.util.IReleasable}
|
|
31
|
+
* @export
|
|
32
32
|
*/
|
|
33
|
-
shaka.util.EventManager =
|
|
33
|
+
shaka.util.EventManager = class {
|
|
34
|
+
constructor() {
|
|
35
|
+
/**
|
|
36
|
+
* Maps an event type to an array of event bindings.
|
|
37
|
+
* @private {shaka.util.MultiMap.<!shaka.util.EventManager.Binding_>}
|
|
38
|
+
*/
|
|
39
|
+
this.bindingMap_ = new shaka.util.MultiMap();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
34
43
|
/**
|
|
35
|
-
*
|
|
36
|
-
* @
|
|
44
|
+
* Detaches all event listeners.
|
|
45
|
+
* @override
|
|
46
|
+
* @export
|
|
37
47
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
48
|
+
release() {
|
|
49
|
+
this.removeAll();
|
|
50
|
+
this.bindingMap_ = null;
|
|
51
|
+
}
|
|
41
52
|
|
|
42
|
-
/**
|
|
43
|
-
* @typedef {function(!Event)}
|
|
44
|
-
*/
|
|
45
|
-
shaka.util.EventManager.ListenerType;
|
|
46
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Attaches an event listener to an event target.
|
|
56
|
+
* @param {EventTarget} target The event target.
|
|
57
|
+
* @param {string} type The event type.
|
|
58
|
+
* @param {shaka.util.EventManager.ListenerType} listener The event listener.
|
|
59
|
+
* @param {(boolean|!AddEventListenerOptions)=} options An object that
|
|
60
|
+
* specifies characteristics about the event listener.
|
|
61
|
+
* The passive option, if true, indicates that this function will never
|
|
62
|
+
* call preventDefault(), which improves scrolling performance.
|
|
63
|
+
* @export
|
|
64
|
+
*/
|
|
65
|
+
listen(target, type, listener, options) {
|
|
66
|
+
if (!this.bindingMap_) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
47
69
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
shaka.util.EventManager.prototype.release = function() {
|
|
53
|
-
this.removeAll();
|
|
54
|
-
this.bindingMap_ = null;
|
|
55
|
-
};
|
|
70
|
+
const binding =
|
|
71
|
+
new shaka.util.EventManager.Binding_(target, type, listener, options);
|
|
72
|
+
this.bindingMap_.push(type, binding);
|
|
73
|
+
}
|
|
56
74
|
|
|
57
75
|
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Attaches an event listener to an event target. The listener will be
|
|
78
|
+
* removed when the first instance of the event is fired.
|
|
79
|
+
* @param {EventTarget} target The event target.
|
|
80
|
+
* @param {string} type The event type.
|
|
81
|
+
* @param {shaka.util.EventManager.ListenerType} listener The event listener.
|
|
82
|
+
* @param {(boolean|!AddEventListenerOptions)=} options An object that
|
|
83
|
+
* specifies characteristics about the event listener.
|
|
84
|
+
* The passive option, if true, indicates that this function will never
|
|
85
|
+
* call preventDefault(), which improves scrolling performance.
|
|
86
|
+
* @export
|
|
87
|
+
*/
|
|
88
|
+
listenOnce(target, type, listener, options) {
|
|
89
|
+
// Install a shim listener that will stop listening after the first event.
|
|
90
|
+
const shim = (event) => {
|
|
91
|
+
// Stop listening to this event.
|
|
92
|
+
this.unlisten(target, type, shim);
|
|
93
|
+
// Call the original listener.
|
|
94
|
+
listener(event);
|
|
95
|
+
};
|
|
96
|
+
this.listen(target, type, shim, options);
|
|
97
|
+
}
|
|
66
98
|
|
|
67
|
-
let binding = new shaka.util.EventManager.Binding_(target, type, listener);
|
|
68
|
-
this.bindingMap_.push(type, binding);
|
|
69
|
-
};
|
|
70
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Detaches an event listener from an event target.
|
|
102
|
+
* @param {EventTarget} target The event target.
|
|
103
|
+
* @param {string} type The event type.
|
|
104
|
+
* @param {shaka.util.EventManager.ListenerType=} listener The event listener.
|
|
105
|
+
* @export
|
|
106
|
+
*/
|
|
107
|
+
unlisten(target, type, listener) {
|
|
108
|
+
if (!this.bindingMap_) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
71
111
|
|
|
72
|
-
|
|
73
|
-
* Attaches an event listener to an event target. The listener will be removed
|
|
74
|
-
* when the first instance of the event is fired.
|
|
75
|
-
* @param {EventTarget} target The event target.
|
|
76
|
-
* @param {string} type The event type.
|
|
77
|
-
* @param {shaka.util.EventManager.ListenerType} listener The event listener.
|
|
78
|
-
*/
|
|
79
|
-
shaka.util.EventManager.prototype.listenOnce =
|
|
80
|
-
function(target, type, listener) {
|
|
81
|
-
// Install a shim listener that will stop listening after the first event.
|
|
82
|
-
const shim = (event) => {
|
|
83
|
-
// Stop listening to this event.
|
|
84
|
-
this.unlisten(target, type, shim);
|
|
85
|
-
// Call the original listener.
|
|
86
|
-
listener(event);
|
|
87
|
-
};
|
|
88
|
-
this.listen(target, type, shim);
|
|
89
|
-
};
|
|
112
|
+
const list = this.bindingMap_.get(type) || [];
|
|
90
113
|
|
|
114
|
+
for (const binding of list) {
|
|
115
|
+
if (binding.target == target) {
|
|
116
|
+
if (listener == binding.listener || !listener) {
|
|
117
|
+
binding.unlisten();
|
|
118
|
+
this.bindingMap_.remove(type, binding);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
91
123
|
|
|
92
|
-
/**
|
|
93
|
-
* Detaches an event listener from an event target.
|
|
94
|
-
* @param {EventTarget} target The event target.
|
|
95
|
-
* @param {string} type The event type.
|
|
96
|
-
* @param {shaka.util.EventManager.ListenerType=} listener The event listener.
|
|
97
|
-
*/
|
|
98
|
-
shaka.util.EventManager.prototype.unlisten = function(target, type, listener) {
|
|
99
|
-
if (!this.bindingMap_) return;
|
|
100
124
|
|
|
101
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Detaches all event listeners from all targets.
|
|
127
|
+
* @export
|
|
128
|
+
*/
|
|
129
|
+
removeAll() {
|
|
130
|
+
if (!this.bindingMap_) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
102
133
|
|
|
103
|
-
|
|
104
|
-
let binding = list[i];
|
|
134
|
+
const list = this.bindingMap_.getAll();
|
|
105
135
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
binding.unlisten();
|
|
109
|
-
this.bindingMap_.remove(type, binding);
|
|
110
|
-
}
|
|
136
|
+
for (const binding of list) {
|
|
137
|
+
binding.unlisten();
|
|
111
138
|
}
|
|
139
|
+
|
|
140
|
+
this.bindingMap_.clear();
|
|
112
141
|
}
|
|
113
142
|
};
|
|
114
143
|
|
|
115
144
|
|
|
116
145
|
/**
|
|
117
|
-
*
|
|
146
|
+
* @typedef {function(!Event)}
|
|
147
|
+
* @export
|
|
118
148
|
*/
|
|
119
|
-
shaka.util.EventManager.
|
|
120
|
-
if (!this.bindingMap_) return;
|
|
121
|
-
|
|
122
|
-
let list = this.bindingMap_.getAll();
|
|
123
|
-
|
|
124
|
-
for (let i = 0; i < list.length; ++i) {
|
|
125
|
-
list[i].unlisten();
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
this.bindingMap_.clear();
|
|
129
|
-
};
|
|
149
|
+
shaka.util.EventManager.ListenerType;
|
|
130
150
|
|
|
131
151
|
|
|
132
152
|
/**
|
|
133
153
|
* Creates a new Binding_ and attaches the event listener to the event target.
|
|
134
|
-
*
|
|
135
|
-
* @param {string} type The event type.
|
|
136
|
-
* @param {shaka.util.EventManager.ListenerType} listener The event listener.
|
|
137
|
-
* @constructor
|
|
154
|
+
*
|
|
138
155
|
* @private
|
|
139
156
|
*/
|
|
140
|
-
shaka.util.EventManager.Binding_ =
|
|
141
|
-
/**
|
|
142
|
-
|
|
157
|
+
shaka.util.EventManager.Binding_ = class {
|
|
158
|
+
/**
|
|
159
|
+
* @param {EventTarget} target The event target.
|
|
160
|
+
* @param {string} type The event type.
|
|
161
|
+
* @param {shaka.util.EventManager.ListenerType} listener The event listener.
|
|
162
|
+
* @param {(boolean|!AddEventListenerOptions)=} options An object that
|
|
163
|
+
* specifies characteristics about the event listener.
|
|
164
|
+
* The passive option, if true, indicates that this function will never
|
|
165
|
+
* call preventDefault(), which improves scrolling performance.
|
|
166
|
+
*/
|
|
167
|
+
constructor(target, type, listener, options) {
|
|
168
|
+
/** @type {EventTarget} */
|
|
169
|
+
this.target = target;
|
|
143
170
|
|
|
144
|
-
|
|
145
|
-
|
|
171
|
+
/** @type {string} */
|
|
172
|
+
this.type = type;
|
|
146
173
|
|
|
147
|
-
|
|
148
|
-
|
|
174
|
+
/** @type {?shaka.util.EventManager.ListenerType} */
|
|
175
|
+
this.listener = listener;
|
|
149
176
|
|
|
150
|
-
|
|
151
|
-
|
|
177
|
+
/** @type {(boolean|!AddEventListenerOptions)} */
|
|
178
|
+
this.options =
|
|
179
|
+
shaka.util.EventManager.Binding_.convertOptions_(target, options);
|
|
152
180
|
|
|
181
|
+
this.target.addEventListener(type, listener, this.options);
|
|
182
|
+
}
|
|
153
183
|
|
|
154
|
-
/**
|
|
155
|
-
* Detaches the event listener from the event target. This does nothing if the
|
|
156
|
-
* event listener is already detached.
|
|
157
|
-
*/
|
|
158
|
-
shaka.util.EventManager.Binding_.prototype.unlisten = function() {
|
|
159
|
-
goog.asserts.assert(this.target, 'Missing target');
|
|
160
|
-
this.target.removeEventListener(this.type, this.listener, false);
|
|
161
184
|
|
|
162
|
-
|
|
163
|
-
|
|
185
|
+
/**
|
|
186
|
+
* Detaches the event listener from the event target. This does nothing if
|
|
187
|
+
* the event listener is already detached.
|
|
188
|
+
* @export
|
|
189
|
+
*/
|
|
190
|
+
unlisten() {
|
|
191
|
+
goog.asserts.assert(this.target, 'Missing target');
|
|
192
|
+
this.target.removeEventListener(this.type, this.listener, this.options);
|
|
193
|
+
|
|
194
|
+
this.target = null;
|
|
195
|
+
this.listener = null;
|
|
196
|
+
this.options = false;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Converts the provided options value into a value accepted by the browser.
|
|
201
|
+
* Some browsers (e.g. IE11 and Tizen) don't support passing options as an
|
|
202
|
+
* object. So this detects this case and converts it.
|
|
203
|
+
*
|
|
204
|
+
* @param {EventTarget} target
|
|
205
|
+
* @param {(boolean|!AddEventListenerOptions)=} value
|
|
206
|
+
* @return {(boolean|!AddEventListenerOptions)}
|
|
207
|
+
* @private
|
|
208
|
+
*/
|
|
209
|
+
static convertOptions_(target, value) {
|
|
210
|
+
if (value == undefined) {
|
|
211
|
+
return false;
|
|
212
|
+
} else if (typeof value == 'boolean') {
|
|
213
|
+
return value;
|
|
214
|
+
} else {
|
|
215
|
+
// Ignore the 'passive' option since it is just an optimization and
|
|
216
|
+
// doesn't affect behavior. Assert there aren't any other settings to
|
|
217
|
+
// ensure we don't have different behavior on different browsers by
|
|
218
|
+
// ignoring an important option.
|
|
219
|
+
const ignored = new Set(['passive', 'capture']);
|
|
220
|
+
const keys = Object.keys(value).filter((k) => !ignored.has(k));
|
|
221
|
+
goog.asserts.assert(
|
|
222
|
+
keys.length == 0,
|
|
223
|
+
'Unsupported flag(s) to addEventListener: ' + keys.join(','));
|
|
224
|
+
|
|
225
|
+
const supports =
|
|
226
|
+
shaka.util.EventManager.Binding_.doesSupportObject_(target);
|
|
227
|
+
if (supports) {
|
|
228
|
+
return value;
|
|
229
|
+
} else {
|
|
230
|
+
return value['capture'] || false;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Checks whether the browser supports passing objects as the third argument
|
|
237
|
+
* to addEventListener. This caches the result value in a static field to
|
|
238
|
+
* avoid a bunch of checks.
|
|
239
|
+
*
|
|
240
|
+
* @param {EventTarget} target
|
|
241
|
+
* @return {boolean}
|
|
242
|
+
* @private
|
|
243
|
+
*/
|
|
244
|
+
static doesSupportObject_(target) {
|
|
245
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
|
|
246
|
+
let supports = shaka.util.EventManager.Binding_.supportsObject_;
|
|
247
|
+
if (supports == undefined) {
|
|
248
|
+
supports = false;
|
|
249
|
+
try {
|
|
250
|
+
const options = {};
|
|
251
|
+
// This defines a getter that will set this variable if called. So if
|
|
252
|
+
// the browser gets this property, it supports using an object. If the
|
|
253
|
+
// browser doesn't get these fields, it won't support objects.
|
|
254
|
+
const prop = {
|
|
255
|
+
get: () => {
|
|
256
|
+
supports = true;
|
|
257
|
+
return false;
|
|
258
|
+
},
|
|
259
|
+
};
|
|
260
|
+
Object.defineProperty(options, 'passive', prop);
|
|
261
|
+
Object.defineProperty(options, 'capture', prop);
|
|
262
|
+
|
|
263
|
+
const call = () => {};
|
|
264
|
+
target.addEventListener('test', call, options);
|
|
265
|
+
target.removeEventListener('test', call, options);
|
|
266
|
+
} catch (e) {
|
|
267
|
+
supports = false;
|
|
268
|
+
}
|
|
269
|
+
shaka.util.EventManager.Binding_.supportsObject_ = supports;
|
|
270
|
+
}
|
|
271
|
+
return supports || false; // "false" fallback needed for compiler.
|
|
272
|
+
}
|
|
164
273
|
};
|
|
165
274
|
|
|
275
|
+
/** @private {(boolean|undefined)} */
|
|
276
|
+
shaka.util.EventManager.Binding_.supportsObject_ = undefined;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2016 Google Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
goog.provide('shaka.util.FairPlayUtils');
|
|
19
|
+
|
|
20
|
+
goog.require('goog.Uri');
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @summary A set of FairPlay utility functions.
|
|
25
|
+
* @exportInterface
|
|
26
|
+
*/
|
|
27
|
+
shaka.util.FairPlayUtils = class {
|
|
28
|
+
/**
|
|
29
|
+
* Using the default method, extract a content ID from the init data. This is
|
|
30
|
+
* based on the FairPlay example documentation.
|
|
31
|
+
*
|
|
32
|
+
* @param {!BufferSource} initData
|
|
33
|
+
* @return {string}
|
|
34
|
+
* @export
|
|
35
|
+
*/
|
|
36
|
+
static defaultGetContentId(initData) {
|
|
37
|
+
const uint8 = new Uint8Array(initData);
|
|
38
|
+
const dataview = new DataView(
|
|
39
|
+
uint8.buffer, uint8.byteOffset, uint8.byteLength);
|
|
40
|
+
// The first part is a 4 byte little-endian int, which is the length of
|
|
41
|
+
// the second part.
|
|
42
|
+
const length = dataview.getUint32(
|
|
43
|
+
/* position= */ 0, /* littleEndian= */ true);
|
|
44
|
+
if (length + 4 != uint8.byteLength) {
|
|
45
|
+
throw new RangeError('Malformed FairPlay init data');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// The second part is a UTF-16 LE URI from the manifest.
|
|
49
|
+
const uriString = shaka.util.StringUtils.fromUTF16(
|
|
50
|
+
uint8.subarray(4), /* littleEndian= */ true);
|
|
51
|
+
|
|
52
|
+
// The domain of that URI is the content ID according to Apple's FPS
|
|
53
|
+
// sample.
|
|
54
|
+
const uri = new goog.Uri(uriString);
|
|
55
|
+
return uri.getDomain();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Transforms the init data buffer using the given data. The format is:
|
|
60
|
+
*
|
|
61
|
+
* <pre>
|
|
62
|
+
* [4 bytes] initDataSize
|
|
63
|
+
* [initDataSize bytes] initData
|
|
64
|
+
* [4 bytes] contentIdSize
|
|
65
|
+
* [contentIdSize bytes] contentId
|
|
66
|
+
* [4 bytes] certSize
|
|
67
|
+
* [certSize bytes] cert
|
|
68
|
+
* </pre>
|
|
69
|
+
*
|
|
70
|
+
* @param {!BufferSource} initData
|
|
71
|
+
* @param {!BufferSource|string} contentId
|
|
72
|
+
* @param {?BufferSource} cert The server certificate; this will throw if not
|
|
73
|
+
* provided.
|
|
74
|
+
* @return {!Uint8Array}
|
|
75
|
+
* @export
|
|
76
|
+
*/
|
|
77
|
+
static initDataTransform(initData, contentId, cert) {
|
|
78
|
+
if (!cert || !cert.byteLength) {
|
|
79
|
+
throw new shaka.util.Error(
|
|
80
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
81
|
+
shaka.util.Error.Category.DRM,
|
|
82
|
+
shaka.util.Error.Code.SERVER_CERTIFICATE_REQUIRED);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// From that, we build a new init data to use in the session. This is
|
|
86
|
+
// composed of several parts. First, the raw init data we already got.
|
|
87
|
+
// Second, a 4-byte LE length followed by the content ID in UTF-16-LE.
|
|
88
|
+
// Third, a 4-byte LE length followed by the certificate.
|
|
89
|
+
/** @type {!Uint8Array} */
|
|
90
|
+
let contentIdArray;
|
|
91
|
+
if (typeof contentId == 'string') {
|
|
92
|
+
contentIdArray = new Uint8Array(
|
|
93
|
+
shaka.util.StringUtils.toUTF16(contentId, /* littleEndian= */ true));
|
|
94
|
+
} else {
|
|
95
|
+
contentIdArray = new Uint8Array(contentId);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const rebuiltInitData = new Uint8Array(
|
|
99
|
+
8 + initData.byteLength + contentIdArray.byteLength + cert.byteLength);
|
|
100
|
+
|
|
101
|
+
let offset = 0;
|
|
102
|
+
/** @param {!Uint8Array} array */
|
|
103
|
+
const append = (array) => {
|
|
104
|
+
rebuiltInitData.set(array, offset);
|
|
105
|
+
offset += array.byteLength;
|
|
106
|
+
};
|
|
107
|
+
/** @param {!Uint8Array} array */
|
|
108
|
+
const appendWithLength = (array) => {
|
|
109
|
+
const view = new DataView(rebuiltInitData.buffer);
|
|
110
|
+
const value = array.byteLength;
|
|
111
|
+
view.setUint32(offset, value, /* littleEndian= */ true);
|
|
112
|
+
offset += 4;
|
|
113
|
+
append(array);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
append(new Uint8Array(initData));
|
|
117
|
+
appendWithLength(contentIdArray);
|
|
118
|
+
appendWithLength(new Uint8Array(cert));
|
|
119
|
+
|
|
120
|
+
return rebuiltInitData;
|
|
121
|
+
}
|
|
122
|
+
};
|
package/lib/util/i_releasable.js
CHANGED
|
@@ -31,6 +31,7 @@ goog.require('shaka.util.ConfigUtils');
|
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* @final
|
|
34
|
+
* @export
|
|
34
35
|
*/
|
|
35
36
|
shaka.util.PlayerConfiguration = class {
|
|
36
37
|
/** @return {shaka.extern.PlayerConfiguration} */
|
|
@@ -82,6 +83,8 @@ shaka.util.PlayerConfiguration = class {
|
|
|
82
83
|
clearKeys: {}, // key is arbitrary key system ID, value must be string
|
|
83
84
|
advanced: {}, // key is arbitrary key system ID, value is a record type
|
|
84
85
|
delayLicenseRequestUntilPlayed: false,
|
|
86
|
+
initDataTransform: (initData) => initData,
|
|
87
|
+
fairPlayTransform: true,
|
|
85
88
|
};
|
|
86
89
|
|
|
87
90
|
const manifest = {
|
|
@@ -101,6 +104,9 @@ shaka.util.PlayerConfiguration = class {
|
|
|
101
104
|
ignoreMinBufferTime: false,
|
|
102
105
|
autoCorrectDrift: true,
|
|
103
106
|
},
|
|
107
|
+
hls: {
|
|
108
|
+
ignoreTextStreamFailures: false,
|
|
109
|
+
},
|
|
104
110
|
};
|
|
105
111
|
|
|
106
112
|
const streaming = {
|
|
@@ -223,6 +229,7 @@ shaka.util.PlayerConfiguration = class {
|
|
|
223
229
|
* @param {!Object} updates
|
|
224
230
|
* @param {shaka.extern.PlayerConfiguration=} template
|
|
225
231
|
* @return {boolean}
|
|
232
|
+
* @export
|
|
226
233
|
*/
|
|
227
234
|
static mergeConfigObjects(destination, updates, template) {
|
|
228
235
|
const overrides = {
|
package/lib/util/pssh.js
CHANGED
|
@@ -104,3 +104,44 @@ shaka.util.Pssh.prototype.parseBox_ = function(box) {
|
|
|
104
104
|
shaka.log.warning('Mismatch between box size and data size!');
|
|
105
105
|
}
|
|
106
106
|
};
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Creates a pssh blob from the given system ID and data.
|
|
111
|
+
*
|
|
112
|
+
* @param {!Uint8Array} data
|
|
113
|
+
* @param {!Uint8Array} systemId
|
|
114
|
+
* @return {!Uint8Array}
|
|
115
|
+
*/
|
|
116
|
+
shaka.util.Pssh.createPssh = function(data, systemId) {
|
|
117
|
+
const dataLength = data.length;
|
|
118
|
+
const psshSize = 0x4 + 0x4 + 0x4 + systemId.length + 0x4 + dataLength;
|
|
119
|
+
|
|
120
|
+
/** @type {!ArrayBuffer} */
|
|
121
|
+
const psshBoxBuffer = new ArrayBuffer(psshSize);
|
|
122
|
+
|
|
123
|
+
/** @type {!Uint8Array} */
|
|
124
|
+
const psshBox = new Uint8Array(psshBoxBuffer);
|
|
125
|
+
|
|
126
|
+
/** @type {!DataView} */
|
|
127
|
+
const psshData = new DataView(psshBoxBuffer);
|
|
128
|
+
|
|
129
|
+
let byteCursor = 0;
|
|
130
|
+
psshData.setUint32(byteCursor, psshSize);
|
|
131
|
+
byteCursor += 0x4;
|
|
132
|
+
psshData.setUint32(byteCursor, 0x70737368); // 'pssh'
|
|
133
|
+
byteCursor += 0x4;
|
|
134
|
+
psshData.setUint32(byteCursor, 0); // flags
|
|
135
|
+
byteCursor += 0x4;
|
|
136
|
+
psshBox.set(systemId, byteCursor);
|
|
137
|
+
byteCursor += systemId.length;
|
|
138
|
+
psshData.setUint32(byteCursor, dataLength);
|
|
139
|
+
byteCursor += 0x4;
|
|
140
|
+
psshBox.set(data, byteCursor);
|
|
141
|
+
byteCursor += dataLength;
|
|
142
|
+
|
|
143
|
+
goog.asserts.assert(byteCursor === psshSize,
|
|
144
|
+
'MS PRO invalid length.');
|
|
145
|
+
|
|
146
|
+
return psshBox;
|
|
147
|
+
};
|