rx-player 4.5.0-dev.2026041501 → 4.5.0-dev.2026043000
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 +4 -1
- package/VERSION +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/core/entry/content_time_boundaries_observer.d.ts.map +1 -1
- package/dist/commonjs/core/entry/content_time_boundaries_observer.js +18 -4
- 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/main_thread/api/public_api.js +2 -2
- 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 +1 -4
- 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/core/entry/content_time_boundaries_observer.d.ts.map +1 -1
- package/dist/es2017/core/entry/content_time_boundaries_observer.js +18 -4
- 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/main_thread/api/public_api.js +2 -2
- 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 +2 -5
- package/dist/worker.js +5 -5
- package/package.json +2 -2
- package/src/__GENERATED_CODE/embedded_worker.ts +1 -1
- package/src/core/entry/__tests__/content_time_boundaries_observer.test.ts +5 -0
- package/src/core/entry/content_time_boundaries_observer.ts +18 -4
- 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/main_thread/api/public_api.ts +2 -2
- package/src/main_thread/init/media_source_content_initializer.ts +3 -5
|
@@ -143,6 +143,11 @@ 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
|
+
});
|
|
146
151
|
});
|
|
147
152
|
|
|
148
153
|
it("should trigger warning when position is after manifest maximum", async () => {
|
|
@@ -113,20 +113,34 @@ export default class ContentTimeBoundariesObserver extends EventEmitter<IContent
|
|
|
113
113
|
playbackObserver.listen(
|
|
114
114
|
({ position }) => {
|
|
115
115
|
const wantedPosition = position.getWanted();
|
|
116
|
-
|
|
116
|
+
const minimumPosition = manifest.getMinimumSafePosition();
|
|
117
|
+
const maximumPosition = maximumPositionCalculator.getMaximumAvailablePosition();
|
|
118
|
+
if (wantedPosition < minimumPosition) {
|
|
117
119
|
const warning = new MediaError(
|
|
118
120
|
"MEDIA_TIME_BEFORE_MANIFEST",
|
|
119
121
|
"The current position is behind the " +
|
|
120
122
|
"earliest time announced in the Manifest.",
|
|
123
|
+
{
|
|
124
|
+
timeInfo: {
|
|
125
|
+
position: wantedPosition,
|
|
126
|
+
minPosition: minimumPosition,
|
|
127
|
+
maxPosition: maximumPosition,
|
|
128
|
+
},
|
|
129
|
+
},
|
|
121
130
|
);
|
|
122
131
|
this.trigger("warning", warning);
|
|
123
|
-
} else if (
|
|
124
|
-
wantedPosition > maximumPositionCalculator.getMaximumAvailablePosition()
|
|
125
|
-
) {
|
|
132
|
+
} else if (wantedPosition > maximumPosition) {
|
|
126
133
|
const warning = new MediaError(
|
|
127
134
|
"MEDIA_TIME_AFTER_MANIFEST",
|
|
128
135
|
"The current position is after the latest " +
|
|
129
136
|
"time announced in the Manifest.",
|
|
137
|
+
{
|
|
138
|
+
timeInfo: {
|
|
139
|
+
position: wantedPosition,
|
|
140
|
+
minPosition: minimumPosition,
|
|
141
|
+
maxPosition: maximumPosition,
|
|
142
|
+
},
|
|
143
|
+
},
|
|
130
144
|
);
|
|
131
145
|
this.trigger("warning", warning);
|
|
132
146
|
}
|
|
@@ -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
|
}
|
|
@@ -437,7 +437,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
437
437
|
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1194624
|
|
438
438
|
videoElement.preload = "auto";
|
|
439
439
|
|
|
440
|
-
this.version = /* PLAYER_VERSION */ "4.5.0-dev.
|
|
440
|
+
this.version = /* PLAYER_VERSION */ "4.5.0-dev.2026043000";
|
|
441
441
|
this.log = log;
|
|
442
442
|
this.state = "STOPPED";
|
|
443
443
|
this.videoElement = videoElement;
|
|
@@ -3837,7 +3837,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
3837
3837
|
return true;
|
|
3838
3838
|
}
|
|
3839
3839
|
}
|
|
3840
|
-
Player.version = /* PLAYER_VERSION */ "4.5.0-dev.
|
|
3840
|
+
Player.version = /* PLAYER_VERSION */ "4.5.0-dev.2026043000";
|
|
3841
3841
|
|
|
3842
3842
|
/** Every events sent by the RxPlayer's public API. */
|
|
3843
3843
|
interface IPublicAPIEvent {
|
|
@@ -15,9 +15,10 @@ import type {
|
|
|
15
15
|
ISentLogValue,
|
|
16
16
|
} from "../../core/types";
|
|
17
17
|
import { CoreMessageType } from "../../core/types";
|
|
18
|
+
import type { MediaError } from "../../errors";
|
|
18
19
|
import {
|
|
20
|
+
deserializeMediaError,
|
|
19
21
|
EncryptedMediaError,
|
|
20
|
-
MediaError,
|
|
21
22
|
NetworkError,
|
|
22
23
|
OtherError,
|
|
23
24
|
SourceBufferError,
|
|
@@ -2292,10 +2293,7 @@ function formatCoreError(sentError: ISentError): IPlayerError {
|
|
|
2292
2293
|
),
|
|
2293
2294
|
);
|
|
2294
2295
|
case "MediaError":
|
|
2295
|
-
|
|
2296
|
-
return new MediaError(sentError.code as any, sentError.reason, {
|
|
2297
|
-
tracks: sentError.tracks,
|
|
2298
|
-
});
|
|
2296
|
+
return deserializeMediaError(sentError);
|
|
2299
2297
|
case "EncryptedMediaError":
|
|
2300
2298
|
// We assume that everything have already been checked Worker-side here
|
|
2301
2299
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|