rx-player 3.30.0-dev.2023020100 → 3.30.0-dev.2023022200

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.
Files changed (167) hide show
  1. package/CHANGELOG.md +2 -1
  2. package/VERSION +1 -1
  3. package/dist/_esm5.processed/compat/eme/close_session.js +2 -2
  4. package/dist/_esm5.processed/compat/event_listeners.js +1 -1
  5. package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.js +4 -2
  6. package/dist/_esm5.processed/core/api/debug/buffer_graph.d.ts +28 -0
  7. package/dist/_esm5.processed/core/api/debug/buffer_graph.js +175 -0
  8. package/dist/_esm5.processed/core/api/debug/buffer_size_graph.d.ts +10 -0
  9. package/dist/_esm5.processed/core/api/debug/buffer_size_graph.js +105 -0
  10. package/dist/_esm5.processed/core/api/debug/constants.d.ts +2 -0
  11. package/dist/_esm5.processed/core/api/debug/constants.js +2 -0
  12. package/dist/_esm5.processed/core/api/debug/index.d.ts +2 -0
  13. package/dist/_esm5.processed/core/api/debug/index.js +2 -0
  14. package/dist/_esm5.processed/core/api/debug/modules/general_info.d.ts +3 -0
  15. package/dist/_esm5.processed/core/api/debug/modules/general_info.js +199 -0
  16. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_content.d.ts +4 -0
  17. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_content.js +121 -0
  18. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_size.d.ts +3 -0
  19. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_size.js +35 -0
  20. package/dist/_esm5.processed/core/api/debug/render.d.ts +3 -0
  21. package/dist/_esm5.processed/core/api/debug/render.js +32 -0
  22. package/dist/_esm5.processed/core/api/debug/utils.d.ts +39 -0
  23. package/dist/_esm5.processed/core/api/debug/utils.js +57 -0
  24. package/dist/_esm5.processed/core/api/playback_observer.js +3 -2
  25. package/dist/_esm5.processed/core/api/public_api.d.ts +3 -0
  26. package/dist/_esm5.processed/core/api/public_api.js +24 -13
  27. package/dist/_esm5.processed/core/api/utils.js +3 -3
  28. package/dist/_esm5.processed/core/decrypt/__tests__/__global__/utils.d.ts +5 -5
  29. package/dist/_esm5.processed/core/decrypt/attach_media_keys.js +1 -1
  30. package/dist/_esm5.processed/core/decrypt/content_decryptor.js +1 -1
  31. package/dist/_esm5.processed/core/decrypt/session_events_listener.js +37 -47
  32. package/dist/_esm5.processed/core/decrypt/utils/check_key_statuses.js +4 -0
  33. package/dist/_esm5.processed/core/fetchers/cdn_prioritizer.d.ts +17 -8
  34. package/dist/_esm5.processed/core/fetchers/cdn_prioritizer.js +10 -6
  35. package/dist/_esm5.processed/core/fetchers/manifest/manifest_fetcher.js +5 -4
  36. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.d.ts +22 -5
  37. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.js +37 -21
  38. package/dist/_esm5.processed/core/fetchers/segment/task_prioritizer.js +21 -23
  39. package/dist/_esm5.processed/core/fetchers/utils/schedule_request.js +6 -5
  40. package/dist/_esm5.processed/core/init/directfile_content_initializer.js +1 -1
  41. package/dist/_esm5.processed/core/init/media_source_content_initializer.js +27 -31
  42. package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.js +2 -2
  43. package/dist/_esm5.processed/core/init/utils/create_media_source.js +3 -12
  44. package/dist/_esm5.processed/core/init/utils/end_of_stream.js +6 -3
  45. package/dist/_esm5.processed/core/init/utils/get_loaded_reference.js +2 -1
  46. package/dist/_esm5.processed/core/init/utils/initial_seek_and_play.js +9 -5
  47. package/dist/_esm5.processed/core/init/utils/initialize_content_decryption.js +2 -1
  48. package/dist/_esm5.processed/core/init/utils/media_duration_updater.js +23 -19
  49. package/dist/_esm5.processed/core/init/utils/stream_events_emitter/stream_events_emitter.js +6 -4
  50. package/dist/_esm5.processed/core/init/utils/throw_on_media_error.js +1 -1
  51. package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.js +7 -10
  52. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.js +4 -2
  53. package/dist/_esm5.processed/core/segment_buffers/segment_buffers_store.js +13 -9
  54. package/dist/_esm5.processed/core/stream/adaptation/adaptation_stream.js +10 -11
  55. package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +26 -12
  56. package/dist/_esm5.processed/core/stream/period/period_stream.js +11 -10
  57. package/dist/_esm5.processed/core/stream/representation/representation_stream.js +15 -15
  58. package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.js +1 -1
  59. package/dist/_esm5.processed/core/stream/representation/utils/downloading_queue.js +16 -6
  60. package/dist/_esm5.processed/experimental/features/debug_element.d.ts +8 -0
  61. package/dist/_esm5.processed/experimental/features/debug_element.js +10 -0
  62. package/dist/_esm5.processed/experimental/features/index.d.ts +1 -0
  63. package/dist/_esm5.processed/experimental/features/index.js +1 -0
  64. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.js +7 -4
  65. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.js +5 -4
  66. package/dist/_esm5.processed/features/features_object.js +1 -0
  67. package/dist/_esm5.processed/features/initialize_features.js +13 -10
  68. package/dist/_esm5.processed/features/types.d.ts +3 -0
  69. package/dist/_esm5.processed/manifest/adaptation.js +4 -0
  70. package/dist/_esm5.processed/manifest/manifest.js +2 -0
  71. package/dist/_esm5.processed/manifest/representation.js +11 -4
  72. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_adaptation_sets.js +105 -137
  73. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representations.js +25 -5
  74. package/dist/_esm5.processed/public_types.d.ts +1 -0
  75. package/dist/_esm5.processed/transports/dash/add_segment_integrity_checks_to_loader.js +13 -12
  76. package/dist/_esm5.processed/transports/dash/low_latency_segment_loader.js +2 -2
  77. package/dist/_esm5.processed/transports/dash/manifest_parser.js +1 -1
  78. package/dist/_esm5.processed/transports/dash/segment_loader.js +4 -4
  79. package/dist/_esm5.processed/transports/local/segment_loader.js +13 -26
  80. package/dist/_esm5.processed/transports/smooth/segment_loader.js +4 -4
  81. package/dist/_esm5.processed/transports/utils/call_custom_manifest_loader.js +3 -3
  82. package/dist/_esm5.processed/utils/cancellable_sleep.js +4 -10
  83. package/dist/_esm5.processed/utils/create_cancellable_promise.d.ts +26 -0
  84. package/dist/_esm5.processed/utils/create_cancellable_promise.js +52 -0
  85. package/dist/_esm5.processed/utils/reference.js +6 -0
  86. package/dist/_esm5.processed/utils/request/xhr.js +1 -1
  87. package/dist/_esm5.processed/utils/task_canceller.d.ts +34 -15
  88. package/dist/_esm5.processed/utils/task_canceller.js +55 -22
  89. package/dist/rx-player.js +739 -626
  90. package/dist/rx-player.min.js +1 -1
  91. package/jest.config.js +1 -0
  92. package/package.json +18 -18
  93. package/scripts/build/constants.d.ts +1 -0
  94. package/scripts/report_build_sizes +4 -0
  95. package/sonar-project.properties +1 -1
  96. package/src/compat/eme/close_session.ts +2 -2
  97. package/src/compat/event_listeners.ts +1 -1
  98. package/src/core/adaptive/adaptive_representation_selector.ts +4 -2
  99. package/src/core/api/debug/buffer_graph.ts +247 -0
  100. package/src/core/api/debug/buffer_size_graph.ts +131 -0
  101. package/src/core/api/debug/constants.ts +2 -0
  102. package/src/core/api/debug/index.ts +3 -0
  103. package/src/core/api/debug/modules/general_info.ts +204 -0
  104. package/src/core/api/debug/modules/segment_buffer_content.ts +155 -0
  105. package/src/core/api/debug/modules/segment_buffer_size.ts +48 -0
  106. package/src/core/api/debug/render.ts +40 -0
  107. package/src/core/api/debug/utils.ts +103 -0
  108. package/src/core/api/playback_observer.ts +4 -2
  109. package/src/core/api/public_api.ts +27 -13
  110. package/src/core/api/utils.ts +3 -3
  111. package/src/core/decrypt/attach_media_keys.ts +1 -1
  112. package/src/core/decrypt/content_decryptor.ts +1 -1
  113. package/src/core/decrypt/session_events_listener.ts +37 -49
  114. package/src/core/decrypt/utils/check_key_statuses.ts +6 -0
  115. package/src/core/fetchers/cdn_prioritizer.ts +18 -9
  116. package/src/core/fetchers/manifest/manifest_fetcher.ts +5 -4
  117. package/src/core/fetchers/segment/segment_fetcher.ts +36 -14
  118. package/src/core/fetchers/segment/task_prioritizer.ts +25 -30
  119. package/src/core/fetchers/utils/schedule_request.ts +6 -5
  120. package/src/core/init/directfile_content_initializer.ts +1 -1
  121. package/src/core/init/media_source_content_initializer.ts +37 -41
  122. package/src/core/init/utils/content_time_boundaries_observer.ts +2 -2
  123. package/src/core/init/utils/create_media_source.ts +4 -16
  124. package/src/core/init/utils/end_of_stream.ts +6 -3
  125. package/src/core/init/utils/get_loaded_reference.ts +2 -1
  126. package/src/core/init/utils/initial_seek_and_play.ts +9 -5
  127. package/src/core/init/utils/initialize_content_decryption.ts +2 -1
  128. package/src/core/init/utils/media_duration_updater.ts +25 -20
  129. package/src/core/init/utils/stream_events_emitter/stream_events_emitter.ts +6 -4
  130. package/src/core/init/utils/throw_on_media_error.ts +1 -1
  131. package/src/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.ts +7 -11
  132. package/src/core/segment_buffers/implementations/text/html/html_text_segment_buffer.ts +4 -2
  133. package/src/core/segment_buffers/segment_buffers_store.ts +16 -13
  134. package/src/core/stream/adaptation/adaptation_stream.ts +10 -11
  135. package/src/core/stream/orchestrator/stream_orchestrator.ts +26 -12
  136. package/src/core/stream/period/period_stream.ts +11 -10
  137. package/src/core/stream/representation/representation_stream.ts +15 -15
  138. package/src/core/stream/representation/utils/append_segment_to_buffer.ts +1 -1
  139. package/src/core/stream/representation/utils/downloading_queue.ts +16 -4
  140. package/src/experimental/features/__tests__/debug_element.test.ts +26 -0
  141. package/src/experimental/features/debug_element.ts +13 -0
  142. package/src/experimental/features/index.ts +1 -0
  143. package/src/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.ts +7 -4
  144. package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.ts +5 -4
  145. package/src/features/__tests__/initialize_features.test.ts +11 -0
  146. package/src/features/features_object.ts +1 -0
  147. package/src/features/initialize_features.ts +15 -10
  148. package/src/features/types.ts +9 -0
  149. package/src/manifest/adaptation.ts +7 -0
  150. package/src/manifest/manifest.ts +4 -0
  151. package/src/manifest/representation.ts +10 -4
  152. package/src/parsers/manifest/dash/common/parse_adaptation_sets.ts +116 -151
  153. package/src/parsers/manifest/dash/common/parse_representations.ts +21 -4
  154. package/src/public_types.ts +1 -0
  155. package/src/transports/dash/add_segment_integrity_checks_to_loader.ts +30 -24
  156. package/src/transports/dash/low_latency_segment_loader.ts +2 -2
  157. package/src/transports/dash/manifest_parser.ts +1 -1
  158. package/src/transports/dash/segment_loader.ts +4 -4
  159. package/src/transports/local/segment_loader.ts +14 -30
  160. package/src/transports/smooth/segment_loader.ts +4 -4
  161. package/src/transports/utils/call_custom_manifest_loader.ts +3 -3
  162. package/src/typings/globals.d.ts +2 -0
  163. package/src/utils/cancellable_sleep.ts +5 -14
  164. package/src/utils/create_cancellable_promise.ts +69 -0
  165. package/src/utils/reference.ts +6 -0
  166. package/src/utils/request/xhr.ts +1 -1
  167. package/src/utils/task_canceller.ts +63 -34
