rx-player 3.33.0-dev.2023120600 → 3.33.0
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 +12 -3
- package/README.md +2 -33
- package/VERSION +1 -1
- package/dist/_esm5.processed/compat/browser_detection.d.ts +3 -1
- package/dist/_esm5.processed/compat/browser_detection.js +24 -4
- package/dist/_esm5.processed/compat/should_prevent_seeking_at_0_initially.d.ts +14 -0
- package/dist/_esm5.processed/compat/should_prevent_seeking_at_0_initially.js +17 -0
- package/dist/_esm5.processed/config.d.ts +1 -0
- package/dist/_esm5.processed/core/api/public_api.js +3 -3
- package/dist/_esm5.processed/core/decrypt/attach_media_keys.d.ts +2 -1
- package/dist/_esm5.processed/core/decrypt/attach_media_keys.js +2 -1
- package/dist/_esm5.processed/core/decrypt/init_media_keys.js +13 -5
- package/dist/_esm5.processed/core/init/directfile_content_initializer.js +1 -1
- package/dist/_esm5.processed/core/init/media_source_content_initializer.js +1 -1
- package/dist/_esm5.processed/core/init/utils/get_loaded_reference.js +7 -5
- package/dist/_esm5.processed/core/init/utils/initial_seek_and_play.d.ts +2 -1
- package/dist/_esm5.processed/core/init/utils/initial_seek_and_play.js +59 -6
- package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.js +9 -2
- package/dist/_esm5.processed/core/segment_buffers/implementations/image/image_segment_buffer.js +1 -1
- package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.js +1 -1
- package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.js +1 -1
- package/dist/_esm5.processed/core/segment_buffers/implementations/types.d.ts +6 -1
- package/dist/_esm5.processed/core/segment_buffers/implementations/types.js +7 -2
- package/dist/_esm5.processed/core/segment_buffers/index.d.ts +2 -2
- package/dist/_esm5.processed/core/segment_buffers/inventory/index.d.ts +2 -2
- package/dist/_esm5.processed/core/segment_buffers/inventory/segment_inventory.d.ts +31 -9
- package/dist/_esm5.processed/core/segment_buffers/inventory/segment_inventory.js +27 -12
- package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +16 -11
- package/dist/_esm5.processed/core/stream/representation/utils/get_buffer_status.js +3 -2
- package/dist/_esm5.processed/default_config.d.ts +7 -0
- package/dist/_esm5.processed/default_config.js +16 -0
- package/dist/_esm5.processed/manifest/manifest.js +8 -4
- package/dist/_esm5.processed/manifest/period.d.ts +3 -1
- package/dist/_esm5.processed/manifest/period.js +16 -3
- package/dist/mpd-parser.wasm +0 -0
- package/dist/rx-player.d.ts +1 -1
- package/dist/rx-player.js +262 -77
- package/dist/rx-player.min.d.ts +1 -1
- package/dist/rx-player.min.js +1 -1
- package/package.json +5 -1
- package/scripts/canal-release.patch +24 -28
- package/scripts/make-dev-releases +90 -0
- package/scripts/update-version +5 -0
- package/sonar-project.properties +1 -1
- package/src/compat/browser_detection.ts +21 -1
- package/src/compat/should_prevent_seeking_at_0_initially.ts +19 -0
- package/src/core/api/public_api.ts +3 -3
- package/src/core/decrypt/attach_media_keys.ts +5 -2
- package/src/core/decrypt/init_media_keys.ts +10 -1
- package/src/core/init/directfile_content_initializer.ts +1 -0
- package/src/core/init/media_source_content_initializer.ts +1 -0
- package/src/core/init/utils/get_loaded_reference.ts +7 -5
- package/src/core/init/utils/initial_seek_and_play.ts +59 -5
- package/src/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.ts +10 -2
- package/src/core/segment_buffers/implementations/image/image_segment_buffer.ts +1 -1
- package/src/core/segment_buffers/implementations/text/html/html_text_segment_buffer.ts +1 -1
- package/src/core/segment_buffers/implementations/text/native/native_text_segment_buffer.ts +1 -1
- package/src/core/segment_buffers/implementations/types.ts +7 -2
- package/src/core/segment_buffers/index.ts +2 -0
- package/src/core/segment_buffers/inventory/index.ts +2 -0
- package/src/core/segment_buffers/inventory/segment_inventory.ts +56 -19
- package/src/core/stream/orchestrator/stream_orchestrator.ts +19 -15
- package/src/core/stream/representation/utils/get_buffer_status.ts +4 -2
- package/src/default_config.ts +17 -0
- package/src/manifest/manifest.ts +8 -4
- package/src/manifest/period.ts +16 -3
- package/scripts/make-releases +0 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## v3.33.0
|
|
3
|
+
## v3.33.0 (2024-01-24)
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
6
|
|
|
@@ -8,11 +8,16 @@
|
|
|
8
8
|
- Add `startAt.fromLivePosition` `loadVideo` option [#1300]
|
|
9
9
|
- Add the possibility to set a new `keySystems` option on the `reload` API [#1308]
|
|
10
10
|
|
|
11
|
-
### Bug
|
|
11
|
+
### Bug fixes
|
|
12
12
|
|
|
13
13
|
- Fix subtitles "blinking" in some specific conditions, especially with some DASH low-latency contents [#1314]
|
|
14
14
|
- DASH: Fix Period overlap resolution logic for when the first Period is removed [#1311]
|
|
15
|
-
- Fix
|
|
15
|
+
- TTML: Fix handling of the `tts:lineHeight` attribute [#1320]
|
|
16
|
+
- Fix import of the `LOCAL_MANIFEST` experimental feature
|
|
17
|
+
- Avoid very rarely skipping segments which initially were too big to be pushed due to memory limitations [#1323]
|
|
18
|
+
- Fix issue arising when using track APIs at the exact last possible position of a Period with no consecutive Period [#1337]
|
|
19
|
+
- Starting at the end (through a `startAt` `loadVideo` option) or reloading at the end led to the restart of the content [#1338]
|
|
20
|
+
- DRM/Safari: also perform Safari DRM work-arounds when the page is launched from the dock [#1351, #1356]
|
|
16
21
|
|
|
17
22
|
### Other improvements
|
|
18
23
|
|
|
@@ -21,6 +26,10 @@
|
|
|
21
26
|
- DEBUG_ELEMENT: Add unsupported and undecipherable bitrates to the debug element [#1321]
|
|
22
27
|
- DEBUG_ELEMENT: update buffer graph maximum size so it becomes more readable for lengthy contents [#1316]
|
|
23
28
|
- DEBUG_ELEMENT: always synchronize inventory of segments before rendering it [#1317]
|
|
29
|
+
- Remove remaining RxPlayer dependency removing possibility of some application-side bundling errors [#1312]
|
|
30
|
+
- Add exception to text Garbage collection logic to avoid unnecessarily reload text segments frequently [#1325]
|
|
31
|
+
- Avoid logging too much the buffer's content when our debugging UI or the demo is used [#1341]
|
|
32
|
+
- Demo: Fix reporting of live position in demo page [#1313]
|
|
24
33
|
|
|
25
34
|
|
|
26
35
|
## v3.32.1 (2023-10-19)
|
package/README.md
CHANGED
|
@@ -179,21 +179,11 @@ Demo pages for our previous versions are also available
|
|
|
179
179
|
|
|
180
180
|
|
|
181
181
|
|
|
182
|
-
## Your questions ##############################################################
|
|
183
|
-
|
|
184
|
-
You can ask directly your questions about the project on [our
|
|
185
|
-
gitter](https://gitter.im/canalplus/rx-player).
|
|
186
|
-
We will try our best to answer them as quickly as possible.
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
182
|
## Contribute ##################################################################
|
|
191
183
|
|
|
192
184
|
Details on how to contribute is written in the [CONTRIBUTING.md
|
|
193
185
|
file](./CONTRIBUTING.md) at the root of this repository.
|
|
194
186
|
|
|
195
|
-
If you need more information, you can contact us via our [gitter
|
|
196
|
-
room](https://gitter.im/canalplus/rx-player).
|
|
197
187
|
|
|
198
188
|
|
|
199
189
|
### Dependencies ###############################################################
|
|
@@ -238,7 +228,7 @@ Canal+ Group is a media company with many advanced needs when it comes to media
|
|
|
238
228
|
playback: it provides both live and VoD stream with multiple encryption
|
|
239
229
|
requirements, supports a very large panel of devices and has many other
|
|
240
230
|
specificities (like adult content restrictions, ad-insertion, Peer-To-Peer
|
|
241
|
-
integration...).
|
|
231
|
+
integration, low-latency live streaming...).
|
|
242
232
|
|
|
243
233
|
When the time came to switch from a plugin-based web player approach to an HTML5
|
|
244
234
|
one back in 2015, no media player had the key features we wanted, and including
|
|
@@ -249,7 +239,7 @@ The R&D department of Canal+ Group thus started to work on a new featureful
|
|
|
249
239
|
media-player: the RxPlayer. To both help and profit from the community, it also
|
|
250
240
|
decided to share it to everyone under a permissive open-source licence.
|
|
251
241
|
|
|
252
|
-
Now, more than
|
|
242
|
+
Now, more than 8 years later, the RxPlayer continues to evolve at the same fast
|
|
253
243
|
pace to include a lot of features and improvements you may not find in other
|
|
254
244
|
media players.
|
|
255
245
|
You can look at our
|
|
@@ -296,24 +286,3 @@ them. Amongst those:
|
|
|
296
286
|
risks always low.
|
|
297
287
|
|
|
298
288
|
\* In "directfile" mode, on compatible browsers
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
## Target support ##############################################################
|
|
302
|
-
|
|
303
|
-
Here is a basic list of supported platforms:
|
|
304
|
-
|
|
305
|
-
| | Chrome | IE [1] | Edge | Firefox | Safari | Opera |
|
|
306
|
-
|-------------|:-------:|:-------:|:------:|:---------:|:--------:|:-------:|
|
|
307
|
-
| Windows | >= 30 | >= 11 | >= 12 | >= 42 | >= 8 | >= 25 |
|
|
308
|
-
| OSX | >= 30 | - | - | >= 42 | >= 8 | >= 25 |
|
|
309
|
-
| Linux | >= 37 | - | - | >= 42 | - | >= 25 |
|
|
310
|
-
| Android [2] | >= 30 | - | - | >= 42 | - | >= 15 |
|
|
311
|
-
| iOS | No | - | - | No | No | No |
|
|
312
|
-
|
|
313
|
-
[1] Only on Windows >= 8.
|
|
314
|
-
|
|
315
|
-
[2] Android version >= 4.2
|
|
316
|
-
|
|
317
|
-
And more. A good way to know if the browser should be supported by our player is
|
|
318
|
-
to go on the page https://www.youtube.com/html5 and check for "Media Source
|
|
319
|
-
Extensions" support.
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.33.0
|
|
1
|
+
3.33.0
|
|
@@ -39,4 +39,6 @@ declare let isWebOs2022: boolean;
|
|
|
39
39
|
declare let isPanasonic: boolean;
|
|
40
40
|
/** `true` for the PlayStation 5 game console. */
|
|
41
41
|
declare let isPlayStation5: boolean;
|
|
42
|
-
|
|
42
|
+
/** `true` for the Xbox game consoles. */
|
|
43
|
+
declare let isXbox: boolean;
|
|
44
|
+
export { isEdgeChromium, isIE11, isIEOrEdge, isFirefox, isPanasonic, isPlayStation5, isXbox, isSafariDesktop, isSafariMobile, isSamsungBrowser, isTizen, isWebOs, isWebOs2021, isWebOs2022, };
|
|
@@ -40,8 +40,10 @@ var isWebOs2022 = false;
|
|
|
40
40
|
var isPanasonic = false;
|
|
41
41
|
/** `true` for the PlayStation 5 game console. */
|
|
42
42
|
var isPlayStation5 = false;
|
|
43
|
+
/** `true` for the Xbox game consoles. */
|
|
44
|
+
var isXbox = false;
|
|
43
45
|
((function findCurrentBrowser() {
|
|
44
|
-
var _a, _b;
|
|
46
|
+
var _a, _b, _c;
|
|
45
47
|
if (isNode) {
|
|
46
48
|
return;
|
|
47
49
|
}
|
|
@@ -66,9 +68,24 @@ var isPlayStation5 = false;
|
|
|
66
68
|
/iPad|iPhone|iPod/.test(navigator.platform)) {
|
|
67
69
|
isSafariMobile = true;
|
|
68
70
|
}
|
|
69
|
-
else if (
|
|
71
|
+
else if (
|
|
72
|
+
// the following statement check if the window.safari contains the method
|
|
73
|
+
// "pushNotification", this condition is not met when using web app from the dock
|
|
74
|
+
// on macOS, this is why we also check userAgent.
|
|
75
|
+
Object.prototype.toString.call(window.HTMLElement).indexOf("Constructor") >= 0 ||
|
|
70
76
|
((_b = (_a = window.safari) === null || _a === void 0 ? void 0 : _a.pushNotification) === null || _b === void 0 ? void 0 : _b.toString()) ===
|
|
71
|
-
"[object SafariRemoteNotification]"
|
|
77
|
+
"[object SafariRemoteNotification]" ||
|
|
78
|
+
// browsers are lying: Chrome reports both as Chrome and Safari in user
|
|
79
|
+
// agent string, So to detect Safari we have to check for the Safari string
|
|
80
|
+
// and the absence of the Chrome string
|
|
81
|
+
// eslint-disable-next-line max-len
|
|
82
|
+
// @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent#which_part_of_the_user_agent_contains_the_information_you_are_looking_for
|
|
83
|
+
((/Safari\/(\d+)/).test(navigator.userAgent) &&
|
|
84
|
+
// Safari should contain Version/ in userAgent
|
|
85
|
+
(/Version\/(\d+)/).test(navigator.userAgent) &&
|
|
86
|
+
(((_c = navigator.vendor) === null || _c === void 0 ? void 0 : _c.indexOf("Apple")) !== -1) &&
|
|
87
|
+
!(/Chrome\/(\d+)/).test(navigator.userAgent) &&
|
|
88
|
+
!(/Chromium\/(\d+)/).test(navigator.userAgent))) {
|
|
72
89
|
isSafariDesktop = true;
|
|
73
90
|
}
|
|
74
91
|
// 2 - Find out specific device/platform information
|
|
@@ -99,5 +116,8 @@ var isPlayStation5 = false;
|
|
|
99
116
|
else if (/[Pp]anasonic/.test(navigator.userAgent)) {
|
|
100
117
|
isPanasonic = true;
|
|
101
118
|
}
|
|
119
|
+
else if (navigator.userAgent.indexOf("Xbox") !== -1) {
|
|
120
|
+
isXbox = true;
|
|
121
|
+
}
|
|
102
122
|
})());
|
|
103
|
-
export { isEdgeChromium, isIE11, isIEOrEdge, isFirefox, isPanasonic, isPlayStation5, isSafariDesktop, isSafariMobile, isSamsungBrowser, isTizen, isWebOs, isWebOs2021, isWebOs2022, };
|
|
123
|
+
export { isEdgeChromium, isIE11, isIEOrEdge, isFirefox, isPanasonic, isPlayStation5, isXbox, isSafariDesktop, isSafariMobile, isSamsungBrowser, isTizen, isWebOs, isWebOs2021, isWebOs2022, };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* We noticed that on Xbox game consoles and Universal windows platforms
|
|
3
|
+
* (presumably an Edge version is in cause here), the browser didn't send
|
|
4
|
+
* a "seeking" event if we were seeking at a 0 position initially.
|
|
5
|
+
*
|
|
6
|
+
* We could theoretically never seek at 0 initially as the initial position of
|
|
7
|
+
* an HTMLMediaElement should be at 0 anyway, but we still do it as a safe
|
|
8
|
+
* solution, as many devices have a buggy integration of HTML5 media API.
|
|
9
|
+
*
|
|
10
|
+
* This function returns `true` when we should avoid doing so, for now only for
|
|
11
|
+
* the non-standard behavior of those Edge platforms.
|
|
12
|
+
* @returns {number}
|
|
13
|
+
*/
|
|
14
|
+
export default function shouldPreventSeekingAt0Initially(): boolean;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { isIEOrEdge, isXbox } from "./browser_detection";
|
|
2
|
+
/**
|
|
3
|
+
* We noticed that on Xbox game consoles and Universal windows platforms
|
|
4
|
+
* (presumably an Edge version is in cause here), the browser didn't send
|
|
5
|
+
* a "seeking" event if we were seeking at a 0 position initially.
|
|
6
|
+
*
|
|
7
|
+
* We could theoretically never seek at 0 initially as the initial position of
|
|
8
|
+
* an HTMLMediaElement should be at 0 anyway, but we still do it as a safe
|
|
9
|
+
* solution, as many devices have a buggy integration of HTML5 media API.
|
|
10
|
+
*
|
|
11
|
+
* This function returns `true` when we should avoid doing so, for now only for
|
|
12
|
+
* the non-standard behavior of those Edge platforms.
|
|
13
|
+
* @returns {number}
|
|
14
|
+
*/
|
|
15
|
+
export default function shouldPreventSeekingAt0Initially() {
|
|
16
|
+
return isXbox || isIEOrEdge;
|
|
17
|
+
}
|
|
@@ -39,6 +39,7 @@ declare class ConfigHandler {
|
|
|
39
39
|
DEFAULT_MAX_BUFFER_BEHIND: number;
|
|
40
40
|
DEFAULT_MAX_VIDEO_BUFFER_SIZE: number;
|
|
41
41
|
MAXIMUM_MAX_BUFFER_AHEAD: Partial<Record<"audio" | "video" | "image" | "text", number>>;
|
|
42
|
+
MINIMUM_MAX_BUFFER_AHEAD: Partial<Record<"audio" | "video" | "image" | "text", number>>;
|
|
42
43
|
MAXIMUM_MAX_BUFFER_BEHIND: Partial<Record<"audio" | "video" | "image" | "text", number>>;
|
|
43
44
|
DEFAULT_INITIAL_BITRATES: {
|
|
44
45
|
audio: number;
|
|
@@ -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.33.0
|
|
91
|
+
_this.version = /* PLAYER_VERSION */ "3.33.0";
|
|
92
92
|
_this.log = log;
|
|
93
93
|
_this.state = "STOPPED";
|
|
94
94
|
_this.videoElement = videoElement;
|
|
@@ -1942,7 +1942,7 @@ var Player = /** @class */ (function (_super) {
|
|
|
1942
1942
|
var segmentBufferStatus = this._priv_contentInfos
|
|
1943
1943
|
.segmentBuffersStore.getStatus(bufferType);
|
|
1944
1944
|
if (segmentBufferStatus.type === "initialized") {
|
|
1945
|
-
segmentBufferStatus.value.synchronizeInventory();
|
|
1945
|
+
segmentBufferStatus.value.synchronizeInventory(true);
|
|
1946
1946
|
return segmentBufferStatus.value.getInventory();
|
|
1947
1947
|
}
|
|
1948
1948
|
return null;
|
|
@@ -2472,5 +2472,5 @@ var Player = /** @class */ (function (_super) {
|
|
|
2472
2472
|
};
|
|
2473
2473
|
return Player;
|
|
2474
2474
|
}(EventEmitter));
|
|
2475
|
-
Player.version = /* PLAYER_VERSION */ "3.33.0
|
|
2475
|
+
Player.version = /* PLAYER_VERSION */ "3.33.0";
|
|
2476
2476
|
export default Player;
|
|
@@ -21,8 +21,9 @@ import LoadedSessionsStore from "./utils/loaded_sessions_store";
|
|
|
21
21
|
* Dispose of the MediaKeys instance attached to the given media element, if
|
|
22
22
|
* one.
|
|
23
23
|
* @param {Object} mediaElement
|
|
24
|
+
* @returns {Promise}
|
|
24
25
|
*/
|
|
25
|
-
export declare function disableMediaKeys(mediaElement: HTMLMediaElement):
|
|
26
|
+
export declare function disableMediaKeys(mediaElement: HTMLMediaElement): Promise<unknown>;
|
|
26
27
|
/**
|
|
27
28
|
* Attach MediaKeys and its associated state to an HTMLMediaElement.
|
|
28
29
|
*
|
|
@@ -56,10 +56,11 @@ import MediaKeysInfosStore from "./utils/media_keys_infos_store";
|
|
|
56
56
|
* Dispose of the MediaKeys instance attached to the given media element, if
|
|
57
57
|
* one.
|
|
58
58
|
* @param {Object} mediaElement
|
|
59
|
+
* @returns {Promise}
|
|
59
60
|
*/
|
|
60
61
|
export function disableMediaKeys(mediaElement) {
|
|
61
62
|
MediaKeysInfosStore.setState(mediaElement, null);
|
|
62
|
-
eme.setMediaKeys(mediaElement, null)
|
|
63
|
+
return eme.setMediaKeys(mediaElement, null)
|
|
63
64
|
.then(function () {
|
|
64
65
|
log.info("DRM: MediaKeys disabled with success");
|
|
65
66
|
})
|
|
@@ -49,7 +49,9 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
49
49
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
50
50
|
}
|
|
51
51
|
};
|
|
52
|
+
import { isWebOs } from "../../compat/browser_detection";
|
|
52
53
|
import log from "../../log";
|
|
54
|
+
import noop from "../../utils/noop";
|
|
53
55
|
import { disableMediaKeys } from "./attach_media_keys";
|
|
54
56
|
import getMediaKeysInfos from "./get_media_keys";
|
|
55
57
|
/**
|
|
@@ -71,11 +73,17 @@ export default function initMediaKeys(mediaElement, keySystemsConfigs, cancelSig
|
|
|
71
73
|
shouldDisableOldMediaKeys = mediaElement.mediaKeys !== null &&
|
|
72
74
|
mediaElement.mediaKeys !== undefined &&
|
|
73
75
|
mediaKeys !== mediaElement.mediaKeys;
|
|
74
|
-
if (shouldDisableOldMediaKeys)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
if (!shouldDisableOldMediaKeys) return [3 /*break*/, 4];
|
|
77
|
+
log.debug("DRM: Disabling old MediaKeys");
|
|
78
|
+
if (!isWebOs) return [3 /*break*/, 3];
|
|
79
|
+
return [4 /*yield*/, disableMediaKeys(mediaElement)];
|
|
80
|
+
case 2:
|
|
81
|
+
_a.sent();
|
|
82
|
+
return [3 /*break*/, 4];
|
|
83
|
+
case 3:
|
|
84
|
+
disableMediaKeys(mediaElement).catch(noop);
|
|
85
|
+
_a.label = 4;
|
|
86
|
+
case 4: return [2 /*return*/, mediaKeysInfo];
|
|
79
87
|
}
|
|
80
88
|
});
|
|
81
89
|
});
|
|
@@ -178,7 +178,7 @@ var DirectFileContentInitializer = /** @class */ (function (_super) {
|
|
|
178
178
|
log.debug("Init: Initial time calculated:", initTime);
|
|
179
179
|
return initTime;
|
|
180
180
|
};
|
|
181
|
-
performInitialSeekAndPlay(mediaElement, playbackObserver, initialTime, autoPlay, function (err) { return _this.trigger("warning", err); }, cancelSignal).autoPlayResult
|
|
181
|
+
performInitialSeekAndPlay(mediaElement, playbackObserver, initialTime, autoPlay, function (err) { return _this.trigger("warning", err); }, true, cancelSignal).autoPlayResult
|
|
182
182
|
.then(function () {
|
|
183
183
|
return getLoadedReference(playbackObserver, mediaElement, true, cancelSignal)
|
|
184
184
|
.onUpdate(function (isLoaded, stopListening) {
|
|
@@ -331,7 +331,7 @@ var MediaSourceContentInitializer = /** @class */ (function (_super) {
|
|
|
331
331
|
cancelSignal.register(function () {
|
|
332
332
|
segmentBuffersStore.disposeAll();
|
|
333
333
|
});
|
|
334
|
-
var _b = performInitialSeekAndPlay(mediaElement, playbackObserver, initialTime, autoPlay, function (err) { return _this.trigger("warning", err); }, cancelSignal), autoPlayResult = _b.autoPlayResult, initialPlayPerformed = _b.initialPlayPerformed, initialSeekPerformed = _b.initialSeekPerformed;
|
|
334
|
+
var _b = performInitialSeekAndPlay(mediaElement, playbackObserver, initialTime, autoPlay, function (err) { return _this.trigger("warning", err); }, true, cancelSignal), autoPlayResult = _b.autoPlayResult, initialPlayPerformed = _b.initialPlayPerformed, initialSeekPerformed = _b.initialSeekPerformed;
|
|
335
335
|
if (cancelSignal.isCancelled()) {
|
|
336
336
|
return;
|
|
337
337
|
}
|
|
@@ -44,11 +44,13 @@ export default function getLoadedReference(playbackObserver, mediaElement, isDir
|
|
|
44
44
|
}
|
|
45
45
|
var minReadyState = shouldWaitForHaveEnoughData() ? 4 :
|
|
46
46
|
3;
|
|
47
|
-
if (observation.readyState >= minReadyState
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
if (observation.readyState >= minReadyState) {
|
|
48
|
+
if (observation.currentRange !== null || observation.ended) {
|
|
49
|
+
if (!shouldValidateMetadata() || mediaElement.duration > 0) {
|
|
50
|
+
isLoaded.setValue(true);
|
|
51
|
+
listenCanceller.cancel();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
56
|
}, { includeLastObservation: true, clearSignal: listenCanceller.signal });
|
|
@@ -57,7 +57,8 @@ export interface IInitialSeekAndPlayObject {
|
|
|
57
57
|
* @param {number|Function} startTime
|
|
58
58
|
* @param {boolean} mustAutoPlay
|
|
59
59
|
* @param {Function} onWarning
|
|
60
|
+
* @param {boolean} isDirectfile
|
|
60
61
|
* @param {Object} cancelSignal
|
|
61
62
|
* @returns {Object}
|
|
62
63
|
*/
|
|
63
|
-
export default function performInitialSeekAndPlay(mediaElement: HTMLMediaElement, playbackObserver: PlaybackObserver, startTime: number | (() => number), mustAutoPlay: boolean, onWarning: (err: IPlayerError) => void, cancelSignal: CancellationSignal): IInitialSeekAndPlayObject;
|
|
64
|
+
export default function performInitialSeekAndPlay(mediaElement: HTMLMediaElement, playbackObserver: PlaybackObserver, startTime: number | (() => number), mustAutoPlay: boolean, onWarning: (err: IPlayerError) => void, isDirectfile: boolean, cancelSignal: CancellationSignal): IInitialSeekAndPlayObject;
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { shouldValidateMetadata } from "../../../compat";
|
|
17
17
|
import { READY_STATES } from "../../../compat/browser_compatibility_types";
|
|
18
|
+
import { isSafariMobile } from "../../../compat/browser_detection";
|
|
19
|
+
/* eslint-disable-next-line max-len */
|
|
20
|
+
import shouldPreventSeekingAt0Initially from "../../../compat/should_prevent_seeking_at_0_initially";
|
|
18
21
|
import { MediaError } from "../../../errors";
|
|
19
22
|
import log from "../../../log";
|
|
20
23
|
import SharedReference from "../../../utils/reference";
|
|
@@ -26,10 +29,11 @@ import SharedReference from "../../../utils/reference";
|
|
|
26
29
|
* @param {number|Function} startTime
|
|
27
30
|
* @param {boolean} mustAutoPlay
|
|
28
31
|
* @param {Function} onWarning
|
|
32
|
+
* @param {boolean} isDirectfile
|
|
29
33
|
* @param {Object} cancelSignal
|
|
30
34
|
* @returns {Object}
|
|
31
35
|
*/
|
|
32
|
-
export default function performInitialSeekAndPlay(mediaElement, playbackObserver, startTime, mustAutoPlay, onWarning, cancelSignal) {
|
|
36
|
+
export default function performInitialSeekAndPlay(mediaElement, playbackObserver, startTime, mustAutoPlay, onWarning, isDirectfile, cancelSignal) {
|
|
33
37
|
var resolveAutoPlay;
|
|
34
38
|
var rejectAutoPlay;
|
|
35
39
|
var autoPlayResult = new Promise(function (res, rej) {
|
|
@@ -49,12 +53,39 @@ export default function performInitialSeekAndPlay(mediaElement, playbackObserver
|
|
|
49
53
|
return { autoPlayResult: autoPlayResult, initialPlayPerformed: initialPlayPerformed, initialSeekPerformed: initialSeekPerformed };
|
|
50
54
|
function onLoadedMetadata() {
|
|
51
55
|
mediaElement.removeEventListener("loadedmetadata", onLoadedMetadata);
|
|
56
|
+
/** `true` if we asked the `PlaybackObserver` to perform an initial seek. */
|
|
57
|
+
var hasAskedForInitialSeek = false;
|
|
58
|
+
var performInitialSeek = function (initialSeekTime) {
|
|
59
|
+
log.info("Init: Set initial time", initialSeekTime);
|
|
60
|
+
playbackObserver.setCurrentTime(initialSeekTime);
|
|
61
|
+
hasAskedForInitialSeek = true;
|
|
62
|
+
initialSeekPerformed.setValue(true);
|
|
63
|
+
initialSeekPerformed.finish();
|
|
64
|
+
};
|
|
65
|
+
// `startTime` defined as a function might depend on metadata to make its
|
|
66
|
+
// choice, such as the content duration, minimum and/or maximum position.
|
|
67
|
+
//
|
|
68
|
+
// The RxPlayer might already know those through the Manifest file for
|
|
69
|
+
// non-Directfile contents, yet only through the `HTMLMediaElement` once a
|
|
70
|
+
// a sufficient `readyState` has been reached for directfile contents.
|
|
71
|
+
// So let's divide the two possibilities here.
|
|
52
72
|
var initialTime = typeof startTime === "function" ? startTime() :
|
|
53
73
|
startTime;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
74
|
+
if (shouldPreventSeekingAt0Initially() && initialTime === 0) {
|
|
75
|
+
initialSeekPerformed.setValue(true);
|
|
76
|
+
initialSeekPerformed.finish();
|
|
77
|
+
}
|
|
78
|
+
else if (isDirectfile && isSafariMobile) {
|
|
79
|
+
// On safari mobile (version 17.1.2) seeking too early cause the video
|
|
80
|
+
// to never buffer media data. Using setTimeout 0 defers the seek
|
|
81
|
+
// to a moment at which safari should be more able to handle a seek.
|
|
82
|
+
setTimeout(function () {
|
|
83
|
+
performInitialSeek(initialTime);
|
|
84
|
+
}, 0);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
performInitialSeek(initialTime);
|
|
88
|
+
}
|
|
58
89
|
if (shouldValidateMetadata() && mediaElement.duration === 0) {
|
|
59
90
|
var error = new MediaError("MEDIA_ERR_NOT_LOADED_METADATA", "Cannot load automatically: your browser " +
|
|
60
91
|
"falsely announced having loaded the content.");
|
|
@@ -63,8 +94,19 @@ export default function performInitialSeekAndPlay(mediaElement, playbackObserver
|
|
|
63
94
|
if (cancelSignal.isCancelled()) {
|
|
64
95
|
return;
|
|
65
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* We only want to continue to `play` when a `seek` has actually been
|
|
99
|
+
* performed (if it has been asked). This boolean keep track of if the
|
|
100
|
+
* seek arised.
|
|
101
|
+
*/
|
|
102
|
+
var isAwaitingSeek = hasAskedForInitialSeek;
|
|
66
103
|
playbackObserver.listen(function (observation, stopListening) {
|
|
67
|
-
if (
|
|
104
|
+
if (hasAskedForInitialSeek && observation.seeking) {
|
|
105
|
+
isAwaitingSeek = false;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (!isAwaitingSeek &&
|
|
109
|
+
!observation.seeking &&
|
|
68
110
|
observation.rebuffering === null &&
|
|
69
111
|
observation.readyState >= 1) {
|
|
70
112
|
stopListening();
|
|
@@ -85,6 +127,17 @@ export default function performInitialSeekAndPlay(mediaElement, playbackObserver
|
|
|
85
127
|
deregisterCancellation();
|
|
86
128
|
return resolveAutoPlay({ type: "skipped" });
|
|
87
129
|
}
|
|
130
|
+
else if (mediaElement.ended) {
|
|
131
|
+
// the video has ended state to true, executing VideoElement.play() will
|
|
132
|
+
// restart the video from the start, which is not wanted in most cases.
|
|
133
|
+
// returning "skipped" prevents the call to play() and fix the issue
|
|
134
|
+
log.warn("Init: autoplay is enabled but the video is ended. " +
|
|
135
|
+
"Skipping autoplay to prevent video to start again");
|
|
136
|
+
initialPlayPerformed.setValue(true);
|
|
137
|
+
initialPlayPerformed.finish();
|
|
138
|
+
deregisterCancellation();
|
|
139
|
+
return resolveAutoPlay({ type: "skipped" });
|
|
140
|
+
}
|
|
88
141
|
var playResult;
|
|
89
142
|
try {
|
|
90
143
|
playResult = (_a = mediaElement.play()) !== null && _a !== void 0 ? _a : Promise.resolve();
|
|
@@ -224,7 +224,14 @@ var AudioVideoSegmentBuffer = /** @class */ (function (_super) {
|
|
|
224
224
|
err :
|
|
225
225
|
new Error("An unknown error occured when doing operations " +
|
|
226
226
|
"on the SourceBuffer");
|
|
227
|
-
this._pendingTask
|
|
227
|
+
var task = this._pendingTask;
|
|
228
|
+
if (task.type === SegmentBufferOperation.Push &&
|
|
229
|
+
task.data.length === 0 &&
|
|
230
|
+
task.inventoryData !== null) {
|
|
231
|
+
this._segmentInventory.insertChunk(task.inventoryData, false);
|
|
232
|
+
}
|
|
233
|
+
this._pendingTask = null;
|
|
234
|
+
task.reject(error);
|
|
228
235
|
}
|
|
229
236
|
};
|
|
230
237
|
/**
|
|
@@ -272,7 +279,7 @@ var AudioVideoSegmentBuffer = /** @class */ (function (_super) {
|
|
|
272
279
|
switch (task.type) {
|
|
273
280
|
case SegmentBufferOperation.Push:
|
|
274
281
|
if (task.inventoryData !== null) {
|
|
275
|
-
this._segmentInventory.insertChunk(task.inventoryData);
|
|
282
|
+
this._segmentInventory.insertChunk(task.inventoryData, true);
|
|
276
283
|
}
|
|
277
284
|
break;
|
|
278
285
|
case SegmentBufferOperation.EndOfSegment:
|
package/dist/_esm5.processed/core/segment_buffers/implementations/image/image_segment_buffer.js
CHANGED
|
@@ -80,7 +80,7 @@ var ImageSegmentBuffer = /** @class */ (function (_super) {
|
|
|
80
80
|
try {
|
|
81
81
|
this._buffered.insert(startTime, endTime);
|
|
82
82
|
if (infos.inventoryInfos !== null) {
|
|
83
|
-
this._segmentInventory.insertChunk(infos.inventoryInfos);
|
|
83
|
+
this._segmentInventory.insertChunk(infos.inventoryInfos, true);
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
catch (err) {
|
|
@@ -231,7 +231,7 @@ var HTMLTextSegmentBuffer = /** @class */ (function (_super) {
|
|
|
231
231
|
return;
|
|
232
232
|
}
|
|
233
233
|
if (infos.inventoryInfos !== null) {
|
|
234
|
-
this._segmentInventory.insertChunk(infos.inventoryInfos);
|
|
234
|
+
this._segmentInventory.insertChunk(infos.inventoryInfos, true);
|
|
235
235
|
}
|
|
236
236
|
this._buffer.insert(cues, start, end);
|
|
237
237
|
this._buffered.insert(start, end);
|
|
@@ -157,7 +157,7 @@ var NativeTextSegmentBuffer = /** @class */ (function (_super) {
|
|
|
157
157
|
}
|
|
158
158
|
this._buffered.insert(start, end);
|
|
159
159
|
if (infos.inventoryInfos !== null) {
|
|
160
|
-
this._segmentInventory.insertChunk(infos.inventoryInfos);
|
|
160
|
+
this._segmentInventory.insertChunk(infos.inventoryInfos, true);
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
catch (err) {
|
|
@@ -131,8 +131,13 @@ export declare abstract class SegmentBuffer {
|
|
|
131
131
|
* This methods allow to manually trigger a synchronization. It should be
|
|
132
132
|
* called before retrieving Segment information from it (e.g. with
|
|
133
133
|
* `getInventory`).
|
|
134
|
+
* @param {boolean} [skipLog] - This method may trigger a voluminous debug
|
|
135
|
+
* log once synchronization is finished if debug logs are enabled.
|
|
136
|
+
* As this method might be called very often in some specific debugging
|
|
137
|
+
* situations, setting this value to `true` allows to prevent the call from
|
|
138
|
+
* triggering a log.
|
|
134
139
|
*/
|
|
135
|
-
synchronizeInventory(): void;
|
|
140
|
+
synchronizeInventory(skipLog?: boolean): void;
|
|
136
141
|
/**
|
|
137
142
|
* Returns the currently buffered data for which the content is known with
|
|
138
143
|
* the corresponding content information.
|
|
@@ -63,10 +63,15 @@ var SegmentBuffer = /** @class */ (function () {
|
|
|
63
63
|
* This methods allow to manually trigger a synchronization. It should be
|
|
64
64
|
* called before retrieving Segment information from it (e.g. with
|
|
65
65
|
* `getInventory`).
|
|
66
|
+
* @param {boolean} [skipLog] - This method may trigger a voluminous debug
|
|
67
|
+
* log once synchronization is finished if debug logs are enabled.
|
|
68
|
+
* As this method might be called very often in some specific debugging
|
|
69
|
+
* situations, setting this value to `true` allows to prevent the call from
|
|
70
|
+
* triggering a log.
|
|
66
71
|
*/
|
|
67
|
-
SegmentBuffer.prototype.synchronizeInventory = function () {
|
|
72
|
+
SegmentBuffer.prototype.synchronizeInventory = function (skipLog) {
|
|
68
73
|
// The default implementation just use the SegmentInventory
|
|
69
|
-
this._segmentInventory.synchronizeBuffered(this.getBufferedRanges());
|
|
74
|
+
this._segmentInventory.synchronizeBuffered(this.getBufferedRanges(), skipLog);
|
|
70
75
|
};
|
|
71
76
|
/**
|
|
72
77
|
* Returns the currently buffered data for which the content is known with
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import BufferGarbageCollector from "./garbage_collector";
|
|
17
17
|
import { IBufferType, IEndOfSegmentInfos, IEndOfSegmentOperation, IPushChunkInfos, IPushedChunkData, IPushOperation, IRemoveOperation, ISBOperation, SegmentBuffer, SegmentBufferOperation } from "./implementations";
|
|
18
|
-
import { IBufferedChunk, IChunkContext, IInsertedChunkInfos } from "./inventory";
|
|
18
|
+
import { ChunkStatus, IBufferedChunk, IChunkContext, IInsertedChunkInfos } from "./inventory";
|
|
19
19
|
import SegmentBuffersStore, { ISegmentBufferOptions, ITextTrackSegmentBufferOptions } from "./segment_buffers_store";
|
|
20
20
|
export default SegmentBuffersStore;
|
|
21
|
-
export { BufferGarbageCollector, ISegmentBufferOptions, ITextTrackSegmentBufferOptions, SegmentBuffer, IBufferType, IBufferedChunk, IChunkContext, IInsertedChunkInfos, IPushChunkInfos, IPushedChunkData, IEndOfSegmentInfos, SegmentBufferOperation, ISBOperation, IEndOfSegmentOperation, IPushOperation, IRemoveOperation, };
|
|
21
|
+
export { BufferGarbageCollector, ChunkStatus, ISegmentBufferOptions, ITextTrackSegmentBufferOptions, SegmentBuffer, IBufferType, IBufferedChunk, IChunkContext, IInsertedChunkInfos, IPushChunkInfos, IPushedChunkData, IEndOfSegmentInfos, SegmentBufferOperation, ISBOperation, IEndOfSegmentOperation, IPushOperation, IRemoveOperation, };
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import SegmentInventory, { IBufferedChunk, IInsertedChunkInfos } from "./segment_inventory";
|
|
16
|
+
import SegmentInventory, { ChunkStatus, IBufferedChunk, IInsertedChunkInfos } from "./segment_inventory";
|
|
17
17
|
export default SegmentInventory;
|
|
18
|
-
export { IBufferedChunk, IInsertedChunkInfos, };
|
|
18
|
+
export { ChunkStatus, IBufferedChunk, IInsertedChunkInfos, };
|
|
19
19
|
export { IBufferedHistoryEntry } from "./buffered_history";
|
|
20
20
|
export { IChunkContext } from "./types";
|
|
@@ -16,6 +16,27 @@
|
|
|
16
16
|
import { Adaptation, ISegment, Period, Representation } from "../../../manifest";
|
|
17
17
|
import { IBufferedHistoryEntry } from "./buffered_history";
|
|
18
18
|
import { IChunkContext } from "./types";
|
|
19
|
+
/** Categorization of a given chunk in the `SegmentInventory`. */
|
|
20
|
+
export declare const enum ChunkStatus {
|
|
21
|
+
/**
|
|
22
|
+
* This chunk is only a part of a partially-pushed segment for now, meaning
|
|
23
|
+
* that it is only a sub-part of a requested segment that was not yet
|
|
24
|
+
* fully-loaded and pushed.
|
|
25
|
+
*
|
|
26
|
+
* Once and if the corresponding segment is fully-pushed, its `ChunkStatus`
|
|
27
|
+
* switches to `Complete`.
|
|
28
|
+
*/
|
|
29
|
+
PartiallyPushed = 0,
|
|
30
|
+
/** This chunk corresponds to a fully-loaded segment. */
|
|
31
|
+
Complete = 1,
|
|
32
|
+
/**
|
|
33
|
+
* This chunk's push operation failed, in this scenario there is no certitude
|
|
34
|
+
* about the presence of that chunk in the buffer: it may not be present,
|
|
35
|
+
* partially-present, or fully-present depending on why that push operation
|
|
36
|
+
* failed, which is generally only known by the lower-level code.
|
|
37
|
+
*/
|
|
38
|
+
Failed = 2
|
|
39
|
+
}
|
|
19
40
|
/** Information stored on a single chunk by the SegmentInventory. */
|
|
20
41
|
export interface IBufferedChunk {
|
|
21
42
|
/**
|
|
@@ -69,14 +90,10 @@ export interface IBufferedChunk {
|
|
|
69
90
|
/** Information on what that chunk actually contains. */
|
|
70
91
|
infos: IChunkContext;
|
|
71
92
|
/**
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* Inversely, if `false`, this chunk is a whole segment whose inner chunks
|
|
75
|
-
* have all been fully pushed.
|
|
76
|
-
* In that condition, the `start` and `end` properties refer to that fully
|
|
77
|
-
* pushed segment.
|
|
93
|
+
* Status of this chunk.
|
|
94
|
+
* @see ChunkStatus
|
|
78
95
|
*/
|
|
79
|
-
|
|
96
|
+
status: ChunkStatus;
|
|
80
97
|
/**
|
|
81
98
|
* If `true`, the segment as a whole is divided into multiple parts in the
|
|
82
99
|
* buffer, with other segment(s) between them.
|
|
@@ -160,8 +177,13 @@ export default class SegmentInventory {
|
|
|
160
177
|
* at a time, so each `synchronizeBuffered` call should be given a TimeRanges
|
|
161
178
|
* coming from the same buffer.
|
|
162
179
|
* @param {TimeRanges} buffered
|
|
180
|
+
* @param {boolean|undefined} [skipLog=false] - This method normally may
|
|
181
|
+
* trigger a voluminous debug log if debug logs are enabled.
|
|
182
|
+
* As this method might be called very often in some specific debugging
|
|
183
|
+
* situations, setting this value to `true` allows to prevent the call from
|
|
184
|
+
* triggering a log.
|
|
163
185
|
*/
|
|
164
|
-
synchronizeBuffered(buffered: TimeRanges): void;
|
|
186
|
+
synchronizeBuffered(buffered: TimeRanges, skipLog?: boolean): void;
|
|
165
187
|
/**
|
|
166
188
|
* Add a new chunk in the inventory.
|
|
167
189
|
*
|
|
@@ -169,7 +191,7 @@ export default class SegmentInventory {
|
|
|
169
191
|
* segment have been inserted, you should call the `completeSegment` method.
|
|
170
192
|
* @param {Object} chunkInformation
|
|
171
193
|
*/
|
|
172
|
-
insertChunk({ period, adaptation, representation, segment, chunkSize, start, end }: IInsertedChunkInfos): void;
|
|
194
|
+
insertChunk({ period, adaptation, representation, segment, chunkSize, start, end }: IInsertedChunkInfos, succeed: boolean): void;
|
|
173
195
|
/**
|
|
174
196
|
* Indicate that inserted chunks can now be considered as a complete segment.
|
|
175
197
|
* Take in argument the same content than what was given to `insertChunk` for
|