rx-player 3.28.0-dev.2022061700 → 3.28.0-dev.2022062700
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/CHANGELOG.md +5 -3
- package/VERSION +1 -1
- package/appveyor.yml +1 -1
- package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.d.ts +32 -11
- package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.js +19 -26
- package/dist/_esm5.processed/core/api/playback_observer.d.ts +47 -35
- package/dist/_esm5.processed/core/api/playback_observer.js +120 -117
- package/dist/_esm5.processed/core/api/public_api.d.ts +4 -6
- package/dist/_esm5.processed/core/api/public_api.js +18 -18
- package/dist/_esm5.processed/core/decrypt/content_decryptor.js +60 -31
- package/dist/_esm5.processed/core/init/content_time_boundaries_observer.js +1 -1
- package/dist/_esm5.processed/core/init/create_stream_playback_observer.d.ts +1 -1
- package/dist/_esm5.processed/core/init/create_stream_playback_observer.js +23 -6
- package/dist/_esm5.processed/core/init/initial_seek_and_play.js +3 -3
- package/dist/_esm5.processed/core/init/initialize_directfile.js +1 -1
- package/dist/_esm5.processed/core/init/load_on_media_source.js +1 -1
- package/dist/_esm5.processed/core/init/stall_avoider.js +12 -8
- package/dist/_esm5.processed/core/stream/adaptation/create_representation_estimator.js +1 -1
- package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +5 -4
- package/dist/_esm5.processed/core/stream/period/create_empty_adaptation_stream.js +1 -1
- package/dist/_esm5.processed/core/stream/period/period_stream.js +21 -5
- package/dist/_esm5.processed/core/stream/reload_after_switch.js +1 -1
- package/dist/_esm5.processed/core/stream/representation/append_segment_to_buffer.js +1 -1
- package/dist/_esm5.processed/core/stream/representation/representation_stream.js +1 -1
- package/dist/_esm5.processed/utils/reference.d.ts +29 -19
- package/dist/_esm5.processed/utils/reference.js +21 -5
- package/dist/rx-player.js +366 -257
- package/dist/rx-player.min.js +1 -1
- package/package.json +2 -2
- package/sonar-project.properties +1 -1
- package/src/README.md +84 -68
- package/src/core/adaptive/adaptive_representation_selector.ts +47 -40
- package/src/core/api/playback_observer.ts +185 -173
- package/src/core/api/public_api.ts +23 -21
- package/src/core/decrypt/content_decryptor.ts +57 -23
- package/src/core/init/content_time_boundaries_observer.ts +1 -1
- package/src/core/init/create_stream_playback_observer.ts +69 -47
- package/src/core/init/initial_seek_and_play.ts +3 -3
- package/src/core/init/initialize_directfile.ts +1 -1
- package/src/core/init/load_on_media_source.ts +1 -1
- package/src/core/init/stall_avoider.ts +12 -9
- package/src/core/stream/adaptation/create_representation_estimator.ts +6 -6
- package/src/core/stream/orchestrator/stream_orchestrator.ts +5 -4
- package/src/core/stream/period/create_empty_adaptation_stream.ts +1 -1
- package/src/core/stream/period/period_stream.ts +33 -14
- package/src/core/stream/reload_after_switch.ts +1 -1
- package/src/core/stream/representation/append_segment_to_buffer.ts +1 -1
- package/src/core/stream/representation/representation_stream.ts +1 -1
- package/src/utils/reference.ts +40 -28
|
@@ -13,21 +13,13 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
17
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
18
|
-
if (ar || !(i in from)) {
|
|
19
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
20
|
-
ar[i] = from[i];
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
24
|
-
};
|
|
25
|
-
import { defer as observableDefer, fromEvent as observableFromEvent, interval as observableInterval, map, merge as observableMerge, share, shareReplay, skip, startWith, } from "rxjs";
|
|
26
16
|
import config from "../../config";
|
|
27
17
|
import log from "../../log";
|
|
28
18
|
import noop from "../../utils/noop";
|
|
29
19
|
import objectAssign from "../../utils/object_assign";
|
|
30
20
|
import { getRange } from "../../utils/ranges";
|
|
21
|
+
import createSharedReference from "../../utils/reference";
|
|
22
|
+
import TaskCanceller from "../../utils/task_canceller";
|
|
31
23
|
/**
|
|
32
24
|
* HTMLMediaElement Events for which playback observations are calculated and
|
|
33
25
|
* emitted.
|
|
@@ -56,6 +48,12 @@ var SCANNED_MEDIA_ELEMENTS_EVENTS = ["canplay",
|
|
|
56
48
|
*/
|
|
57
49
|
var PlaybackObserver = /** @class */ (function () {
|
|
58
50
|
/**
|
|
51
|
+
* Create a new `PlaybackObserver`, which allows to produce new "playback
|
|
52
|
+
* observations" on various media events and intervals.
|
|
53
|
+
*
|
|
54
|
+
* Note that creating a `PlaybackObserver` lead to the usage of resources,
|
|
55
|
+
* such as event listeners which will only be freed once the `stop` method is
|
|
56
|
+
* called.
|
|
59
57
|
* @param {HTMLMediaElement} mediaElement
|
|
60
58
|
* @param {Object} options
|
|
61
59
|
*/
|
|
@@ -64,9 +62,22 @@ var PlaybackObserver = /** @class */ (function () {
|
|
|
64
62
|
this._mediaElement = mediaElement;
|
|
65
63
|
this._withMediaSource = options.withMediaSource;
|
|
66
64
|
this._lowLatencyMode = options.lowLatencyMode;
|
|
67
|
-
this.
|
|
68
|
-
this.
|
|
65
|
+
this._canceller = new TaskCanceller();
|
|
66
|
+
this._observationRef = this._createSharedReference();
|
|
69
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Stop the `PlaybackObserver` from emitting playback observations and free all
|
|
70
|
+
* resources reserved to emitting them such as event listeners, intervals and
|
|
71
|
+
* subscribing callbacks.
|
|
72
|
+
*
|
|
73
|
+
* Once `stop` is called, no new playback observation will ever be emitted.
|
|
74
|
+
*
|
|
75
|
+
* Note that it is important to call stop once the `PlaybackObserver` is no
|
|
76
|
+
* more needed to avoid unnecessarily leaking resources.
|
|
77
|
+
*/
|
|
78
|
+
PlaybackObserver.prototype.stop = function () {
|
|
79
|
+
this._canceller.cancel();
|
|
80
|
+
};
|
|
70
81
|
/**
|
|
71
82
|
* Returns the current position advertised by the `HTMLMediaElement`, in
|
|
72
83
|
* seconds.
|
|
@@ -107,31 +118,17 @@ var PlaybackObserver = /** @class */ (function () {
|
|
|
107
118
|
return this._mediaElement.readyState;
|
|
108
119
|
};
|
|
109
120
|
/**
|
|
110
|
-
* Returns an
|
|
111
|
-
*
|
|
121
|
+
* Returns an `IReadOnlySharedReference` storing the last playback observation
|
|
122
|
+
* produced by the `PlaybackObserver` and updated each time a new one is
|
|
123
|
+
* produced.
|
|
112
124
|
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* `subscribe` will receive the same events at the same time.
|
|
116
|
-
* This was done for performance and simplicity reasons.
|
|
125
|
+
* This value can then be for example subscribed to to be notified of future
|
|
126
|
+
* playback observations.
|
|
117
127
|
*
|
|
118
|
-
* @
|
|
119
|
-
* @returns {Observable}
|
|
128
|
+
* @returns {Object}
|
|
120
129
|
*/
|
|
121
|
-
PlaybackObserver.prototype.
|
|
122
|
-
|
|
123
|
-
return observableDefer(function () {
|
|
124
|
-
if (_this._observation$ === null || _this._lastObservation === null) {
|
|
125
|
-
_this._lastObservation = _this._generateInitialObservation();
|
|
126
|
-
_this._observation$ = _this._createInnerObservable().pipe(share());
|
|
127
|
-
return _this.observe(includeLastObservation);
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
return includeLastObservation ?
|
|
131
|
-
_this._observation$.pipe(startWith(_this._lastObservation)) :
|
|
132
|
-
_this._observation$;
|
|
133
|
-
}
|
|
134
|
-
});
|
|
130
|
+
PlaybackObserver.prototype.getReference = function () {
|
|
131
|
+
return this._observationRef;
|
|
135
132
|
};
|
|
136
133
|
/**
|
|
137
134
|
* Register a callback so it regularly receives playback observations.
|
|
@@ -141,22 +138,16 @@ var PlaybackObserver = /** @class */ (function () {
|
|
|
141
138
|
* be first emitted synchronously.
|
|
142
139
|
* - `clearSignal`: If set, the callback will be unregistered when this
|
|
143
140
|
* CancellationSignal emits.
|
|
144
|
-
* @returns {Function} - Allows to easily unregister the callback
|
|
145
141
|
*/
|
|
146
142
|
PlaybackObserver.prototype.listen = function (cb, options) {
|
|
147
|
-
var _a
|
|
148
|
-
if (((_a = options === null || options === void 0 ? void 0 : options.clearSignal) === null || _a === void 0 ? void 0 : _a.isCancelled) === true) {
|
|
143
|
+
var _a;
|
|
144
|
+
if (this._canceller.isUsed || ((_a = options === null || options === void 0 ? void 0 : options.clearSignal) === null || _a === void 0 ? void 0 : _a.isCancelled) === true) {
|
|
149
145
|
return noop;
|
|
150
146
|
}
|
|
151
|
-
|
|
152
|
-
.
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
})) !== null && _d !== void 0 ? _d : noop;
|
|
156
|
-
return function () {
|
|
157
|
-
unregister();
|
|
158
|
-
sub.unsubscribe();
|
|
159
|
-
};
|
|
147
|
+
this._observationRef.onUpdate(cb, {
|
|
148
|
+
clearSignal: options === null || options === void 0 ? void 0 : options.clearSignal,
|
|
149
|
+
emitCurrentValue: options === null || options === void 0 ? void 0 : options.includeLastObservation,
|
|
150
|
+
});
|
|
160
151
|
};
|
|
161
152
|
/**
|
|
162
153
|
* Generate a new playback observer which can listen to other
|
|
@@ -169,63 +160,84 @@ var PlaybackObserver = /** @class */ (function () {
|
|
|
169
160
|
*
|
|
170
161
|
* As argument, this method takes a function which will allow to produce
|
|
171
162
|
* the new set of properties to be present on each observation.
|
|
172
|
-
* @param {Function}
|
|
163
|
+
* @param {Function} transform
|
|
173
164
|
* @returns {Object}
|
|
174
165
|
*/
|
|
175
|
-
PlaybackObserver.prototype.deriveReadOnlyObserver = function (
|
|
176
|
-
return generateReadOnlyObserver(this,
|
|
166
|
+
PlaybackObserver.prototype.deriveReadOnlyObserver = function (transform) {
|
|
167
|
+
return generateReadOnlyObserver(this, transform, this._canceller.signal);
|
|
177
168
|
};
|
|
178
169
|
/**
|
|
179
|
-
* Creates the
|
|
170
|
+
* Creates the `IReadOnlySharedReference` that will generate playback
|
|
171
|
+
* observations.
|
|
180
172
|
* @returns {Observable}
|
|
181
173
|
*/
|
|
182
|
-
PlaybackObserver.prototype.
|
|
174
|
+
PlaybackObserver.prototype._createSharedReference = function () {
|
|
183
175
|
var _this = this;
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
176
|
+
if (this._observationRef !== undefined) {
|
|
177
|
+
return this._observationRef;
|
|
178
|
+
}
|
|
179
|
+
var lastObservation;
|
|
180
|
+
var _a = config.getCurrent(), SAMPLING_INTERVAL_MEDIASOURCE = _a.SAMPLING_INTERVAL_MEDIASOURCE, SAMPLING_INTERVAL_LOW_LATENCY = _a.SAMPLING_INTERVAL_LOW_LATENCY, SAMPLING_INTERVAL_NO_MEDIASOURCE = _a.SAMPLING_INTERVAL_NO_MEDIASOURCE;
|
|
181
|
+
var getCurrentObservation = function (event) {
|
|
182
|
+
var tmpEvt = event;
|
|
183
|
+
if (tmpEvt === "seeking" && _this._internalSeekingEventsIncomingCounter > 0) {
|
|
184
|
+
tmpEvt = "internal-seeking";
|
|
185
|
+
_this._internalSeekingEventsIncomingCounter -= 1;
|
|
186
|
+
}
|
|
187
|
+
var _lastObservation = lastObservation !== null && lastObservation !== void 0 ? lastObservation : _this._generateInitialObservation();
|
|
188
|
+
var mediaTimings = getMediaInfos(_this._mediaElement, tmpEvt);
|
|
189
|
+
var internalSeeking = mediaTimings.seeking &&
|
|
190
|
+
// We've just received the event for internally seeking
|
|
191
|
+
(tmpEvt === "internal-seeking" ||
|
|
192
|
+
// or We're still waiting on the previous internal-seek
|
|
193
|
+
(_lastObservation.internalSeeking && tmpEvt !== "seeking"));
|
|
194
|
+
var rebufferingStatus = getRebufferingStatus(_lastObservation, mediaTimings, { lowLatencyMode: _this._lowLatencyMode,
|
|
195
|
+
withMediaSource: _this._withMediaSource });
|
|
196
|
+
var freezingStatus = getFreezingStatus(_lastObservation, mediaTimings);
|
|
197
|
+
var timings = objectAssign({}, { rebuffering: rebufferingStatus,
|
|
198
|
+
freezing: freezingStatus, internalSeeking: internalSeeking }, mediaTimings);
|
|
199
|
+
if (log.hasLevel("DEBUG")) {
|
|
200
|
+
log.debug("API: current media element state tick", "event", timings.event, "position", timings.position, "seeking", timings.seeking, "internalSeeking", timings.internalSeeking, "rebuffering", timings.rebuffering !== null, "freezing", timings.freezing !== null, "ended", timings.ended, "paused", timings.paused, "playbackRate", timings.playbackRate, "readyState", timings.readyState);
|
|
201
|
+
}
|
|
202
|
+
return timings;
|
|
203
|
+
};
|
|
204
|
+
var returnedSharedReference = createSharedReference(getCurrentObservation("init"));
|
|
205
|
+
var generateObservationForEvent = function (event) {
|
|
206
|
+
var newObservation = getCurrentObservation(event);
|
|
207
|
+
if (log.hasLevel("DEBUG")) {
|
|
208
|
+
log.debug("API: current playback timeline:\n" +
|
|
209
|
+
prettyPrintBuffered(newObservation.buffered, newObservation.position), "\n".concat(event));
|
|
210
|
+
}
|
|
211
|
+
lastObservation = newObservation;
|
|
212
|
+
returnedSharedReference.setValue(newObservation);
|
|
213
|
+
};
|
|
214
|
+
var interval = this._lowLatencyMode ? SAMPLING_INTERVAL_LOW_LATENCY :
|
|
215
|
+
this._withMediaSource ? SAMPLING_INTERVAL_MEDIASOURCE :
|
|
216
|
+
SAMPLING_INTERVAL_NO_MEDIASOURCE;
|
|
217
|
+
var intervalId = setInterval(onInterval, interval);
|
|
218
|
+
var removeEventListeners = SCANNED_MEDIA_ELEMENTS_EVENTS.map(function (eventName) {
|
|
219
|
+
_this._mediaElement.addEventListener(eventName, onMediaEvent);
|
|
220
|
+
function onMediaEvent() {
|
|
221
|
+
restartInterval();
|
|
222
|
+
generateObservationForEvent(eventName);
|
|
223
|
+
}
|
|
224
|
+
return function () {
|
|
225
|
+
_this._mediaElement.removeEventListener(eventName, onMediaEvent);
|
|
209
226
|
};
|
|
210
|
-
var eventObs = SCANNED_MEDIA_ELEMENTS_EVENTS.map(function (eventName) {
|
|
211
|
-
return observableFromEvent(_this._mediaElement, eventName)
|
|
212
|
-
.pipe(map(function () { return eventName; }));
|
|
213
|
-
});
|
|
214
|
-
var interval = _this._lowLatencyMode ? SAMPLING_INTERVAL_LOW_LATENCY :
|
|
215
|
-
_this._withMediaSource ? SAMPLING_INTERVAL_MEDIASOURCE :
|
|
216
|
-
SAMPLING_INTERVAL_NO_MEDIASOURCE;
|
|
217
|
-
var interval$ = observableInterval(interval)
|
|
218
|
-
.pipe(map(function () { return "timeupdate"; }));
|
|
219
|
-
return observableMerge.apply(void 0, __spreadArray([interval$], eventObs, false)).pipe(map(function (event) {
|
|
220
|
-
var newObservation = getCurrentObservation(event);
|
|
221
|
-
if (log.hasLevel("DEBUG")) {
|
|
222
|
-
log.debug("API: current playback timeline:\n" +
|
|
223
|
-
prettyPrintBuffered(newObservation.buffered, newObservation.position), "\n".concat(event));
|
|
224
|
-
}
|
|
225
|
-
_this._lastObservation = newObservation;
|
|
226
|
-
return newObservation;
|
|
227
|
-
}));
|
|
228
227
|
});
|
|
228
|
+
this._canceller.signal.register(function () {
|
|
229
|
+
clearInterval(intervalId);
|
|
230
|
+
removeEventListeners.forEach(function (cb) { return cb(); });
|
|
231
|
+
returnedSharedReference.finish();
|
|
232
|
+
});
|
|
233
|
+
return returnedSharedReference;
|
|
234
|
+
function onInterval() {
|
|
235
|
+
generateObservationForEvent("timeupdate");
|
|
236
|
+
}
|
|
237
|
+
function restartInterval() {
|
|
238
|
+
clearInterval(intervalId);
|
|
239
|
+
intervalId = setInterval(onInterval, interval);
|
|
240
|
+
}
|
|
229
241
|
};
|
|
230
242
|
PlaybackObserver.prototype._generateInitialObservation = function () {
|
|
231
243
|
return objectAssign(getMediaInfos(this._mediaElement, "init"), { rebuffering: null,
|
|
@@ -480,13 +492,11 @@ function prettyPrintBuffered(buffered, currentTime) {
|
|
|
480
492
|
* Create `IReadOnlyPlaybackObserver` from a source `IReadOnlyPlaybackObserver`
|
|
481
493
|
* and a mapping function.
|
|
482
494
|
* @param {Object} src
|
|
483
|
-
* @param {Function}
|
|
495
|
+
* @param {Function} transform
|
|
484
496
|
* @returns {Object}
|
|
485
497
|
*/
|
|
486
|
-
function generateReadOnlyObserver(src,
|
|
487
|
-
var
|
|
488
|
-
return mapObservable(src.observe(true));
|
|
489
|
-
}).pipe(shareReplay({ bufferSize: 1, refCount: true }));
|
|
498
|
+
function generateReadOnlyObserver(src, transform, cancellationSignal) {
|
|
499
|
+
var mappedRef = transform(src.getReference(), cancellationSignal);
|
|
490
500
|
return {
|
|
491
501
|
getCurrentTime: function () {
|
|
492
502
|
return src.getCurrentTime();
|
|
@@ -497,28 +507,21 @@ function generateReadOnlyObserver(src, mapObservable) {
|
|
|
497
507
|
getIsPaused: function () {
|
|
498
508
|
return src.getIsPaused();
|
|
499
509
|
},
|
|
500
|
-
|
|
501
|
-
return
|
|
502
|
-
newObs.pipe(skip(1));
|
|
510
|
+
getReference: function () {
|
|
511
|
+
return mappedRef;
|
|
503
512
|
},
|
|
504
513
|
listen: function (cb, options) {
|
|
505
|
-
var _a
|
|
506
|
-
if (((_a = options === null || options === void 0 ? void 0 : options.clearSignal) === null || _a === void 0 ? void 0 : _a.isCancelled) === true) {
|
|
507
|
-
return
|
|
514
|
+
var _a;
|
|
515
|
+
if (cancellationSignal.isCancelled || ((_a = options === null || options === void 0 ? void 0 : options.clearSignal) === null || _a === void 0 ? void 0 : _a.isCancelled) === true) {
|
|
516
|
+
return;
|
|
508
517
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
sub.unsubscribe();
|
|
514
|
-
})) !== null && _c !== void 0 ? _c : noop;
|
|
515
|
-
return function () {
|
|
516
|
-
unregister();
|
|
517
|
-
sub.unsubscribe();
|
|
518
|
-
};
|
|
518
|
+
mappedRef.onUpdate(cb, {
|
|
519
|
+
clearSignal: options === null || options === void 0 ? void 0 : options.clearSignal,
|
|
520
|
+
emitCurrentValue: options === null || options === void 0 ? void 0 : options.includeLastObservation,
|
|
521
|
+
});
|
|
519
522
|
},
|
|
520
|
-
deriveReadOnlyObserver: function (
|
|
521
|
-
return generateReadOnlyObserver(this,
|
|
523
|
+
deriveReadOnlyObserver: function (newTransformFn) {
|
|
524
|
+
return generateReadOnlyObserver(this, newTransformFn, cancellationSignal);
|
|
522
525
|
},
|
|
523
526
|
};
|
|
524
527
|
}
|
|
@@ -29,7 +29,10 @@ declare class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
29
29
|
static version: string;
|
|
30
30
|
/** Current version of the RxPlayer. */
|
|
31
31
|
readonly version: string;
|
|
32
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Media element attached to the RxPlayer.
|
|
34
|
+
* Set to `null` when the RxPlayer is disposed.
|
|
35
|
+
*/
|
|
33
36
|
videoElement: HTMLMediaElement | null;
|
|
34
37
|
/** Logger the RxPlayer uses. */
|
|
35
38
|
readonly log: Logger;
|
|
@@ -693,11 +696,6 @@ declare class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
693
696
|
* @param {Error} error
|
|
694
697
|
*/
|
|
695
698
|
private _priv_onPlaybackError;
|
|
696
|
-
/**
|
|
697
|
-
* Triggered when the playback Observable completes.
|
|
698
|
-
* Clean-up ressources and signal that the content has ended.
|
|
699
|
-
*/
|
|
700
|
-
private _priv_onPlaybackFinished;
|
|
701
699
|
/**
|
|
702
700
|
* Triggered when we received a warning event during playback.
|
|
703
701
|
* Trigger the right API event.
|
|
@@ -88,7 +88,7 @@ var Player = /** @class */ (function (_super) {
|
|
|
88
88
|
// Workaround to support Firefox autoplay on FF 42.
|
|
89
89
|
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1194624
|
|
90
90
|
videoElement.preload = "auto";
|
|
91
|
-
_this.version = /* PLAYER_VERSION */ "3.28.0-dev.
|
|
91
|
+
_this.version = /* PLAYER_VERSION */ "3.28.0-dev.2022062700";
|
|
92
92
|
_this.log = log;
|
|
93
93
|
_this.state = "STOPPED";
|
|
94
94
|
_this.videoElement = videoElement;
|
|
@@ -359,6 +359,9 @@ var Player = /** @class */ (function (_super) {
|
|
|
359
359
|
withMediaSource: !isDirectFile,
|
|
360
360
|
lowLatencyMode: lowLatencyMode,
|
|
361
361
|
});
|
|
362
|
+
currentContentCanceller.signal.register(function () {
|
|
363
|
+
playbackObserver.stop();
|
|
364
|
+
});
|
|
362
365
|
/** Emit playback events. */
|
|
363
366
|
var playback$;
|
|
364
367
|
if (!isDirectFile) {
|
|
@@ -534,7 +537,7 @@ var Player = /** @class */ (function (_super) {
|
|
|
534
537
|
return evt.type === "reloading-media-source";
|
|
535
538
|
}), share());
|
|
536
539
|
/** Emit when the media element emits a "seeking" event. */
|
|
537
|
-
var observation$ = playbackObserver.
|
|
540
|
+
var observation$ = playbackObserver.getReference().asObservable();
|
|
538
541
|
var stateChangingEvent$ = observation$.pipe(filter(function (o) {
|
|
539
542
|
return o.event === "seeking" || o.event === "ended" ||
|
|
540
543
|
o.event === "play" || o.event === "pause";
|
|
@@ -598,7 +601,14 @@ var Player = /** @class */ (function (_super) {
|
|
|
598
601
|
playback$.subscribe({
|
|
599
602
|
next: function (x) { return _this._priv_onPlaybackEvent(x); },
|
|
600
603
|
error: function (err) { return _this._priv_onPlaybackError(err); },
|
|
601
|
-
complete: function () {
|
|
604
|
+
complete: function () {
|
|
605
|
+
if (!contentInfos.currentContentCanceller.isUsed) {
|
|
606
|
+
log.info("API: Previous playback finished. Stopping and cleaning-up...");
|
|
607
|
+
contentInfos.currentContentCanceller.cancel();
|
|
608
|
+
_this._priv_cleanUpCurrentContentState();
|
|
609
|
+
_this._priv_setPlayerState(PLAYER_STATES.STOPPED);
|
|
610
|
+
}
|
|
611
|
+
},
|
|
602
612
|
});
|
|
603
613
|
// initialize the content only when the lock is inactive
|
|
604
614
|
this._priv_contentLock.asObservable()
|
|
@@ -1758,8 +1768,10 @@ var Player = /** @class */ (function (_super) {
|
|
|
1758
1768
|
this._priv_contentEventsMemory = {};
|
|
1759
1769
|
// DRM-related clean-up
|
|
1760
1770
|
var freeUpContentLock = function () {
|
|
1761
|
-
|
|
1762
|
-
|
|
1771
|
+
if (_this.videoElement !== null) { // If not disposed
|
|
1772
|
+
log.debug("Unlocking `contentLock`. Next content can begin.");
|
|
1773
|
+
_this._priv_contentLock.setValue(false);
|
|
1774
|
+
}
|
|
1763
1775
|
};
|
|
1764
1776
|
if (!isNullOrUndefined(this.videoElement)) {
|
|
1765
1777
|
clearOnStop(this.videoElement).then(function () {
|
|
@@ -1878,18 +1890,6 @@ var Player = /** @class */ (function (_super) {
|
|
|
1878
1890
|
this.trigger("error", formattedError);
|
|
1879
1891
|
}
|
|
1880
1892
|
};
|
|
1881
|
-
/**
|
|
1882
|
-
* Triggered when the playback Observable completes.
|
|
1883
|
-
* Clean-up ressources and signal that the content has ended.
|
|
1884
|
-
*/
|
|
1885
|
-
Player.prototype._priv_onPlaybackFinished = function () {
|
|
1886
|
-
log.info("API: Previous playback finished. Stopping and cleaning-up...");
|
|
1887
|
-
if (this._priv_contentInfos !== null) {
|
|
1888
|
-
this._priv_contentInfos.currentContentCanceller.cancel();
|
|
1889
|
-
}
|
|
1890
|
-
this._priv_cleanUpCurrentContentState();
|
|
1891
|
-
this._priv_setPlayerState(PLAYER_STATES.ENDED);
|
|
1892
|
-
};
|
|
1893
1893
|
/**
|
|
1894
1894
|
* Triggered when we received a warning event during playback.
|
|
1895
1895
|
* Trigger the right API event.
|
|
@@ -2295,5 +2295,5 @@ var Player = /** @class */ (function (_super) {
|
|
|
2295
2295
|
};
|
|
2296
2296
|
return Player;
|
|
2297
2297
|
}(EventEmitter));
|
|
2298
|
-
Player.version = /* PLAYER_VERSION */ "3.28.0-dev.
|
|
2298
|
+
Player.version = /* PLAYER_VERSION */ "3.28.0-dev.2022062700";
|
|
2299
2299
|
export default Player;
|
|
@@ -428,18 +428,7 @@ var ContentDecryptor = /** @class */ (function (_super) {
|
|
|
428
428
|
_this.trigger("warning", evt.value);
|
|
429
429
|
return;
|
|
430
430
|
}
|
|
431
|
-
var linkedKeys;
|
|
432
|
-
if (sessionInfo.source === "created-session" /* MediaKeySessionLoadingType.Created */) {
|
|
433
|
-
// When the license has been fetched, there might be implicit key ids
|
|
434
|
-
// linked to the session depending on the `singleLicensePer` option.
|
|
435
|
-
linkedKeys = getFetchedLicenseKeysInfo(initializationData, options.singleLicensePer, evt.value.whitelistedKeyIds, evt.value.blacklistedKeyIDs);
|
|
436
|
-
}
|
|
437
|
-
else {
|
|
438
|
-
// When the MediaKeySession is just a cached/persisted one, we don't
|
|
439
|
-
// have any concept of "implicit key id".
|
|
440
|
-
linkedKeys = { whitelisted: evt.value.whitelistedKeyIds,
|
|
441
|
-
blacklisted: evt.value.blacklistedKeyIDs };
|
|
442
|
-
}
|
|
431
|
+
var linkedKeys = getKeyIdsLinkedToSession(initializationData, sessionInfo.record, options.singleLicensePer, sessionInfo.source === "created-session" /* MediaKeySessionLoadingType.Created */, evt.value.whitelistedKeyIds, evt.value.blacklistedKeyIDs);
|
|
443
432
|
sessionInfo.record.associateKeyIds(linkedKeys.whitelisted);
|
|
444
433
|
sessionInfo.record.associateKeyIds(linkedKeys.blacklisted);
|
|
445
434
|
sessionInfo.keyStatuses = { whitelisted: linkedKeys.whitelisted,
|
|
@@ -758,26 +747,63 @@ export var ContentDecryptorState;
|
|
|
758
747
|
ContentDecryptorState[ContentDecryptorState["Disposed"] = 4] = "Disposed";
|
|
759
748
|
})(ContentDecryptorState || (ContentDecryptorState = {}));
|
|
760
749
|
/**
|
|
761
|
-
* Returns
|
|
762
|
-
* a
|
|
750
|
+
* Returns set of all usable and unusable keys - explicit or implicit - that are
|
|
751
|
+
* linked to a `MediaKeySession`.
|
|
763
752
|
*
|
|
764
753
|
* In the RxPlayer, there is a concept of "explicit" key ids, which are key ids
|
|
765
754
|
* found in a license whose status can be known through the `keyStatuses`
|
|
766
755
|
* property from a `MediaKeySession`, and of "implicit" key ids, which are key
|
|
767
756
|
* ids which were expected to be in a fetched license, but apparently weren't.
|
|
768
|
-
*
|
|
769
|
-
* @param {
|
|
770
|
-
*
|
|
771
|
-
* @param {
|
|
772
|
-
*
|
|
757
|
+
*
|
|
758
|
+
* @param {Object} initializationData - Initialization data object used to make
|
|
759
|
+
* the request for the current license.
|
|
760
|
+
* @param {Object} keySessionRecord - The `KeySessionRecord` associated with the
|
|
761
|
+
* session that has been loaded. It might give supplementary information on
|
|
762
|
+
* keys implicitly linked to the license.
|
|
763
|
+
* @param {string|undefined} singleLicensePer - Setting allowing to indicate the
|
|
764
|
+
* scope a given license should have.
|
|
765
|
+
* @param {boolean} isCurrentLicense - If `true` the license has been fetched
|
|
766
|
+
* especially for the current content.
|
|
767
|
+
*
|
|
768
|
+
* Knowing this allows to determine that if decryption keys that should have
|
|
769
|
+
* been referenced in the fetched license (according to the `singleLicensePer`
|
|
770
|
+
* setting) are missing, then the keys surely must have been voluntarly
|
|
771
|
+
* removed from the license.
|
|
772
|
+
*
|
|
773
|
+
* If it is however set to `false`, it means that the license is an older
|
|
774
|
+
* license that might have been linked to another content, thus we cannot make
|
|
775
|
+
* that assumption.
|
|
776
|
+
* @param {Array.<Uint8Array>} usableKeyIds - Key ids that are present in the
|
|
777
|
+
* license and can be used.
|
|
778
|
+
* @param {Array.<Uint8Array>} unusableKeyIds - Key ids that are present in the
|
|
779
|
+
* license yet cannot be used.
|
|
780
|
+
* @returns {Object} - Returns an object with the following properties:
|
|
781
|
+
* - `whitelisted`: Array of key ids for keys that are known to be usable
|
|
782
|
+
* - `blacklisted`: Array of key ids for keys that are considered unusable.
|
|
783
|
+
* The qualities linked to those keys should not be played.
|
|
773
784
|
*/
|
|
774
|
-
function
|
|
785
|
+
function getKeyIdsLinkedToSession(initializationData, keySessionRecord, singleLicensePer, isCurrentLicense, usableKeyIds, unusableKeyIds) {
|
|
775
786
|
var _a;
|
|
776
787
|
/**
|
|
777
788
|
* Every key id associated with the MediaKeySession, starting with
|
|
778
789
|
* whitelisted ones.
|
|
779
790
|
*/
|
|
780
791
|
var associatedKeyIds = __spreadArray(__spreadArray([], usableKeyIds, true), unusableKeyIds, true);
|
|
792
|
+
// Add all key ids associated to the `KeySessionRecord` yet not in
|
|
793
|
+
// `usableKeyIds` nor in `unusableKeyIds`
|
|
794
|
+
var allKnownKeyIds = keySessionRecord.getAssociatedKeyIds();
|
|
795
|
+
var _loop_2 = function (kid) {
|
|
796
|
+
if (!associatedKeyIds.some(function (ak) { return areKeyIdsEqual(ak, kid); })) {
|
|
797
|
+
if (log.hasLevel("DEBUG")) {
|
|
798
|
+
log.debug("DRM: KeySessionRecord's key missing in the license, blacklisting it", bytesToHex(kid));
|
|
799
|
+
}
|
|
800
|
+
associatedKeyIds.push(kid);
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
for (var _i = 0, allKnownKeyIds_1 = allKnownKeyIds; _i < allKnownKeyIds_1.length; _i++) {
|
|
804
|
+
var kid = allKnownKeyIds_1[_i];
|
|
805
|
+
_loop_2(kid);
|
|
806
|
+
}
|
|
781
807
|
if (singleLicensePer !== undefined && singleLicensePer !== "init-data") {
|
|
782
808
|
// We want to add the current key ids in the blacklist if it is
|
|
783
809
|
// not already there.
|
|
@@ -798,24 +824,27 @@ function getFetchedLicenseKeysInfo(initializationData, singleLicensePer, usableK
|
|
|
798
824
|
return !associatedKeyIds.some(function (k) { return areKeyIdsEqual(k, expected); });
|
|
799
825
|
});
|
|
800
826
|
if (missingKeyIds.length > 0) {
|
|
827
|
+
if (log.hasLevel("DEBUG")) {
|
|
828
|
+
log.debug("DRM: init data keys missing in the license, blacklisting them", missingKeyIds.map(function (m) { return bytesToHex(m); }).join(", "));
|
|
829
|
+
}
|
|
801
830
|
associatedKeyIds.push.apply(associatedKeyIds, missingKeyIds);
|
|
802
831
|
}
|
|
803
832
|
}
|
|
804
|
-
if (content !== undefined) {
|
|
833
|
+
if (isCurrentLicense && content !== undefined) {
|
|
805
834
|
if (singleLicensePer === "content") {
|
|
806
835
|
// Put it in a Set to automatically filter out duplicates (by ref)
|
|
807
836
|
var contentKeys = new Set();
|
|
808
837
|
var manifest = content.manifest;
|
|
809
|
-
for (var
|
|
810
|
-
var period = _b
|
|
838
|
+
for (var _b = 0, _c = manifest.periods; _b < _c.length; _b++) {
|
|
839
|
+
var period = _c[_b];
|
|
811
840
|
addKeyIdsFromPeriod(contentKeys, period);
|
|
812
841
|
}
|
|
813
842
|
mergeKeyIdSetIntoArray(contentKeys, associatedKeyIds);
|
|
814
843
|
}
|
|
815
844
|
else if (singleLicensePer === "periods") {
|
|
816
845
|
var manifest = content.manifest;
|
|
817
|
-
for (var
|
|
818
|
-
var period = _d
|
|
846
|
+
for (var _d = 0, _e = manifest.periods; _d < _e.length; _d++) {
|
|
847
|
+
var period = _e[_d];
|
|
819
848
|
var periodKeys = new Set();
|
|
820
849
|
addKeyIdsFromPeriod(periodKeys, period);
|
|
821
850
|
if (((_a = initializationData.content) === null || _a === void 0 ? void 0 : _a.period.id) === period.id) {
|
|
@@ -823,16 +852,16 @@ function getFetchedLicenseKeysInfo(initializationData, singleLicensePer, usableK
|
|
|
823
852
|
}
|
|
824
853
|
else {
|
|
825
854
|
var periodKeysArr = Array.from(periodKeys);
|
|
826
|
-
var
|
|
855
|
+
var _loop_3 = function (kid) {
|
|
827
856
|
var isFound = associatedKeyIds.some(function (k) { return areKeyIdsEqual(k, kid); });
|
|
828
857
|
if (isFound) {
|
|
829
858
|
mergeKeyIdSetIntoArray(periodKeys, associatedKeyIds);
|
|
830
859
|
return "break";
|
|
831
860
|
}
|
|
832
861
|
};
|
|
833
|
-
for (var
|
|
834
|
-
var kid = periodKeysArr_3[
|
|
835
|
-
var state_2 =
|
|
862
|
+
for (var _f = 0, periodKeysArr_3 = periodKeysArr; _f < periodKeysArr_3.length; _f++) {
|
|
863
|
+
var kid = periodKeysArr_3[_f];
|
|
864
|
+
var state_2 = _loop_3(kid);
|
|
836
865
|
if (state_2 === "break")
|
|
837
866
|
break;
|
|
838
867
|
}
|
|
@@ -847,7 +876,7 @@ function getFetchedLicenseKeysInfo(initializationData, singleLicensePer, usableK
|
|
|
847
876
|
}
|
|
848
877
|
function mergeKeyIdSetIntoArray(set, arr) {
|
|
849
878
|
var setArr = Array.from(set.values());
|
|
850
|
-
var
|
|
879
|
+
var _loop_4 = function (kid) {
|
|
851
880
|
var isFound = arr.some(function (k) { return areKeyIdsEqual(k, kid); });
|
|
852
881
|
if (!isFound) {
|
|
853
882
|
arr.push(kid);
|
|
@@ -855,7 +884,7 @@ function mergeKeyIdSetIntoArray(set, arr) {
|
|
|
855
884
|
};
|
|
856
885
|
for (var _i = 0, setArr_1 = setArr; _i < setArr_1.length; _i++) {
|
|
857
886
|
var kid = setArr_1[_i];
|
|
858
|
-
|
|
887
|
+
_loop_4(kid);
|
|
859
888
|
}
|
|
860
889
|
}
|
|
861
890
|
function addKeyIdsFromPeriod(set, period) {
|
|
@@ -45,7 +45,7 @@ export default function ContentTimeBoundariesObserver(manifest, streams, playbac
|
|
|
45
45
|
var maximumPositionCalculator = new MaximumPositionCalculator(manifest);
|
|
46
46
|
// trigger warnings when the wanted time is before or after the manifest's
|
|
47
47
|
// segments
|
|
48
|
-
var outOfManifest$ = playbackObserver.
|
|
48
|
+
var outOfManifest$ = playbackObserver.getReference().asObservable().pipe(filterMap(function (_a) {
|
|
49
49
|
var _b;
|
|
50
50
|
var position = _a.position;
|
|
51
51
|
var wantedPosition = (_b = position.pending) !== null && _b !== void 0 ? _b : position.last;
|
|
@@ -35,6 +35,6 @@ export interface IStreamPlaybackObserverArguments {
|
|
|
35
35
|
* @param {Object} manifest
|
|
36
36
|
* @param {Object} playbackObserver
|
|
37
37
|
* @param {Object} args
|
|
38
|
-
* @returns {
|
|
38
|
+
* @returns {Object}
|
|
39
39
|
*/
|
|
40
40
|
export default function createStreamPlaybackObserver(manifest: Manifest, playbackObserver: PlaybackObserver, { autoPlay, initialPlayPerformed, initialSeekPerformed, speed, startTime }: IStreamPlaybackObserverArguments): IReadOnlyPlaybackObserver<IStreamOrchestratorPlaybackObservation>;
|