rx-player 3.31.0-dev.2023052200 → 3.31.1-dev.2023062700
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 +11 -3
- package/VERSION +1 -1
- package/dist/_esm5.processed/core/api/public_api.d.ts +32 -0
- package/dist/_esm5.processed/core/api/public_api.js +95 -4
- package/dist/_esm5.processed/core/api/utils.d.ts +10 -0
- package/dist/_esm5.processed/core/api/utils.js +20 -0
- package/dist/_esm5.processed/core/decrypt/session_events_listener.js +7 -1
- package/dist/_esm5.processed/core/init/directfile_content_initializer.d.ts +60 -1
- package/dist/_esm5.processed/core/init/directfile_content_initializer.js +51 -7
- package/dist/_esm5.processed/core/init/media_source_content_initializer.js +1 -1
- package/dist/_esm5.processed/core/init/types.d.ts +9 -1
- package/dist/_esm5.processed/core/init/utils/initialize_content_decryption.js +2 -2
- package/dist/_esm5.processed/core/stream/representation/utils/get_buffer_status.js +2 -1
- package/dist/rx-player.js +1083 -916
- package/dist/rx-player.min.js +1 -1
- package/package.json +31 -31
- package/scripts/build/generate_build.js +1 -1
- package/scripts/fast_demo_build.js +3 -2
- package/sonar-project.properties +1 -1
- package/src/core/api/public_api.ts +110 -4
- package/src/core/api/utils.ts +26 -0
- package/src/core/decrypt/session_events_listener.ts +6 -1
- package/src/core/init/directfile_content_initializer.ts +75 -15
- package/src/core/init/media_source_content_initializer.ts +1 -1
- package/src/core/init/types.ts +9 -1
- package/src/core/init/utils/initialize_content_decryption.ts +2 -2
- package/src/core/stream/representation/utils/get_buffer_status.ts +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## v3.31.
|
|
3
|
+
## v3.31.1-dev.2023062700 (2023-06-27)
|
|
4
|
+
|
|
5
|
+
### Other improvements
|
|
6
|
+
|
|
7
|
+
- Do not load the last text segment if the current position goes after it as it is unnecessary [#1256]
|
|
8
|
+
- Set a better error message for when no `keySystems` option is set when playing an encrypted content
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## v3.31.0 (2023-06-14)
|
|
4
12
|
|
|
5
13
|
### Features
|
|
6
14
|
|
|
15
|
+
- Add `isContentLoaded`, `isBuffering`, `isPaused`, and `getLastStoredContentPosition` methods [#1248]
|
|
16
|
+
- Add `play` and `paused` events [#1253]
|
|
7
17
|
- Add `trackInfo` property to some `MediaError` to expose information on the track that caused the error [#1241]
|
|
8
18
|
|
|
9
19
|
### Bug fixes
|
|
@@ -12,13 +22,11 @@
|
|
|
12
22
|
- Return actual ending duration through the `getVideoDuration` method when playing dynamic contents whose future end is already known [#1235]
|
|
13
23
|
- DASH/WASM: actually reject the `DASH_WASM.initialize`'s Promise if it fails [#1238]
|
|
14
24
|
- On the PlayStation 5, set `Infinity` MediaSource duration for live contents to prevent playback issues [#1250]
|
|
15
|
-
- DASH/WASM: actually reject the DASH_WASM.initialize's Promise if it fails [#1238]
|
|
16
25
|
|
|
17
26
|
### Other improvements
|
|
18
27
|
|
|
19
28
|
- adaptive: Perform various adaptive tweaks to avoid switching too much between qualities in some conditions [#1237]
|
|
20
29
|
- Directfile: Detect "forced" subtitles on Safari when playing directfile contents (such as HLS) [#1239]
|
|
21
|
-
- DRM: Reload when playback is unexpectedly frozen with encrypted but only decipherable data in the buffer [#1236]
|
|
22
30
|
- Improve `"direct"` `audioTrackSwitchingMode` compatibility by re-seeking [#1246]
|
|
23
31
|
- The `DEBUG_ELEMENT` feature now uses the `monospace` fallback font as a default for a better rendering on apple devices
|
|
24
32
|
- doc: externalize documentation-generator code
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.31.
|
|
1
|
+
3.31.1-dev.2023062700
|
|
@@ -105,6 +105,10 @@ declare class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
105
105
|
* It should refer to the last content being played.
|
|
106
106
|
*/
|
|
107
107
|
private _priv_reloadingMetadata;
|
|
108
|
+
/**
|
|
109
|
+
* Store last value of autoPlay, from the last load or reload.
|
|
110
|
+
*/
|
|
111
|
+
private _priv_lastAutoPlay;
|
|
108
112
|
/** All possible Error types emitted by the RxPlayer. */
|
|
109
113
|
static get ErrorTypes(): Record<IErrorType, IErrorType>;
|
|
110
114
|
/** All possible Error codes emitted by the RxPlayer. */
|
|
@@ -217,6 +221,26 @@ declare class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
217
221
|
* @returns {string} - The current Player's state
|
|
218
222
|
*/
|
|
219
223
|
getPlayerState(): string;
|
|
224
|
+
/**
|
|
225
|
+
* Returns true if a content is loaded.
|
|
226
|
+
* @returns {Boolean} - `true` if a content is loaded, `false` otherwise.
|
|
227
|
+
*/
|
|
228
|
+
isContentLoaded(): boolean;
|
|
229
|
+
/**
|
|
230
|
+
* Returns true if the player is buffering.
|
|
231
|
+
* @returns {Boolean} - `true` if the player is buffering, `false` otherwise.
|
|
232
|
+
*/
|
|
233
|
+
isBuffering(): boolean;
|
|
234
|
+
/**
|
|
235
|
+
* Returns the play/pause status of the player :
|
|
236
|
+
* - when `LOADING` or `RELOADING`, returns the scheduled play/pause condition
|
|
237
|
+
* for when loading is over,
|
|
238
|
+
* - in other states, returns the `<video>` element .paused value,
|
|
239
|
+
* - if the player is disposed, returns `true`.
|
|
240
|
+
* @returns {Boolean} - `true` if the player is paused or will be after loading,
|
|
241
|
+
* `false` otherwise.
|
|
242
|
+
*/
|
|
243
|
+
isPaused(): boolean;
|
|
220
244
|
/**
|
|
221
245
|
* Returns true if both:
|
|
222
246
|
* - a content is loaded
|
|
@@ -303,6 +327,12 @@ declare class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
303
327
|
* @returns {Number}
|
|
304
328
|
*/
|
|
305
329
|
getPosition(): number;
|
|
330
|
+
/**
|
|
331
|
+
* Returns the last stored content position, in seconds.
|
|
332
|
+
*
|
|
333
|
+
* @returns {number|undefined}
|
|
334
|
+
*/
|
|
335
|
+
getLastStoredContentPosition(): number | undefined;
|
|
306
336
|
/**
|
|
307
337
|
* Returns the current playback rate at which the video plays.
|
|
308
338
|
* @returns {Number}
|
|
@@ -832,6 +862,8 @@ interface IPublicAPIEvent {
|
|
|
832
862
|
availableTextTracksChange: IAvailableTextTrack[];
|
|
833
863
|
availableVideoTracksChange: IAvailableVideoTrack[];
|
|
834
864
|
decipherabilityUpdate: IDecipherabilityUpdateContent[];
|
|
865
|
+
play: null;
|
|
866
|
+
pause: null;
|
|
835
867
|
seeking: null;
|
|
836
868
|
seeked: null;
|
|
837
869
|
streamEvent: IStreamEvent;
|
|
@@ -51,6 +51,7 @@ import { ErrorCodes, ErrorTypes, formatError, MediaError, } from "../../errors";
|
|
|
51
51
|
import features from "../../features";
|
|
52
52
|
import log from "../../log";
|
|
53
53
|
import areArraysOfNumbersEqual from "../../utils/are_arrays_of_numbers_equal";
|
|
54
|
+
import arrayIncludes from "../../utils/array_includes";
|
|
54
55
|
import assert from "../../utils/assert";
|
|
55
56
|
import EventEmitter from "../../utils/event_emitter";
|
|
56
57
|
import idGenerator from "../../utils/id_generator";
|
|
@@ -65,7 +66,7 @@ import MediaSourceContentInitializer from "../init/media_source_content_initiali
|
|
|
65
66
|
import { checkReloadOptions, parseConstructorOptions, parseLoadVideoOptions, } from "./option_utils";
|
|
66
67
|
import PlaybackObserver from "./playback_observer";
|
|
67
68
|
import TrackChoiceManager from "./tracks_management/track_choice_manager";
|
|
68
|
-
import { constructPlayerStateReference, emitSeekEvents, isLoadedState, } from "./utils";
|
|
69
|
+
import { constructPlayerStateReference, emitPlayPauseEvents, emitSeekEvents, isLoadedState, } from "./utils";
|
|
69
70
|
/* eslint-disable @typescript-eslint/naming-convention */
|
|
70
71
|
var generateContentId = idGenerator();
|
|
71
72
|
var getPageActivityRef = events.getPageActivityRef, getPictureOnPictureStateRef = events.getPictureOnPictureStateRef, getVideoVisibilityRef = events.getVideoVisibilityRef, getVideoWidthRef = events.getVideoWidthRef, onFullscreenChange = events.onFullscreenChange, onTextTrackAdded = events.onTextTrackAdded, onTextTrackRemoved = events.onTextTrackRemoved;
|
|
@@ -89,7 +90,7 @@ var Player = /** @class */ (function (_super) {
|
|
|
89
90
|
// Workaround to support Firefox autoplay on FF 42.
|
|
90
91
|
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1194624
|
|
91
92
|
videoElement.preload = "auto";
|
|
92
|
-
_this.version = /* PLAYER_VERSION */ "3.31.
|
|
93
|
+
_this.version = /* PLAYER_VERSION */ "3.31.1-dev.2023062700";
|
|
93
94
|
_this.log = log;
|
|
94
95
|
_this.state = "STOPPED";
|
|
95
96
|
_this.videoElement = videoElement;
|
|
@@ -172,6 +173,7 @@ var Player = /** @class */ (function (_super) {
|
|
|
172
173
|
_this._priv_preferredTextTracks = preferredTextTracks;
|
|
173
174
|
_this._priv_preferredVideoTracks = preferredVideoTracks;
|
|
174
175
|
_this._priv_reloadingMetadata = {};
|
|
176
|
+
_this._priv_lastAutoPlay = false;
|
|
175
177
|
return _this;
|
|
176
178
|
}
|
|
177
179
|
Object.defineProperty(Player, "ErrorTypes", {
|
|
@@ -269,6 +271,7 @@ var Player = /** @class */ (function (_super) {
|
|
|
269
271
|
log.info("API: Calling loadvideo", options.url, options.transport);
|
|
270
272
|
this._priv_reloadingMetadata = { options: options };
|
|
271
273
|
this._priv_initializeContentPlayback(options);
|
|
274
|
+
this._priv_lastAutoPlay = options.autoPlay;
|
|
272
275
|
};
|
|
273
276
|
/**
|
|
274
277
|
* Reload the last loaded content.
|
|
@@ -432,6 +435,9 @@ var Player = /** @class */ (function (_super) {
|
|
|
432
435
|
this._priv_currentError = null;
|
|
433
436
|
throw new Error("DirectFile feature not activated in your build.");
|
|
434
437
|
}
|
|
438
|
+
else if (isNullOrUndefined(url)) {
|
|
439
|
+
throw new Error("No URL for a DirectFile content");
|
|
440
|
+
}
|
|
435
441
|
mediaElementTrackChoiceManager =
|
|
436
442
|
this._priv_initializeMediaElementTrackChoiceManager(defaultAudioTrack, defaultTextTrack, currentContentCanceller.signal);
|
|
437
443
|
if (currentContentCanceller.isUsed()) {
|
|
@@ -485,11 +491,12 @@ var Player = /** @class */ (function (_super) {
|
|
|
485
491
|
log.warn("API: Sending warning:", formattedError);
|
|
486
492
|
_this.trigger("warning", formattedError);
|
|
487
493
|
});
|
|
488
|
-
initializer.addEventListener("reloadingMediaSource", function () {
|
|
494
|
+
initializer.addEventListener("reloadingMediaSource", function (payload) {
|
|
489
495
|
contentInfos.segmentBuffersStore = null;
|
|
490
496
|
if (contentInfos.trackChoiceManager !== null) {
|
|
491
497
|
contentInfos.trackChoiceManager.resetPeriods();
|
|
492
498
|
}
|
|
499
|
+
_this._priv_lastAutoPlay = payload.autoPlay;
|
|
493
500
|
});
|
|
494
501
|
initializer.addEventListener("inbandEvents", function (inbandEvents) {
|
|
495
502
|
return _this.trigger("inbandEvents", inbandEvents);
|
|
@@ -591,6 +598,48 @@ var Player = /** @class */ (function (_super) {
|
|
|
591
598
|
break;
|
|
592
599
|
}
|
|
593
600
|
};
|
|
601
|
+
/**
|
|
602
|
+
* `TaskCanceller` allowing to stop emitting `"play"` and `"pause"`
|
|
603
|
+
* events.
|
|
604
|
+
* `null` when such events are not emitted currently.
|
|
605
|
+
*/
|
|
606
|
+
var playPauseEventsCanceller = null;
|
|
607
|
+
/**
|
|
608
|
+
* Callback emitting `"play"` and `"pause`" events once the content is
|
|
609
|
+
* loaded, starting from the state indicated in argument.
|
|
610
|
+
* @param {boolean} willAutoPlay - If `false`, we're currently paused.
|
|
611
|
+
*/
|
|
612
|
+
var triggerPlayPauseEventsWhenReady = function (willAutoPlay) {
|
|
613
|
+
if (playPauseEventsCanceller !== null) {
|
|
614
|
+
playPauseEventsCanceller.cancel(); // cancel previous logic
|
|
615
|
+
playPauseEventsCanceller = null;
|
|
616
|
+
}
|
|
617
|
+
playerStateRef.onUpdate(function (val, stopListeningToStateUpdates) {
|
|
618
|
+
if (!isLoadedState(val)) {
|
|
619
|
+
return; // content not loaded yet: no event
|
|
620
|
+
}
|
|
621
|
+
stopListeningToStateUpdates();
|
|
622
|
+
if (playPauseEventsCanceller !== null) {
|
|
623
|
+
playPauseEventsCanceller.cancel();
|
|
624
|
+
}
|
|
625
|
+
playPauseEventsCanceller = new TaskCanceller();
|
|
626
|
+
playPauseEventsCanceller.linkToSignal(currentContentCanceller.signal);
|
|
627
|
+
if (willAutoPlay !== !videoElement.paused) {
|
|
628
|
+
// paused status is not at the expected value on load: emit event
|
|
629
|
+
if (videoElement.paused) {
|
|
630
|
+
_this.trigger("pause", null);
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
_this.trigger("play", null);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
emitPlayPauseEvents(videoElement, function () { return _this.trigger("play", null); }, function () { return _this.trigger("pause", null); }, currentContentCanceller.signal);
|
|
637
|
+
}, { emitCurrentValue: false, clearSignal: currentContentCanceller.signal });
|
|
638
|
+
};
|
|
639
|
+
triggerPlayPauseEventsWhenReady(autoPlay);
|
|
640
|
+
initializer.addEventListener("reloadingMediaSource", function (payload) {
|
|
641
|
+
triggerPlayPauseEventsWhenReady(payload.autoPlay);
|
|
642
|
+
});
|
|
594
643
|
/**
|
|
595
644
|
* `TaskCanceller` allowing to stop emitting `"seeking"` and `"seeked"`
|
|
596
645
|
* events.
|
|
@@ -732,6 +781,40 @@ var Player = /** @class */ (function (_super) {
|
|
|
732
781
|
Player.prototype.getPlayerState = function () {
|
|
733
782
|
return this.state;
|
|
734
783
|
};
|
|
784
|
+
/**
|
|
785
|
+
* Returns true if a content is loaded.
|
|
786
|
+
* @returns {Boolean} - `true` if a content is loaded, `false` otherwise.
|
|
787
|
+
*/
|
|
788
|
+
Player.prototype.isContentLoaded = function () {
|
|
789
|
+
return !arrayIncludes(["LOADING", "RELOADING", "STOPPED"], this.state);
|
|
790
|
+
};
|
|
791
|
+
/**
|
|
792
|
+
* Returns true if the player is buffering.
|
|
793
|
+
* @returns {Boolean} - `true` if the player is buffering, `false` otherwise.
|
|
794
|
+
*/
|
|
795
|
+
Player.prototype.isBuffering = function () {
|
|
796
|
+
return arrayIncludes(["BUFFERING", "SEEKING", "LOADING", "RELOADING"], this.state);
|
|
797
|
+
};
|
|
798
|
+
/**
|
|
799
|
+
* Returns the play/pause status of the player :
|
|
800
|
+
* - when `LOADING` or `RELOADING`, returns the scheduled play/pause condition
|
|
801
|
+
* for when loading is over,
|
|
802
|
+
* - in other states, returns the `<video>` element .paused value,
|
|
803
|
+
* - if the player is disposed, returns `true`.
|
|
804
|
+
* @returns {Boolean} - `true` if the player is paused or will be after loading,
|
|
805
|
+
* `false` otherwise.
|
|
806
|
+
*/
|
|
807
|
+
Player.prototype.isPaused = function () {
|
|
808
|
+
if (this.videoElement) {
|
|
809
|
+
if (arrayIncludes(["LOADING", "RELOADING"], this.state)) {
|
|
810
|
+
return !this._priv_lastAutoPlay;
|
|
811
|
+
}
|
|
812
|
+
else {
|
|
813
|
+
return this.videoElement.paused;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
return true;
|
|
817
|
+
};
|
|
735
818
|
/**
|
|
736
819
|
* Returns true if both:
|
|
737
820
|
* - a content is loaded
|
|
@@ -897,6 +980,14 @@ var Player = /** @class */ (function (_super) {
|
|
|
897
980
|
}
|
|
898
981
|
return this.videoElement.currentTime;
|
|
899
982
|
};
|
|
983
|
+
/**
|
|
984
|
+
* Returns the last stored content position, in seconds.
|
|
985
|
+
*
|
|
986
|
+
* @returns {number|undefined}
|
|
987
|
+
*/
|
|
988
|
+
Player.prototype.getLastStoredContentPosition = function () {
|
|
989
|
+
return this._priv_reloadingMetadata.reloadPosition;
|
|
990
|
+
};
|
|
900
991
|
/**
|
|
901
992
|
* Returns the current playback rate at which the video plays.
|
|
902
993
|
* @returns {Number}
|
|
@@ -2340,5 +2431,5 @@ var Player = /** @class */ (function (_super) {
|
|
|
2340
2431
|
};
|
|
2341
2432
|
return Player;
|
|
2342
2433
|
}(EventEmitter));
|
|
2343
|
-
Player.version = /* PLAYER_VERSION */ "3.31.
|
|
2434
|
+
Player.version = /* PLAYER_VERSION */ "3.31.1-dev.2023062700";
|
|
2344
2435
|
export default Player;
|
|
@@ -30,6 +30,16 @@ import { IPlaybackObservation, IReadOnlyPlaybackObserver } from "./playback_obse
|
|
|
30
30
|
* remove all listeners this function has registered.
|
|
31
31
|
*/
|
|
32
32
|
export declare function emitSeekEvents(mediaElement: HTMLMediaElement | null, playbackObserver: IReadOnlyPlaybackObserver<IPlaybackObservation>, onSeeking: () => void, onSeeked: () => void, cancelSignal: CancellationSignal): void;
|
|
33
|
+
/**
|
|
34
|
+
* @param {HTMLMediaElement} mediaElement
|
|
35
|
+
* @param {function} onPlay - Callback called when a play operation has started
|
|
36
|
+
* on `mediaElement`.
|
|
37
|
+
* @param {function} onPause - Callback called when a pause operation has
|
|
38
|
+
* started on `mediaElement`.
|
|
39
|
+
* @param {Object} cancelSignal - When triggered, stop calling callbacks and
|
|
40
|
+
* remove all listeners this function has registered.
|
|
41
|
+
*/
|
|
42
|
+
export declare function emitPlayPauseEvents(mediaElement: HTMLMediaElement | null, onPlay: () => void, onPause: () => void, cancelSignal: CancellationSignal): void;
|
|
33
43
|
/** Player state dictionnary. */
|
|
34
44
|
export declare const enum PLAYER_STATES {
|
|
35
45
|
STOPPED = "STOPPED",
|
|
@@ -49,6 +49,26 @@ export function emitSeekEvents(mediaElement, playbackObserver, onSeeking, onSeek
|
|
|
49
49
|
}
|
|
50
50
|
}, { includeLastObservation: true, clearSignal: cancelSignal });
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* @param {HTMLMediaElement} mediaElement
|
|
54
|
+
* @param {function} onPlay - Callback called when a play operation has started
|
|
55
|
+
* on `mediaElement`.
|
|
56
|
+
* @param {function} onPause - Callback called when a pause operation has
|
|
57
|
+
* started on `mediaElement`.
|
|
58
|
+
* @param {Object} cancelSignal - When triggered, stop calling callbacks and
|
|
59
|
+
* remove all listeners this function has registered.
|
|
60
|
+
*/
|
|
61
|
+
export function emitPlayPauseEvents(mediaElement, onPlay, onPause, cancelSignal) {
|
|
62
|
+
if (cancelSignal.isCancelled() || mediaElement === null) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
mediaElement.addEventListener("play", onPlay);
|
|
66
|
+
mediaElement.addEventListener("pause", onPause);
|
|
67
|
+
cancelSignal.register(function () {
|
|
68
|
+
mediaElement.removeEventListener("play", onPlay);
|
|
69
|
+
mediaElement.removeEventListener("pause", onPause);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
52
72
|
export function constructPlayerStateReference(initializer, mediaElement, playbackObserver, cancelSignal) {
|
|
53
73
|
var playerStateRef = createSharedReference("LOADING" /* PLAYER_STATES.LOADING */, cancelSignal);
|
|
54
74
|
initializer.addEventListener("loaded", function () {
|
|
@@ -130,7 +130,13 @@ export default function SessionEventsListener(session, keySystemOptions, keySyst
|
|
|
130
130
|
log.info("DRM: No license given, skipping session.update");
|
|
131
131
|
}
|
|
132
132
|
else {
|
|
133
|
-
|
|
133
|
+
try {
|
|
134
|
+
return updateSessionWithMessage(session, licenseObject);
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
manualCanceller.cancel();
|
|
138
|
+
callbacks.onError(err);
|
|
139
|
+
}
|
|
134
140
|
}
|
|
135
141
|
})
|
|
136
142
|
.catch(function (err) {
|
|
@@ -18,21 +18,80 @@ import { IReadOnlySharedReference } from "../../utils/reference";
|
|
|
18
18
|
import { PlaybackObserver } from "../api";
|
|
19
19
|
import { ContentInitializer } from "./types";
|
|
20
20
|
import { IInitialTimeOptions } from "./utils/get_initial_time";
|
|
21
|
+
/**
|
|
22
|
+
* `ContentIntializer` which will load contents by putting their URL in the
|
|
23
|
+
* `src` attribute of the given HTMLMediaElement.
|
|
24
|
+
*
|
|
25
|
+
* Because such contents are mainly loaded by the browser, those (called
|
|
26
|
+
* "directfile" contents in the RxPlayer) needs a simpler logic in-JS when
|
|
27
|
+
* compared to a content that relies on the MSE API.
|
|
28
|
+
*
|
|
29
|
+
* @class DirectFileContentInitializer
|
|
30
|
+
*/
|
|
21
31
|
export default class DirectFileContentInitializer extends ContentInitializer {
|
|
32
|
+
/**
|
|
33
|
+
* Initial options given to the `DirectFileContentInitializer`.
|
|
34
|
+
*/
|
|
22
35
|
private _settings;
|
|
36
|
+
/**
|
|
37
|
+
* Allows to abort and clean everything the `DirectFileContentInitializer` is
|
|
38
|
+
* doing.
|
|
39
|
+
*/
|
|
23
40
|
private _initCanceller;
|
|
41
|
+
/**
|
|
42
|
+
* Creates a new `DirectFileContentInitializer` linked to the given settings.
|
|
43
|
+
* @param {Object} settings
|
|
44
|
+
*/
|
|
24
45
|
constructor(settings: IDirectFileOptions);
|
|
46
|
+
/**
|
|
47
|
+
* "Prepare" content so it can later be played by calling `start`.
|
|
48
|
+
*/
|
|
25
49
|
prepare(): void;
|
|
50
|
+
/**
|
|
51
|
+
* Start playback of the content linked to this `DirectFileContentInitializer`
|
|
52
|
+
* on the given `HTMLMediaElement` and its associated `PlaybackObserver`.
|
|
53
|
+
* @param {HTMLMediaElement} mediaElement - HTMLMediaElement on which the
|
|
54
|
+
* content will be played.
|
|
55
|
+
* @param {Object} playbackObserver - Object regularly emitting playback
|
|
56
|
+
* information.
|
|
57
|
+
*/
|
|
26
58
|
start(mediaElement: HTMLMediaElement, playbackObserver: PlaybackObserver): void;
|
|
59
|
+
/**
|
|
60
|
+
* Update URL this `ContentIntializer` depends on.
|
|
61
|
+
* @param {Array.<string>|undefined} _urls
|
|
62
|
+
* @param {boolean} _refreshNow
|
|
63
|
+
*/
|
|
27
64
|
updateContentUrls(_urls: string[] | undefined, _refreshNow: boolean): void;
|
|
65
|
+
/**
|
|
66
|
+
* Stop content and free all resources linked to this `ContentIntializer`.
|
|
67
|
+
*/
|
|
28
68
|
dispose(): void;
|
|
69
|
+
/**
|
|
70
|
+
* Logic performed when a fatal error was triggered.
|
|
71
|
+
* @param {*} err - The fatal error in question.
|
|
72
|
+
*/
|
|
29
73
|
private _onFatalError;
|
|
74
|
+
/**
|
|
75
|
+
* Perform the initial seek (to begin playback at an initially-calculated
|
|
76
|
+
* position based on settings) and auto-play if needed when loaded.
|
|
77
|
+
* @param {HTMLMediaElement} mediaElement
|
|
78
|
+
* @param {Object} playbackObserver
|
|
79
|
+
*/
|
|
30
80
|
private _seekAndPlay;
|
|
31
81
|
}
|
|
82
|
+
/** Options used by the `DirectFileContentInitializer` */
|
|
32
83
|
export interface IDirectFileOptions {
|
|
84
|
+
/** If `true` we will play right after the content is considered "loaded". */
|
|
33
85
|
autoPlay: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Encryption-related settings. Can be left as an empty array if the content
|
|
88
|
+
* isn't encrypted.
|
|
89
|
+
*/
|
|
34
90
|
keySystems: IKeySystemOption[];
|
|
91
|
+
/** Communicate the playback rate wanted by the user. */
|
|
35
92
|
speed: IReadOnlySharedReference<number>;
|
|
93
|
+
/** Optional initial position to start at. */
|
|
36
94
|
startAt?: IInitialTimeOptions | undefined;
|
|
37
|
-
|
|
95
|
+
/** URL that should be played. */
|
|
96
|
+
url: string;
|
|
38
97
|
}
|
|
@@ -34,6 +34,7 @@ var __extends = (this && this.__extends) || (function () {
|
|
|
34
34
|
*/
|
|
35
35
|
import { clearElementSrc } from "../../compat";
|
|
36
36
|
import log from "../../log";
|
|
37
|
+
import assert from "../../utils/assert";
|
|
37
38
|
import createSharedReference from "../../utils/reference";
|
|
38
39
|
import TaskCanceller from "../../utils/task_canceller";
|
|
39
40
|
import { ContentInitializer } from "./types";
|
|
@@ -42,25 +43,51 @@ import performInitialSeekAndPlay from "./utils/initial_seek_and_play";
|
|
|
42
43
|
import initializeContentDecryption from "./utils/initialize_content_decryption";
|
|
43
44
|
import RebufferingController from "./utils/rebuffering_controller";
|
|
44
45
|
import listenToMediaError from "./utils/throw_on_media_error";
|
|
46
|
+
/**
|
|
47
|
+
* `ContentIntializer` which will load contents by putting their URL in the
|
|
48
|
+
* `src` attribute of the given HTMLMediaElement.
|
|
49
|
+
*
|
|
50
|
+
* Because such contents are mainly loaded by the browser, those (called
|
|
51
|
+
* "directfile" contents in the RxPlayer) needs a simpler logic in-JS when
|
|
52
|
+
* compared to a content that relies on the MSE API.
|
|
53
|
+
*
|
|
54
|
+
* @class DirectFileContentInitializer
|
|
55
|
+
*/
|
|
45
56
|
var DirectFileContentInitializer = /** @class */ (function (_super) {
|
|
46
57
|
__extends(DirectFileContentInitializer, _super);
|
|
58
|
+
/**
|
|
59
|
+
* Creates a new `DirectFileContentInitializer` linked to the given settings.
|
|
60
|
+
* @param {Object} settings
|
|
61
|
+
*/
|
|
47
62
|
function DirectFileContentInitializer(settings) {
|
|
48
63
|
var _this = _super.call(this) || this;
|
|
49
64
|
_this._settings = settings;
|
|
50
65
|
_this._initCanceller = new TaskCanceller();
|
|
51
66
|
return _this;
|
|
52
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* "Prepare" content so it can later be played by calling `start`.
|
|
70
|
+
*/
|
|
53
71
|
DirectFileContentInitializer.prototype.prepare = function () {
|
|
54
72
|
return; // Directfile contents do not have any preparation
|
|
55
73
|
};
|
|
74
|
+
/**
|
|
75
|
+
* Start playback of the content linked to this `DirectFileContentInitializer`
|
|
76
|
+
* on the given `HTMLMediaElement` and its associated `PlaybackObserver`.
|
|
77
|
+
* @param {HTMLMediaElement} mediaElement - HTMLMediaElement on which the
|
|
78
|
+
* content will be played.
|
|
79
|
+
* @param {Object} playbackObserver - Object regularly emitting playback
|
|
80
|
+
* information.
|
|
81
|
+
*/
|
|
56
82
|
DirectFileContentInitializer.prototype.start = function (mediaElement, playbackObserver) {
|
|
57
83
|
var _this = this;
|
|
58
84
|
var cancelSignal = this._initCanceller.signal;
|
|
59
85
|
var _a = this._settings, keySystems = _a.keySystems, speed = _a.speed, url = _a.url;
|
|
60
86
|
clearElementSrc(mediaElement);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Create dummy encryption data emitter, as those are not sent from the
|
|
89
|
+
* RxPlayer for directfile contents.
|
|
90
|
+
*/
|
|
64
91
|
var decryptionRef = createSharedReference(null);
|
|
65
92
|
decryptionRef.finish();
|
|
66
93
|
var drmInitRef = initializeContentDecryption(mediaElement, keySystems, decryptionRef, {
|
|
@@ -89,7 +116,7 @@ var DirectFileContentInitializer = /** @class */ (function (_super) {
|
|
|
89
116
|
rebufferingController.start();
|
|
90
117
|
drmInitRef.onUpdate(function (evt, stopListeningToDrmUpdates) {
|
|
91
118
|
if (evt.initializationState.type === "uninitialized") {
|
|
92
|
-
return;
|
|
119
|
+
return; // nothing done yet
|
|
93
120
|
}
|
|
94
121
|
stopListeningToDrmUpdates();
|
|
95
122
|
// Start everything! (Just put the URL in the element's src).
|
|
@@ -104,26 +131,43 @@ var DirectFileContentInitializer = /** @class */ (function (_super) {
|
|
|
104
131
|
if (newDrmStatus.initializationState.type === "initialized") {
|
|
105
132
|
stopListeningToDrmUpdatesAgain();
|
|
106
133
|
_this._seekAndPlay(mediaElement, playbackObserver);
|
|
107
|
-
return;
|
|
108
134
|
}
|
|
109
135
|
}, { emitCurrentValue: true, clearSignal: cancelSignal });
|
|
110
136
|
}
|
|
111
137
|
else {
|
|
138
|
+
assert(evt.initializationState.type === "initialized");
|
|
112
139
|
_this._seekAndPlay(mediaElement, playbackObserver);
|
|
113
|
-
return;
|
|
114
140
|
}
|
|
115
141
|
}, { emitCurrentValue: true, clearSignal: cancelSignal });
|
|
116
142
|
};
|
|
143
|
+
/**
|
|
144
|
+
* Update URL this `ContentIntializer` depends on.
|
|
145
|
+
* @param {Array.<string>|undefined} _urls
|
|
146
|
+
* @param {boolean} _refreshNow
|
|
147
|
+
*/
|
|
117
148
|
DirectFileContentInitializer.prototype.updateContentUrls = function (_urls, _refreshNow) {
|
|
118
149
|
throw new Error("Cannot update content URL of directfile contents");
|
|
119
150
|
};
|
|
151
|
+
/**
|
|
152
|
+
* Stop content and free all resources linked to this `ContentIntializer`.
|
|
153
|
+
*/
|
|
120
154
|
DirectFileContentInitializer.prototype.dispose = function () {
|
|
121
155
|
this._initCanceller.cancel();
|
|
122
156
|
};
|
|
157
|
+
/**
|
|
158
|
+
* Logic performed when a fatal error was triggered.
|
|
159
|
+
* @param {*} err - The fatal error in question.
|
|
160
|
+
*/
|
|
123
161
|
DirectFileContentInitializer.prototype._onFatalError = function (err) {
|
|
124
162
|
this._initCanceller.cancel();
|
|
125
163
|
this.trigger("error", err);
|
|
126
164
|
};
|
|
165
|
+
/**
|
|
166
|
+
* Perform the initial seek (to begin playback at an initially-calculated
|
|
167
|
+
* position based on settings) and auto-play if needed when loaded.
|
|
168
|
+
* @param {HTMLMediaElement} mediaElement
|
|
169
|
+
* @param {Object} playbackObserver
|
|
170
|
+
*/
|
|
127
171
|
DirectFileContentInitializer.prototype._seekAndPlay = function (mediaElement, playbackObserver) {
|
|
128
172
|
var _this = this;
|
|
129
173
|
var cancelSignal = this._initCanceller.signal;
|
|
@@ -156,7 +200,7 @@ export default DirectFileContentInitializer;
|
|
|
156
200
|
/**
|
|
157
201
|
* calculate initial time as a position in seconds.
|
|
158
202
|
* @param {HTMLMediaElement} mediaElement
|
|
159
|
-
* @param {Object|undefined} startAt
|
|
203
|
+
* @param {Object|undefined} [startAt]
|
|
160
204
|
* @returns {number}
|
|
161
205
|
*/
|
|
162
206
|
function getDirectFileInitialTime(mediaElement, startAt) {
|
|
@@ -249,7 +249,7 @@ var MediaSourceContentInitializer = /** @class */ (function (_super) {
|
|
|
249
249
|
if (initCanceller.isUsed()) {
|
|
250
250
|
return;
|
|
251
251
|
}
|
|
252
|
-
triggerEvent("reloadingMediaSource",
|
|
252
|
+
triggerEvent("reloadingMediaSource", reloadOrder);
|
|
253
253
|
if (initCanceller.isUsed()) {
|
|
254
254
|
return;
|
|
255
255
|
}
|
|
@@ -95,7 +95,15 @@ export interface IContentInitializerEvents {
|
|
|
95
95
|
* Event sent when we're starting attach a new MediaSource to the media element
|
|
96
96
|
* (after removing the previous one).
|
|
97
97
|
*/
|
|
98
|
-
reloadingMediaSource:
|
|
98
|
+
reloadingMediaSource: {
|
|
99
|
+
/** The position we're reloading at, in seconds. */
|
|
100
|
+
position: number;
|
|
101
|
+
/**
|
|
102
|
+
* If `true`, we'll play directly after finishing the reloading operation.
|
|
103
|
+
* If `false`, we'll be paused after it.
|
|
104
|
+
*/
|
|
105
|
+
autoPlay: boolean;
|
|
106
|
+
};
|
|
99
107
|
/** Event sent after the player stalled. */
|
|
100
108
|
stalled: IStallingSituation;
|
|
101
109
|
/** Event sent when the player goes out of a stalling situation. */
|
|
@@ -34,8 +34,8 @@ export default function initializeContentDecryption(mediaElement, keySystems, pr
|
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
36
|
stopListening();
|
|
37
|
-
log.error("Init: Encrypted event but
|
|
38
|
-
var err = new EncryptedMediaError("MEDIA_IS_ENCRYPTED_ERROR", "
|
|
37
|
+
log.error("Init: Encrypted event but no `keySystems` given");
|
|
38
|
+
var err = new EncryptedMediaError("MEDIA_IS_ENCRYPTED_ERROR", "no `keySystems` given.");
|
|
39
39
|
callbacks.onError(err);
|
|
40
40
|
}, { clearSignal: cancelSignal });
|
|
41
41
|
var ref = createSharedReference({
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import config from "../../../../config";
|
|
17
17
|
import isNullOrUndefined from "../../../../utils/is_null_or_undefined";
|
|
18
|
-
import { SegmentBufferOperation, } from "../../../segment_buffers";
|
|
18
|
+
import SegmentBuffersStore, { SegmentBufferOperation, } from "../../../segment_buffers";
|
|
19
19
|
import checkForDiscontinuity from "./check_for_discontinuity";
|
|
20
20
|
import getNeededSegments from "./get_needed_segments";
|
|
21
21
|
import getSegmentPriority from "./get_segment_priority";
|
|
@@ -116,6 +116,7 @@ function getRangeOfNeededSegments(content, initialWantedTime, bufferGoal) {
|
|
|
116
116
|
// avoid ending the last Period - and by extension the content - with a
|
|
117
117
|
// segment which isn't the last one.
|
|
118
118
|
if (!isNullOrUndefined(lastIndexPosition) &&
|
|
119
|
+
SegmentBuffersStore.isNative(content.adaptation.type) &&
|
|
119
120
|
initialWantedTime >= lastIndexPosition &&
|
|
120
121
|
representationIndex.isInitialized() &&
|
|
121
122
|
representationIndex.isFinished() &&
|