rx-player 3.28.0-dev.2022062300 → 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 +2 -1
- package/VERSION +1 -1
- package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.js +1 -6
- 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 -1
- package/dist/_esm5.processed/core/api/public_api.js +10 -5
- 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/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 +2 -2
- package/dist/_esm5.processed/utils/reference.js +5 -4
- package/dist/rx-player.js +241 -179
- package/dist/rx-player.min.js +1 -1
- package/package.json +2 -2
- package/sonar-project.properties +1 -1
- package/src/core/adaptive/adaptive_representation_selector.ts +1 -7
- package/src/core/api/playback_observer.ts +185 -173
- package/src/core/api/public_api.ts +15 -6
- 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/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 +7 -5
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rx-player",
|
|
3
3
|
"author": "Canal+",
|
|
4
|
-
"version": "3.28.0-dev.
|
|
4
|
+
"version": "3.28.0-dev.2022062700",
|
|
5
5
|
"description": "Canal+ HTML5 Video Player",
|
|
6
6
|
"main": "./dist/rx-player.js",
|
|
7
7
|
"keywords": [
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"build:modular": "./scripts/build/generate_build.js",
|
|
33
33
|
"build:report": "webpack --progress --config webpack.config.js --env production --env reportSize",
|
|
34
34
|
"build:rxp:all": "npm run build && npm run build:min && npm run build:modular",
|
|
35
|
-
"build:watch": "webpack --progress --config webpack.config.js -w
|
|
35
|
+
"build:watch": "webpack --progress --config webpack.config.js -w --env production",
|
|
36
36
|
"build:min:watch": "webpack --progress --config webpack.config.js -w --env production --env minify",
|
|
37
37
|
"build:wasm:debug": "cd ./src/parsers/manifest/dash/wasm-parser && cargo build --target wasm32-unknown-unknown && cp target/wasm32-unknown-unknown/debug/mpd_node_parser.wasm ../../../../../dist/mpd-parser.wasm",
|
|
38
38
|
"build:wasm:release": "cd ./src/parsers/manifest/dash/wasm-parser && cargo build --target wasm32-unknown-unknown --release && wasm-opt -O3 -o ../../../../../dist/mpd-parser.wasm target/wasm32-unknown-unknown/release/mpd_node_parser.wasm && cd ../../../../../ && npm run wasm-strip",
|
package/sonar-project.properties
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
sonar.projectKey=rx-player
|
|
2
2
|
sonar.organization=rx-player
|
|
3
3
|
sonar.projectName=rx-player
|
|
4
|
-
sonar.projectVersion=3.28.0-dev.
|
|
4
|
+
sonar.projectVersion=3.28.0-dev.2022062700
|
|
5
5
|
sonar.sources=./src,./demo,./tests
|
|
6
6
|
sonar.exclusions=demo/full/bundle.js,demo/standalone/lib.js,demo/bundle.js
|
|
7
7
|
sonar.host.url=https://sonarcloud.io
|
|
@@ -268,14 +268,8 @@ function getEstimateReference(
|
|
|
268
268
|
*/
|
|
269
269
|
const guessBasedChooser = new GuessBasedChooser(scoreCalculator, prevEstimate);
|
|
270
270
|
|
|
271
|
-
let lastPlaybackObservation : IRepresentationEstimatorPlaybackObservation;
|
|
272
|
-
|
|
273
271
|
// get initial observation for initial estimate
|
|
274
|
-
|
|
275
|
-
lastPlaybackObservation = obs;
|
|
276
|
-
}, { includeLastObservation: true });
|
|
277
|
-
unregisterInitial(); // The initial is emitted synchronously, we can now remove it
|
|
278
|
-
// TODO cleaner playbackObserver.getLast() or something?
|
|
272
|
+
let lastPlaybackObservation = playbackObserver.getReference().getValue();
|
|
279
273
|
|
|
280
274
|
/** Reference through which estimates are emitted. */
|
|
281
275
|
const innerEstimateRef = createSharedReference<IABREstimate>(getCurrentEstimate());
|
|
@@ -14,25 +14,17 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
18
|
-
defer as observableDefer,
|
|
19
|
-
fromEvent as observableFromEvent,
|
|
20
|
-
interval as observableInterval,
|
|
21
|
-
map,
|
|
22
|
-
merge as observableMerge,
|
|
23
|
-
Observable,
|
|
24
|
-
share,
|
|
25
|
-
shareReplay,
|
|
26
|
-
skip,
|
|
27
|
-
startWith,
|
|
28
|
-
} from "rxjs";
|
|
29
17
|
import config from "../../config";
|
|
30
18
|
import log from "../../log";
|
|
31
19
|
import noop from "../../utils/noop";
|
|
32
20
|
import objectAssign from "../../utils/object_assign";
|
|
33
21
|
import { getRange } from "../../utils/ranges";
|
|
34
|
-
import {
|
|
35
|
-
|
|
22
|
+
import createSharedReference, {
|
|
23
|
+
IReadOnlySharedReference,
|
|
24
|
+
} from "../../utils/reference";
|
|
25
|
+
import TaskCanceller, {
|
|
26
|
+
CancellationSignal,
|
|
27
|
+
} from "../../utils/task_canceller";
|
|
36
28
|
|
|
37
29
|
/**
|
|
38
30
|
* HTMLMediaElement Events for which playback observations are calculated and
|
|
@@ -93,19 +85,23 @@ export default class PlaybackObserver {
|
|
|
93
85
|
private _internalSeekingEventsIncomingCounter : number;
|
|
94
86
|
|
|
95
87
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* `null` if no observation has been made yet.
|
|
88
|
+
* Stores the last playback observation produced by the `PlaybackObserver`.:
|
|
99
89
|
*/
|
|
100
|
-
private
|
|
90
|
+
private _observationRef : IReadOnlySharedReference<IPlaybackObservation>;
|
|
101
91
|
|
|
102
92
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
93
|
+
* `TaskCanceller` allowing to free all resources and stop producing playback
|
|
94
|
+
* observations.
|
|
105
95
|
*/
|
|
106
|
-
private
|
|
96
|
+
private _canceller : TaskCanceller;
|
|
107
97
|
|
|
108
98
|
/**
|
|
99
|
+
* Create a new `PlaybackObserver`, which allows to produce new "playback
|
|
100
|
+
* observations" on various media events and intervals.
|
|
101
|
+
*
|
|
102
|
+
* Note that creating a `PlaybackObserver` lead to the usage of resources,
|
|
103
|
+
* such as event listeners which will only be freed once the `stop` method is
|
|
104
|
+
* called.
|
|
109
105
|
* @param {HTMLMediaElement} mediaElement
|
|
110
106
|
* @param {Object} options
|
|
111
107
|
*/
|
|
@@ -114,8 +110,22 @@ export default class PlaybackObserver {
|
|
|
114
110
|
this._mediaElement = mediaElement;
|
|
115
111
|
this._withMediaSource = options.withMediaSource;
|
|
116
112
|
this._lowLatencyMode = options.lowLatencyMode;
|
|
117
|
-
this.
|
|
118
|
-
this.
|
|
113
|
+
this._canceller = new TaskCanceller();
|
|
114
|
+
this._observationRef = this._createSharedReference();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Stop the `PlaybackObserver` from emitting playback observations and free all
|
|
119
|
+
* resources reserved to emitting them such as event listeners, intervals and
|
|
120
|
+
* subscribing callbacks.
|
|
121
|
+
*
|
|
122
|
+
* Once `stop` is called, no new playback observation will ever be emitted.
|
|
123
|
+
*
|
|
124
|
+
* Note that it is important to call stop once the `PlaybackObserver` is no
|
|
125
|
+
* more needed to avoid unnecessarily leaking resources.
|
|
126
|
+
*/
|
|
127
|
+
public stop() {
|
|
128
|
+
this._canceller.cancel();
|
|
119
129
|
}
|
|
120
130
|
|
|
121
131
|
/**
|
|
@@ -162,29 +172,17 @@ export default class PlaybackObserver {
|
|
|
162
172
|
}
|
|
163
173
|
|
|
164
174
|
/**
|
|
165
|
-
* Returns an
|
|
166
|
-
*
|
|
175
|
+
* Returns an `IReadOnlySharedReference` storing the last playback observation
|
|
176
|
+
* produced by the `PlaybackObserver` and updated each time a new one is
|
|
177
|
+
* produced.
|
|
167
178
|
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
* `subscribe` will receive the same events at the same time.
|
|
171
|
-
* This was done for performance and simplicity reasons.
|
|
179
|
+
* This value can then be for example subscribed to to be notified of future
|
|
180
|
+
* playback observations.
|
|
172
181
|
*
|
|
173
|
-
* @
|
|
174
|
-
* @returns {Observable}
|
|
182
|
+
* @returns {Object}
|
|
175
183
|
*/
|
|
176
|
-
public
|
|
177
|
-
return
|
|
178
|
-
if (this._observation$ === null || this._lastObservation === null) {
|
|
179
|
-
this._lastObservation = this._generateInitialObservation();
|
|
180
|
-
this._observation$ = this._createInnerObservable().pipe(share());
|
|
181
|
-
return this.observe(includeLastObservation);
|
|
182
|
-
} else {
|
|
183
|
-
return includeLastObservation ?
|
|
184
|
-
this._observation$.pipe(startWith(this._lastObservation)) :
|
|
185
|
-
this._observation$;
|
|
186
|
-
}
|
|
187
|
-
});
|
|
184
|
+
public getReference() : IReadOnlySharedReference<IPlaybackObservation> {
|
|
185
|
+
return this._observationRef;
|
|
188
186
|
}
|
|
189
187
|
|
|
190
188
|
/**
|
|
@@ -195,26 +193,19 @@ export default class PlaybackObserver {
|
|
|
195
193
|
* be first emitted synchronously.
|
|
196
194
|
* - `clearSignal`: If set, the callback will be unregistered when this
|
|
197
195
|
* CancellationSignal emits.
|
|
198
|
-
* @returns {Function} - Allows to easily unregister the callback
|
|
199
196
|
*/
|
|
200
197
|
public listen(
|
|
201
198
|
cb : (observation : IPlaybackObservation) => void,
|
|
202
199
|
options? : { includeLastObservation? : boolean | undefined;
|
|
203
200
|
clearSignal? : CancellationSignal | undefined; }
|
|
204
|
-
)
|
|
205
|
-
if (options?.clearSignal?.isCancelled === true) {
|
|
201
|
+
) {
|
|
202
|
+
if (this._canceller.isUsed || options?.clearSignal?.isCancelled === true) {
|
|
206
203
|
return noop;
|
|
207
204
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}) ?? noop;
|
|
213
|
-
|
|
214
|
-
return () => {
|
|
215
|
-
unregister();
|
|
216
|
-
sub.unsubscribe();
|
|
217
|
-
};
|
|
205
|
+
this._observationRef.onUpdate(cb, {
|
|
206
|
+
clearSignal: options?.clearSignal,
|
|
207
|
+
emitCurrentValue: options?.includeLastObservation,
|
|
208
|
+
});
|
|
218
209
|
}
|
|
219
210
|
|
|
220
211
|
/**
|
|
@@ -228,99 +219,122 @@ export default class PlaybackObserver {
|
|
|
228
219
|
*
|
|
229
220
|
* As argument, this method takes a function which will allow to produce
|
|
230
221
|
* the new set of properties to be present on each observation.
|
|
231
|
-
* @param {Function}
|
|
222
|
+
* @param {Function} transform
|
|
232
223
|
* @returns {Object}
|
|
233
224
|
*/
|
|
234
225
|
public deriveReadOnlyObserver<TDest>(
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
226
|
+
transform : (
|
|
227
|
+
observationRef : IReadOnlySharedReference<IPlaybackObservation>,
|
|
228
|
+
cancellationSignal : CancellationSignal
|
|
229
|
+
) => IReadOnlySharedReference<TDest>
|
|
238
230
|
) : IReadOnlyPlaybackObserver<TDest> {
|
|
239
|
-
return generateReadOnlyObserver(this,
|
|
231
|
+
return generateReadOnlyObserver(this, transform, this._canceller.signal);
|
|
240
232
|
}
|
|
241
233
|
|
|
242
234
|
/**
|
|
243
|
-
* Creates the
|
|
235
|
+
* Creates the `IReadOnlySharedReference` that will generate playback
|
|
236
|
+
* observations.
|
|
244
237
|
* @returns {Observable}
|
|
245
238
|
*/
|
|
246
|
-
private
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
239
|
+
private _createSharedReference() : IReadOnlySharedReference<IPlaybackObservation> {
|
|
240
|
+
if (this._observationRef !== undefined) {
|
|
241
|
+
return this._observationRef;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
let lastObservation : IPlaybackObservation | null;
|
|
245
|
+
const { SAMPLING_INTERVAL_MEDIASOURCE,
|
|
246
|
+
SAMPLING_INTERVAL_LOW_LATENCY,
|
|
247
|
+
SAMPLING_INTERVAL_NO_MEDIASOURCE } = config.getCurrent();
|
|
248
|
+
|
|
249
|
+
const getCurrentObservation = (
|
|
250
|
+
event : IPlaybackObserverEventType
|
|
251
|
+
) : IPlaybackObservation => {
|
|
252
|
+
let tmpEvt: IPlaybackObserverEventType = event;
|
|
253
|
+
if (tmpEvt === "seeking" && this._internalSeekingEventsIncomingCounter > 0) {
|
|
254
|
+
tmpEvt = "internal-seeking";
|
|
255
|
+
this._internalSeekingEventsIncomingCounter -= 1;
|
|
256
|
+
}
|
|
257
|
+
const _lastObservation = lastObservation ?? this._generateInitialObservation();
|
|
258
|
+
const mediaTimings = getMediaInfos(this._mediaElement, tmpEvt);
|
|
259
|
+
const internalSeeking = mediaTimings.seeking &&
|
|
260
|
+
// We've just received the event for internally seeking
|
|
261
|
+
(tmpEvt === "internal-seeking" ||
|
|
262
|
+
// or We're still waiting on the previous internal-seek
|
|
263
|
+
(_lastObservation.internalSeeking && tmpEvt !== "seeking"));
|
|
264
|
+
const rebufferingStatus = getRebufferingStatus(
|
|
265
|
+
_lastObservation,
|
|
266
|
+
mediaTimings,
|
|
267
|
+
{ lowLatencyMode: this._lowLatencyMode,
|
|
268
|
+
withMediaSource: this._withMediaSource });
|
|
269
|
+
|
|
270
|
+
const freezingStatus = getFreezingStatus(_lastObservation, mediaTimings);
|
|
271
|
+
const timings = objectAssign(
|
|
272
|
+
{},
|
|
273
|
+
{ rebuffering: rebufferingStatus,
|
|
274
|
+
freezing: freezingStatus,
|
|
275
|
+
internalSeeking },
|
|
276
|
+
mediaTimings);
|
|
277
|
+
if (log.hasLevel("DEBUG")) {
|
|
278
|
+
log.debug("API: current media element state tick",
|
|
279
|
+
"event", timings.event,
|
|
280
|
+
"position", timings.position,
|
|
281
|
+
"seeking", timings.seeking,
|
|
282
|
+
"internalSeeking", timings.internalSeeking,
|
|
283
|
+
"rebuffering", timings.rebuffering !== null,
|
|
284
|
+
"freezing", timings.freezing !== null,
|
|
285
|
+
"ended", timings.ended,
|
|
286
|
+
"paused", timings.paused,
|
|
287
|
+
"playbackRate", timings.playbackRate,
|
|
288
|
+
"readyState", timings.readyState);
|
|
289
|
+
}
|
|
290
|
+
return timings;
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
const returnedSharedReference = createSharedReference(getCurrentObservation("init"));
|
|
294
|
+
|
|
295
|
+
const generateObservationForEvent = (event : IPlaybackObserverEventType) => {
|
|
296
|
+
const newObservation = getCurrentObservation(event);
|
|
297
|
+
if (log.hasLevel("DEBUG")) {
|
|
298
|
+
log.debug("API: current playback timeline:\n" +
|
|
299
|
+
prettyPrintBuffered(newObservation.buffered,
|
|
300
|
+
newObservation.position),
|
|
301
|
+
`\n${event}`);
|
|
302
|
+
}
|
|
303
|
+
lastObservation = newObservation;
|
|
304
|
+
returnedSharedReference.setValue(newObservation);
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
const interval = this._lowLatencyMode ? SAMPLING_INTERVAL_LOW_LATENCY :
|
|
308
|
+
this._withMediaSource ? SAMPLING_INTERVAL_MEDIASOURCE :
|
|
309
|
+
SAMPLING_INTERVAL_NO_MEDIASOURCE;
|
|
310
|
+
let intervalId = setInterval(onInterval, interval);
|
|
311
|
+
const removeEventListeners = SCANNED_MEDIA_ELEMENTS_EVENTS.map((eventName) => {
|
|
312
|
+
this._mediaElement.addEventListener(eventName, onMediaEvent);
|
|
313
|
+
function onMediaEvent() {
|
|
314
|
+
restartInterval();
|
|
315
|
+
generateObservationForEvent(eventName);
|
|
316
|
+
}
|
|
317
|
+
return () => {
|
|
318
|
+
this._mediaElement.removeEventListener(eventName, onMediaEvent);
|
|
296
319
|
};
|
|
320
|
+
});
|
|
297
321
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const interval = this._lowLatencyMode ? SAMPLING_INTERVAL_LOW_LATENCY :
|
|
304
|
-
this._withMediaSource ? SAMPLING_INTERVAL_MEDIASOURCE :
|
|
305
|
-
SAMPLING_INTERVAL_NO_MEDIASOURCE;
|
|
306
|
-
|
|
307
|
-
const interval$ : Observable<"timeupdate"> =
|
|
308
|
-
observableInterval(interval)
|
|
309
|
-
.pipe(map(() => "timeupdate"));
|
|
310
|
-
|
|
311
|
-
return observableMerge(interval$, ...eventObs).pipe(
|
|
312
|
-
map((event : IPlaybackObserverEventType) => {
|
|
313
|
-
const newObservation = getCurrentObservation(event);
|
|
314
|
-
if (log.hasLevel("DEBUG")) {
|
|
315
|
-
log.debug("API: current playback timeline:\n" +
|
|
316
|
-
prettyPrintBuffered(newObservation.buffered,
|
|
317
|
-
newObservation.position),
|
|
318
|
-
`\n${event}`);
|
|
319
|
-
}
|
|
320
|
-
this._lastObservation = newObservation;
|
|
321
|
-
return newObservation;
|
|
322
|
-
}));
|
|
322
|
+
this._canceller.signal.register(() => {
|
|
323
|
+
clearInterval(intervalId);
|
|
324
|
+
removeEventListeners.forEach(cb => cb());
|
|
325
|
+
returnedSharedReference.finish();
|
|
323
326
|
});
|
|
327
|
+
|
|
328
|
+
return returnedSharedReference;
|
|
329
|
+
|
|
330
|
+
function onInterval() {
|
|
331
|
+
generateObservationForEvent("timeupdate");
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function restartInterval() {
|
|
335
|
+
clearInterval(intervalId);
|
|
336
|
+
intervalId = setInterval(onInterval, interval);
|
|
337
|
+
}
|
|
324
338
|
}
|
|
325
339
|
|
|
326
340
|
private _generateInitialObservation() : IPlaybackObservation {
|
|
@@ -472,18 +486,16 @@ export interface IReadOnlyPlaybackObserver<TObservationType> {
|
|
|
472
486
|
*/
|
|
473
487
|
getIsPaused() : boolean;
|
|
474
488
|
/**
|
|
475
|
-
* Returns an
|
|
476
|
-
*
|
|
489
|
+
* Returns an `IReadOnlySharedReference` storing the last playback observation
|
|
490
|
+
* produced by the `IReadOnlyPlaybackObserver` and updated each time a new one
|
|
491
|
+
* is produced.
|
|
477
492
|
*
|
|
478
|
-
*
|
|
479
|
-
*
|
|
480
|
-
* `subscribe` will receive the same events at the same time.
|
|
481
|
-
* This was done for performance and simplicity reasons.
|
|
493
|
+
* This value can then be for example subscribed to to be notified of future
|
|
494
|
+
* playback observations.
|
|
482
495
|
*
|
|
483
|
-
* @
|
|
484
|
-
* @returns {Observable}
|
|
496
|
+
* @returns {Object}
|
|
485
497
|
*/
|
|
486
|
-
|
|
498
|
+
getReference() : IReadOnlySharedReference<TObservationType>;
|
|
487
499
|
/**
|
|
488
500
|
* Register a callback so it regularly receives playback observations.
|
|
489
501
|
* @param {Function} cb
|
|
@@ -498,18 +510,20 @@ export interface IReadOnlyPlaybackObserver<TObservationType> {
|
|
|
498
510
|
cb : (observation : TObservationType) => void,
|
|
499
511
|
options? : { includeLastObservation? : boolean | undefined;
|
|
500
512
|
clearSignal? : CancellationSignal | undefined; }
|
|
501
|
-
) :
|
|
513
|
+
) : void;
|
|
502
514
|
/**
|
|
503
515
|
* Generate a new `IReadOnlyPlaybackObserver` from this one.
|
|
504
516
|
*
|
|
505
517
|
* As argument, this method takes a function which will allow to produce
|
|
506
518
|
* the new set of properties to be present on each observation.
|
|
507
|
-
* @param {Function}
|
|
519
|
+
* @param {Function} transform
|
|
508
520
|
* @returns {Object}
|
|
509
521
|
*/
|
|
510
522
|
deriveReadOnlyObserver<TDest>(
|
|
511
|
-
|
|
512
|
-
|
|
523
|
+
transform : (
|
|
524
|
+
observationRef : IReadOnlySharedReference<TObservationType>,
|
|
525
|
+
cancellationSignal : CancellationSignal
|
|
526
|
+
) => IReadOnlySharedReference<TDest>
|
|
513
527
|
) : IReadOnlyPlaybackObserver<TDest>;
|
|
514
528
|
}
|
|
515
529
|
|
|
@@ -826,16 +840,18 @@ function prettyPrintBuffered(
|
|
|
826
840
|
* Create `IReadOnlyPlaybackObserver` from a source `IReadOnlyPlaybackObserver`
|
|
827
841
|
* and a mapping function.
|
|
828
842
|
* @param {Object} src
|
|
829
|
-
* @param {Function}
|
|
843
|
+
* @param {Function} transform
|
|
830
844
|
* @returns {Object}
|
|
831
845
|
*/
|
|
832
846
|
function generateReadOnlyObserver<TSource, TDest>(
|
|
833
847
|
src : IReadOnlyPlaybackObserver<TSource>,
|
|
834
|
-
|
|
848
|
+
transform : (
|
|
849
|
+
observationRef : IReadOnlySharedReference<TSource>,
|
|
850
|
+
cancellationSignal : CancellationSignal
|
|
851
|
+
) => IReadOnlySharedReference<TDest>,
|
|
852
|
+
cancellationSignal : CancellationSignal
|
|
835
853
|
) : IReadOnlyPlaybackObserver<TDest> {
|
|
836
|
-
const
|
|
837
|
-
mapObservable(src.observe(true))
|
|
838
|
-
).pipe(shareReplay({ bufferSize: 1, refCount: true }));
|
|
854
|
+
const mappedRef = transform(src.getReference(), cancellationSignal);
|
|
839
855
|
return {
|
|
840
856
|
getCurrentTime() {
|
|
841
857
|
return src.getCurrentTime();
|
|
@@ -846,33 +862,29 @@ function generateReadOnlyObserver<TSource, TDest>(
|
|
|
846
862
|
getIsPaused() {
|
|
847
863
|
return src.getIsPaused();
|
|
848
864
|
},
|
|
849
|
-
|
|
850
|
-
return
|
|
851
|
-
newObs.pipe(skip(1));
|
|
865
|
+
getReference() : IReadOnlySharedReference<TDest> {
|
|
866
|
+
return mappedRef;
|
|
852
867
|
},
|
|
853
868
|
listen(
|
|
854
869
|
cb : (observation : TDest) => void,
|
|
855
870
|
options? : { includeLastObservation? : boolean | undefined;
|
|
856
871
|
clearSignal? : CancellationSignal | undefined; }
|
|
857
|
-
) :
|
|
858
|
-
if (options?.clearSignal?.isCancelled === true) {
|
|
859
|
-
return
|
|
872
|
+
) : void {
|
|
873
|
+
if (cancellationSignal.isCancelled || options?.clearSignal?.isCancelled === true) {
|
|
874
|
+
return ;
|
|
860
875
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
sub.unsubscribe();
|
|
866
|
-
}) ?? noop;
|
|
867
|
-
return () => {
|
|
868
|
-
unregister();
|
|
869
|
-
sub.unsubscribe();
|
|
870
|
-
};
|
|
876
|
+
mappedRef.onUpdate(cb, {
|
|
877
|
+
clearSignal: options?.clearSignal,
|
|
878
|
+
emitCurrentValue: options?.includeLastObservation,
|
|
879
|
+
});
|
|
871
880
|
},
|
|
872
881
|
deriveReadOnlyObserver<TNext>(
|
|
873
|
-
|
|
882
|
+
newTransformFn : (
|
|
883
|
+
observationRef : IReadOnlySharedReference<TDest>,
|
|
884
|
+
signal : CancellationSignal
|
|
885
|
+
) => IReadOnlySharedReference<TNext>
|
|
874
886
|
) : IReadOnlyPlaybackObserver<TNext> {
|
|
875
|
-
return generateReadOnlyObserver(this,
|
|
887
|
+
return generateReadOnlyObserver(this, newTransformFn, cancellationSignal);
|
|
876
888
|
},
|
|
877
889
|
};
|
|
878
890
|
}
|
|
@@ -170,7 +170,10 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
170
170
|
/** Current version of the RxPlayer. */
|
|
171
171
|
public readonly version : string;
|
|
172
172
|
|
|
173
|
-
/**
|
|
173
|
+
/**
|
|
174
|
+
* Media element attached to the RxPlayer.
|
|
175
|
+
* Set to `null` when the RxPlayer is disposed.
|
|
176
|
+
*/
|
|
174
177
|
public videoElement : HTMLMediaElement|null; // null on dispose
|
|
175
178
|
|
|
176
179
|
/** Logger the RxPlayer uses. */
|
|
@@ -429,7 +432,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
429
432
|
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1194624
|
|
430
433
|
videoElement.preload = "auto";
|
|
431
434
|
|
|
432
|
-
this.version = /* PLAYER_VERSION */"3.28.0-dev.
|
|
435
|
+
this.version = /* PLAYER_VERSION */"3.28.0-dev.2022062700";
|
|
433
436
|
this.log = log;
|
|
434
437
|
this.state = "STOPPED";
|
|
435
438
|
this.videoElement = videoElement;
|
|
@@ -720,6 +723,10 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
720
723
|
lowLatencyMode,
|
|
721
724
|
});
|
|
722
725
|
|
|
726
|
+
currentContentCanceller.signal.register(() => {
|
|
727
|
+
playbackObserver.stop();
|
|
728
|
+
});
|
|
729
|
+
|
|
723
730
|
/** Emit playback events. */
|
|
724
731
|
let playback$ : Connectable<IInitEvent>;
|
|
725
732
|
|
|
@@ -971,7 +978,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
971
978
|
share());
|
|
972
979
|
|
|
973
980
|
/** Emit when the media element emits a "seeking" event. */
|
|
974
|
-
const observation$ = playbackObserver.
|
|
981
|
+
const observation$ = playbackObserver.getReference().asObservable();
|
|
975
982
|
|
|
976
983
|
const stateChangingEvent$ = observation$.pipe(filter(o => {
|
|
977
984
|
return o.event === "seeking" || o.event === "ended" ||
|
|
@@ -2325,8 +2332,10 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
2325
2332
|
|
|
2326
2333
|
// DRM-related clean-up
|
|
2327
2334
|
const freeUpContentLock = () => {
|
|
2328
|
-
|
|
2329
|
-
|
|
2335
|
+
if (this.videoElement !== null) { // If not disposed
|
|
2336
|
+
log.debug("Unlocking `contentLock`. Next content can begin.");
|
|
2337
|
+
this._priv_contentLock.setValue(false);
|
|
2338
|
+
}
|
|
2330
2339
|
};
|
|
2331
2340
|
|
|
2332
2341
|
if (!isNullOrUndefined(this.videoElement)) {
|
|
@@ -2934,7 +2943,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
2934
2943
|
return activeRepresentations[currentPeriod.id];
|
|
2935
2944
|
}
|
|
2936
2945
|
}
|
|
2937
|
-
Player.version = /* PLAYER_VERSION */"3.28.0-dev.
|
|
2946
|
+
Player.version = /* PLAYER_VERSION */"3.28.0-dev.2022062700";
|
|
2938
2947
|
|
|
2939
2948
|
/** Every events sent by the RxPlayer's public API. */
|
|
2940
2949
|
interface IPublicAPIEvent {
|
|
@@ -73,7 +73,7 @@ export default function ContentTimeBoundariesObserver(
|
|
|
73
73
|
|
|
74
74
|
// trigger warnings when the wanted time is before or after the manifest's
|
|
75
75
|
// segments
|
|
76
|
-
const outOfManifest$ = playbackObserver.
|
|
76
|
+
const outOfManifest$ = playbackObserver.getReference().asObservable().pipe(
|
|
77
77
|
filterMap<IContentTimeObserverPlaybackObservation, IWarningEvent, null>((
|
|
78
78
|
{ position }
|
|
79
79
|
) => {
|