@@ -0,0 +1,204 @@
1
+ import { CancellationSignal } from "../../../../utils/task_canceller";
2
+ import RxPlayer from "../../public_api";
3
+ import { DEFAULT_REFRESH_INTERVAL } from "../constants";
4
+ import {
5
+ createCompositeElement,
6
+ createElement,
7
+ createMetricTitle,
8
+ isExtendedMode,
9
+ } from "../utils";
10
+
11
+ export default function constructDebugGeneralInfo(
12
+ instance : RxPlayer,
13
+ parentElt : HTMLElement,
14
+ cancelSignal : CancellationSignal
15
+ ) : HTMLElement {
16
+ const generalInfoElt = createElement("div");
17
+ const adaptationsElt = createElement("div");
18
+ const representationsElt = createElement("div");
19
+ updateGeneralInfo();
20
+ const generalInfoItv = setInterval(() => {
21
+ updateGeneralInfo();
22
+ }, DEFAULT_REFRESH_INTERVAL);
23
+ cancelSignal.register(() => {
24
+ clearInterval(generalInfoItv);
25
+ });
26
+
27
+ return createCompositeElement("div", [
28
+ generalInfoElt,
29
+ adaptationsElt,
30
+ representationsElt,
31
+ ]);
32
+ function updateGeneralInfo() {
33
+ const videoElement = instance.getVideoElement();
34
+ if (videoElement === null) {
35
+ // disposed player. Clean-up everything
36
+ generalInfoElt.innerHTML = "";
37
+ adaptationsElt.innerHTML = "";
38
+ representationsElt.innerHTML = "";
39
+ clearInterval(generalInfoItv);
40
+ return;
41
+ } else {
42
+ const currentTime = instance.getPosition();
43
+ const bufferGap = instance.getVideoBufferGap();
44
+ const bufferGapStr = bufferGap === Infinity ? "0" : bufferGap.toFixed(2);
45
+ const valuesLine1 : Array<[string, string]> = [
46
+ ["ct", currentTime.toFixed(2)],
47
+ ["bg", bufferGapStr],
48
+ ["rs", String(videoElement.readyState)],
49
+ ["pr", String(videoElement.playbackRate)],
50
+ ["sp", String(instance.getPlaybackRate())],
51
+ ["pa", String(videoElement.paused ? 1 : 0)],
52
+ ["en", String(videoElement.ended ? 1 : 0)],
53
+ ["li", String(instance.isLive() ? 1 : 0)],
54
+ ["wba", String(instance.getWantedBufferAhead())],
55
+ ["st", `"${instance.getPlayerState()}"`],
56
+ ];
57
+
58
+ const valuesLine2 : Array<[string, string]> = [];
59
+ const ks = instance.getKeySystemConfiguration();
60
+ if (ks !== null) {
61
+ valuesLine2.push(["ks", ks.keySystem]);
62
+ }
63
+ const mbb = instance.getMaxBufferBehind();
64
+ if (mbb !== Infinity) {
65
+ valuesLine2.push(["mbb", String(mbb)]);
66
+ }
67
+ const mba = instance.getMaxBufferAhead();
68
+ if (mba !== Infinity) {
69
+ valuesLine2.push(["mba", String(mba)]);
70
+ }
71
+ const mia = instance.getMinAudioBitrate();
72
+ if (mia !== 0) {
73
+ valuesLine2.push(["mia", String(mia)]);
74
+ }
75
+ const miv = instance.getMinVideoBitrate();
76
+ if (miv !== 0) {
77
+ valuesLine2.push(["miv", String(miv)]);
78
+ }
79
+ const maa = instance.getMaxAudioBitrate();
80
+ if (maa !== Infinity) {
81
+ valuesLine2.push(["maa", String(maa)]);
82
+ }
83
+ const mav = instance.getMaxVideoBitrate();
84
+ if (mav !== Infinity) {
85
+ valuesLine2.push(["mav", String(mav)]);
86
+ }
87
+ const fab = instance.getManualAudioBitrate();
88
+ if (fab >= 0) {
89
+ valuesLine2.push(["fab", String(fab)]);
90
+ }
91
+ const fvb = instance.getManualVideoBitrate();
92
+ if (fvb >= 0) {
93
+ valuesLine2.push(["fvb", String(fvb)]);
94
+ }
95
+ const mbs = instance.getMaxVideoBufferSize();
96
+ if (mbs !== Infinity) {
97
+ valuesLine2.push(["mbs", String(mbs)]);
98
+ }
99
+ const minPos = instance.getMinimumPosition();
100
+ if (minPos !== null) {
101
+ valuesLine1.push(["mip", minPos.toFixed(2)]);
102
+ valuesLine2.push(["dmi", (currentTime - minPos).toFixed(2)]);
103
+ }
104
+ const maxPos = instance.getMaximumPosition();
105
+ if (maxPos !== null) {
106
+ valuesLine1.push(["map", maxPos.toFixed(2)]);
107
+ valuesLine2.push(["dma", (maxPos - currentTime).toFixed(2)]);
108
+ }
109
+ const valuesLine3 : Array<[string, string]> = [];
110
+ const error = instance.getError();
111
+ if (error !== null) {
112
+ valuesLine3.push(["er", `"${String(error)}"`]);
113
+ }
114
+ generalInfoElt.innerHTML = "";
115
+ for (const valueSet of [valuesLine1, valuesLine2, valuesLine3]) {
116
+ if (valueSet.length > 0) {
117
+ const lineInfoElt = createElement("div");
118
+ for (const value of valueSet) {
119
+ lineInfoElt.appendChild(createMetricTitle(value[0]));
120
+ lineInfoElt.appendChild(createElement("span", {
121
+ textContent: value[1] + " ",
122
+ }));
123
+ }
124
+ generalInfoElt.appendChild(lineInfoElt);
125
+ }
126
+ }
127
+ if (isExtendedMode(parentElt)) {
128
+ const url = instance.getUrl();
129
+ if (url !== undefined) {
130
+ const reducedUrl = url.length > 100 ?
131
+ url.substring(0, 99) + "…" :
132
+ url;
133
+
134
+ generalInfoElt.appendChild(createCompositeElement("div", [
135
+ createMetricTitle("url"),
136
+ createElement("span", {
137
+ textContent: reducedUrl,
138
+ }),
139
+ ]));
140
+ }
141
+ }
142
+ }
143
+ if (isExtendedMode(parentElt)) {
144
+ const videoId = instance.getAvailableVideoTracks().map(({ id, active }) =>
145
+ active ? `*${id}` : id);
146
+ const audioId = instance.getAvailableAudioTracks().map(({ id, active }) =>
147
+ active ? `*${id}` : id);
148
+ const textId = instance.getAvailableTextTracks().map(({ id, active }) =>
149
+ active ? `*${id}` : id);
150
+ adaptationsElt.innerHTML = "";
151
+ if (videoId.length > 0) {
152
+ let textContent = `${videoId.length}:${videoId.join(" ")} `;
153
+ if (textContent.length > 100) {
154
+ textContent = textContent.substring(0, 98) + "… ";
155
+ }
156
+ const videoAdaps = createCompositeElement("div", [
157
+ createMetricTitle("vt"),
158
+ createElement("span", { textContent }),
159
+ ]);
160
+ adaptationsElt.appendChild(videoAdaps);
161
+ }
162
+ if (audioId.length > 0) {
163
+ let textContent = `${audioId.length}:${audioId.join(" ")} `;
164
+ if (textContent.length > 100) {
165
+ textContent = textContent.substring(0, 98) + "… ";
166
+ }
167
+ const audioAdaps = createCompositeElement("div", [
168
+ createMetricTitle("at"),
169
+ createElement("span", { textContent }),
170
+ ]);
171
+ adaptationsElt.appendChild(audioAdaps);
172
+ }
173
+ if (textId.length > 0) {
174
+ let textContent = `${textId.length}:${textId.join(" ")} `;
175
+ if (textContent.length > 100) {
176
+ textContent = textContent.substring(0, 98) + "… ";
177
+ }
178
+ const textAdaps = createCompositeElement("div", [
179
+ createMetricTitle("tt"),
180
+ createElement("span", { textContent }),
181
+ ]);
182
+ adaptationsElt.appendChild(textAdaps);
183
+ }
184
+ const videoBitrates = instance.getAvailableVideoBitrates();
185
+ const audioBitrates = instance.getAvailableAudioBitrates();
186
+ representationsElt.innerHTML = "";
187
+ if (videoBitrates.length > 0) {
188
+ representationsElt.appendChild(createMetricTitle("vb"));
189
+ representationsElt.appendChild(createElement("span", {
190
+ textContent: videoBitrates.join(" ") + " ",
191
+ }));
192
+ }
193
+ if (audioBitrates.length > 0) {
194
+ representationsElt.appendChild(createMetricTitle("ab"));
195
+ representationsElt.appendChild(createElement("span", {
196
+ textContent: audioBitrates.join(" ") + " ",
197
+ }));
198
+ }
199
+ } else {
200
+ adaptationsElt.innerHTML = "";
201
+ representationsElt.innerHTML = "";
202
+ }
203
+ }
204
+ }
@@ -0,0 +1,155 @@
1
+ import {
2
+ IAdaptation,
3
+ IPeriod,
4
+ IRepresentation,
5
+ } from "../../../../public_types";
6
+ import isNullOrUndefined from "../../../../utils/is_null_or_undefined";
7
+ import { CancellationSignal } from "../../../../utils/task_canceller";
8
+ import { IBufferType } from "../../../segment_buffers";
9
+ import RxPlayer from "../../public_api";
10
+ import SegmentBufferGraph from "../buffer_graph";
11
+ import { DEFAULT_REFRESH_INTERVAL } from "../constants";
12
+ import {
13
+ createElement,
14
+ createGraphCanvas,
15
+ createMetricTitle,
16
+ isExtendedMode,
17
+ } from "../utils";
18
+
19
+ export default function createSegmentBufferGraph(
20
+ instance : RxPlayer,
21
+ bufferType : IBufferType,
22
+ title : string,
23
+ parentElt : HTMLElement,
24
+ cancelSignal : CancellationSignal
25
+ ) : HTMLElement {
26
+ const bufferGraphWrapper = createElement("div");
27
+ const bufferTitle = createMetricTitle(title);
28
+ const canvasElt = createGraphCanvas();
29
+ const currentRangeRepInfoElt = createElement("div");
30
+ const loadingRangeRepInfoElt = createElement("div");
31
+ const bufferGraph = new SegmentBufferGraph(canvasElt);
32
+ const intervalId = setInterval(update, DEFAULT_REFRESH_INTERVAL);
33
+ cancelSignal.register(() => {
34
+ clearInterval(intervalId);
35
+ });
36
+ bufferGraphWrapper.appendChild(bufferTitle);
37
+ bufferGraphWrapper.appendChild(canvasElt);
38
+ bufferGraphWrapper.appendChild(currentRangeRepInfoElt);
39
+ bufferGraphWrapper.appendChild(loadingRangeRepInfoElt);
40
+ bufferGraphWrapper.style.padding = "5px 0px";
41
+ update();
42
+ return bufferGraphWrapper;
43
+
44
+ function update() {
45
+ if (instance.getVideoElement() === null) {
46
+ // disposed player. Clean-up everything
47
+ bufferGraphWrapper.style.display = "none";
48
+ bufferGraphWrapper.innerHTML = "";
49
+ clearInterval(intervalId);
50
+ return;
51
+ }
52
+ const showAllInfo = isExtendedMode(parentElt);
53
+ const inventory = instance.__priv_getSegmentBufferContent(bufferType);
54
+ if (inventory === null) {
55
+ bufferGraphWrapper.style.display = "none";
56
+ currentRangeRepInfoElt.innerHTML = "";
57
+ loadingRangeRepInfoElt.innerHTML = "";
58
+ } else {
59
+ bufferGraphWrapper.style.display = "block";
60
+ const currentTime = instance.getPosition();
61
+ const width = Math.min(parentElt.clientWidth - 150, 600);
62
+ bufferGraph.update({
63
+ currentTime,
64
+ minimumPosition: instance.getMinimumPosition() ?? undefined,
65
+ maximumPosition: instance.getMaximumPosition() ?? undefined,
66
+ inventory,
67
+ width,
68
+ height: 10,
69
+ });
70
+
71
+ if (!showAllInfo) {
72
+ currentRangeRepInfoElt.innerHTML = "";
73
+ loadingRangeRepInfoElt.innerHTML = "";
74
+ return;
75
+ }
76
+
77
+ currentRangeRepInfoElt.innerHTML = "";
78
+ for (let i = 0; i < inventory.length; i++) {
79
+ const rangeInfo = inventory[i];
80
+ const { bufferedStart, bufferedEnd, infos } = rangeInfo;
81
+ if (bufferedStart !== undefined && bufferedEnd !== undefined &&
82
+ currentTime >= bufferedStart && currentTime < bufferedEnd)
83
+ {
84
+ currentRangeRepInfoElt.appendChild(createMetricTitle("play"));
85
+ currentRangeRepInfoElt.appendChild(createElement("span", {
86
+ textContent: constructRepresentationInfo(infos),
87
+ }));
88
+ break;
89
+ }
90
+ }
91
+
92
+ loadingRangeRepInfoElt.innerHTML = "";
93
+ const rep = instance.getCurrentRepresentations()?.[bufferType];
94
+ const adap = instance.getCurrentAdaptations()?.[bufferType];
95
+ const manifest = instance.getManifest();
96
+ if (manifest !== null && !isNullOrUndefined(rep) && !isNullOrUndefined(adap)) {
97
+ const period = manifest.getPeriodForTime(currentTime);
98
+ if (period !== undefined) {
99
+ loadingRangeRepInfoElt.appendChild(createMetricTitle("load"));
100
+ loadingRangeRepInfoElt.appendChild(createElement("span", {
101
+ textContent: constructRepresentationInfo({
102
+ period,
103
+ adaptation: adap,
104
+ representation: rep,
105
+ }),
106
+ }));
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+
113
+ function constructRepresentationInfo(
114
+ content : {
115
+ period : IPeriod;
116
+ adaptation : IAdaptation;
117
+ representation : IRepresentation;
118
+ }
119
+ ) : string {
120
+ const period = content.period;
121
+ const { language,
122
+ isAudioDescription,
123
+ isClosedCaption,
124
+ isTrickModeTrack,
125
+ isSignInterpreted,
126
+ type: bufferType } = content.adaptation;
127
+ const { id, height, width, bitrate, codec } = content.representation;
128
+ let representationInfo = `"${id}" `;
129
+ if (height !== undefined && width !== undefined) {
130
+ representationInfo += `${width}x${height} `;
131
+ }
132
+ if (bitrate !== undefined) {
133
+ representationInfo += `(${(bitrate / 1000).toFixed(0)}kbps) `;
134
+ }
135
+ if (codec !== undefined) {
136
+ representationInfo += `c:"${codec}" `;
137
+ }
138
+ if (language !== undefined) {
139
+ representationInfo += `l:"${language}" `;
140
+ }
141
+ if (bufferType === "video" && typeof isSignInterpreted === "boolean") {
142
+ representationInfo += `si:${isSignInterpreted ? 1 : 0} `;
143
+ }
144
+ if (bufferType === "video" && typeof isTrickModeTrack === "boolean") {
145
+ representationInfo += `tm:${isTrickModeTrack ? 1 : 0} `;
146
+ }
147
+ if (bufferType === "audio" && typeof isAudioDescription === "boolean") {
148
+ representationInfo += `ad:${isAudioDescription ? 1 : 0} `;
149
+ }
150
+ if (bufferType === "text" && typeof isClosedCaption === "boolean") {
151
+ representationInfo += `cc:${isClosedCaption ? 1 : 0} `;
152
+ }
153
+ representationInfo += `p:${period.start}-${period.end ?? "?"}`;
154
+ return representationInfo;
155
+ }
@@ -0,0 +1,48 @@
1
+ import { CancellationSignal } from "../../../../utils/task_canceller";
2
+ import RxPlayer from "../../public_api";
3
+ import BufferSizeGraph from "../buffer_size_graph";
4
+ import { DEFAULT_REFRESH_INTERVAL } from "../constants";
5
+ import {
6
+ createElement,
7
+ createGraphCanvas,
8
+ createMetricTitle,
9
+ } from "../utils";
10
+
11
+ export default function createSegmentBufferSizeGraph(
12
+ instance : RxPlayer,
13
+ parentElt : HTMLElement,
14
+ cancelSignal : CancellationSignal
15
+ ) : HTMLElement {
16
+ const bufferSizeGraphWrapperElt = createElement("div");
17
+ const bufferSizeTitle = createMetricTitle("bgap");
18
+ const canvasElt = createGraphCanvas();
19
+
20
+ const bufferSizeGraph = new BufferSizeGraph(canvasElt);
21
+ const intervalId = setInterval(addBufferSize, DEFAULT_REFRESH_INTERVAL);
22
+ cancelSignal.register(() => {
23
+ clearInterval(intervalId);
24
+ });
25
+ bufferSizeGraphWrapperElt.appendChild(bufferSizeTitle);
26
+ bufferSizeGraphWrapperElt.appendChild(canvasElt);
27
+ bufferSizeGraphWrapperElt.style.padding = "7px 0px";
28
+ addBufferSize();
29
+ return bufferSizeGraphWrapperElt;
30
+
31
+ function addBufferSize() {
32
+ if (instance.getVideoElement() === null) {
33
+ // disposed player. Clean-up everything
34
+ bufferSizeGraphWrapperElt.innerHTML = "";
35
+ clearInterval(intervalId);
36
+ return;
37
+ }
38
+ const bufferGap = instance.getVideoBufferGap();
39
+ if (bufferGap === Infinity) {
40
+ bufferSizeGraph.pushBufferSize(0);
41
+ } else {
42
+ bufferSizeGraph.pushBufferSize(bufferGap);
43
+ }
44
+ const width = Math.min(parentElt.clientWidth - 150, 600);
45
+ bufferSizeGraph.reRender(width, 10);
46
+ }
47
+ }
48
+
@@ -0,0 +1,40 @@
1
+ import { CancellationSignal } from "../../../utils/task_canceller";
2
+ import RxPlayer from "../public_api";
3
+ import constructDebugGeneralInfo from "./modules/general_info";
4
+ import createSegmentBufferGraph from "./modules/segment_buffer_content";
5
+ import createSegmentBufferSizeGraph from "./modules/segment_buffer_size";
6
+ import { createCompositeElement, createElement } from "./utils";
7
+
8
+ export default function renderDebugElement(
9
+ parentElt : HTMLElement,
10
+ instance : RxPlayer,
11
+ cancelSignal : CancellationSignal
12
+ ) : void {
13
+ const debugElementTitleElt = createElement("div", {
14
+ textContent: "RxPlayer Debug Information",
15
+ });
16
+ debugElementTitleElt.style.fontWeight = "bold";
17
+ debugElementTitleElt.style.borderBottom = "1px solid white";
18
+ debugElementTitleElt.style.marginBottom = "5px";
19
+ debugElementTitleElt.style.fontStyle = "italic";
20
+
21
+ const debugWrapperElt = createCompositeElement("div", [
22
+ debugElementTitleElt,
23
+ constructDebugGeneralInfo(instance, parentElt, cancelSignal),
24
+ createSegmentBufferGraph(instance, "video", "vbuf", parentElt, cancelSignal),
25
+ createSegmentBufferGraph(instance, "audio", "abuf", parentElt, cancelSignal),
26
+ createSegmentBufferGraph(instance, "text", "tbuf", parentElt, cancelSignal),
27
+ createSegmentBufferSizeGraph(instance, parentElt, cancelSignal),
28
+ ]);
29
+ debugWrapperElt.style.backgroundColor = "#00000099";
30
+ debugWrapperElt.style.padding = "7px";
31
+ debugWrapperElt.style.fontSize = "13px";
32
+ debugWrapperElt.style.fontFamily = "mono";
33
+ debugWrapperElt.style.color = "white";
34
+ debugWrapperElt.style.display = "inline-block";
35
+ debugWrapperElt.style.bottom = "0px";
36
+ parentElt.appendChild(debugWrapperElt);
37
+ cancelSignal.register(() => {
38
+ parentElt.removeChild(debugWrapperElt);
39
+ });
40
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Create an HTML element.
3
+ * @param {string} elementName - The element's name, like `"div"` for example.
4
+ * @param {Object} [options={}] - Optional attributes for the element.
5
+ * @param {string} [options.textContent] - Inner text for that element.
6
+ * @param {string} [options.className] - Value for a `class` attribute
7
+ * associated to this element.
8
+ * @param {string} [options.href] - Value for a `href` attribute
9
+ * associated to this element.
10
+ * @returns {HTMLElement}
11
+ */
12
+ export function createElement(
13
+ elementName : "input",
14
+ opts? : CreateElementOptions | undefined
15
+ ) : HTMLInputElement;
16
+ export function createElement(
17
+ elementName : "button",
18
+ opts? : CreateElementOptions | undefined
19
+ ) : HTMLButtonElement;
20
+ export function createElement(
21
+ elementName : "a",
22
+ opts? : CreateElementOptions | undefined
23
+ ) : HTMLLinkElement;
24
+ export function createElement(
25
+ elementName : "canvas",
26
+ opts? : CreateElementOptions | undefined
27
+ ) : HTMLCanvasElement;
28
+ export function createElement(
29
+ elementName : string,
30
+ opts? : CreateElementOptions | undefined
31
+ ) : HTMLElement;
32
+ export function createElement(
33
+ elementName : string,
34
+ {
35
+ textContent,
36
+ className,
37
+ } : CreateElementOptions | undefined = {}
38
+ ) : HTMLElement {
39
+ const elt = document.createElement(elementName);
40
+ if (className !== undefined) {
41
+ elt.className = className;
42
+ }
43
+ if (textContent !== undefined) {
44
+ elt.textContent = textContent;
45
+ }
46
+ return elt;
47
+ }
48
+
49
+ interface CreateElementOptions {
50
+ textContent? : string | undefined;
51
+ className? : string | undefined;
52
+ }
53
+
54
+ /**
55
+ * Create an HTML element which may contain mutiple HTML sub-elements.
56
+ * @param {string} rootElementName - The element's name, like `"div"` for
57
+ * example.
58
+ * @param {Array.<string|HTMLElement>} parts - The HTML sub-elements, in order.
59
+ * Those can also just be strings, in which case only text nodes (and no actual
60
+ * HTMLElement) will be added at this place.
61
+ * @param {Object} [options={}] - Optional attributes for the element.
62
+ * @param {string} [options.className] - Value for a `class` attribute
63
+ * associated to this element.
64
+ * @returns {HTMLElement}
65
+ */
66
+ export function createCompositeElement(
67
+ rootElementName : string,
68
+ parts : Array<HTMLElement | string>,
69
+ { className } : { className? : string } | undefined = {}
70
+ ) : HTMLElement {
71
+ const elt = document.createElement(rootElementName);
72
+ if (className !== undefined) {
73
+ elt.className = className;
74
+ }
75
+ for (const subElt of parts) {
76
+ if (typeof subElt === "string") {
77
+ elt.appendChild(document.createTextNode(subElt));
78
+ } else {
79
+ elt.appendChild(subElt);
80
+ }
81
+ }
82
+ return elt;
83
+ }
84
+
85
+ export function isExtendedMode(parentElt : HTMLElement) : boolean {
86
+ return parentElt.clientHeight > 400;
87
+ }
88
+
89
+ export function createMetricTitle(title : string) : HTMLElement {
90
+ const elt = createElement("span", {
91
+ textContent: title + "/",
92
+ });
93
+ elt.style.fontWeight = "bold";
94
+ return elt;
95
+ }
96
+
97
+ export function createGraphCanvas() : HTMLCanvasElement {
98
+ const canvasElt = createElement("canvas");
99
+ canvasElt.style.border = "1px solid white";
100
+ canvasElt.style.height = "15px";
101
+ canvasElt.style.marginLeft = "2px";
102
+ return canvasElt;
103
+ }
@@ -217,7 +217,7 @@ export default class PlaybackObserver {
217
217
  options? : { includeLastObservation? : boolean | undefined;
218
218
  clearSignal? : CancellationSignal | undefined; }
219
219
  ) {
220
- if (this._canceller.isUsed || options?.clearSignal?.isCancelled === true) {
220
+ if (this._canceller.isUsed() || options?.clearSignal?.isCancelled() === true) {
221
221
  return noop;
222
222
  }
223
223
  this._observationRef.onUpdate(cb, {
@@ -971,7 +971,9 @@ function generateReadOnlyObserver<TSource, TDest>(
971
971
  options? : { includeLastObservation? : boolean | undefined;
972
972
  clearSignal? : CancellationSignal | undefined; }
973
973
  ) : void {
974
- if (cancellationSignal.isCancelled || options?.clearSignal?.isCancelled === true) {
974
+ if (cancellationSignal.isCancelled() ||
975
+ options?.clearSignal?.isCancelled() === true)
976
+ {
975
977
  return ;
976
978
  }
977
979
  mappedRef.onUpdate(cb, {
@@ -364,7 +364,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
364
364
  // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1194624
365
365
  videoElement.preload = "auto";
366
366
 
367
- this.version = /* PLAYER_VERSION */"3.30.0-dev.2023020100";
367
+ this.version = /* PLAYER_VERSION */"3.30.0-dev.2023022200";
368
368
  this.log = log;
369
369
  this.state = "STOPPED";
370
370
  this.videoElement = videoElement;
@@ -602,6 +602,21 @@ class Player extends EventEmitter<IPublicAPIEvent> {
602
602
  this._priv_initializeContentPlayback(newOptions);
603
603
  }
604
604
 
605
+ public createDebugElement(element : HTMLElement) : {
606
+ dispose() : void;
607
+ } {
608
+ if (features.createDebugElement === null) {
609
+ throw new Error("Feature `DEBUG_ELEMENT` not added to the RxPlayer");
610
+ }
611
+ const canceller = new TaskCanceller() ;
612
+ features.createDebugElement(element, this, canceller.signal);
613
+ return {
614
+ dispose() {
615
+ canceller.cancel();
616
+ },
617
+ };
618
+ }
619
+
605
620
  /**
606
621
  * From given options, initialize content playback.
607
622
  * @param {Object} options
@@ -764,7 +779,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
764
779
  defaultTextTrack,
765
780
  currentContentCanceller.signal
766
781
  );
767
- if (currentContentCanceller.isUsed) {
782
+ if (currentContentCanceller.isUsed()) {
768
783
  return;
769
784
  }
770
785
  initializer = new features.directfile.initDirectFile({ autoPlay,
@@ -943,7 +958,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
943
958
  updateReloadingMetadata(newState);
944
959
  this._priv_setPlayerState(newState);
945
960
 
946
- if (currentContentCanceller.isUsed) {
961
+ if (currentContentCanceller.isUsed()) {
947
962
  return;
948
963
  }
949
964
 
@@ -953,9 +968,8 @@ class Player extends EventEmitter<IPublicAPIEvent> {
953
968
  seekEventsCanceller = null;
954
969
  }
955
970
  } else if (isLoadedState(this.state)) {
956
- seekEventsCanceller = new TaskCanceller({
957
- cancelOn: currentContentCanceller.signal,
958
- });
971
+ seekEventsCanceller = new TaskCanceller();
972
+ seekEventsCanceller.linkToSignal(currentContentCanceller.signal);
959
973
  emitSeekEvents(videoElement,
960
974
  playbackObserver,
961
975
  () => this.trigger("seeking", null),
@@ -2468,20 +2482,20 @@ class Player extends EventEmitter<IPublicAPIEvent> {
2468
2482
  this._priv_triggerAvailableBitratesChangeEvent("availableAudioBitratesChange",
2469
2483
  this.getAvailableAudioBitrates(),
2470
2484
  cancelSignal);
2471
- if (contentInfos.currentContentCanceller.isUsed) {
2485
+ if (contentInfos.currentContentCanceller.isUsed()) {
2472
2486
  return;
2473
2487
  }
2474
2488
  this._priv_triggerAvailableBitratesChangeEvent("availableVideoBitratesChange",
2475
2489
  this.getAvailableVideoBitrates(),
2476
2490
  cancelSignal);
2477
- if (contentInfos.currentContentCanceller.isUsed) {
2491
+ if (contentInfos.currentContentCanceller.isUsed()) {
2478
2492
  return;
2479
2493
  }
2480
2494
  const audioBitrate = this._priv_getCurrentRepresentations()?.audio?.bitrate ?? -1;
2481
2495
  this._priv_triggerCurrentBitrateChangeEvent("audioBitrateChange",
2482
2496
  audioBitrate,
2483
2497
  cancelSignal);
2484
- if (contentInfos.currentContentCanceller.isUsed) {
2498
+ if (contentInfos.currentContentCanceller.isUsed()) {
2485
2499
  return;
2486
2500
  }
2487
2501
 
@@ -2833,7 +2847,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
2833
2847
  currentContentCancelSignal : CancellationSignal
2834
2848
  ) : void {
2835
2849
  const prevVal = this._priv_contentEventsMemory[event];
2836
- if (!currentContentCancelSignal.isCancelled &&
2850
+ if (!currentContentCancelSignal.isCancelled() &&
2837
2851
  (prevVal === undefined || !areArraysOfNumbersEqual(newVal, prevVal)))
2838
2852
  {
2839
2853
  this._priv_contentEventsMemory[event] = newVal;
@@ -2853,7 +2867,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
2853
2867
  newVal : number,
2854
2868
  currentContentCancelSignal : CancellationSignal
2855
2869
  ) : void {
2856
- if (!currentContentCancelSignal.isCancelled &&
2870
+ if (!currentContentCancelSignal.isCancelled() &&
2857
2871
  newVal !== this._priv_contentEventsMemory[event])
2858
2872
  {
2859
2873
  this._priv_contentEventsMemory[event] = newVal;
@@ -2886,7 +2900,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
2886
2900
  arg : IEventPayload<IPublicAPIEvent, TEventName>,
2887
2901
  currentContentCancelSignal : CancellationSignal
2888
2902
  ) {
2889
- if (!currentContentCancelSignal.isCancelled) {
2903
+ if (!currentContentCancelSignal.isCancelled()) {
2890
2904
  this.trigger(evt, arg);
2891
2905
  }
2892
2906
  }
@@ -2971,7 +2985,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
2971
2985
  return mediaElementTrackChoiceManager;
2972
2986
  }
2973
2987
  }
2974
- Player.version = /* PLAYER_VERSION */"3.30.0-dev.2023020100";
2988
+ Player.version = /* PLAYER_VERSION */"3.30.0-dev.2023022200";
2975
2989
 
2976
2990
  /** Every events sent by the RxPlayer's public API. */
2977
2991
  interface IPublicAPIEvent {