rx-player 3.29.0-dev.2022090500 → 3.29.0-dev.2022091600
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 +5 -1
- package/VERSION +1 -1
- package/dist/_esm5.processed/core/api/option_utils.js +7 -11
- package/dist/_esm5.processed/core/api/public_api.d.ts +4 -4
- package/dist/_esm5.processed/core/api/public_api.js +18 -19
- package/dist/_esm5.processed/core/api/{media_element_track_choice_manager.d.ts → tracks_management/media_element_track_choice_manager.d.ts} +2 -2
- package/dist/_esm5.processed/core/api/{media_element_track_choice_manager.js → tracks_management/media_element_track_choice_manager.js} +7 -4
- package/dist/_esm5.processed/core/api/{track_choice_manager.d.ts → tracks_management/track_choice_manager.d.ts} +2 -2
- package/dist/_esm5.processed/core/api/{track_choice_manager.js → tracks_management/track_choice_manager.js} +7 -7
- package/dist/_esm5.processed/core/api/{emit_seek_events.d.ts → utils.d.ts} +24 -1
- package/dist/_esm5.processed/core/api/{emit_seek_events.js → utils.js} +32 -1
- package/dist/_esm5.processed/core/decrypt/content_decryptor.d.ts +26 -0
- package/dist/_esm5.processed/core/decrypt/content_decryptor.js +101 -9
- package/dist/_esm5.processed/core/decrypt/session_events_listener.d.ts +15 -18
- package/dist/_esm5.processed/core/decrypt/session_events_listener.js +9 -7
- package/dist/_esm5.processed/core/decrypt/utils/check_key_statuses.d.ts +19 -22
- package/dist/_esm5.processed/core/decrypt/utils/check_key_statuses.js +87 -16
- package/dist/_esm5.processed/core/decrypt/utils/persistent_sessions_store.d.ts +1 -2
- package/dist/_esm5.processed/core/decrypt/utils/persistent_sessions_store.js +1 -2
- package/dist/_esm5.processed/core/fetchers/index.d.ts +2 -2
- package/dist/_esm5.processed/core/fetchers/segment/index.d.ts +2 -3
- package/dist/_esm5.processed/core/fetchers/segment/prioritized_segment_fetcher.d.ts +9 -9
- package/dist/_esm5.processed/core/fetchers/segment/prioritized_segment_fetcher.js +17 -15
- package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.d.ts +33 -40
- package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.js +156 -153
- package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher_creator.d.ts +3 -3
- package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher_creator.js +2 -2
- package/dist/_esm5.processed/core/fetchers/segment/task_prioritizer.d.ts +145 -0
- package/dist/_esm5.processed/core/fetchers/segment/task_prioritizer.js +325 -0
- package/dist/_esm5.processed/core/fetchers/utils/try_urls_with_backoff.d.ts +2 -2
- package/dist/_esm5.processed/core/fetchers/utils/try_urls_with_backoff.js +3 -3
- package/dist/_esm5.processed/core/init/create_media_source.d.ts +10 -0
- package/dist/_esm5.processed/core/init/create_media_source.js +1 -1
- package/dist/_esm5.processed/core/init/stall_avoider.d.ts +2 -1
- package/dist/_esm5.processed/core/init/stall_avoider.js +2 -1
- package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.js +1 -1
- package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.js +3 -3
- package/dist/_esm5.processed/core/segment_buffers/implementations/types.d.ts +6 -2
- package/dist/_esm5.processed/core/stream/orchestrator/{get_blacklisted_ranges.d.ts → get_time_ranges_for_content.d.ts} +1 -1
- package/dist/_esm5.processed/core/stream/orchestrator/{get_blacklisted_ranges.js → get_time_ranges_for_content.js} +1 -1
- package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +61 -19
- package/dist/_esm5.processed/core/stream/representation/downloading_queue.d.ts +8 -4
- package/dist/_esm5.processed/core/stream/representation/downloading_queue.js +200 -83
- package/dist/_esm5.processed/core/stream/types.d.ts +3 -1
- package/dist/_esm5.processed/errors/encrypted_media_error.d.ts +6 -1
- package/dist/_esm5.processed/errors/encrypted_media_error.js +4 -5
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/index.d.ts +1 -1
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/index.js +1 -1
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.d.ts +26 -0
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.js +60 -0
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.d.ts +6 -5
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.js +40 -9
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/remove_buffer_around_time.d.ts +3 -2
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/remove_buffer_around_time.js +7 -14
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/types.d.ts +1 -1
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/{thumbnail_loader.d.ts → video_thumbnail_loader.d.ts} +1 -13
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.js +331 -0
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader_error.d.ts +1 -2
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader_error.js +1 -2
- package/dist/_esm5.processed/features/initialize_features.js +2 -1
- package/dist/_esm5.processed/features/list/directfile.js +1 -1
- package/dist/_esm5.processed/features/types.d.ts +1 -1
- package/dist/_esm5.processed/manifest/index.d.ts +2 -2
- package/dist/_esm5.processed/public_types.d.ts +47 -0
- package/dist/_esm5.processed/utils/reference.d.ts +23 -3
- package/dist/_esm5.processed/utils/reference.js +23 -2
- package/dist/rx-player.js +1253 -1014
- package/dist/rx-player.min.js +1 -1
- package/package.json +1 -1
- package/sonar-project.properties +1 -1
- package/src/core/api/README.md +1 -1
- package/src/core/api/__tests__/{get_player_state.test.ts → utils.test.ts} +1 -1
- package/src/core/api/option_utils.ts +1 -5
- package/src/core/api/public_api.ts +15 -13
- package/src/core/api/{__tests__ → tracks_management/__tests__}/media_element_track_choice_manager.test.ts +0 -0
- package/src/core/api/{media_element_track_choice_manager.ts → tracks_management/media_element_track_choice_manager.ts} +10 -7
- package/src/core/api/{track_choice_manager.ts → tracks_management/track_choice_manager.ts} +9 -9
- package/src/core/api/{get_player_state.ts → utils.ts} +62 -11
- package/src/core/decrypt/content_decryptor.ts +112 -13
- package/src/core/decrypt/session_events_listener.ts +34 -30
- package/src/core/decrypt/utils/check_key_statuses.ts +89 -45
- package/src/core/decrypt/utils/persistent_sessions_store.ts +1 -2
- package/src/core/fetchers/index.ts +0 -12
- package/src/core/fetchers/segment/__tests__/task_prioritizer.test.ts +763 -0
- package/src/core/fetchers/segment/index.ts +0 -12
- package/src/core/fetchers/segment/prioritized_segment_fetcher.ts +40 -47
- package/src/core/fetchers/segment/segment_fetcher.ts +249 -268
- package/src/core/fetchers/segment/segment_fetcher_creator.ts +6 -7
- package/src/core/fetchers/segment/task_prioritizer.ts +460 -0
- package/src/core/fetchers/utils/try_urls_with_backoff.ts +3 -3
- package/src/core/init/create_media_source.ts +1 -1
- package/src/core/init/stall_avoider.ts +2 -1
- package/src/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.ts +1 -1
- package/src/core/segment_buffers/implementations/text/html/html_text_segment_buffer.ts +3 -3
- package/src/core/segment_buffers/implementations/types.ts +6 -2
- package/src/core/stream/orchestrator/{get_blacklisted_ranges.ts → get_time_ranges_for_content.ts} +1 -1
- package/src/core/stream/orchestrator/stream_orchestrator.ts +115 -56
- package/src/core/stream/representation/downloading_queue.ts +269 -142
- package/src/core/stream/types.ts +3 -1
- package/src/errors/encrypted_media_error.ts +20 -1
- package/src/experimental/tools/VideoThumbnailLoader/index.ts +1 -1
- package/src/experimental/tools/VideoThumbnailLoader/load_and_push_segment.ts +74 -0
- package/src/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.ts +50 -16
- package/src/experimental/tools/VideoThumbnailLoader/remove_buffer_around_time.ts +14 -21
- package/src/experimental/tools/VideoThumbnailLoader/types.ts +7 -4
- package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.ts +407 -0
- package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader_error.ts +1 -2
- package/src/features/__tests__/initialize_features.test.ts +3 -1
- package/src/features/initialize_features.ts +2 -1
- package/src/features/list/__tests__/directfile.test.ts +1 -1
- package/src/features/list/directfile.ts +1 -1
- package/src/features/types.ts +1 -1
- package/src/manifest/index.ts +2 -0
- package/src/public_types.ts +53 -0
- package/src/utils/reference.ts +58 -4
- package/dist/_esm5.processed/core/api/get_player_state.d.ts +0 -28
- package/dist/_esm5.processed/core/api/get_player_state.js +0 -56
- package/dist/_esm5.processed/core/fetchers/segment/prioritizer.d.ts +0 -232
- package/dist/_esm5.processed/core/fetchers/segment/prioritizer.js +0 -422
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/create_request.d.ts +0 -29
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/create_request.js +0 -68
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/get_complete_segment_id.d.ts +0 -24
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/get_complete_segment_id.js +0 -29
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/get_content_infos.d.ts +0 -25
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/get_content_infos.js +0 -40
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/get_initialized_source_buffer.d.ts +0 -33
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/get_initialized_source_buffer.js +0 -124
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_segments.d.ts +0 -17
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_segments.js +0 -41
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/push_data.d.ts +0 -22
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/push_data.js +0 -21
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/thumbnail_loader.js +0 -212
- package/src/core/api/emit_seek_events.ts +0 -66
- package/src/core/fetchers/segment/__tests__/prioritizer.test.ts +0 -962
- package/src/core/fetchers/segment/prioritizer.ts +0 -558
- package/src/experimental/tools/VideoThumbnailLoader/create_request.ts +0 -113
- package/src/experimental/tools/VideoThumbnailLoader/get_complete_segment_id.ts +0 -34
- package/src/experimental/tools/VideoThumbnailLoader/get_content_infos.ts +0 -48
- package/src/experimental/tools/VideoThumbnailLoader/get_initialized_source_buffer.ts +0 -171
- package/src/experimental/tools/VideoThumbnailLoader/load_segments.ts +0 -69
- package/src/experimental/tools/VideoThumbnailLoader/push_data.ts +0 -48
- package/src/experimental/tools/VideoThumbnailLoader/thumbnail_loader.ts +0 -311
|
@@ -13,12 +13,11 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import { map, } from "rxjs";
|
|
17
16
|
import log from "../../../log";
|
|
18
17
|
/**
|
|
19
18
|
* This function basically put in relation:
|
|
20
19
|
* - an `ISegmentFetcher`, which will be used to perform the segment requests
|
|
21
|
-
* - a
|
|
20
|
+
* - a `TaskPrioritizer`, which will handle the priority of a segment request
|
|
22
21
|
*
|
|
23
22
|
* and returns functions to fetch segments with a given priority.
|
|
24
23
|
* @param {Object} prioritizer
|
|
@@ -26,7 +25,11 @@ import log from "../../../log";
|
|
|
26
25
|
* @returns {Object}
|
|
27
26
|
*/
|
|
28
27
|
export default function applyPrioritizerToSegmentFetcher(prioritizer, fetcher) {
|
|
29
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Map Promises returned by the `createRequest` method into the actual tasks
|
|
30
|
+
* used by the `TaskPrioritizer`, allowing to update task priorities just by
|
|
31
|
+
* using the Promise.
|
|
32
|
+
*/
|
|
30
33
|
var taskHandlers = new WeakMap();
|
|
31
34
|
return {
|
|
32
35
|
/**
|
|
@@ -34,26 +37,25 @@ export default function applyPrioritizerToSegmentFetcher(prioritizer, fetcher) {
|
|
|
34
37
|
* @param {Object} content - content to request
|
|
35
38
|
* @param {Number} priority - priority at which the content should be requested.
|
|
36
39
|
* Lower number == higher priority.
|
|
37
|
-
* @returns {
|
|
40
|
+
* @returns {Promise}
|
|
38
41
|
*/
|
|
39
|
-
createRequest: function (content, priority) {
|
|
42
|
+
createRequest: function (content, priority, callbacks, cancelSignal) {
|
|
40
43
|
if (priority === void 0) { priority = 0; }
|
|
41
|
-
var
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return flattenTask;
|
|
44
|
+
var givenTask = function (innerCancelSignal) {
|
|
45
|
+
return fetcher(content, callbacks, innerCancelSignal);
|
|
46
|
+
};
|
|
47
|
+
var ret = prioritizer.create(givenTask, priority, callbacks, cancelSignal);
|
|
48
|
+
taskHandlers.set(ret, givenTask);
|
|
49
|
+
return ret;
|
|
48
50
|
},
|
|
49
51
|
/**
|
|
50
52
|
* Update the priority of a pending request, created through
|
|
51
53
|
* `createRequest`.
|
|
52
|
-
* @param {
|
|
54
|
+
* @param {Promise} task - The Promise returned by `createRequest`.
|
|
53
55
|
* @param {Number} priority - The new priority value.
|
|
54
56
|
*/
|
|
55
|
-
updatePriority: function (
|
|
56
|
-
var correspondingTask = taskHandlers.get(
|
|
57
|
+
updatePriority: function (task, priority) {
|
|
58
|
+
var correspondingTask = taskHandlers.get(task);
|
|
57
59
|
if (correspondingTask === undefined) {
|
|
58
60
|
log.warn("Fetchers: Cannot update the priority of a request: task not found.");
|
|
59
61
|
return;
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import { Observable } from "rxjs";
|
|
17
16
|
import Manifest, { Adaptation, ISegment, Period, Representation } from "../../../manifest";
|
|
18
17
|
import { IPlayerError } from "../../../public_types";
|
|
19
18
|
import { ISegmentParserParsedInitChunk, ISegmentParserParsedMediaChunk, ISegmentPipeline } from "../../../transports";
|
|
19
|
+
import { CancellationSignal } from "../../../utils/task_canceller";
|
|
20
20
|
import { IMetricsCallbackPayload, IRequestBeginCallbackPayload, IRequestEndCallbackPayload, IRequestProgressCallbackPayload } from "../../adaptive";
|
|
21
21
|
import { IBufferType } from "../../segment_buffers";
|
|
22
22
|
/**
|
|
@@ -27,40 +27,42 @@ import { IBufferType } from "../../segment_buffers";
|
|
|
27
27
|
*
|
|
28
28
|
* @param {string} bufferType
|
|
29
29
|
* @param {Object} pipeline
|
|
30
|
-
* @param {Object}
|
|
30
|
+
* @param {Object} lifecycleCallbacks
|
|
31
31
|
* @param {Object} options
|
|
32
32
|
* @returns {Function}
|
|
33
33
|
*/
|
|
34
|
-
export default function createSegmentFetcher<TLoadedFormat, TSegmentDataType>(bufferType: IBufferType, pipeline: ISegmentPipeline<TLoadedFormat, TSegmentDataType>,
|
|
35
|
-
export declare type ISegmentFetcher<TSegmentDataType> = (content: ISegmentLoaderContent) => Observable<ISegmentFetcherEvent<TSegmentDataType>>;
|
|
36
|
-
/** Event sent by the SegmentFetcher when fetching a segment. */
|
|
37
|
-
export declare type ISegmentFetcherEvent<TSegmentDataType> = ISegmentFetcherChunkEvent<TSegmentDataType> | ISegmentFetcherChunkCompleteEvent | ISegmentFetcherRetry;
|
|
34
|
+
export default function createSegmentFetcher<TLoadedFormat, TSegmentDataType>(bufferType: IBufferType, pipeline: ISegmentPipeline<TLoadedFormat, TSegmentDataType>, lifecycleCallbacks: ISegmentFetcherLifecycleCallbacks, options: ISegmentFetcherOptions): ISegmentFetcher<TSegmentDataType>;
|
|
38
35
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
36
|
+
* Defines the `ISegmentFetcher` function which allows to load a single segment.
|
|
37
|
+
*
|
|
38
|
+
* Loaded data is entirely communicated through callbacks present in the
|
|
39
|
+
* `callbacks` arguments.
|
|
40
|
+
*
|
|
41
|
+
* The returned Promise only gives an indication of if the request ended with
|
|
42
|
+
* success or on error.
|
|
41
43
|
*/
|
|
42
|
-
export
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
* parsing an initialization segment from the same Representation.
|
|
50
|
-
* Can be left to `undefined` if unknown or inexistant, segment parsers should
|
|
51
|
-
* be resilient and still work without that information.
|
|
52
|
-
*
|
|
53
|
-
* @param {number} initTimescale
|
|
54
|
-
* @returns {Object}
|
|
55
|
-
*/
|
|
56
|
-
parse(initTimescale?: number): ISegmentParserParsedInitChunk<TSegmentDataType> | ISegmentParserParsedMediaChunk<TSegmentDataType>;
|
|
57
|
-
}
|
|
44
|
+
export declare type ISegmentFetcher<TSegmentDataType> = (
|
|
45
|
+
/** Information on the segment wanted. */
|
|
46
|
+
content: ISegmentLoaderContent,
|
|
47
|
+
/** Callbacks the `ISegmentFetcher` will call as it loads the data. */
|
|
48
|
+
callbacks: ISegmentFetcherCallbacks<TSegmentDataType>,
|
|
49
|
+
/** CancellationSignal allowing to cancel the request. */
|
|
50
|
+
cancellationSignal: CancellationSignal) => Promise<void>;
|
|
58
51
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
52
|
+
* Callbacks given to an `ISegmentFetcher` allowing to be notified on its
|
|
53
|
+
* inner request's various events.
|
|
61
54
|
*/
|
|
62
|
-
export interface
|
|
63
|
-
|
|
55
|
+
export interface ISegmentFetcherCallbacks<TSegmentDataType> {
|
|
56
|
+
/** Called when a decodable chunk of the whole segment is available. */
|
|
57
|
+
onChunk(parse: (initTimescale: number | undefined) => ISegmentParserParsedInitChunk<TSegmentDataType> | ISegmentParserParsedMediaChunk<TSegmentDataType>): void;
|
|
58
|
+
/**
|
|
59
|
+
* Callback called when all decodable chunks of the loaded segment have been
|
|
60
|
+
* communicated through the `onChunk` callback.
|
|
61
|
+
*/
|
|
62
|
+
onAllChunksReceived(): void;
|
|
63
|
+
/**
|
|
64
|
+
* Callback called when the segment request has to restart from scratch. */
|
|
65
|
+
onRetry(error: IPlayerError): void;
|
|
64
66
|
}
|
|
65
67
|
/** Content used by the segment loader as a context to load a new segment. */
|
|
66
68
|
export interface ISegmentLoaderContent {
|
|
@@ -71,19 +73,10 @@ export interface ISegmentLoaderContent {
|
|
|
71
73
|
segment: ISegment;
|
|
72
74
|
}
|
|
73
75
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*/
|
|
77
|
-
export interface ISegmentFetcherRetry {
|
|
78
|
-
type: "retry";
|
|
79
|
-
value: IPlayerError;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Callbacks that can be bound when creating an `ISegmentFetcher`.
|
|
83
|
-
* Those allows to be notified of an `ISegmentFetcher` various lifecycles and of
|
|
84
|
-
* network information.
|
|
76
|
+
* Callbacks given when creating an `ISegmentFetcher`, allowing to be notified
|
|
77
|
+
* on high-level metadata about performed requests.
|
|
85
78
|
*/
|
|
86
|
-
export interface
|
|
79
|
+
export interface ISegmentFetcherLifecycleCallbacks {
|
|
87
80
|
/** Called when a segment request begins. */
|
|
88
81
|
onRequestBegin?: (arg: IRequestBeginCallbackPayload) => void;
|
|
89
82
|
/** Called when progress information is available on a pending segment request. */
|
|
@@ -13,7 +13,42 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
|
|
16
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
17
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
18
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
19
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
20
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
21
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
22
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
26
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
27
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
28
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
29
|
+
function step(op) {
|
|
30
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
31
|
+
while (_) try {
|
|
32
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
33
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
34
|
+
switch (op[0]) {
|
|
35
|
+
case 0: case 1: t = op; break;
|
|
36
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
37
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
38
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
39
|
+
default:
|
|
40
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
41
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
42
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
43
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
44
|
+
if (t[2]) _.ops.pop();
|
|
45
|
+
_.trys.pop(); continue;
|
|
46
|
+
}
|
|
47
|
+
op = body.call(thisArg, _);
|
|
48
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
49
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
50
|
+
}
|
|
51
|
+
};
|
|
17
52
|
import config from "../../../config";
|
|
18
53
|
import { formatError } from "../../../errors";
|
|
19
54
|
import log from "../../../log";
|
|
@@ -23,9 +58,10 @@ import idGenerator from "../../../utils/id_generator";
|
|
|
23
58
|
import InitializationSegmentCache from "../../../utils/initialization_segment_cache";
|
|
24
59
|
import isNullOrUndefined from "../../../utils/is_null_or_undefined";
|
|
25
60
|
import objectAssign from "../../../utils/object_assign";
|
|
26
|
-
import
|
|
61
|
+
import { CancellationError, } from "../../../utils/task_canceller";
|
|
27
62
|
import errorSelector from "../utils/error_selector";
|
|
28
63
|
import { tryURLsWithBackoff } from "../utils/try_urls_with_backoff";
|
|
64
|
+
/** Allows to generate a unique identifies for each request. */
|
|
29
65
|
var generateRequestID = idGenerator();
|
|
30
66
|
/**
|
|
31
67
|
* Create an `ISegmentFetcher` object which will allow to easily fetch and parse
|
|
@@ -35,11 +71,11 @@ var generateRequestID = idGenerator();
|
|
|
35
71
|
*
|
|
36
72
|
* @param {string} bufferType
|
|
37
73
|
* @param {Object} pipeline
|
|
38
|
-
* @param {Object}
|
|
74
|
+
* @param {Object} lifecycleCallbacks
|
|
39
75
|
* @param {Object} options
|
|
40
76
|
* @returns {Function}
|
|
41
77
|
*/
|
|
42
|
-
export default function createSegmentFetcher(bufferType, pipeline,
|
|
78
|
+
export default function createSegmentFetcher(bufferType, pipeline, lifecycleCallbacks, options) {
|
|
43
79
|
var requestOptions = {
|
|
44
80
|
timeout: options.requestTimeout < 0 ? undefined :
|
|
45
81
|
options.requestTimeout,
|
|
@@ -55,158 +91,20 @@ export default function createSegmentFetcher(bufferType, pipeline, callbacks, op
|
|
|
55
91
|
var loadSegment = pipeline.loadSegment, parseSegment = pipeline.parseSegment;
|
|
56
92
|
/**
|
|
57
93
|
* Fetch a specific segment.
|
|
58
|
-
*
|
|
59
|
-
* This function returns an Observable which will fetch segments on
|
|
60
|
-
* subscription.
|
|
61
|
-
* If the corresponding request fails, it may retry it based on the given
|
|
62
|
-
* options.
|
|
63
|
-
*
|
|
64
|
-
* This Observable will emit various events during that request lifecycle and
|
|
65
|
-
* throw if the segment request(s) (including potential retries) fail.
|
|
66
|
-
* The Observable will automatically complete once no events are left to be
|
|
67
|
-
* sent.
|
|
68
94
|
* @param {Object} content
|
|
69
|
-
* @
|
|
95
|
+
* @param {Object} fetcherCallbacks
|
|
96
|
+
* @param {Object} cancellationSignal
|
|
97
|
+
* @returns {Promise}
|
|
70
98
|
*/
|
|
71
|
-
return function fetchSegment(content) {
|
|
72
|
-
var
|
|
73
|
-
|
|
74
|
-
var segmentIdString = getLoggableSegmentId(content);
|
|
75
|
-
return new Observable(function (obs) {
|
|
76
|
-
var _a, _b;
|
|
77
|
-
var requestId = generateRequestID();
|
|
78
|
-
var canceller = new TaskCanceller();
|
|
79
|
-
/**
|
|
80
|
-
* If the request succeeded, set to the corresponding
|
|
81
|
-
* `IChunkCompleteInformation` object.
|
|
82
|
-
* For any other completion cases: if the request either failed, was
|
|
83
|
-
* cancelled or just if no request was needed, set to `null`.
|
|
84
|
-
*
|
|
85
|
-
* Stays to `undefined` when the request is still pending.
|
|
86
|
-
*/
|
|
87
|
-
var requestInfo;
|
|
88
|
-
/**
|
|
89
|
-
* Array containing one entry per loaded chunk, in chronological order.
|
|
90
|
-
* The boolean indicates if the chunk has been parsed at least once.
|
|
91
|
-
*
|
|
92
|
-
* This is used to know when all loaded chunks have been parsed, which
|
|
93
|
-
* can be useful to e.g. construct metrics about the loaded segment.
|
|
94
|
-
*/
|
|
95
|
-
var parsedChunks = [];
|
|
96
|
-
/**
|
|
97
|
-
* Addition of the duration of each encountered and parsed chunks.
|
|
98
|
-
* Allows to have an idea of the real duration of the full segment once
|
|
99
|
-
* all chunks have been parsed.
|
|
100
|
-
*
|
|
101
|
-
* `undefined` if at least one of the parsed chunks has unknown duration.
|
|
102
|
-
*/
|
|
103
|
-
var segmentDurationAcc = 0;
|
|
104
|
-
/** Set to `true` once network metrics have been sent. */
|
|
105
|
-
var metricsSent = false;
|
|
106
|
-
var loaderCallbacks = {
|
|
107
|
-
/**
|
|
108
|
-
* Callback called when the segment loader has progress information on
|
|
109
|
-
* the request.
|
|
110
|
-
* @param {Object} info
|
|
111
|
-
*/
|
|
112
|
-
onProgress: function (info) {
|
|
113
|
-
var _a;
|
|
114
|
-
if (requestInfo !== undefined) {
|
|
115
|
-
return; // Request already terminated
|
|
116
|
-
}
|
|
117
|
-
if (info.totalSize !== undefined && info.size < info.totalSize) {
|
|
118
|
-
(_a = callbacks.onProgress) === null || _a === void 0 ? void 0 : _a.call(callbacks, { duration: info.duration,
|
|
119
|
-
size: info.size,
|
|
120
|
-
totalSize: info.totalSize,
|
|
121
|
-
timestamp: performance.now(),
|
|
122
|
-
id: requestId });
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
/**
|
|
126
|
-
* Callback called when the segment is communicated by the loader
|
|
127
|
-
* through decodable sub-segment(s) called chunk(s), with a chunk in
|
|
128
|
-
* argument.
|
|
129
|
-
* @param {*} chunkData
|
|
130
|
-
*/
|
|
131
|
-
onNewChunk: function (chunkData) {
|
|
132
|
-
obs.next({ type: "chunk",
|
|
133
|
-
parse: generateParserFunction(chunkData, true) });
|
|
134
|
-
},
|
|
135
|
-
};
|
|
136
|
-
// Retrieve from cache if it exists
|
|
137
|
-
var cached = cache !== undefined ? cache.get(content) :
|
|
138
|
-
null;
|
|
139
|
-
if (cached !== null) {
|
|
140
|
-
log.debug("SF: Found wanted segment in cache", segmentIdString);
|
|
141
|
-
obs.next({ type: "chunk",
|
|
142
|
-
parse: generateParserFunction(cached, false) });
|
|
143
|
-
obs.next({ type: "chunk-complete" });
|
|
144
|
-
obs.complete();
|
|
145
|
-
return undefined;
|
|
146
|
-
}
|
|
147
|
-
log.debug("SF: Beginning request", segmentIdString);
|
|
148
|
-
(_a = callbacks.onRequestBegin) === null || _a === void 0 ? void 0 : _a.call(callbacks, { requestTimestamp: performance.now(),
|
|
149
|
-
id: requestId, content: content });
|
|
150
|
-
tryURLsWithBackoff((_b = segment.mediaURLs) !== null && _b !== void 0 ? _b : [null], callLoaderWithUrl, objectAssign({ onRetry: onRetry }, options), canceller.signal)
|
|
151
|
-
.then(function (res) {
|
|
152
|
-
var _a;
|
|
153
|
-
log.debug("SF: Segment request ended with success", segmentIdString);
|
|
154
|
-
if (res.resultType === "segment-loaded") {
|
|
155
|
-
var loadedData = res.resultData.responseData;
|
|
156
|
-
if (cache !== undefined) {
|
|
157
|
-
cache.add(content, res.resultData.responseData);
|
|
158
|
-
}
|
|
159
|
-
obs.next({ type: "chunk",
|
|
160
|
-
parse: generateParserFunction(loadedData, false) });
|
|
161
|
-
}
|
|
162
|
-
else if (res.resultType === "segment-created") {
|
|
163
|
-
obs.next({ type: "chunk",
|
|
164
|
-
parse: generateParserFunction(res.resultData, false) });
|
|
165
|
-
}
|
|
166
|
-
log.debug("SF: Segment request ended with success", segmentIdString);
|
|
167
|
-
obs.next({ type: "chunk-complete" });
|
|
168
|
-
if (res.resultType !== "segment-created") {
|
|
169
|
-
requestInfo = res.resultData;
|
|
170
|
-
sendNetworkMetricsIfAvailable();
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
requestInfo = null;
|
|
174
|
-
}
|
|
175
|
-
if (!canceller.isUsed) {
|
|
176
|
-
// The current Observable could have been canceled as a result of one
|
|
177
|
-
// of the previous `next` calls. In that case, we don't want to send
|
|
178
|
-
// a "requestEnd" again as it has already been sent on cancellation.
|
|
179
|
-
//
|
|
180
|
-
// Note that we only perform this check for `onRequestEnd` on
|
|
181
|
-
// purpose. Observable's events should have been ignored by RxJS if
|
|
182
|
-
// the Observable has already been canceled and we don't care if
|
|
183
|
-
// `"metrics"` is sent there.
|
|
184
|
-
(_a = callbacks.onRequestEnd) === null || _a === void 0 ? void 0 : _a.call(callbacks, { id: requestId });
|
|
185
|
-
}
|
|
186
|
-
obs.complete();
|
|
187
|
-
})
|
|
188
|
-
.catch(function (err) {
|
|
189
|
-
log.debug("SF: Segment request failed", segmentIdString);
|
|
190
|
-
requestInfo = null;
|
|
191
|
-
obs.error(errorSelector(err));
|
|
192
|
-
});
|
|
193
|
-
return function () {
|
|
194
|
-
var _a;
|
|
195
|
-
if (requestInfo !== undefined) {
|
|
196
|
-
return; // Request already terminated
|
|
197
|
-
}
|
|
198
|
-
log.debug("SF: Segment request cancelled", segmentIdString);
|
|
199
|
-
requestInfo = null;
|
|
200
|
-
canceller.cancel();
|
|
201
|
-
(_a = callbacks.onRequestEnd) === null || _a === void 0 ? void 0 : _a.call(callbacks, { id: requestId });
|
|
202
|
-
};
|
|
99
|
+
return function fetchSegment(content, fetcherCallbacks, cancellationSignal) {
|
|
100
|
+
var _a, _b, _c;
|
|
101
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
203
102
|
/**
|
|
204
103
|
* Call a segment loader for the given URL with the right arguments.
|
|
205
104
|
* @param {string|null} url
|
|
206
|
-
* @param {Object} cancellationSignal
|
|
207
105
|
* @returns {Promise}
|
|
208
106
|
*/
|
|
209
|
-
function callLoaderWithUrl(url
|
|
107
|
+
function callLoaderWithUrl(url) {
|
|
210
108
|
return loadSegment(url, content, requestOptions, cancellationSignal, loaderCallbacks);
|
|
211
109
|
}
|
|
212
110
|
/**
|
|
@@ -245,8 +143,7 @@ export default function createSegmentFetcher(bufferType, pipeline, callbacks, op
|
|
|
245
143
|
* @param {*} err
|
|
246
144
|
*/
|
|
247
145
|
function onRetry(err) {
|
|
248
|
-
|
|
249
|
-
value: errorSelector(err) });
|
|
146
|
+
fetcherCallbacks.onRetry(errorSelector(err));
|
|
250
147
|
}
|
|
251
148
|
/**
|
|
252
149
|
* Send netork metrics if they haven't yet been sent and if all data to
|
|
@@ -263,10 +160,116 @@ export default function createSegmentFetcher(bufferType, pipeline, callbacks, op
|
|
|
263
160
|
parsedChunks.length > 0 &&
|
|
264
161
|
parsedChunks.every(function (isParsed) { return isParsed; })) {
|
|
265
162
|
metricsSent = true;
|
|
266
|
-
(_a =
|
|
267
|
-
|
|
163
|
+
(_a = lifecycleCallbacks.onMetrics) === null || _a === void 0 ? void 0 : _a.call(lifecycleCallbacks, {
|
|
164
|
+
size: requestInfo.size,
|
|
165
|
+
requestDuration: requestInfo.requestDuration,
|
|
166
|
+
content: content,
|
|
167
|
+
segmentDuration: segmentDurationAcc,
|
|
168
|
+
});
|
|
268
169
|
}
|
|
269
170
|
}
|
|
171
|
+
var segment, segmentIdString, requestId, requestInfo, parsedChunks, segmentDurationAcc, metricsSent, loaderCallbacks, cached, res, loadedData, err_1;
|
|
172
|
+
return __generator(this, function (_d) {
|
|
173
|
+
switch (_d.label) {
|
|
174
|
+
case 0:
|
|
175
|
+
segment = content.segment;
|
|
176
|
+
segmentIdString = getLoggableSegmentId(content);
|
|
177
|
+
requestId = generateRequestID();
|
|
178
|
+
parsedChunks = [];
|
|
179
|
+
segmentDurationAcc = 0;
|
|
180
|
+
metricsSent = false;
|
|
181
|
+
loaderCallbacks = {
|
|
182
|
+
/**
|
|
183
|
+
* Callback called when the segment loader has progress information on
|
|
184
|
+
* the request.
|
|
185
|
+
* @param {Object} info
|
|
186
|
+
*/
|
|
187
|
+
onProgress: function (info) {
|
|
188
|
+
var _a;
|
|
189
|
+
if (requestInfo !== undefined) {
|
|
190
|
+
return; // request already termminated
|
|
191
|
+
}
|
|
192
|
+
if (info.totalSize !== undefined && info.size < info.totalSize) {
|
|
193
|
+
(_a = lifecycleCallbacks.onProgress) === null || _a === void 0 ? void 0 : _a.call(lifecycleCallbacks, { duration: info.duration,
|
|
194
|
+
size: info.size,
|
|
195
|
+
totalSize: info.totalSize,
|
|
196
|
+
timestamp: performance.now(),
|
|
197
|
+
id: requestId });
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
/**
|
|
201
|
+
* Callback called when the segment is communicated by the loader
|
|
202
|
+
* through decodable sub-segment(s) called chunk(s), with a chunk in
|
|
203
|
+
* argument.
|
|
204
|
+
* @param {*} chunkData
|
|
205
|
+
*/
|
|
206
|
+
onNewChunk: function (chunkData) {
|
|
207
|
+
fetcherCallbacks.onChunk(generateParserFunction(chunkData, true));
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
cached = cache !== undefined ? cache.get(content) :
|
|
211
|
+
null;
|
|
212
|
+
if (cached !== null) {
|
|
213
|
+
log.debug("SF: Found wanted segment in cache", segmentIdString);
|
|
214
|
+
fetcherCallbacks.onChunk(generateParserFunction(cached, false));
|
|
215
|
+
return [2 /*return*/, Promise.resolve()];
|
|
216
|
+
}
|
|
217
|
+
log.debug("SF: Beginning request", segmentIdString);
|
|
218
|
+
(_a = lifecycleCallbacks.onRequestBegin) === null || _a === void 0 ? void 0 : _a.call(lifecycleCallbacks, { requestTimestamp: performance.now(),
|
|
219
|
+
id: requestId, content: content });
|
|
220
|
+
cancellationSignal.register(function () {
|
|
221
|
+
var _a;
|
|
222
|
+
if (requestInfo !== undefined) {
|
|
223
|
+
return; // Request already terminated
|
|
224
|
+
}
|
|
225
|
+
log.debug("SF: Segment request cancelled", segmentIdString);
|
|
226
|
+
requestInfo = null;
|
|
227
|
+
(_a = lifecycleCallbacks.onRequestEnd) === null || _a === void 0 ? void 0 : _a.call(lifecycleCallbacks, { id: requestId });
|
|
228
|
+
});
|
|
229
|
+
_d.label = 1;
|
|
230
|
+
case 1:
|
|
231
|
+
_d.trys.push([1, 3, , 4]);
|
|
232
|
+
return [4 /*yield*/, tryURLsWithBackoff((_b = segment.mediaURLs) !== null && _b !== void 0 ? _b : [null], callLoaderWithUrl, objectAssign({ onRetry: onRetry }, options), cancellationSignal)];
|
|
233
|
+
case 2:
|
|
234
|
+
res = _d.sent();
|
|
235
|
+
if (res.resultType === "segment-loaded") {
|
|
236
|
+
loadedData = res.resultData.responseData;
|
|
237
|
+
if (cache !== undefined) {
|
|
238
|
+
cache.add(content, res.resultData.responseData);
|
|
239
|
+
}
|
|
240
|
+
fetcherCallbacks.onChunk(generateParserFunction(loadedData, false));
|
|
241
|
+
}
|
|
242
|
+
else if (res.resultType === "segment-created") {
|
|
243
|
+
fetcherCallbacks.onChunk(generateParserFunction(res.resultData, false));
|
|
244
|
+
}
|
|
245
|
+
log.debug("SF: Segment request ended with success", segmentIdString);
|
|
246
|
+
fetcherCallbacks.onAllChunksReceived();
|
|
247
|
+
if (res.resultType !== "segment-created") {
|
|
248
|
+
requestInfo = res.resultData;
|
|
249
|
+
sendNetworkMetricsIfAvailable();
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
requestInfo = null;
|
|
253
|
+
}
|
|
254
|
+
if (!cancellationSignal.isCancelled) {
|
|
255
|
+
// The current task could have been canceled as a result of one
|
|
256
|
+
// of the previous callbacks call. In that case, we don't want to send
|
|
257
|
+
// a "requestEnd" again as it has already been sent on cancellation.
|
|
258
|
+
(_c = lifecycleCallbacks.onRequestEnd) === null || _c === void 0 ? void 0 : _c.call(lifecycleCallbacks, { id: requestId });
|
|
259
|
+
}
|
|
260
|
+
return [3 /*break*/, 4];
|
|
261
|
+
case 3:
|
|
262
|
+
err_1 = _d.sent();
|
|
263
|
+
requestInfo = null;
|
|
264
|
+
if (err_1 instanceof CancellationError) {
|
|
265
|
+
log.debug("SF: Segment request aborted", segmentIdString);
|
|
266
|
+
throw err_1;
|
|
267
|
+
}
|
|
268
|
+
log.debug("SF: Segment request failed", segmentIdString);
|
|
269
|
+
throw errorSelector(err_1);
|
|
270
|
+
case 4: return [2 /*return*/];
|
|
271
|
+
}
|
|
272
|
+
});
|
|
270
273
|
});
|
|
271
274
|
};
|
|
272
275
|
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import { ITransportPipelines } from "../../../transports";
|
|
17
17
|
import { IBufferType } from "../../segment_buffers";
|
|
18
18
|
import { IPrioritizedSegmentFetcher } from "./prioritized_segment_fetcher";
|
|
19
|
-
import {
|
|
19
|
+
import { ISegmentFetcherLifecycleCallbacks } from "./segment_fetcher";
|
|
20
20
|
/**
|
|
21
21
|
* Interact with the transport pipelines to download segments with the right
|
|
22
22
|
* priority.
|
|
@@ -54,7 +54,7 @@ export default class SegmentFetcherCreator {
|
|
|
54
54
|
*/
|
|
55
55
|
private readonly _transport;
|
|
56
56
|
/**
|
|
57
|
-
* `
|
|
57
|
+
* `TaskPrioritizer` linked to this SegmentFetcherCreator.
|
|
58
58
|
*
|
|
59
59
|
* Note: this is typed as `any` because segment loaders / parsers can use
|
|
60
60
|
* different types depending on the type of buffer. We could maybe be smarter
|
|
@@ -78,7 +78,7 @@ export default class SegmentFetcherCreator {
|
|
|
78
78
|
* @param {Object} callbacks
|
|
79
79
|
* @returns {Object}
|
|
80
80
|
*/
|
|
81
|
-
createSegmentFetcher(bufferType: IBufferType, callbacks:
|
|
81
|
+
createSegmentFetcher(bufferType: IBufferType, callbacks: ISegmentFetcherLifecycleCallbacks): IPrioritizedSegmentFetcher<unknown>;
|
|
82
82
|
}
|
|
83
83
|
/** Options used by the `SegmentFetcherCreator`. */
|
|
84
84
|
export interface ISegmentFetcherCreatorBackoffOptions {
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import config from "../../../config";
|
|
17
17
|
import applyPrioritizerToSegmentFetcher from "./prioritized_segment_fetcher";
|
|
18
|
-
import ObservablePrioritizer from "./prioritizer";
|
|
19
18
|
import createSegmentFetcher, { getSegmentFetcherOptions, } from "./segment_fetcher";
|
|
19
|
+
import TaskPrioritizer from "./task_prioritizer";
|
|
20
20
|
/**
|
|
21
21
|
* Interact with the transport pipelines to download segments with the right
|
|
22
22
|
* priority.
|
|
@@ -54,7 +54,7 @@ var SegmentFetcherCreator = /** @class */ (function () {
|
|
|
54
54
|
function SegmentFetcherCreator(transport, options) {
|
|
55
55
|
var _a = config.getCurrent(), MIN_CANCELABLE_PRIORITY = _a.MIN_CANCELABLE_PRIORITY, MAX_HIGH_PRIORITY_LEVEL = _a.MAX_HIGH_PRIORITY_LEVEL;
|
|
56
56
|
this._transport = transport;
|
|
57
|
-
this._prioritizer = new
|
|
57
|
+
this._prioritizer = new TaskPrioritizer({
|
|
58
58
|
prioritySteps: { high: MAX_HIGH_PRIORITY_LEVEL,
|
|
59
59
|
low: MIN_CANCELABLE_PRIORITY },
|
|
60
60
|
});
|