rx-player 4.5.0-dev.2026012302 → 4.5.0-dev.2026021900
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/should_seek_at_zero.d.ts +12 -0
- package/dist/commonjs/compat/should_seek_at_zero.d.ts.map +1 -0
- package/dist/commonjs/compat/should_seek_at_zero.js +23 -0
- package/dist/commonjs/core/entry/FreezeResolver.js +2 -2
- package/dist/commonjs/core/entry/content_time_boundaries_observer.d.ts.map +1 -1
- package/dist/commonjs/core/entry/content_time_boundaries_observer.js +8 -0
- package/dist/commonjs/core/stream/representation/encryption_data_notifier.d.ts +70 -0
- package/dist/commonjs/core/stream/representation/encryption_data_notifier.d.ts.map +1 -0
- package/dist/commonjs/core/stream/representation/encryption_data_notifier.js +107 -0
- package/dist/commonjs/core/stream/representation/representation_stream.d.ts.map +1 -1
- package/dist/commonjs/core/stream/representation/representation_stream.js +12 -60
- package/dist/commonjs/core/stream/representation/utils/get_needed_segments.js +1 -1
- package/dist/commonjs/default_config.d.ts +5 -0
- package/dist/commonjs/default_config.d.ts.map +1 -1
- package/dist/commonjs/default_config.js +5 -0
- package/dist/commonjs/main_thread/api/public_api.d.ts.map +1 -1
- package/dist/commonjs/main_thread/api/public_api.js +27 -3
- package/dist/commonjs/main_thread/init/directfile_content_initializer.d.ts.map +1 -1
- package/dist/commonjs/main_thread/init/directfile_content_initializer.js +23 -1
- package/dist/commonjs/main_thread/init/utils/initial_seek_and_play.d.ts.map +1 -1
- package/dist/commonjs/main_thread/init/utils/initial_seek_and_play.js +3 -1
- package/dist/commonjs/manifest/classes/index.d.ts +2 -1
- package/dist/commonjs/manifest/classes/index.d.ts.map +1 -1
- package/dist/commonjs/manifest/classes/representation.d.ts +1 -1
- package/dist/commonjs/manifest/classes/representation.d.ts.map +1 -1
- package/dist/commonjs/manifest/classes/representation.js +2 -2
- package/dist/commonjs/manifest/classes/representation_index/types.d.ts +2 -2
- package/dist/commonjs/utils/base64.d.ts +15 -1
- package/dist/commonjs/utils/base64.d.ts.map +1 -1
- package/dist/commonjs/utils/base64.js +6 -0
- package/dist/commonjs/utils/ranges.d.ts +1 -1
- package/dist/commonjs/utils/ranges.js +1 -1
- 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/should_seek_at_zero.d.ts +12 -0
- package/dist/es2017/compat/should_seek_at_zero.d.ts.map +1 -0
- package/dist/es2017/compat/should_seek_at_zero.js +20 -0
- package/dist/es2017/core/entry/FreezeResolver.js +1 -1
- package/dist/es2017/core/entry/content_time_boundaries_observer.d.ts.map +1 -1
- package/dist/es2017/core/entry/content_time_boundaries_observer.js +8 -0
- package/dist/es2017/core/stream/representation/encryption_data_notifier.d.ts +70 -0
- package/dist/es2017/core/stream/representation/encryption_data_notifier.d.ts.map +1 -0
- package/dist/es2017/core/stream/representation/encryption_data_notifier.js +80 -0
- package/dist/es2017/core/stream/representation/representation_stream.d.ts.map +1 -1
- package/dist/es2017/core/stream/representation/representation_stream.js +10 -38
- package/dist/es2017/core/stream/representation/utils/get_needed_segments.js +1 -1
- package/dist/es2017/default_config.d.ts +5 -0
- package/dist/es2017/default_config.d.ts.map +1 -1
- package/dist/es2017/default_config.js +5 -0
- package/dist/es2017/main_thread/api/public_api.d.ts.map +1 -1
- package/dist/es2017/main_thread/api/public_api.js +27 -3
- package/dist/es2017/main_thread/init/directfile_content_initializer.d.ts.map +1 -1
- package/dist/es2017/main_thread/init/directfile_content_initializer.js +23 -1
- package/dist/es2017/main_thread/init/utils/initial_seek_and_play.d.ts.map +1 -1
- package/dist/es2017/main_thread/init/utils/initial_seek_and_play.js +3 -1
- package/dist/es2017/manifest/classes/index.d.ts +2 -1
- package/dist/es2017/manifest/classes/index.d.ts.map +1 -1
- package/dist/es2017/manifest/classes/representation.d.ts +1 -1
- package/dist/es2017/manifest/classes/representation.d.ts.map +1 -1
- package/dist/es2017/manifest/classes/representation.js +1 -1
- package/dist/es2017/manifest/classes/representation_index/types.d.ts +2 -2
- package/dist/es2017/utils/base64.d.ts +15 -1
- package/dist/es2017/utils/base64.d.ts.map +1 -1
- package/dist/es2017/utils/base64.js +6 -0
- package/dist/es2017/utils/ranges.d.ts +1 -1
- package/dist/es2017/utils/ranges.js +1 -1
- package/dist/mpd-parser.wasm +0 -0
- package/dist/worker.js +6 -6
- package/package.json +9 -3
- package/src/__GENERATED_CODE/embedded_dash_wasm.ts +1 -1
- package/src/__GENERATED_CODE/embedded_worker.ts +1 -1
- package/src/compat/should_seek_at_zero.ts +23 -0
- package/src/core/adaptive/__tests__/guess_based_chooser.test.ts +790 -0
- package/src/core/adaptive/__tests__/network_analyzer.test.ts +514 -0
- package/src/core/adaptive/utils/__tests__/pending_requests_store.test.ts +285 -0
- package/src/core/adaptive/utils/__tests__/representation_score_calculator.test.ts +247 -0
- package/src/core/entry/FreezeResolver.ts +1 -1
- package/src/core/entry/__tests__/FreezeResolver.test.ts +542 -0
- package/src/core/entry/__tests__/content_time_boundaries_observer.test.ts +868 -0
- package/src/core/entry/content_time_boundaries_observer.ts +10 -0
- package/src/core/stream/adaptation/__tests__/get_representations_switch_strategy.test.ts +592 -0
- package/src/core/stream/period/utils/__tests__/get_adaptation_switch_strategy.test.ts +646 -0
- package/src/core/stream/representation/__tests__/encryption_data_notifier.test.ts +531 -0
- package/src/core/stream/representation/encryption_data_notifier.ts +122 -0
- package/src/core/stream/representation/representation_stream.ts +11 -49
- package/src/core/stream/representation/utils/__tests__/append_segment_to_buffer.test.ts +321 -0
- package/src/core/stream/representation/utils/__tests__/check_for_discontinuity.test.ts +513 -0
- package/src/core/stream/representation/utils/__tests__/get_segment_priority.test.ts +132 -0
- package/src/core/stream/representation/utils/__tests__/push_init_segment.test.ts +209 -0
- package/src/core/stream/representation/utils/__tests__/push_media_segment.test.ts +343 -0
- package/src/core/stream/representation/utils/get_needed_segments.ts +1 -1
- package/src/default_config.ts +6 -0
- package/src/main_thread/api/public_api.ts +32 -3
- package/src/main_thread/init/directfile_content_initializer.ts +26 -1
- package/src/main_thread/init/utils/initial_seek_and_play.ts +5 -1
- package/src/manifest/classes/index.ts +2 -0
- package/src/manifest/classes/representation.ts +2 -1
- package/src/manifest/classes/representation_index/types.ts +2 -2
- package/src/utils/base64.ts +30 -1
- package/src/utils/ranges.ts +1 -1
|
@@ -33,6 +33,7 @@ import type {
|
|
|
33
33
|
IParsedInitSegmentPayload,
|
|
34
34
|
IParsedSegmentPayload,
|
|
35
35
|
} from "../../fetchers/segment/segment_queue";
|
|
36
|
+
import EncryptionDataNotifier from "./encryption_data_notifier";
|
|
36
37
|
import type {
|
|
37
38
|
IQueuedSegment,
|
|
38
39
|
IRepresentationStreamArguments,
|
|
@@ -125,33 +126,16 @@ export default function RepresentationStream<TSegmentDataType>(
|
|
|
125
126
|
initSegmentState.isLoaded = true;
|
|
126
127
|
}
|
|
127
128
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
*/
|
|
133
|
-
let hasSentEncryptionData = false;
|
|
134
|
-
|
|
135
|
-
// If the DRM system id is already known, and if we already have encryption data
|
|
136
|
-
// for it, we may not need to wait until the initialization segment is loaded to
|
|
137
|
-
// signal required protection data, thus performing License negotiations sooner
|
|
138
|
-
if (drmSystemId !== undefined) {
|
|
139
|
-
const encryptionData = representation.getEncryptionData(drmSystemId);
|
|
140
|
-
|
|
141
|
-
// If some key ids are not known yet, it may be safer to wait for this initialization
|
|
142
|
-
// segment to be loaded first
|
|
143
|
-
if (
|
|
144
|
-
encryptionData.length > 0 &&
|
|
145
|
-
encryptionData.every((e) => e.keyIds !== undefined)
|
|
146
|
-
) {
|
|
147
|
-
hasSentEncryptionData = true;
|
|
129
|
+
const drmNotifier = new EncryptionDataNotifier({
|
|
130
|
+
drmSystemId,
|
|
131
|
+
representation,
|
|
132
|
+
notify: (encryptionData) =>
|
|
148
133
|
callbacks.encryptionDataEncountered(
|
|
149
134
|
encryptionData.map((d) => objectAssign({ content }, d)),
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
135
|
+
),
|
|
136
|
+
});
|
|
137
|
+
if (canceller.isUsed()) {
|
|
138
|
+
return;
|
|
155
139
|
}
|
|
156
140
|
|
|
157
141
|
segmentQueue.addEventListener(
|
|
@@ -260,7 +244,7 @@ export default function RepresentationStream<TSegmentDataType>(
|
|
|
260
244
|
} else if (initSegmentState.isLoaded) {
|
|
261
245
|
log.warn(
|
|
262
246
|
"Stream",
|
|
263
|
-
"Uninitialized index with an already loaded
|
|
247
|
+
"Uninitialized index with an already loaded initialization segment",
|
|
264
248
|
{
|
|
265
249
|
bufferType,
|
|
266
250
|
representationBitrate: content.representation.bitrate,
|
|
@@ -369,29 +353,7 @@ export default function RepresentationStream<TSegmentDataType>(
|
|
|
369
353
|
| IParsedInitSegmentPayload<TSegmentDataType>
|
|
370
354
|
| IParsedSegmentPayload<TSegmentDataType>,
|
|
371
355
|
): void {
|
|
372
|
-
|
|
373
|
-
for (const protInfo of evt.protectionData) {
|
|
374
|
-
// TODO better handle use cases like key rotation by not always grouping
|
|
375
|
-
// every protection data together? To check.
|
|
376
|
-
representation.addProtectionData(
|
|
377
|
-
protInfo.initDataType,
|
|
378
|
-
protInfo.keyId,
|
|
379
|
-
protInfo.initData,
|
|
380
|
-
);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// Now that the initialization segment has been parsed - which may have
|
|
384
|
-
// included encryption information - take care of the encryption event
|
|
385
|
-
// if not already done.
|
|
386
|
-
if (!hasSentEncryptionData) {
|
|
387
|
-
const allEncryptionData = representation.getAllEncryptionData();
|
|
388
|
-
if (allEncryptionData.length > 0) {
|
|
389
|
-
callbacks.encryptionDataEncountered(
|
|
390
|
-
allEncryptionData.map((p) => objectAssign({ content }, p)),
|
|
391
|
-
);
|
|
392
|
-
hasSentEncryptionData = true;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
356
|
+
drmNotifier.onNewProtectionData(evt.protectionData);
|
|
395
357
|
|
|
396
358
|
if (evt.segmentType === "init") {
|
|
397
359
|
if (!representation.index.isInitialized() && evt.segmentList !== undefined) {
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { MediaError, SourceBufferError } from "../../../../../errors";
|
|
3
|
+
import SharedReference from "../../../../../utils/reference";
|
|
4
|
+
import TaskCanceller, { CancellationError } from "../../../../../utils/task_canceller";
|
|
5
|
+
import appendSegmentToBuffer from "../append_segment_to_buffer";
|
|
6
|
+
|
|
7
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
8
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
9
|
+
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
10
|
+
|
|
11
|
+
vi.mock("../../../../../log", () => ({
|
|
12
|
+
default: {
|
|
13
|
+
debug: vi.fn(),
|
|
14
|
+
warn: vi.fn(),
|
|
15
|
+
},
|
|
16
|
+
}));
|
|
17
|
+
vi.mock("../../../../../utils/sleep", () => ({
|
|
18
|
+
default: vi.fn(() => Promise.resolve()),
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
describe("appendSegmentToBuffer", () => {
|
|
22
|
+
let mockPlaybackObserver: any;
|
|
23
|
+
let mockSegmentSink: any;
|
|
24
|
+
let mockDataInfos: any;
|
|
25
|
+
let mockBufferGoal: SharedReference<number>;
|
|
26
|
+
let mockTaskCanceller = new TaskCanceller("test canceller");
|
|
27
|
+
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
mockPlaybackObserver = {
|
|
30
|
+
getReference: vi.fn(
|
|
31
|
+
() =>
|
|
32
|
+
new SharedReference({
|
|
33
|
+
position: {
|
|
34
|
+
getWanted: () => 10,
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
),
|
|
38
|
+
};
|
|
39
|
+
mockSegmentSink = {
|
|
40
|
+
pushChunk: vi.fn(() => Promise.resolve([{ start: 0, end: 10 }])),
|
|
41
|
+
removeBuffer: vi.fn(() => Promise.resolve(undefined)),
|
|
42
|
+
};
|
|
43
|
+
mockDataInfos = {
|
|
44
|
+
inventoryInfos: {
|
|
45
|
+
adaptation: { id: "test-adaptation", type: "video", representations: [] },
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
mockBufferGoal = new SharedReference(30);
|
|
49
|
+
mockTaskCanceller.cancel("test end");
|
|
50
|
+
mockTaskCanceller = new TaskCanceller("test canceller");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
afterEach(() => {
|
|
54
|
+
vi.clearAllMocks();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe("successful append", () => {
|
|
58
|
+
it("should push chunk successfully on first try", async () => {
|
|
59
|
+
const result = await appendSegmentToBuffer(
|
|
60
|
+
mockPlaybackObserver,
|
|
61
|
+
mockSegmentSink,
|
|
62
|
+
mockDataInfos,
|
|
63
|
+
mockBufferGoal,
|
|
64
|
+
mockTaskCanceller.signal,
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
expect(mockSegmentSink.pushChunk).toHaveBeenCalledTimes(1);
|
|
68
|
+
expect(mockSegmentSink.pushChunk).toHaveBeenCalledWith(mockDataInfos);
|
|
69
|
+
expect(result).toEqual([{ start: 0, end: 10 }]);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe("buffer full error handling", () => {
|
|
74
|
+
it("should run garbage collector and retry on buffer full error", async () => {
|
|
75
|
+
const bufferFullError = new SourceBufferError(
|
|
76
|
+
"BUFFER_FULL",
|
|
77
|
+
"Buffer is full",
|
|
78
|
+
true,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
mockSegmentSink.pushChunk
|
|
82
|
+
.mockRejectedValueOnce(bufferFullError)
|
|
83
|
+
.mockResolvedValueOnce([{ start: 0, end: 10 }]);
|
|
84
|
+
|
|
85
|
+
const result = await appendSegmentToBuffer(
|
|
86
|
+
mockPlaybackObserver,
|
|
87
|
+
mockSegmentSink,
|
|
88
|
+
mockDataInfos,
|
|
89
|
+
mockBufferGoal,
|
|
90
|
+
mockTaskCanceller.signal,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
expect(mockSegmentSink.pushChunk).toHaveBeenCalledTimes(2);
|
|
94
|
+
expect(mockSegmentSink.removeBuffer).toHaveBeenCalledTimes(2);
|
|
95
|
+
expect(result).toEqual([{ start: 0, end: 10 }]);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should remove buffer before current position (start)", async () => {
|
|
99
|
+
const bufferFullError = new SourceBufferError(
|
|
100
|
+
"BUFFER_FULL",
|
|
101
|
+
"Buffer is full",
|
|
102
|
+
true,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
mockSegmentSink.pushChunk
|
|
106
|
+
.mockRejectedValueOnce(bufferFullError)
|
|
107
|
+
.mockResolvedValueOnce([{ start: 0, end: 10 }]);
|
|
108
|
+
|
|
109
|
+
await appendSegmentToBuffer(
|
|
110
|
+
mockPlaybackObserver,
|
|
111
|
+
mockSegmentSink,
|
|
112
|
+
mockDataInfos,
|
|
113
|
+
mockBufferGoal,
|
|
114
|
+
mockTaskCanceller.signal,
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
// Should remove from 0 to (currentPos - 5) = 5
|
|
118
|
+
expect(mockSegmentSink.removeBuffer).toHaveBeenCalledWith(0, 5);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("should remove buffer after buffer goal (end)", async () => {
|
|
122
|
+
const bufferFullError = new SourceBufferError(
|
|
123
|
+
"BUFFER_FULL",
|
|
124
|
+
"Buffer is full",
|
|
125
|
+
true,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
mockSegmentSink.pushChunk
|
|
129
|
+
.mockRejectedValueOnce(bufferFullError)
|
|
130
|
+
.mockResolvedValueOnce([{ start: 0, end: 10 }]);
|
|
131
|
+
|
|
132
|
+
mockBufferGoal.setValue(30);
|
|
133
|
+
|
|
134
|
+
await appendSegmentToBuffer(
|
|
135
|
+
mockPlaybackObserver,
|
|
136
|
+
mockSegmentSink,
|
|
137
|
+
mockDataInfos,
|
|
138
|
+
mockBufferGoal,
|
|
139
|
+
mockTaskCanceller.signal,
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
// Should remove from (currentPos + bufferGoal + 12) = 52 to MAX_VALUE
|
|
143
|
+
expect(mockSegmentSink.removeBuffer).toHaveBeenCalledWith(52, Number.MAX_VALUE);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("should not remove start buffer when position is < 5", async () => {
|
|
147
|
+
const bufferFullError = new SourceBufferError(
|
|
148
|
+
"BUFFER_FULL",
|
|
149
|
+
"Buffer is full",
|
|
150
|
+
true,
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
mockSegmentSink.pushChunk
|
|
154
|
+
.mockRejectedValueOnce(bufferFullError)
|
|
155
|
+
.mockResolvedValueOnce([{ start: 0, end: 10 }]);
|
|
156
|
+
|
|
157
|
+
mockPlaybackObserver.getReference.mockReturnValue(
|
|
158
|
+
new SharedReference({
|
|
159
|
+
position: {
|
|
160
|
+
getWanted: vi.fn(() => 3),
|
|
161
|
+
},
|
|
162
|
+
}),
|
|
163
|
+
);
|
|
164
|
+
await appendSegmentToBuffer(
|
|
165
|
+
mockPlaybackObserver,
|
|
166
|
+
mockSegmentSink,
|
|
167
|
+
mockDataInfos,
|
|
168
|
+
mockBufferGoal,
|
|
169
|
+
mockTaskCanceller.signal,
|
|
170
|
+
);
|
|
171
|
+
expect(mockSegmentSink.removeBuffer).toHaveBeenCalledWith(45, Number.MAX_VALUE);
|
|
172
|
+
|
|
173
|
+
// Should only be called once for the end buffer
|
|
174
|
+
expect(mockSegmentSink.removeBuffer).toHaveBeenCalledTimes(1);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("should throw BUFFER_FULL_ERROR if retry fails", async () => {
|
|
178
|
+
const bufferFullError = new SourceBufferError(
|
|
179
|
+
"BUFFER_FULL",
|
|
180
|
+
"Buffer is full",
|
|
181
|
+
true,
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
const retryError = new Error("Retry failed");
|
|
185
|
+
|
|
186
|
+
mockSegmentSink.pushChunk
|
|
187
|
+
.mockRejectedValueOnce(bufferFullError)
|
|
188
|
+
.mockRejectedValueOnce(retryError);
|
|
189
|
+
|
|
190
|
+
await expect(
|
|
191
|
+
appendSegmentToBuffer(
|
|
192
|
+
mockPlaybackObserver,
|
|
193
|
+
mockSegmentSink,
|
|
194
|
+
mockDataInfos,
|
|
195
|
+
mockBufferGoal,
|
|
196
|
+
mockTaskCanceller.signal,
|
|
197
|
+
),
|
|
198
|
+
).rejects.toThrow("BUFFER_FULL_ERROR");
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
describe("non-buffer-full errors", () => {
|
|
203
|
+
it("should throw BUFFER_APPEND_ERROR for non-buffer-full SourceBufferError", async () => {
|
|
204
|
+
const error = new SourceBufferError("SOME_ERROR", "Some error", false);
|
|
205
|
+
mockSegmentSink.pushChunk.mockRejectedValueOnce(error);
|
|
206
|
+
await expect(
|
|
207
|
+
appendSegmentToBuffer(
|
|
208
|
+
mockPlaybackObserver,
|
|
209
|
+
mockSegmentSink,
|
|
210
|
+
mockDataInfos,
|
|
211
|
+
mockBufferGoal,
|
|
212
|
+
mockTaskCanceller.signal,
|
|
213
|
+
),
|
|
214
|
+
).rejects.toThrow(
|
|
215
|
+
new MediaError("BUFFER_APPEND_ERROR", "SOME_ERROR: Some error", {
|
|
216
|
+
tracks: [
|
|
217
|
+
{
|
|
218
|
+
type: "video",
|
|
219
|
+
track: {
|
|
220
|
+
id: "test-adaptation",
|
|
221
|
+
representations: [],
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
}),
|
|
226
|
+
);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it("should throw BUFFER_APPEND_ERROR for generic Error", async () => {
|
|
230
|
+
const error = new Error("Generic error");
|
|
231
|
+
mockSegmentSink.pushChunk.mockRejectedValueOnce(error);
|
|
232
|
+
|
|
233
|
+
await expect(
|
|
234
|
+
appendSegmentToBuffer(
|
|
235
|
+
mockPlaybackObserver,
|
|
236
|
+
mockSegmentSink,
|
|
237
|
+
mockDataInfos,
|
|
238
|
+
mockBufferGoal,
|
|
239
|
+
mockTaskCanceller.signal,
|
|
240
|
+
),
|
|
241
|
+
).rejects.toThrow(MediaError);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it("should throw BUFFER_APPEND_ERROR for unknown error type", async () => {
|
|
245
|
+
mockSegmentSink.pushChunk.mockRejectedValueOnce("string error");
|
|
246
|
+
|
|
247
|
+
await expect(
|
|
248
|
+
appendSegmentToBuffer(
|
|
249
|
+
mockPlaybackObserver,
|
|
250
|
+
mockSegmentSink,
|
|
251
|
+
mockDataInfos,
|
|
252
|
+
mockBufferGoal,
|
|
253
|
+
mockTaskCanceller.signal,
|
|
254
|
+
),
|
|
255
|
+
).rejects.toThrow(MediaError);
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
describe("cancellation handling", () => {
|
|
260
|
+
it("should throw CancellationError on initial pushChunk if cancelled", async () => {
|
|
261
|
+
const cancellationError = new CancellationError("Test", "test");
|
|
262
|
+
mockTaskCanceller.cancel("test cancellation");
|
|
263
|
+
mockSegmentSink.pushChunk.mockRejectedValueOnce(cancellationError);
|
|
264
|
+
|
|
265
|
+
await expect(
|
|
266
|
+
appendSegmentToBuffer(
|
|
267
|
+
mockPlaybackObserver,
|
|
268
|
+
mockSegmentSink,
|
|
269
|
+
mockDataInfos,
|
|
270
|
+
mockBufferGoal,
|
|
271
|
+
mockTaskCanceller.signal,
|
|
272
|
+
),
|
|
273
|
+
).rejects.toThrow(CancellationError);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it("should throw CancellationError during retry if cancelled", async () => {
|
|
277
|
+
const bufferFullError = new SourceBufferError(
|
|
278
|
+
"BUFFER_FULL",
|
|
279
|
+
"Buffer is full",
|
|
280
|
+
true,
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
mockSegmentSink.pushChunk.mockRejectedValueOnce(bufferFullError);
|
|
284
|
+
mockTaskCanceller.cancel("test 523");
|
|
285
|
+
|
|
286
|
+
await expect(
|
|
287
|
+
appendSegmentToBuffer(
|
|
288
|
+
mockPlaybackObserver,
|
|
289
|
+
mockSegmentSink,
|
|
290
|
+
mockDataInfos,
|
|
291
|
+
mockBufferGoal,
|
|
292
|
+
mockTaskCanceller.signal,
|
|
293
|
+
),
|
|
294
|
+
).rejects.toThrow(CancellationError);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it("should throw CancellationError if retry pushChunk is cancelled", async () => {
|
|
298
|
+
const bufferFullError = new SourceBufferError(
|
|
299
|
+
"BUFFER_FULL",
|
|
300
|
+
"Buffer is full",
|
|
301
|
+
true,
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
const cancellationError = new CancellationError("Test", "test");
|
|
305
|
+
|
|
306
|
+
mockSegmentSink.pushChunk
|
|
307
|
+
.mockRejectedValueOnce(bufferFullError)
|
|
308
|
+
.mockRejectedValueOnce(cancellationError);
|
|
309
|
+
|
|
310
|
+
await expect(
|
|
311
|
+
appendSegmentToBuffer(
|
|
312
|
+
mockPlaybackObserver,
|
|
313
|
+
mockSegmentSink,
|
|
314
|
+
mockDataInfos,
|
|
315
|
+
mockBufferGoal,
|
|
316
|
+
mockTaskCanceller.signal,
|
|
317
|
+
),
|
|
318
|
+
).rejects.toThrow(CancellationError);
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
});
|