rx-player 4.5.0-dev.2026041501 → 4.5.0-dev.2026060400
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 +9 -1
- package/VERSION +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_dash_wasm.d.ts.map +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_dash_wasm.js +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_worker.js +1 -1
- package/dist/commonjs/compat/eme/eme-api-implementation.js +1 -1
- package/dist/commonjs/compat/patch_webkit_source_buffer.d.ts.map +1 -1
- package/dist/commonjs/core/adaptive/utils/pending_requests_store.d.ts.map +1 -1
- package/dist/commonjs/core/adaptive/utils/pending_requests_store.js +2 -0
- package/dist/commonjs/core/entry/content_preparer.js +3 -1
- package/dist/commonjs/core/entry/content_time_boundaries_observer.d.ts +0 -13
- package/dist/commonjs/core/entry/content_time_boundaries_observer.d.ts.map +1 -1
- package/dist/commonjs/core/entry/content_time_boundaries_observer.js +25 -4
- package/dist/commonjs/core/segment_sinks/implementations/audio_video/audio_video_segment_sink.js +3 -1
- package/dist/commonjs/core/segment_sinks/implementations/text/text_segment_sink.d.ts.map +1 -1
- package/dist/commonjs/core/segment_sinks/implementations/text/text_segment_sink.js +4 -1
- package/dist/commonjs/core/segment_sinks/implementations/utils/manual_time_ranges.d.ts.map +1 -1
- package/dist/commonjs/core/segment_sinks/implementations/utils/manual_time_ranges.js +2 -0
- package/dist/commonjs/core/stream/adaptation/types.d.ts.map +1 -1
- package/dist/commonjs/core/stream/orchestrator/stream_orchestrator.d.ts.map +1 -1
- package/dist/commonjs/errors/index.d.ts +2 -2
- package/dist/commonjs/errors/index.d.ts.map +1 -1
- package/dist/commonjs/errors/index.js +2 -1
- package/dist/commonjs/errors/media_error.d.ts +19 -4
- package/dist/commonjs/errors/media_error.d.ts.map +1 -1
- package/dist/commonjs/errors/media_error.js +29 -0
- package/dist/commonjs/experimental/tools/mediaCapabilitiesProber/utils.d.ts.map +1 -1
- package/dist/commonjs/experimental/tools/mediaCapabilitiesProber/utils.js +2 -0
- package/dist/commonjs/importable_worker.d.ts.map +1 -1
- package/dist/commonjs/importable_worker.js +1 -0
- package/dist/commonjs/main_thread/api/public_api.d.ts +3 -1
- package/dist/commonjs/main_thread/api/public_api.d.ts.map +1 -1
- package/dist/commonjs/main_thread/api/public_api.js +13 -6
- package/dist/commonjs/main_thread/decrypt/utils/loaded_sessions_store.d.ts.map +1 -1
- package/dist/commonjs/main_thread/init/directfile_content_initializer.d.ts.map +1 -1
- package/dist/commonjs/main_thread/init/directfile_content_initializer.js +20 -11
- package/dist/commonjs/main_thread/init/media_source_content_initializer.d.ts +0 -1
- package/dist/commonjs/main_thread/init/media_source_content_initializer.d.ts.map +1 -1
- package/dist/commonjs/main_thread/init/media_source_content_initializer.js +7 -14
- package/dist/commonjs/main_thread/text_displayer/html/html_text_displayer.js +1 -0
- package/dist/commonjs/main_thread/tracks_store/media_element_tracks_store.d.ts +2 -0
- package/dist/commonjs/main_thread/tracks_store/media_element_tracks_store.d.ts.map +1 -1
- package/dist/commonjs/main_thread/tracks_store/media_element_tracks_store.js +57 -24
- package/dist/commonjs/main_thread/tracks_store/tracks_store.d.ts +12 -1
- package/dist/commonjs/main_thread/tracks_store/tracks_store.d.ts.map +1 -1
- package/dist/commonjs/main_thread/tracks_store/tracks_store.js +15 -3
- package/dist/commonjs/main_thread/utils/media_capabilities.d.ts +5 -0
- package/dist/commonjs/main_thread/utils/media_capabilities.d.ts.map +1 -0
- package/dist/commonjs/main_thread/utils/media_capabilities.js +12 -0
- package/dist/commonjs/playback_observer/core_playback_observer.d.ts.map +1 -1
- package/dist/commonjs/transports/dash/manifest_parser.js +6 -2
- package/dist/commonjs/transports/smooth/segment_loader.d.ts.map +1 -1
- package/dist/commonjs/transports/smooth/segment_loader.js +3 -1
- package/dist/commonjs/utils/assert.d.ts.map +1 -1
- package/dist/commonjs/utils/assert.js +3 -1
- package/dist/commonjs/utils/create_uuid.js +2 -2
- package/dist/commonjs/utils/event_emitter.d.ts.map +1 -1
- package/dist/commonjs/utils/event_emitter.js +1 -0
- package/dist/commonjs/utils/reference.d.ts.map +1 -1
- package/dist/commonjs/utils/reference.js +1 -0
- package/dist/es2017/__GENERATED_CODE/embedded_dash_wasm.d.ts.map +1 -1
- package/dist/es2017/__GENERATED_CODE/embedded_dash_wasm.js +1 -1
- package/dist/es2017/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
- package/dist/es2017/__GENERATED_CODE/embedded_worker.js +1 -1
- package/dist/es2017/compat/eme/eme-api-implementation.js +1 -1
- package/dist/es2017/compat/patch_webkit_source_buffer.d.ts.map +1 -1
- package/dist/es2017/core/adaptive/utils/pending_requests_store.d.ts.map +1 -1
- package/dist/es2017/core/adaptive/utils/pending_requests_store.js +2 -0
- package/dist/es2017/core/entry/content_preparer.js +3 -1
- package/dist/es2017/core/entry/content_time_boundaries_observer.d.ts +0 -13
- package/dist/es2017/core/entry/content_time_boundaries_observer.d.ts.map +1 -1
- package/dist/es2017/core/entry/content_time_boundaries_observer.js +25 -4
- package/dist/es2017/core/segment_sinks/implementations/audio_video/audio_video_segment_sink.js +3 -1
- package/dist/es2017/core/segment_sinks/implementations/text/text_segment_sink.d.ts.map +1 -1
- package/dist/es2017/core/segment_sinks/implementations/text/text_segment_sink.js +4 -1
- package/dist/es2017/core/segment_sinks/implementations/utils/manual_time_ranges.d.ts.map +1 -1
- package/dist/es2017/core/segment_sinks/implementations/utils/manual_time_ranges.js +2 -0
- package/dist/es2017/core/stream/adaptation/types.d.ts.map +1 -1
- package/dist/es2017/core/stream/orchestrator/stream_orchestrator.d.ts.map +1 -1
- package/dist/es2017/errors/index.d.ts +2 -2
- package/dist/es2017/errors/index.d.ts.map +1 -1
- package/dist/es2017/errors/index.js +2 -2
- package/dist/es2017/errors/media_error.d.ts +19 -4
- package/dist/es2017/errors/media_error.d.ts.map +1 -1
- package/dist/es2017/errors/media_error.js +28 -0
- package/dist/es2017/experimental/tools/mediaCapabilitiesProber/utils.d.ts.map +1 -1
- package/dist/es2017/experimental/tools/mediaCapabilitiesProber/utils.js +2 -0
- package/dist/es2017/importable_worker.d.ts.map +1 -1
- package/dist/es2017/importable_worker.js +1 -0
- package/dist/es2017/main_thread/api/public_api.d.ts +3 -1
- package/dist/es2017/main_thread/api/public_api.d.ts.map +1 -1
- package/dist/es2017/main_thread/api/public_api.js +13 -6
- package/dist/es2017/main_thread/decrypt/utils/loaded_sessions_store.d.ts.map +1 -1
- package/dist/es2017/main_thread/init/directfile_content_initializer.d.ts.map +1 -1
- package/dist/es2017/main_thread/init/directfile_content_initializer.js +20 -11
- package/dist/es2017/main_thread/init/media_source_content_initializer.d.ts +0 -1
- package/dist/es2017/main_thread/init/media_source_content_initializer.d.ts.map +1 -1
- package/dist/es2017/main_thread/init/media_source_content_initializer.js +8 -15
- package/dist/es2017/main_thread/text_displayer/html/html_text_displayer.js +1 -0
- package/dist/es2017/main_thread/tracks_store/media_element_tracks_store.d.ts +2 -0
- package/dist/es2017/main_thread/tracks_store/media_element_tracks_store.d.ts.map +1 -1
- package/dist/es2017/main_thread/tracks_store/media_element_tracks_store.js +57 -24
- package/dist/es2017/main_thread/tracks_store/tracks_store.d.ts +12 -1
- package/dist/es2017/main_thread/tracks_store/tracks_store.d.ts.map +1 -1
- package/dist/es2017/main_thread/tracks_store/tracks_store.js +15 -3
- package/dist/es2017/main_thread/utils/media_capabilities.d.ts +5 -0
- package/dist/es2017/main_thread/utils/media_capabilities.d.ts.map +1 -0
- package/dist/es2017/main_thread/utils/media_capabilities.js +8 -0
- package/dist/es2017/playback_observer/core_playback_observer.d.ts.map +1 -1
- package/dist/es2017/transports/dash/manifest_parser.js +6 -2
- package/dist/es2017/transports/smooth/segment_loader.d.ts.map +1 -1
- package/dist/es2017/transports/smooth/segment_loader.js +3 -1
- package/dist/es2017/utils/assert.d.ts.map +1 -1
- package/dist/es2017/utils/assert.js +3 -1
- package/dist/es2017/utils/create_uuid.js +2 -2
- package/dist/es2017/utils/event_emitter.d.ts.map +1 -1
- package/dist/es2017/utils/event_emitter.js +1 -0
- package/dist/es2017/utils/reference.d.ts.map +1 -1
- package/dist/es2017/utils/reference.js +1 -0
- package/dist/mpd-parser.wasm +0 -0
- package/dist/worker.js +6 -6
- package/eslint.config.mjs +7 -2
- package/package.json +15 -15
- package/src/__GENERATED_CODE/embedded_dash_wasm.ts +1 -1
- package/src/__GENERATED_CODE/embedded_worker.ts +1 -1
- package/src/compat/__tests__/is_codec_supported.test.ts +8 -2
- package/src/compat/eme/eme-api-implementation.ts +1 -1
- package/src/compat/patch_webkit_source_buffer.ts +6 -7
- package/src/core/adaptive/utils/pending_requests_store.ts +2 -0
- package/src/core/entry/__tests__/content_time_boundaries_observer.test.ts +19 -0
- package/src/core/entry/content_preparer.ts +1 -0
- package/src/core/entry/content_time_boundaries_observer.ts +28 -4
- package/src/core/segment_sinks/implementations/audio_video/audio_video_segment_sink.ts +1 -0
- package/src/core/segment_sinks/implementations/text/text_segment_sink.ts +2 -0
- package/src/core/segment_sinks/implementations/utils/manual_time_ranges.ts +2 -0
- package/src/core/stream/adaptation/types.ts +5 -4
- package/src/core/stream/orchestrator/stream_orchestrator.ts +4 -2
- package/src/errors/__tests__/media_error.test.ts +106 -3
- package/src/errors/index.ts +2 -1
- package/src/errors/media_error.ts +63 -7
- package/src/experimental/tools/mediaCapabilitiesProber/probers/__tests__/HDCPPolicy.test.ts +8 -2
- package/src/experimental/tools/mediaCapabilitiesProber/probers/__tests__/defaultCodecsFinder.test.ts +6 -2
- package/src/experimental/tools/mediaCapabilitiesProber/probers/__tests__/mediaContentType.test.ts +6 -2
- package/src/experimental/tools/mediaCapabilitiesProber/utils.ts +2 -0
- package/src/importable_worker.ts +1 -0
- package/src/main_thread/api/public_api.ts +14 -4
- package/src/main_thread/decrypt/utils/loaded_sessions_store.ts +1 -1
- package/src/main_thread/init/directfile_content_initializer.ts +25 -15
- package/src/main_thread/init/media_source_content_initializer.ts +9 -18
- package/src/main_thread/init/utils/__tests__/stream_events_emitter.test.ts +1 -1
- package/src/main_thread/text_displayer/html/html_text_displayer.ts +1 -0
- package/src/main_thread/tracks_store/__tests__/media_element_tracks_store.test.ts +63 -43
- package/src/main_thread/tracks_store/__tests__/tracks_store.test.ts +91 -0
- package/src/main_thread/tracks_store/media_element_tracks_store.ts +66 -27
- package/src/main_thread/tracks_store/tracks_store.ts +25 -3
- package/src/main_thread/utils/media_capabilities.ts +14 -0
- package/src/manifest/classes/__tests__/update_periods.test.ts +1 -0
- package/src/parsers/manifest/dash/common/__tests__/get_periods_time_infos.test.ts +1 -0
- package/src/playback_observer/core_playback_observer.ts +1 -3
- package/src/transports/dash/manifest_parser.ts +2 -0
- package/src/transports/smooth/segment_loader.ts +1 -0
- package/src/utils/assert.ts +1 -0
- package/src/utils/create_uuid.ts +2 -2
- package/src/utils/event_emitter.ts +1 -0
- package/src/utils/reference.ts +1 -0
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { describe, beforeEach, it, expect, vi, afterEach } from "vitest";
|
|
2
2
|
import isCodecSupported from "../is_codec_supported";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
type IMockedMediaSource =
|
|
5
|
+
| {
|
|
6
|
+
isTypeSupported?: ((codec: string) => boolean) | undefined;
|
|
7
|
+
}
|
|
8
|
+
| undefined;
|
|
9
|
+
|
|
10
|
+
const mocks: { default: { MediaSource_: IMockedMediaSource } } = vi.hoisted(() => {
|
|
5
11
|
return {
|
|
6
12
|
default: {
|
|
7
|
-
MediaSource_: {}
|
|
13
|
+
MediaSource_: {},
|
|
8
14
|
},
|
|
9
15
|
};
|
|
10
16
|
});
|
|
@@ -315,7 +315,7 @@ function defaultSetMediaKeys(
|
|
|
315
315
|
try {
|
|
316
316
|
let ret: unknown;
|
|
317
317
|
if (typeof elt.setMediaKeys === "function") {
|
|
318
|
-
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
|
318
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-restricted-types
|
|
319
319
|
ret = elt.setMediaKeys(mediaKeys as MediaKeys);
|
|
320
320
|
}
|
|
321
321
|
|
|
@@ -25,13 +25,12 @@ interface IWebKitSourceBufferConstructor {
|
|
|
25
25
|
prototype: IWebKitSourceBuffer;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
interface IWebKitSourceBuffer
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}> {
|
|
28
|
+
interface IWebKitSourceBuffer extends EventEmitter<{
|
|
29
|
+
updatestart: Event;
|
|
30
|
+
update: Event;
|
|
31
|
+
updateend: Event;
|
|
32
|
+
error: Event | Error;
|
|
33
|
+
}> {
|
|
35
34
|
_emitUpdate?: (eventName: "error" | "update", val: unknown) => void;
|
|
36
35
|
appendBuffer?: (data: BufferSource) => void;
|
|
37
36
|
updating: boolean;
|
|
@@ -54,6 +54,7 @@ export default class PendingRequestsStore {
|
|
|
54
54
|
public addProgress(progress: IPendingRequestStoreProgress): void {
|
|
55
55
|
const request = this._currentRequests[progress.id];
|
|
56
56
|
if (isNullOrUndefined(request)) {
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
57
58
|
if ((__ENVIRONMENT__.CURRENT_ENV as number) === (__ENVIRONMENT__.DEV as number)) {
|
|
58
59
|
throw new Error("ABR: progress for a request not added");
|
|
59
60
|
}
|
|
@@ -69,6 +70,7 @@ export default class PendingRequestsStore {
|
|
|
69
70
|
*/
|
|
70
71
|
public remove(id: string): void {
|
|
71
72
|
if (isNullOrUndefined(this._currentRequests[id])) {
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
72
74
|
if ((__ENVIRONMENT__.CURRENT_ENV as number) === (__ENVIRONMENT__.DEV as number)) {
|
|
73
75
|
throw new Error("ABR: can't remove unknown request");
|
|
74
76
|
}
|
|
@@ -143,6 +143,25 @@ describe("ContentTimeBoundariesObserver", () => {
|
|
|
143
143
|
expect(mockTrigger).toHaveBeenCalledWith("warning", expect.any(Object));
|
|
144
144
|
const warning = mockTrigger.mock.calls[0][1];
|
|
145
145
|
expect(warning.code).toBe("MEDIA_TIME_BEFORE_MANIFEST");
|
|
146
|
+
expect(warning.timeInfo).toEqual({
|
|
147
|
+
position: 5,
|
|
148
|
+
minPosition: 10,
|
|
149
|
+
maxPosition: 100,
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("should not trigger warning when position is within epsilon of manifest minimum", async () => {
|
|
154
|
+
mockGetMinimumSafePosition.mockReturnValue(10);
|
|
155
|
+
const manifest = createMockManifest();
|
|
156
|
+
const playbackObserver = createMockPlaybackObserver();
|
|
157
|
+
|
|
158
|
+
new ContentTimeBoundariesObserver(manifest, playbackObserver, ["audio"]);
|
|
159
|
+
await sleep(0);
|
|
160
|
+
|
|
161
|
+
const positionCallback = mockPlaybackObserverListen.mock.calls[0][0];
|
|
162
|
+
positionCallback({ position: { getWanted: () => 9.9995 } });
|
|
163
|
+
|
|
164
|
+
expect(mockTrigger).not.toHaveBeenCalled();
|
|
146
165
|
});
|
|
147
166
|
|
|
148
167
|
it("should trigger warning when position is after manifest maximum", async () => {
|
|
@@ -500,6 +500,7 @@ function createMediaSourceInterfaceAndSegmentSinksStore(
|
|
|
500
500
|
value: sentMediaSourceLink,
|
|
501
501
|
mediaSourceId: mediaSourceInterface.id,
|
|
502
502
|
},
|
|
503
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
503
504
|
[handle.value as unknown as Transferable],
|
|
504
505
|
);
|
|
505
506
|
} else {
|
|
@@ -47,6 +47,12 @@ import TaskCanceller from "../../utils/task_canceller";
|
|
|
47
47
|
* Manifest range.
|
|
48
48
|
* @class ContentTimeBoundariesObserver
|
|
49
49
|
*/
|
|
50
|
+
|
|
51
|
+
// `HTMLMediaElement.currentTime` can be off by a very small amount from the
|
|
52
|
+
// Manifest-derived boundaries. We keep an epsilon so those rounding
|
|
53
|
+
// differences do not trigger spurious boundary warnings.
|
|
54
|
+
const EPSILON = 1e-3;
|
|
55
|
+
|
|
50
56
|
export default class ContentTimeBoundariesObserver extends EventEmitter<IContentTimeBoundariesObserverEvent> {
|
|
51
57
|
/** Allows to interrupt everything the `ContentTimeBoundariesObserver` is doing. */
|
|
52
58
|
private _canceller: TaskCanceller;
|
|
@@ -113,20 +119,38 @@ export default class ContentTimeBoundariesObserver extends EventEmitter<IContent
|
|
|
113
119
|
playbackObserver.listen(
|
|
114
120
|
({ position }) => {
|
|
115
121
|
const wantedPosition = position.getWanted();
|
|
116
|
-
|
|
122
|
+
const minimumPosition = manifest.getMinimumSafePosition();
|
|
123
|
+
const maximumPosition = maximumPositionCalculator.getMaximumAvailablePosition();
|
|
124
|
+
|
|
125
|
+
// Only report "before manifest" when the position is meaningfully
|
|
126
|
+
// behind the minimum, not when `<video>.currentTime` and the
|
|
127
|
+
// Manifest disagree by a tiny floating-point delta.
|
|
128
|
+
if (wantedPosition < minimumPosition - EPSILON) {
|
|
117
129
|
const warning = new MediaError(
|
|
118
130
|
"MEDIA_TIME_BEFORE_MANIFEST",
|
|
119
131
|
"The current position is behind the " +
|
|
120
132
|
"earliest time announced in the Manifest.",
|
|
133
|
+
{
|
|
134
|
+
timeInfo: {
|
|
135
|
+
position: wantedPosition,
|
|
136
|
+
minPosition: minimumPosition,
|
|
137
|
+
maxPosition: maximumPosition,
|
|
138
|
+
},
|
|
139
|
+
},
|
|
121
140
|
);
|
|
122
141
|
this.trigger("warning", warning);
|
|
123
|
-
} else if (
|
|
124
|
-
wantedPosition > maximumPositionCalculator.getMaximumAvailablePosition()
|
|
125
|
-
) {
|
|
142
|
+
} else if (wantedPosition > maximumPosition + EPSILON) {
|
|
126
143
|
const warning = new MediaError(
|
|
127
144
|
"MEDIA_TIME_AFTER_MANIFEST",
|
|
128
145
|
"The current position is after the latest " +
|
|
129
146
|
"time announced in the Manifest.",
|
|
147
|
+
{
|
|
148
|
+
timeInfo: {
|
|
149
|
+
position: wantedPosition,
|
|
150
|
+
minPosition: minimumPosition,
|
|
151
|
+
maxPosition: maximumPosition,
|
|
152
|
+
},
|
|
153
|
+
},
|
|
130
154
|
);
|
|
131
155
|
this.trigger("warning", warning);
|
|
132
156
|
}
|
|
@@ -349,6 +349,7 @@ export default class AudioVideoSegmentSink extends SegmentSink {
|
|
|
349
349
|
*/
|
|
350
350
|
function assertDataIsBufferSource(data: unknown): asserts data is BufferSource {
|
|
351
351
|
if (
|
|
352
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
352
353
|
(__ENVIRONMENT__.CURRENT_ENV as number) === (__ENVIRONMENT__.PRODUCTION as number)
|
|
353
354
|
) {
|
|
354
355
|
return;
|
|
@@ -191,6 +191,7 @@ function assertChunkIsTextTrackSegmentData(
|
|
|
191
191
|
chunk: unknown,
|
|
192
192
|
): asserts chunk is ITextTracksBufferSegmentData {
|
|
193
193
|
if (
|
|
194
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
194
195
|
(__ENVIRONMENT__.CURRENT_ENV as number) === (__ENVIRONMENT__.PRODUCTION as number)
|
|
195
196
|
) {
|
|
196
197
|
return;
|
|
@@ -285,6 +286,7 @@ export interface ITextDisplayerInterface {
|
|
|
285
286
|
* It doesn't correspond at all to real code that will be called. This is just
|
|
286
287
|
* a hack to tell TypeScript to perform that check.
|
|
287
288
|
*/
|
|
289
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
288
290
|
if ((__ENVIRONMENT__.CURRENT_ENV as number) === (__ENVIRONMENT__.DEV as number)) {
|
|
289
291
|
// @ts-expect-error: unused function for type checking
|
|
290
292
|
function _checkType(input: ITextTrackSegmentData): void {
|
|
@@ -36,6 +36,7 @@ export default class ManualTimeRanges implements TimeRanges {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
insert(start: number, end: number): void {
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
39
40
|
if ((__ENVIRONMENT__.CURRENT_ENV as number) === (__ENVIRONMENT__.DEV as number)) {
|
|
40
41
|
assert(start >= 0, "invalid start time");
|
|
41
42
|
assert(end - start > 0, "invalid end time");
|
|
@@ -45,6 +46,7 @@ export default class ManualTimeRanges implements TimeRanges {
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
remove(start: number, end: number): void {
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
48
50
|
if ((__ENVIRONMENT__.CURRENT_ENV as number) === (__ENVIRONMENT__.DEV as number)) {
|
|
49
51
|
assert(start >= 0, "invalid start time");
|
|
50
52
|
assert(end - start > 0, "invalid end time");
|
|
@@ -15,8 +15,10 @@ import type {
|
|
|
15
15
|
} from "../representation";
|
|
16
16
|
|
|
17
17
|
/** Callbacks called by the `AdaptationStream` on various events. */
|
|
18
|
-
export interface IAdaptationStreamCallbacks
|
|
19
|
-
|
|
18
|
+
export interface IAdaptationStreamCallbacks extends Omit<
|
|
19
|
+
IRepresentationStreamCallbacks,
|
|
20
|
+
"terminating" | "addedSegment"
|
|
21
|
+
> {
|
|
20
22
|
/** Called as new bitrate estimates are done. */
|
|
21
23
|
bitrateEstimateChange(payload: IBitrateEstimateChangePayload): void;
|
|
22
24
|
/**
|
|
@@ -111,8 +113,7 @@ export interface INeedsBufferFlushPayload {
|
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
/** Regular playback information needed by the AdaptationStream. */
|
|
114
|
-
export interface IAdaptationStreamPlaybackObservation
|
|
115
|
-
extends IRepresentationStreamPlaybackObservation {
|
|
116
|
+
export interface IAdaptationStreamPlaybackObservation extends IRepresentationStreamPlaybackObservation {
|
|
116
117
|
/**
|
|
117
118
|
* For the current SegmentSink, difference in seconds between the next position
|
|
118
119
|
* where no segment data is available and the current position.
|
|
@@ -710,8 +710,10 @@ export type IStreamOrchestratorOptions = IPeriodStreamOptions & {
|
|
|
710
710
|
};
|
|
711
711
|
|
|
712
712
|
/** Callbacks called by the `StreamOrchestrator` on various events. */
|
|
713
|
-
export interface IStreamOrchestratorCallbacks
|
|
714
|
-
|
|
713
|
+
export interface IStreamOrchestratorCallbacks extends Omit<
|
|
714
|
+
IPeriodStreamCallbacks,
|
|
715
|
+
"waitingMediaSourceReload"
|
|
716
|
+
> {
|
|
715
717
|
/**
|
|
716
718
|
* Called when a `PeriodStream` has been removed.
|
|
717
719
|
* This event can be used for clean-up purposes. For example, you are free to
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import
|
|
2
|
+
import type { ISerializedMediaError } from "../media_error";
|
|
3
|
+
import MediaError, { deserializeMediaError } from "../media_error";
|
|
3
4
|
|
|
4
5
|
describe("errors - MediaError", () => {
|
|
5
6
|
it("should format a MediaError", () => {
|
|
6
7
|
const reason = "test";
|
|
7
|
-
const mediaError = new MediaError("MEDIA_TIME_BEFORE_MANIFEST", reason
|
|
8
|
+
const mediaError = new MediaError("MEDIA_TIME_BEFORE_MANIFEST", reason, {
|
|
9
|
+
timeInfo: { position: 5, minPosition: 10, maxPosition: 100 },
|
|
10
|
+
});
|
|
8
11
|
expect(mediaError).toBeInstanceOf(Error);
|
|
9
12
|
expect(mediaError.name).toBe("MediaError");
|
|
10
13
|
expect(mediaError.type).toBe("MEDIA_ERROR");
|
|
@@ -15,7 +18,9 @@ describe("errors - MediaError", () => {
|
|
|
15
18
|
|
|
16
19
|
it("should be able to set it as fatal", () => {
|
|
17
20
|
const reason = "test";
|
|
18
|
-
const mediaError = new MediaError("MEDIA_TIME_AFTER_MANIFEST", reason
|
|
21
|
+
const mediaError = new MediaError("MEDIA_TIME_AFTER_MANIFEST", reason, {
|
|
22
|
+
timeInfo: { position: 5, minPosition: 10, maxPosition: 100 },
|
|
23
|
+
});
|
|
19
24
|
mediaError.fatal = true;
|
|
20
25
|
expect(mediaError).toBeInstanceOf(Error);
|
|
21
26
|
expect(mediaError.name).toBe("MediaError");
|
|
@@ -36,4 +41,102 @@ describe("errors - MediaError", () => {
|
|
|
36
41
|
expect(mediaError.fatal).toBe(true);
|
|
37
42
|
expect(mediaError.message).toBe("MEDIA_ERR_NETWORK: test");
|
|
38
43
|
});
|
|
44
|
+
|
|
45
|
+
it("should expose and serialize custom position metadata", () => {
|
|
46
|
+
const mediaError = new MediaError("MEDIA_TIME_BEFORE_MANIFEST", "test", {
|
|
47
|
+
timeInfo: {
|
|
48
|
+
position: 3,
|
|
49
|
+
minPosition: 10,
|
|
50
|
+
maxPosition: 20,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
expect(mediaError.timeInfo).toEqual({
|
|
55
|
+
position: 3,
|
|
56
|
+
minPosition: 10,
|
|
57
|
+
maxPosition: 20,
|
|
58
|
+
});
|
|
59
|
+
expect(mediaError.serialize()).toEqual({
|
|
60
|
+
isSerializedError: true,
|
|
61
|
+
name: "MediaError",
|
|
62
|
+
code: "MEDIA_TIME_BEFORE_MANIFEST",
|
|
63
|
+
reason: "test",
|
|
64
|
+
tracks: undefined,
|
|
65
|
+
timeInfo: {
|
|
66
|
+
position: 3,
|
|
67
|
+
minPosition: 10,
|
|
68
|
+
maxPosition: 20,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("should deserialize a serialized MediaError with timeInfo", () => {
|
|
74
|
+
const serializedError: ISerializedMediaError = {
|
|
75
|
+
isSerializedError: true,
|
|
76
|
+
name: "MediaError",
|
|
77
|
+
code: "MEDIA_TIME_BEFORE_MANIFEST",
|
|
78
|
+
reason: "test",
|
|
79
|
+
tracks: undefined,
|
|
80
|
+
timeInfo: {
|
|
81
|
+
position: 3,
|
|
82
|
+
minPosition: 10,
|
|
83
|
+
maxPosition: 20,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const mediaError = deserializeMediaError(serializedError);
|
|
88
|
+
|
|
89
|
+
expect(mediaError).toBeInstanceOf(MediaError);
|
|
90
|
+
expect(mediaError.code).toBe("MEDIA_TIME_BEFORE_MANIFEST");
|
|
91
|
+
expect(mediaError.message).toBe("MEDIA_TIME_BEFORE_MANIFEST: test");
|
|
92
|
+
expect(mediaError.timeInfo).toEqual(serializedError.timeInfo);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("should deserialize a serialized MediaError with tracks", () => {
|
|
96
|
+
const serializedError: ISerializedMediaError = {
|
|
97
|
+
isSerializedError: true,
|
|
98
|
+
name: "MediaError",
|
|
99
|
+
code: "BUFFER_APPEND_ERROR",
|
|
100
|
+
reason: "test",
|
|
101
|
+
tracks: [
|
|
102
|
+
{
|
|
103
|
+
type: "audio",
|
|
104
|
+
track: {
|
|
105
|
+
id: "fra1",
|
|
106
|
+
audioDescription: false,
|
|
107
|
+
language: "fra",
|
|
108
|
+
normalized: "fra",
|
|
109
|
+
representations: [],
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
timeInfo: undefined,
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const mediaError = deserializeMediaError(serializedError);
|
|
117
|
+
|
|
118
|
+
expect(mediaError).toBeInstanceOf(MediaError);
|
|
119
|
+
expect(mediaError.code).toBe("BUFFER_APPEND_ERROR");
|
|
120
|
+
expect(mediaError.message).toBe("BUFFER_APPEND_ERROR: test");
|
|
121
|
+
expect(mediaError.tracksInfo).toEqual(serializedError.tracks);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should deserialize a serialized MediaError without metadata", () => {
|
|
125
|
+
const serializedError = {
|
|
126
|
+
isSerializedError: true as const,
|
|
127
|
+
name: "MediaError" as const,
|
|
128
|
+
code: "MEDIA_ERR_NETWORK" as const,
|
|
129
|
+
reason: "test",
|
|
130
|
+
tracks: undefined,
|
|
131
|
+
timeInfo: undefined,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const mediaError = deserializeMediaError(serializedError);
|
|
135
|
+
|
|
136
|
+
expect(mediaError).toBeInstanceOf(MediaError);
|
|
137
|
+
expect(mediaError.code).toBe("MEDIA_ERR_NETWORK");
|
|
138
|
+
expect(mediaError.message).toBe("MEDIA_ERR_NETWORK: test");
|
|
139
|
+
expect(mediaError.timeInfo).toBeUndefined();
|
|
140
|
+
expect(mediaError.tracksInfo).toBeUndefined();
|
|
141
|
+
});
|
|
39
142
|
});
|
package/src/errors/index.ts
CHANGED
|
@@ -22,7 +22,7 @@ import { ErrorCodes, ErrorTypes, NetworkErrorTypes } from "./error_codes";
|
|
|
22
22
|
import formatError from "./format_error";
|
|
23
23
|
import isKnownError from "./is_known_error";
|
|
24
24
|
import type { ISerializedMediaError } from "./media_error";
|
|
25
|
-
import MediaError from "./media_error";
|
|
25
|
+
import MediaError, { deserializeMediaError } from "./media_error";
|
|
26
26
|
import type { ISerializedNetworkError } from "./network_error";
|
|
27
27
|
import NetworkError from "./network_error";
|
|
28
28
|
import type { ISerializedOtherError } from "./other_error";
|
|
@@ -46,6 +46,7 @@ export {
|
|
|
46
46
|
ErrorTypes,
|
|
47
47
|
formatError,
|
|
48
48
|
MediaError,
|
|
49
|
+
deserializeMediaError,
|
|
49
50
|
NetworkError,
|
|
50
51
|
OtherError,
|
|
51
52
|
NetworkErrorTypes,
|
|
@@ -15,16 +15,27 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import type { ITaggedTrack } from "../manifest";
|
|
18
|
+
import assert from "../utils/assert";
|
|
18
19
|
import type { IMediaErrorCode } from "./error_codes";
|
|
19
20
|
import { ErrorTypes } from "./error_codes";
|
|
20
21
|
import errorMessage from "./error_message";
|
|
21
22
|
|
|
22
|
-
type ICodeWithAdaptationType =
|
|
23
|
+
export type ICodeWithAdaptationType =
|
|
23
24
|
| "BUFFER_APPEND_ERROR"
|
|
24
25
|
| "BUFFER_FULL_ERROR"
|
|
25
26
|
| "NO_PLAYABLE_REPRESENTATION"
|
|
26
27
|
| "MANIFEST_INCOMPATIBLE_CODECS_ERROR";
|
|
27
28
|
|
|
29
|
+
export type ICodeWithManifestPositionError =
|
|
30
|
+
| "MEDIA_TIME_BEFORE_MANIFEST"
|
|
31
|
+
| "MEDIA_TIME_AFTER_MANIFEST";
|
|
32
|
+
|
|
33
|
+
interface ITimeInfo {
|
|
34
|
+
position: number;
|
|
35
|
+
minPosition: number;
|
|
36
|
+
maxPosition: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
28
39
|
/**
|
|
29
40
|
* Error linked to the media Playback.
|
|
30
41
|
*
|
|
@@ -36,6 +47,7 @@ export default class MediaError extends Error {
|
|
|
36
47
|
public readonly type: "MEDIA_ERROR";
|
|
37
48
|
public readonly code: IMediaErrorCode;
|
|
38
49
|
public readonly tracksInfo: ITaggedTrack[] | undefined;
|
|
50
|
+
public readonly timeInfo: ITimeInfo | undefined;
|
|
39
51
|
public fatal: boolean;
|
|
40
52
|
private _originalMessage: string;
|
|
41
53
|
|
|
@@ -52,13 +64,18 @@ export default class MediaError extends Error {
|
|
|
52
64
|
},
|
|
53
65
|
);
|
|
54
66
|
constructor(
|
|
55
|
-
code:
|
|
67
|
+
code: ICodeWithManifestPositionError,
|
|
68
|
+
reason: string,
|
|
69
|
+
context: {
|
|
70
|
+
timeInfo: ITimeInfo;
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
constructor(
|
|
74
|
+
code: Exclude<
|
|
75
|
+
IMediaErrorCode,
|
|
76
|
+
ICodeWithAdaptationType | ICodeWithManifestPositionError
|
|
77
|
+
>,
|
|
56
78
|
reason: string,
|
|
57
|
-
context?:
|
|
58
|
-
| {
|
|
59
|
-
tracks?: undefined;
|
|
60
|
-
}
|
|
61
|
-
| undefined,
|
|
62
79
|
);
|
|
63
80
|
constructor(
|
|
64
81
|
code: IMediaErrorCode,
|
|
@@ -66,6 +83,7 @@ export default class MediaError extends Error {
|
|
|
66
83
|
context?:
|
|
67
84
|
| {
|
|
68
85
|
tracks?: ITaggedTrack[] | undefined;
|
|
86
|
+
timeInfo?: ITimeInfo;
|
|
69
87
|
}
|
|
70
88
|
| undefined,
|
|
71
89
|
) {
|
|
@@ -82,6 +100,9 @@ export default class MediaError extends Error {
|
|
|
82
100
|
if (context?.tracks !== undefined && context?.tracks.length > 0) {
|
|
83
101
|
this.tracksInfo = context.tracks;
|
|
84
102
|
}
|
|
103
|
+
if (context?.timeInfo !== undefined) {
|
|
104
|
+
this.timeInfo = context.timeInfo;
|
|
105
|
+
}
|
|
85
106
|
}
|
|
86
107
|
|
|
87
108
|
/**
|
|
@@ -97,10 +118,44 @@ export default class MediaError extends Error {
|
|
|
97
118
|
code: this.code,
|
|
98
119
|
reason: this._originalMessage,
|
|
99
120
|
tracks: this.tracksInfo,
|
|
121
|
+
timeInfo: this.timeInfo,
|
|
100
122
|
};
|
|
101
123
|
}
|
|
102
124
|
}
|
|
103
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Re-create a `MediaError` from a serialized representation.
|
|
128
|
+
* @param {Object} serializedMediaError
|
|
129
|
+
* @returns {MediaError}
|
|
130
|
+
*/
|
|
131
|
+
export function deserializeMediaError(
|
|
132
|
+
serializedMediaError: ISerializedMediaError,
|
|
133
|
+
): MediaError {
|
|
134
|
+
if (
|
|
135
|
+
serializedMediaError.code === "MEDIA_TIME_BEFORE_MANIFEST" ||
|
|
136
|
+
serializedMediaError.code === "MEDIA_TIME_AFTER_MANIFEST"
|
|
137
|
+
) {
|
|
138
|
+
assert(
|
|
139
|
+
serializedMediaError.timeInfo !== undefined,
|
|
140
|
+
`The MediaError with code ${serializedMediaError.code} does not provide "timeinfo"`,
|
|
141
|
+
);
|
|
142
|
+
return new MediaError(serializedMediaError.code, serializedMediaError.reason, {
|
|
143
|
+
timeInfo: serializedMediaError.timeInfo,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
if (
|
|
147
|
+
serializedMediaError.code === "BUFFER_APPEND_ERROR" ||
|
|
148
|
+
serializedMediaError.code === "BUFFER_FULL_ERROR" ||
|
|
149
|
+
serializedMediaError.code === "NO_PLAYABLE_REPRESENTATION" ||
|
|
150
|
+
serializedMediaError.code === "MANIFEST_INCOMPATIBLE_CODECS_ERROR"
|
|
151
|
+
) {
|
|
152
|
+
return new MediaError(serializedMediaError.code, serializedMediaError.reason, {
|
|
153
|
+
tracks: serializedMediaError.tracks,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return new MediaError(serializedMediaError.code, serializedMediaError.reason);
|
|
157
|
+
}
|
|
158
|
+
|
|
104
159
|
/** Serializable object which allows to create a `MediaError` later. */
|
|
105
160
|
export interface ISerializedMediaError {
|
|
106
161
|
isSerializedError: true;
|
|
@@ -108,4 +163,5 @@ export interface ISerializedMediaError {
|
|
|
108
163
|
code: IMediaErrorCode;
|
|
109
164
|
reason: string;
|
|
110
165
|
tracks: ITaggedTrack[] | undefined;
|
|
166
|
+
timeInfo?: ITimeInfo | undefined;
|
|
111
167
|
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { describe, afterEach, it, expect, vi, beforeEach } from "vitest";
|
|
2
2
|
import probeHDCPPolicy from "../../probers/HDCPPolicy";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
type IRequestMediaKeySystemAccess =
|
|
5
|
+
| ((...args: unknown[]) => Promise<unknown>)
|
|
6
|
+
| undefined;
|
|
7
|
+
|
|
8
|
+
const compatEmeMock: {
|
|
9
|
+
default: { requestMediaKeySystemAccess: IRequestMediaKeySystemAccess };
|
|
10
|
+
} = vi.hoisted(() => {
|
|
5
11
|
return {
|
|
6
12
|
default: {
|
|
7
|
-
requestMediaKeySystemAccess: undefined
|
|
13
|
+
requestMediaKeySystemAccess: undefined,
|
|
8
14
|
},
|
|
9
15
|
};
|
|
10
16
|
});
|
package/src/experimental/tools/mediaCapabilitiesProber/probers/__tests__/defaultCodecsFinder.test.ts
CHANGED
|
@@ -4,10 +4,14 @@ import {
|
|
|
4
4
|
findDefaultAudioCodec,
|
|
5
5
|
} from "../../probers/defaultCodecsFinder";
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
type IMockedMediaSource = {
|
|
8
|
+
isTypeSupported?: ((codec: string) => boolean) | undefined;
|
|
9
|
+
} | null;
|
|
10
|
+
|
|
11
|
+
const mocks: { default: { MediaSource_: IMockedMediaSource } } = vi.hoisted(() => {
|
|
8
12
|
return {
|
|
9
13
|
default: {
|
|
10
|
-
MediaSource_: {}
|
|
14
|
+
MediaSource_: {},
|
|
11
15
|
},
|
|
12
16
|
};
|
|
13
17
|
});
|
package/src/experimental/tools/mediaCapabilitiesProber/probers/__tests__/mediaContentType.test.ts
CHANGED
|
@@ -2,10 +2,14 @@ import { describe, beforeEach, it, expect, vi, afterEach } from "vitest";
|
|
|
2
2
|
import probeMediaContentType from "../../probers/mediaContentType";
|
|
3
3
|
import type { IMediaConfiguration } from "../../types";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
type IMockedMediaSource = {
|
|
6
|
+
isTypeSupported?: ((codec: string) => boolean) | boolean | undefined;
|
|
7
|
+
} | null;
|
|
8
|
+
|
|
9
|
+
const mocks: { default: { MediaSource_: IMockedMediaSource } } = vi.hoisted(() => {
|
|
6
10
|
return {
|
|
7
11
|
default: {
|
|
8
|
-
MediaSource_: {}
|
|
12
|
+
MediaSource_: {},
|
|
9
13
|
},
|
|
10
14
|
};
|
|
11
15
|
});
|
|
@@ -83,6 +83,7 @@ export function filterConfigurationWithCapabilities(
|
|
|
83
83
|
}
|
|
84
84
|
)[capability] !== undefined
|
|
85
85
|
) {
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
86
87
|
(probedConfig as { [id: string]: string | IMediaConfiguration })[capability] = (
|
|
87
88
|
configuration as { [id: string]: string | IMediaConfiguration }
|
|
88
89
|
)[capability];
|
|
@@ -105,6 +106,7 @@ export function filterConfigurationWithCapabilities(
|
|
|
105
106
|
Object.keys((configuration as { [id: string]: IMediaConfiguration })[key])
|
|
106
107
|
.length === 0)
|
|
107
108
|
) {
|
|
109
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
108
110
|
(probedConfig as { [id: string]: IMediaConfiguration })[key] = subProbedConfig;
|
|
109
111
|
}
|
|
110
112
|
}
|
package/src/importable_worker.ts
CHANGED
|
@@ -63,6 +63,7 @@ export default class RxPlayerWorker<
|
|
|
63
63
|
globalScope.addEventListener("message", (evt: MessageEvent<IMainThreadMessage>) => {
|
|
64
64
|
if (evt.data.type === MainThreadMessageType.AppDefined) {
|
|
65
65
|
const { name, payload } = evt.data.value;
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
66
67
|
const listeners = this._messageListeners.get(name as keyof TReceivingEventRecord);
|
|
67
68
|
if (listeners === undefined) {
|
|
68
69
|
return;
|