From fbce38af1cc7f05a30992907103af4a82f180520 Mon Sep 17 00:00:00 2001 From: theodab Date: Thu, 23 Feb 2023 11:56:23 -0800 Subject: [PATCH] feat(net): Added advanced type to filters (#5006) This adds an optional parameter to request and response filters, of a new enum called AdvancedRequestType. This enum describes request types that are subtypes of the basic types. For example, INIT_SEGMENT is a type of SEGMENT. This gives users more information about the type of the request, while maintaining backwards compatibility. Closes #4966 --- demo/common/asset.js | 3 +- docs/tutorials/ad_monetization.md | 2 +- docs/tutorials/application-level-redirects.md | 2 +- docs/tutorials/fairplay.md | 8 +- docs/tutorials/license-server-auth.md | 8 +- docs/tutorials/license-wrapping.md | 4 +- externs/shaka/net.js | 16 +++- lib/dash/dash_parser.js | 24 +++-- lib/dash/segment_base.js | 26 +++-- lib/dash/segment_template.js | 14 ++- lib/hls/hls_parser.js | 16 +++- lib/media/streaming_engine.js | 17 +++- lib/net/networking_engine.js | 35 +++++-- lib/util/fairplay_utils.js | 18 ++-- test/dash/dash_parser_live_unit.js | 22 +++-- test/dash/dash_parser_manifest_unit.js | 2 +- test/dash/dash_parser_segment_base_unit.js | 23 +++-- .../dash/dash_parser_segment_template_unit.js | 12 +-- test/hls/hls_live_unit.js | 9 +- test/media/drm_engine_unit.js | 2 +- test/media/streaming_engine_integration.js | 6 +- test/media/streaming_engine_unit.js | 96 +++++++++++-------- test/test/util/fake_networking_engine.js | 53 +++++++--- test/test/util/streaming_engine_util.js | 2 +- 24 files changed, 265 insertions(+), 155 deletions(-) diff --git a/demo/common/asset.js b/demo/common/asset.js index c0579449f5..bbd57e5532 100644 --- a/demo/common/asset.js +++ b/demo/common/asset.js @@ -372,7 +372,8 @@ const ShakaDemoAssetInfo = class { networkingEngine.clearAllResponseFilters(); if (this.licenseRequestHeaders.size) { - const filter = (requestType, request) => { + /** @type {!shaka.extern.RequestFilter} */ + const filter = (requestType, request, advType) => { return this.addLicenseRequestHeaders_(this.licenseRequestHeaders, requestType, request); diff --git a/docs/tutorials/ad_monetization.md b/docs/tutorials/ad_monetization.md index 539abdc72b..8532792491 100644 --- a/docs/tutorials/ad_monetization.md +++ b/docs/tutorials/ad_monetization.md @@ -203,7 +203,7 @@ default, so you should only need to set this if you've enabled it in other parts your code. ```js - player.getNetworkingEngine().registerRequestFilter(function(type, request) { + player.getNetworkingEngine().registerRequestFilter(function(type, request, advType) { if (type == shaka.net.NetworkingEngine.RequestType.MANIFEST || type == shaka.net.NetworkingEngine.RequestType.SEGMENT) { request.withCredentials = false; diff --git a/docs/tutorials/application-level-redirects.md b/docs/tutorials/application-level-redirects.md index 84269c93ca..58c602b03f 100644 --- a/docs/tutorials/application-level-redirects.md +++ b/docs/tutorials/application-level-redirects.md @@ -36,7 +36,7 @@ const HTTP_IN_HEX = 0x68747470; const RequestType = shaka.net.NetworkingEngine.RequestType; -player.getNetworkingEngine().registerResponseFilter(async (type, response) => { +player.getNetworkingEngine().registerResponseFilter(async (type, response, advType) => { // NOTE: If the system requires an ALR for both manifests and segments, // remove this RequestType check. if (type != RequestType.MANIFEST) { diff --git a/docs/tutorials/fairplay.md b/docs/tutorials/fairplay.md index 8bc8e5c907..c9a7ddd39f 100644 --- a/docs/tutorials/fairplay.md +++ b/docs/tutorials/fairplay.md @@ -90,7 +90,7 @@ or give the response in a different format. For more info, see the general {@tutorial license-wrapping} tutorial: ```js -player.getNetworkingEngine().registerRequestFilter((type, request) => { +player.getNetworkingEngine().registerRequestFilter((type, request, advType) => { if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) { return; } @@ -103,7 +103,7 @@ player.getNetworkingEngine().registerRequestFilter((type, request) => { request.body = shaka.util.StringUtils.toUTF8(encodeURIComponent(params)); }); -player.getNetworkingEngine().registerResponseFilter((type, response) => { +player.getNetworkingEngine().registerResponseFilter((type, response, advType) => { if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) { return; } @@ -143,7 +143,7 @@ Note: If the url of the license server has to undergo any transformation (eg: add the contentId), you would have to create your filter manually. ```js -player.getNetworkingEngine().registerRequestFilter((type, request) => { +player.getNetworkingEngine().registerRequestFilter((type, request, advType) => { if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) { return; } @@ -175,7 +175,7 @@ Note: If the url of the license server has to undergo any transformation (eg: add the contentId), you would have to create your filter manually. ```js -player.getNetworkingEngine().registerRequestFilter((type, request) => { +player.getNetworkingEngine().registerRequestFilter((type, request, advType) => { if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) { return; } diff --git a/docs/tutorials/license-server-auth.md b/docs/tutorials/license-server-auth.md index f102d9f5f7..be1ffa01cf 100644 --- a/docs/tutorials/license-server-auth.md +++ b/docs/tutorials/license-server-auth.md @@ -62,7 +62,7 @@ arbitrary headers to Shaka's requests through a request filter callback. Register the filter before calling `player.load()`: ```js - player.getNetworkingEngine().registerRequestFilter(function(type, request) { + player.getNetworkingEngine().registerRequestFilter(function(type, request, advType) { // Only add headers to license requests: if (type == shaka.net.NetworkingEngine.RequestType.LICENSE) { // This is the specific header name and value the server wants: @@ -92,7 +92,7 @@ try to use it without setting the parameter, you will see `Error code 6007` We can use a request filter to modify the URL and add the required parameter: ```js - player.getNetworkingEngine().registerRequestFilter(function(type, request) { + player.getNetworkingEngine().registerRequestFilter(function(type, request, advType) { // Only add headers to license requests: if (type == shaka.net.NetworkingEngine.RequestType.LICENSE) { // This is the specific parameter name and value the server wants: @@ -140,7 +140,7 @@ Our `cookie_auth` endpoint sends back headers that allow credentialed requests, so we set a flag in our request filter to send credentials cross-site: ```js - player.getNetworkingEngine().registerRequestFilter(function(type, request) { + player.getNetworkingEngine().registerRequestFilter(function(type, request, advType) { if (type == shaka.net.NetworkingEngine.RequestType.LICENSE) { request.allowCrossSiteCredentials = true; } @@ -205,7 +205,7 @@ const authToken = null; Now change the request filter: ```js - player.getNetworkingEngine().registerRequestFilter(function(type, request) { + player.getNetworkingEngine().registerRequestFilter(function(type, request, advType) { // Only add headers to license requests: if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) return; diff --git a/docs/tutorials/license-wrapping.md b/docs/tutorials/license-wrapping.md index 17d0a2fb26..61011a6cfa 100644 --- a/docs/tutorials/license-wrapping.md +++ b/docs/tutorials/license-wrapping.md @@ -65,7 +65,7 @@ will see `Error code 6007`, which means `LICENSE_REQUEST_FAILED`. To wrap the license request, we must register a request filter: ```js - player.getNetworkingEngine().registerRequestFilter(function(type, request) { + player.getNetworkingEngine().registerRequestFilter(function(type, request, advType) { // Alias some utilities provided by the library. const StringUtils = shaka.util.StringUtils; const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils; @@ -136,7 +136,7 @@ Widevine CDM does not understand this wrapped format, so we must unwrap it first using a request filter: ```js - player.getNetworkingEngine().registerResponseFilter(function(type, response) { + player.getNetworkingEngine().registerResponseFilter(function(type, response, advType) { // Alias some utilities provided by the library. const StringUtils = shaka.util.StringUtils; const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils; diff --git a/externs/shaka/net.js b/externs/shaka/net.js index 5fe56e7b65..4435ad8bc1 100644 --- a/externs/shaka/net.js +++ b/externs/shaka/net.js @@ -202,12 +202,16 @@ shaka.extern.HeadersReceived; /** * Defines a filter for requests. This filter takes the request and modifies * it before it is sent to the scheme plugin. + * The RequestType describes the basic type of the request (manifest, segment, + * etc). The optional AdvancedRequestType will be provided in the case of a + * sub-type of the basic type (playlist manifest, init segment, etc). * A request filter can run asynchronously by returning a promise; in this case, * the request will not be sent until the promise is resolved. * * @typedef {!function(shaka.net.NetworkingEngine.RequestType, - * shaka.extern.Request): - (Promise|undefined)} + * shaka.extern.Request, + * shaka.net.NetworkingEngine.AdvancedRequestType=): + * (Promise|undefined)} * @exportDoc */ shaka.extern.RequestFilter; @@ -216,11 +220,15 @@ shaka.extern.RequestFilter; /** * Defines a filter for responses. This filter takes the response and modifies * it before it is returned. + * The RequestType describes the basic type of the request (manifest, segment, + * etc). The optional AdvancedRequestType will be provided in the case of a + * sub-type of the basic type (playlist manifest, init segment, etc). * A response filter can run asynchronously by returning a promise. * * @typedef {!function(shaka.net.NetworkingEngine.RequestType, - * shaka.extern.Response): - (Promise|undefined)} + * shaka.extern.Response, + * shaka.net.NetworkingEngine.AdvancedRequestType=): + * (Promise|undefined)} * @exportDoc */ shaka.extern.ResponseFilter; diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index 5b85b4b62c..617fc94655 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -222,6 +222,7 @@ shaka.dash.DashParser = class { */ async requestManifest_() { const requestType = shaka.net.NetworkingEngine.RequestType.MANIFEST; + const advType = shaka.net.NetworkingEngine.AdvancedRequestType.MPD; const request = shaka.net.NetworkingEngine.makeRequest( this.manifestUris_, this.config_.retryParameters); const networkingEngine = this.playerInterface_.networkingEngine; @@ -230,7 +231,7 @@ shaka.dash.DashParser = class { this.playerInterface_.modifyManifestRequest(request, {format: format}); const startTime = Date.now(); - const operation = networkingEngine.request(requestType, request); + const operation = networkingEngine.request(requestType, request, advType); this.operationManager_.manage(operation); const response = await operation.promise; @@ -1175,12 +1176,12 @@ shaka.dash.DashParser = class { const isImage = contentType == ContentType.IMAGE; try { - const requestInitSegment = (uris, startByte, endByte) => { - return this.requestInitSegment_(uris, startByte, endByte); + const requestSegment = (uris, startByte, endByte, isInit) => { + return this.requestSegment_(uris, startByte, endByte, isInit); }; if (context.representation.segmentBase) { streamInfo = shaka.dash.SegmentBase.createStreamInfo( - context, requestInitSegment); + context, requestSegment); } else if (context.representation.segmentList) { streamInfo = shaka.dash.SegmentList.createStreamInfo( context, this.streamMap_); @@ -1188,7 +1189,7 @@ shaka.dash.DashParser = class { const hasManifest = !!this.manifest_; streamInfo = shaka.dash.SegmentTemplate.createStreamInfo( - context, requestInitSegment, this.streamMap_, hasManifest, + context, requestSegment, this.streamMap_, hasManifest, this.config_.dash.initialSegmentLimit, this.periodDurations_); } else { goog.asserts.assert(isText, @@ -1830,11 +1831,15 @@ shaka.dash.DashParser = class { * @param {!Array.} uris * @param {?number} startByte * @param {?number} endByte + * @param {boolean} isInit * @return {!Promise.} * @private */ - async requestInitSegment_(uris, startByte, endByte) { + async requestSegment_(uris, startByte, endByte, isInit) { const requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT; + const advType = isInit ? + shaka.net.NetworkingEngine.AdvancedRequestType.INIT_SEGMENT : + shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; const request = shaka.util.Networking.createSegmentRequest( uris, @@ -1843,7 +1848,7 @@ shaka.dash.DashParser = class { this.config_.retryParameters); const networkingEngine = this.playerInterface_.networkingEngine; - const operation = networkingEngine.request(requestType, request); + const operation = networkingEngine.request(requestType, request, advType); this.operationManager_.manage(operation); const response = await operation.promise; return response.data; @@ -1886,10 +1891,11 @@ shaka.dash.DashParser.MIN_UPDATE_PERIOD_ = 3; /** * @typedef { - * function(!Array., ?number, ?number):!Promise. + * function(!Array., ?number, ?number, boolean): + * !Promise. * } */ -shaka.dash.DashParser.RequestInitSegmentCallback; +shaka.dash.DashParser.RequestSegmentCallback; /** diff --git a/lib/dash/segment_base.js b/lib/dash/segment_base.js index 45d083a7e2..612f2f1712 100644 --- a/lib/dash/segment_base.js +++ b/lib/dash/segment_base.js @@ -70,11 +70,10 @@ shaka.dash.SegmentBase = class { * Creates a new StreamInfo object. * * @param {shaka.dash.DashParser.Context} context - * @param {shaka.dash.DashParser.RequestInitSegmentCallback} - * requestInitSegment + * @param {shaka.dash.DashParser.RequestSegmentCallback} requestSegment * @return {shaka.dash.DashParser.StreamInfo} */ - static createStreamInfo(context, requestInitSegment) { + static createStreamInfo(context, requestSegment) { goog.asserts.assert(context.representation.segmentBase, 'Should only be called with SegmentBase'); // Since SegmentBase does not need updates, simply treat any call as @@ -111,7 +110,7 @@ shaka.dash.SegmentBase = class { return { generateSegmentIndex: () => { return SegmentBase.generateSegmentIndex_( - shallowCopyOfContext, requestInitSegment, initSegmentReference, + shallowCopyOfContext, requestSegment, initSegmentReference, scaledPresentationTimeOffset); }, }; @@ -121,8 +120,7 @@ shaka.dash.SegmentBase = class { * Creates a SegmentIndex for the given URIs and context. * * @param {shaka.dash.DashParser.Context} context - * @param {shaka.dash.DashParser.RequestInitSegmentCallback} - * requestInitSegment + * @param {shaka.dash.DashParser.RequestSegmentCallback} requestSegment * @param {shaka.media.InitSegmentReference} initSegmentReference * @param {!Array.} uris * @param {number} startByte @@ -131,7 +129,7 @@ shaka.dash.SegmentBase = class { * @return {!Promise.} */ static async generateSegmentIndexFromUris( - context, requestInitSegment, initSegmentReference, uris, startByte, + context, requestSegment, initSegmentReference, uris, startByte, endByte, scaledPresentationTimeOffset) { // Unpack context right away, before we start an async process. // This immunizes us against changes to the context object later. @@ -143,16 +141,17 @@ shaka.dash.SegmentBase = class { const containerType = context.representation.mimeType.split('/')[1]; // Create a local variable to bind to so we can set to null to help the GC. - let localRequest = requestInitSegment; + let localRequest = requestSegment; let segmentIndex = null; const responses = [ - localRequest(uris, startByte, endByte), + localRequest(uris, startByte, endByte, /* isInit= */ false), containerType == 'webm' ? localRequest( initSegmentReference.getUris(), initSegmentReference.startByte, - initSegmentReference.endByte) : + initSegmentReference.endByte, + /* isInit= */ true) : null, ]; @@ -327,15 +326,14 @@ shaka.dash.SegmentBase = class { * Generate a SegmentIndex from a Context object. * * @param {shaka.dash.DashParser.Context} context - * @param {shaka.dash.DashParser.RequestInitSegmentCallback} - * requestInitSegment + * @param {shaka.dash.DashParser.RequestSegmentCallback} requestSegment * @param {shaka.media.InitSegmentReference} initSegmentReference * @param {number} scaledPresentationTimeOffset * @return {!Promise.} * @private */ static generateSegmentIndex_( - context, requestInitSegment, initSegmentReference, + context, requestSegment, initSegmentReference, scaledPresentationTimeOffset) { const SegmentBase = shaka.dash.SegmentBase; @@ -344,7 +342,7 @@ shaka.dash.SegmentBase = class { goog.asserts.assert(indexRange, 'Index range should not be null!'); return shaka.dash.SegmentBase.generateSegmentIndexFromUris( - context, requestInitSegment, initSegmentReference, indexUris, + context, requestSegment, initSegmentReference, indexUris, indexRange.start, indexRange.end, scaledPresentationTimeOffset); } diff --git a/lib/dash/segment_template.js b/lib/dash/segment_template.js index daf7145435..80cb792156 100644 --- a/lib/dash/segment_template.js +++ b/lib/dash/segment_template.js @@ -28,8 +28,7 @@ shaka.dash.SegmentTemplate = class { * Updates the existing SegmentIndex, if any. * * @param {shaka.dash.DashParser.Context} context - * @param {shaka.dash.DashParser.RequestInitSegmentCallback} - * requestInitSegment + * @param {shaka.dash.DashParser.RequestSegmentCallback} requestSegment * @param {!Object.} streamMap * @param {boolean} isUpdate True if the manifest is being updated. * @param {number} segmentLimit The maximum number of segments to generate for @@ -38,7 +37,7 @@ shaka.dash.SegmentTemplate = class { * @return {shaka.dash.DashParser.StreamInfo} */ static createStreamInfo( - context, requestInitSegment, streamMap, isUpdate, segmentLimit, + context, requestSegment, streamMap, isUpdate, segmentLimit, periodDurationMap) { goog.asserts.assert(context.representation.segmentTemplate, 'Should only be called with SegmentTemplate'); @@ -62,7 +61,7 @@ shaka.dash.SegmentTemplate = class { return { generateSegmentIndex: () => { return SegmentTemplate.generateSegmentIndexFromIndexTemplate_( - shallowCopyOfContext, requestInitSegment, initSegmentReference, + shallowCopyOfContext, requestSegment, initSegmentReference, info); }, }; @@ -253,15 +252,14 @@ shaka.dash.SegmentTemplate = class { * Generates a SegmentIndex from an index URL template. * * @param {shaka.dash.DashParser.Context} context - * @param {shaka.dash.DashParser.RequestInitSegmentCallback} - * requestInitSegment + * @param {shaka.dash.DashParser.RequestSegmentCallback} requestSegment * @param {shaka.media.InitSegmentReference} init * @param {shaka.dash.SegmentTemplate.SegmentTemplateInfo} info * @return {!Promise.} * @private */ static generateSegmentIndexFromIndexTemplate_( - context, requestInitSegment, init, info) { + context, requestSegment, init, info) { const MpdUtils = shaka.dash.MpdUtils; const ManifestParserUtils = shaka.util.ManifestParserUtils; @@ -274,7 +272,7 @@ shaka.dash.SegmentTemplate = class { context.representation.baseUris, [filledTemplate]); return shaka.dash.SegmentBase.generateSegmentIndexFromUris( - context, requestInitSegment, init, resolvedUris, 0, null, + context, requestSegment, init, resolvedUris, 0, null, info.scaledPresentationTimeOffset); } diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js index 467ced1bb0..a84d4ed6b1 100644 --- a/lib/hls/hls_parser.js +++ b/lib/hls/hls_parser.js @@ -1928,7 +1928,7 @@ shaka.hls.HlsParser = class { const downloadSegmentIndex = async (abortSignal) => { // Download the actual manifest. const response = await this.requestManifest_( - streamInfo.absoluteMediaPlaylistUri); + streamInfo.absoluteMediaPlaylistUri, /* isPlaylist= */ true); if (abortSignal.aborted) { return; } @@ -3263,10 +3263,11 @@ shaka.hls.HlsParser = class { * with the resulting data. * * @param {string} absoluteUri + * @param {boolean=} isPlaylist * @return {!Promise.} * @private */ - requestManifest_(absoluteUri) { + requestManifest_(absoluteUri, isPlaylist) { const requestType = shaka.net.NetworkingEngine.RequestType.MANIFEST; const request = shaka.net.NetworkingEngine.makeRequest( @@ -3275,7 +3276,10 @@ shaka.hls.HlsParser = class { const format = shaka.util.CmcdManager.StreamingFormat.HLS; this.playerInterface_.modifyManifestRequest(request, {format: format}); - return this.makeNetworkRequest_(request, requestType); + const advType = isPlaylist ? + shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_PLAYLIST : + shaka.net.NetworkingEngine.AdvancedRequestType.MASTER_PLAYLIST; + return this.makeNetworkRequest_(request, requestType, advType); } /** @@ -3375,10 +3379,11 @@ shaka.hls.HlsParser = class { * * @param {shaka.extern.Request} request * @param {shaka.net.NetworkingEngine.RequestType} type + * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType * @return {!Promise.} * @private */ - makeNetworkRequest_(request, type) { + makeNetworkRequest_(request, type, advType) { if (!this.operationManager_) { throw new shaka.util.Error( shaka.util.Error.Severity.CRITICAL, @@ -3386,7 +3391,8 @@ shaka.hls.HlsParser = class { shaka.util.Error.Code.OPERATION_ABORTED); } - const op = this.playerInterface_.networkingEngine.request(type, request); + const op = this.playerInterface_.networkingEngine.request( + type, request, advType); this.operationManager_.manage(op); return op.promise; diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index d454f0f99d..a40567182a 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -1687,7 +1687,8 @@ shaka.media.StreamingEngine = class { shaka.log.v1(logPrefix, 'fetching init segment'); const fetchInit = - this.fetch_(mediaState, reference.initSegmentReference); + this.fetch_(mediaState, reference.initSegmentReference, + /* streamDataCallback= */ undefined, /* isInit= */ true); const append = async () => { try { const initSegment = await fetchInit; @@ -2068,12 +2069,13 @@ shaka.media.StreamingEngine = class { * @param {(!shaka.media.InitSegmentReference|!shaka.media.SegmentReference)} * reference * @param {?function(BufferSource):!Promise=} streamDataCallback + * @param {boolean=} isInit * * @return {!Promise.} * @private * @suppress {strictMissingProperties} */ - async fetch_(mediaState, reference, streamDataCallback) { + async fetch_(mediaState, reference, streamDataCallback, isInit) { let op = null; if ( mediaState.segmentPrefetch && @@ -2083,7 +2085,7 @@ shaka.media.StreamingEngine = class { } if (!op) { op = this.dispatchFetch_( - reference, mediaState.stream, streamDataCallback, + reference, mediaState.stream, streamDataCallback, isInit, ); } @@ -2100,12 +2102,16 @@ shaka.media.StreamingEngine = class { * @param {(!shaka.media.InitSegmentReference|!shaka.media.SegmentReference)} * reference * @param {?function(BufferSource):!Promise=} streamDataCallback + * @param {boolean=} isInit * * @return {!shaka.net.NetworkingEngine.PendingRequest} * @private */ - dispatchFetch_(reference, stream, streamDataCallback) { + dispatchFetch_(reference, stream, streamDataCallback, isInit) { const requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT; + const advType = isInit ? + shaka.net.NetworkingEngine.AdvancedRequestType.INIT_SEGMENT : + shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; const request = shaka.util.Networking.createSegmentRequest( reference.getUris(), @@ -2131,7 +2137,8 @@ shaka.media.StreamingEngine = class { bandwidth: stream.bandwidth, }, ); - return this.playerInterface_.netEngine.request(requestType, request); + return this.playerInterface_.netEngine.request( + requestType, request, advType); } /** diff --git a/lib/net/networking_engine.js b/lib/net/networking_engine.js index cefa6c8a26..5354f454e3 100644 --- a/lib/net/networking_engine.js +++ b/lib/net/networking_engine.js @@ -247,10 +247,11 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget { * * @param {shaka.net.NetworkingEngine.RequestType} type * @param {shaka.extern.Request} request + * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType * @return {!shaka.net.NetworkingEngine.PendingRequest} * @export */ - request(type, request) { + request(type, request, advType) { const ObjectUtils = shaka.util.ObjectUtils; const numBytesRemainingObj = new shaka.net.NetworkingEngine.NumBytesRemainingClass(); @@ -285,12 +286,12 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget { request.uris = ObjectUtils.cloneObject(request.uris); // Apply the registered filters to the request. - const requestFilterOperation = this.filterRequest_(type, request); + const requestFilterOperation = this.filterRequest_(type, request, advType); const requestOperation = requestFilterOperation.chain( () => this.makeRequestWithRetry_(type, request, numBytesRemainingObj)); const responseFilterOperation = requestOperation.chain( (responseAndGotProgress) => - this.filterResponse_(type, responseAndGotProgress)); + this.filterResponse_(type, responseAndGotProgress, advType)); // Keep track of time spent in filters. const requestFilterStartTime = Date.now(); @@ -341,10 +342,11 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget { /** * @param {shaka.net.NetworkingEngine.RequestType} type * @param {shaka.extern.Request} request + * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType * @return {!shaka.util.AbortableOperation.} * @private */ - filterRequest_(type, request) { + filterRequest_(type, request, advType) { let filterOperation = shaka.util.AbortableOperation.completed(undefined); for (const requestFilter of this.requestFilters_) { @@ -358,7 +360,7 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget { // copying buffers if this is a partial view. request.body = shaka.util.BufferUtils.toArrayBuffer(request.body); } - return requestFilter(type, request); + return requestFilter(type, request, advType); }); } @@ -607,11 +609,12 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget { * @param {shaka.net.NetworkingEngine.RequestType} type * @param {shaka.net.NetworkingEngine.ResponseAndGotProgress} * responseAndGotProgress + * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType * @return {!shaka.extern.IAbortableOperation.< * shaka.net.NetworkingEngine.ResponseAndGotProgress>} * @private */ - filterResponse_(type, responseAndGotProgress) { + filterResponse_(type, responseAndGotProgress, advType) { let filterOperation = shaka.util.AbortableOperation.completed(undefined); for (const responseFilter of this.responseFilters_) { // Response filters are run sequentially. @@ -621,7 +624,7 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget { // TODO: See TODO in filterRequest_. resp.data = shaka.util.BufferUtils.toArrayBuffer(resp.data); } - return responseFilter(type, resp); + return responseFilter(type, resp, advType); }); } // If successful, return the filtered response with whether it got @@ -752,6 +755,24 @@ shaka.net.NetworkingEngine.RequestType = { 'KEY': 6, }; +/** + * A more advanced form of the RequestType structure, meant to describe + * sub-types of basic request types. + * For example, an INIT_SEGMENT is a sub-type of SEGMENT. + * This is meant to allow for more specificity to be added to the request type + * data, without breaking backwards compatibility. + * + * @enum {number} + * @export + */ +shaka.net.NetworkingEngine.AdvancedRequestType = { + 'INIT_SEGMENT': 0, + 'MEDIA_SEGMENT': 1, + 'MEDIA_PLAYLIST': 2, + 'MASTER_PLAYLIST': 3, + 'MPD': 4, +}; + /** * Priority level for network scheme plugins. diff --git a/lib/util/fairplay_utils.js b/lib/util/fairplay_utils.js index 4ee6b11b5a..22661f2b5b 100644 --- a/lib/util/fairplay_utils.js +++ b/lib/util/fairplay_utils.js @@ -233,9 +233,10 @@ shaka.util.FairPlayUtils = class { * * @param {shaka.net.NetworkingEngine.RequestType} type * @param {shaka.extern.Request} request + * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType * @export */ - static verimatrixFairPlayRequest(type, request) { + static verimatrixFairPlayRequest(type, request, advType) { if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) { return; } @@ -251,9 +252,10 @@ shaka.util.FairPlayUtils = class { * * @param {shaka.net.NetworkingEngine.RequestType} type * @param {shaka.extern.Request} request + * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType * @private */ - static octetStreamFairPlayRequest_(type, request) { + static octetStreamFairPlayRequest_(type, request, advType) { if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) { return; } @@ -265,9 +267,10 @@ shaka.util.FairPlayUtils = class { * * @param {shaka.net.NetworkingEngine.RequestType} type * @param {shaka.extern.Request} request + * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType * @export */ - static ezdrmFairPlayRequest(type, request) { + static ezdrmFairPlayRequest(type, request, advType) { shaka.util.FairPlayUtils.octetStreamFairPlayRequest_(type, request); } @@ -276,9 +279,10 @@ shaka.util.FairPlayUtils = class { * * @param {shaka.net.NetworkingEngine.RequestType} type * @param {shaka.extern.Request} request + * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType * @export */ - static conaxFairPlayRequest(type, request) { + static conaxFairPlayRequest(type, request, advType) { shaka.util.FairPlayUtils.octetStreamFairPlayRequest_(type, request); } @@ -287,9 +291,10 @@ shaka.util.FairPlayUtils = class { * * @param {shaka.net.NetworkingEngine.RequestType} type * @param {shaka.extern.Request} request + * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType * @export */ - static expressplayFairPlayRequest(type, request) { + static expressplayFairPlayRequest(type, request, advType) { shaka.util.FairPlayUtils.octetStreamFairPlayRequest_(type, request); } @@ -298,9 +303,10 @@ shaka.util.FairPlayUtils = class { * * @param {shaka.net.NetworkingEngine.RequestType} type * @param {shaka.extern.Response} response + * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType * @export */ - static commonFairPlayResponse(type, response) { + static commonFairPlayResponse(type, response, advType) { if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) { return; } diff --git a/test/dash/dash_parser_live_unit.js b/test/dash/dash_parser_live_unit.js index 12a3e538f1..1fe4ac86e8 100644 --- a/test/dash/dash_parser_live_unit.js +++ b/test/dash/dash_parser_live_unit.js @@ -708,17 +708,19 @@ describe('DashParser Live', () => { fakeNetEngine.setResponseText('dummy://foo', manifestText); const manifestRequest = shaka.net.NetworkingEngine.RequestType.MANIFEST; + const manifestAdv = shaka.net.NetworkingEngine.AdvancedRequestType.MPD; await parser.start('dummy://foo', playerInterface); expect(fakeNetEngine.request).toHaveBeenCalledTimes(1); - fakeNetEngine.expectRequest('dummy://foo', manifestRequest); + fakeNetEngine.expectRequest('dummy://foo', manifestRequest, manifestAdv); fakeNetEngine.request.calls.reset(); // Create a mock so we can verify it gives two URIs. // The third location is a relative url, and should be resolved as an // absolute url. - fakeNetEngine.request.and.callFake((type, request) => { + fakeNetEngine.request.and.callFake((type, request, advType) => { expect(type).toBe(manifestRequest); + expect(advType).toBe(manifestAdv); expect(request.uris).toEqual( ['http://foobar', 'http://foobar2', 'dummy://foo/foobar3']); const data = shaka.util.StringUtils.toUTF8(manifestText); @@ -951,6 +953,7 @@ describe('DashParser Live', () => { describe('stop', () => { const manifestRequestType = shaka.net.NetworkingEngine.RequestType.MANIFEST; + const manifestAdvType = shaka.net.NetworkingEngine.AdvancedRequestType.MPD; const dateRequestType = shaka.net.NetworkingEngine.RequestType.TIMING; const manifestUri = 'dummy://foo'; const dateUri = 'http://foo.bar/date'; @@ -982,7 +985,8 @@ describe('DashParser Live', () => { it('stops updates', async () => { await parser.start(manifestUri, playerInterface); - fakeNetEngine.expectRequest(manifestUri, manifestRequestType); + fakeNetEngine.expectRequest( + manifestUri, manifestRequestType, manifestAdvType); fakeNetEngine.request.calls.reset(); parser.stop(); @@ -1000,7 +1004,8 @@ describe('DashParser Live', () => { parser.stop(); await expectation; - fakeNetEngine.expectRequest(manifestUri, manifestRequestType); + fakeNetEngine.expectRequest( + manifestUri, manifestRequestType, manifestAdvType); fakeNetEngine.request.calls.reset(); await updateManifest(); // An update should not occur. @@ -1011,7 +1016,8 @@ describe('DashParser Live', () => { const manifest = await parser.start('dummy://foo', playerInterface); expect(manifest).toBeTruthy(); - fakeNetEngine.expectRequest(manifestUri, manifestRequestType); + fakeNetEngine.expectRequest( + manifestUri, manifestRequestType, manifestAdvType); fakeNetEngine.request.calls.reset(); /** @type {!shaka.util.PublicPromise} */ const delay = fakeNetEngine.delayNextRequest(); @@ -1019,7 +1025,8 @@ describe('DashParser Live', () => { await updateManifest(); // The request was made but should not be resolved yet. expect(fakeNetEngine.request).toHaveBeenCalledTimes(1); - fakeNetEngine.expectRequest(manifestUri, manifestRequestType); + fakeNetEngine.expectRequest( + manifestUri, manifestRequestType, manifestAdvType); fakeNetEngine.request.calls.reset(); parser.stop(); delay.resolve(); @@ -1040,7 +1047,8 @@ describe('DashParser Live', () => { await Util.shortDelay(); // This is the initial manifest request. expect(fakeNetEngine.request).toHaveBeenCalledTimes(1); - fakeNetEngine.expectRequest(manifestUri, manifestRequestType); + fakeNetEngine.expectRequest( + manifestUri, manifestRequestType, manifestAdvType); fakeNetEngine.request.calls.reset(); // Resolve the manifest request and wait on the UTCTiming request. delay.resolve(); diff --git a/test/dash/dash_parser_manifest_unit.js b/test/dash/dash_parser_manifest_unit.js index 1ba40cdc50..7c2b63a2f5 100644 --- a/test/dash/dash_parser_manifest_unit.js +++ b/test/dash/dash_parser_manifest_unit.js @@ -727,7 +727,7 @@ describe('DashParser Manifest', () => { ' value="http://foo.bar/date" />', ]); - fakeNetEngine.request.and.callFake((type, request) => { + fakeNetEngine.request.and.callFake((type, request, advType) => { if (request.uris[0] == 'http://foo.bar/manifest') { const data = shaka.util.StringUtils.toUTF8(source); return shaka.util.AbortableOperation.completed({ diff --git a/test/dash/dash_parser_segment_base_unit.js b/test/dash/dash_parser_segment_base_unit.js index c8dbcb2657..19f2fa67b0 100644 --- a/test/dash/dash_parser_segment_base_unit.js +++ b/test/dash/dash_parser_segment_base_unit.js @@ -87,13 +87,13 @@ describe('DashParser SegmentBase', () => { // Expect calls to fetch part of the media and init segments of each stream. fakeNetEngine.expectRangeRequest( - 'http://example.com/media-1.webm', 100, 200); + 'http://example.com/media-1.webm', 100, 200, /* isInit= */ false); fakeNetEngine.expectRangeRequest( - 'http://example.com/init-1.webm', 201, 300); + 'http://example.com/init-1.webm', 201, 300, /* isInit= */ true); fakeNetEngine.expectRangeRequest( - 'http://example.com/media-2.webm', 1100, 1200); + 'http://example.com/media-2.webm', 1100, 1200, /* isInit= */ false); fakeNetEngine.expectRangeRequest( - 'http://example.com/init-2.webm', 1201, 1300); + 'http://example.com/init-2.webm', 1201, 1300, /* isInit= */ true); }); it('inherits from Period', async () => { @@ -125,7 +125,8 @@ describe('DashParser SegmentBase', () => { expect(initSegmentReference.getEndByte()).toBe(300); expect(fakeNetEngine.request).toHaveBeenCalledTimes(2); - fakeNetEngine.expectRangeRequest('http://example.com', 100, 200); + fakeNetEngine.expectRangeRequest( + 'http://example.com', 100, 200, /* isInit= */ false); }); it('inherits from AdaptationSet', async () => { @@ -157,7 +158,8 @@ describe('DashParser SegmentBase', () => { expect(initSegmentReference.getEndByte()).toBe(300); expect(fakeNetEngine.request).toHaveBeenCalledTimes(2); - fakeNetEngine.expectRangeRequest('http://example.com', 100, 200); + fakeNetEngine.expectRangeRequest( + 'http://example.com', 100, 200, /* isInit= */ false); }); it('does not require sourceURL in Initialization', async () => { @@ -190,7 +192,8 @@ describe('DashParser SegmentBase', () => { expect(initSegmentReference.getEndByte()).toBe(300); expect(fakeNetEngine.request).toHaveBeenCalledTimes(2); - fakeNetEngine.expectRangeRequest('http://example.com/stream.mp4', 100, 200); + fakeNetEngine.expectRangeRequest( + 'http://example.com/stream.mp4', 100, 200, /* isInit= */ false); }); it('merges across levels', async () => { @@ -230,7 +233,8 @@ describe('DashParser SegmentBase', () => { expect(segmentReference.timestampOffset).toBe(-10); expect(fakeNetEngine.request).toHaveBeenCalledTimes(2); - fakeNetEngine.expectRangeRequest('http://example.com/index.mp4', 5, 2000); + fakeNetEngine.expectRangeRequest( + 'http://example.com/index.mp4', 5, 2000, /* isInit= */ false); }); it('merges and overrides across levels', async () => { @@ -269,7 +273,8 @@ describe('DashParser SegmentBase', () => { expect(segmentReference.timestampOffset).toBe(-20); expect(fakeNetEngine.request).toHaveBeenCalledTimes(2); - fakeNetEngine.expectRangeRequest('http://example.com', 30, 900); + fakeNetEngine.expectRangeRequest( + 'http://example.com', 30, 900, /* isInit= */ false); }); it('does not assume the same timescale as media', async () => { diff --git a/test/dash/dash_parser_segment_template_unit.js b/test/dash/dash_parser_segment_template_unit.js index e02b49ddc0..b582b5bd1d 100644 --- a/test/dash/dash_parser_segment_template_unit.js +++ b/test/dash/dash_parser_segment_template_unit.js @@ -198,7 +198,7 @@ describe('DashParser SegmentTemplate', () => { expect(fakeNetEngine.request).toHaveBeenCalledTimes(2); fakeNetEngine.expectRangeRequest( - 'http://example.com/index-500.mp4', 0, null); + 'http://example.com/index-500.mp4', 0, null, /* isInit= */ false); }); it('defaults to index with multiple segment sources', async () => { @@ -226,7 +226,7 @@ describe('DashParser SegmentTemplate', () => { expect(fakeNetEngine.request).toHaveBeenCalledTimes(2); fakeNetEngine.expectRangeRequest( - 'http://example.com/index-500.mp4', 0, null); + 'http://example.com/index-500.mp4', 0, null, /* isInit= */ false); }); it('requests init data for WebM', async () => { @@ -261,9 +261,9 @@ describe('DashParser SegmentTemplate', () => { expect(fakeNetEngine.request).toHaveBeenCalledTimes(3); fakeNetEngine.expectRangeRequest( - 'http://example.com/init-500.webm', 0, null); + 'http://example.com/init-500.webm', 0, null, /* isInit= */ true); fakeNetEngine.expectRangeRequest( - 'http://example.com/index-500.webm', 0, null); + 'http://example.com/index-500.webm', 0, null, /* isInit= */ false); }); it('inherits from Period', async () => { @@ -295,7 +295,7 @@ describe('DashParser SegmentTemplate', () => { expect(fakeNetEngine.request).toHaveBeenCalledTimes(2); fakeNetEngine.expectRangeRequest( - 'http://example.com/index-500.mp4', 0, null); + 'http://example.com/index-500.mp4', 0, null, /* isInit= */ false); }); it('inherits from AdaptationSet', async () => { @@ -327,7 +327,7 @@ describe('DashParser SegmentTemplate', () => { expect(fakeNetEngine.request).toHaveBeenCalledTimes(2); fakeNetEngine.expectRangeRequest( - 'http://example.com/index-500.mp4', 0, null); + 'http://example.com/index-500.mp4', 0, null, /* isInit= */ false); }); }); diff --git a/test/hls/hls_live_unit.js b/test/hls/hls_live_unit.js index 4432c0d4a6..ae51076335 100644 --- a/test/hls/hls_live_unit.js +++ b/test/hls/hls_live_unit.js @@ -375,7 +375,8 @@ describe('HlsParser live', () => { // We saw one request for the video playlist, which signalled "ENDLIST". fakeNetEngine.expectRequest( 'test:/video', - shaka.net.NetworkingEngine.RequestType.MANIFEST); + shaka.net.NetworkingEngine.RequestType.MANIFEST, + shaka.net.NetworkingEngine.AdvancedRequestType.MASTER_PLAYLIST); expect(manifest.presentationTimeline.isLive()).toBe(false); fakeNetEngine.request.calls.reset(); @@ -843,7 +844,8 @@ describe('HlsParser live', () => { expect(fakeNetEngine.request).toHaveBeenCalledTimes(1); fakeNetEngine.expectRequest( 'test:/video', - shaka.net.NetworkingEngine.RequestType.MANIFEST); + shaka.net.NetworkingEngine.RequestType.MANIFEST, + shaka.net.NetworkingEngine.AdvancedRequestType.MASTER_PLAYLIST); }); it('request playlist delta updates to skip segments', async () => { @@ -885,7 +887,8 @@ describe('HlsParser live', () => { fakeNetEngine.expectRequest( 'test:/video?_HLS_skip=YES', - shaka.net.NetworkingEngine.RequestType.MANIFEST); + shaka.net.NetworkingEngine.RequestType.MANIFEST, + shaka.net.NetworkingEngine.AdvancedRequestType.MASTER_PLAYLIST); }); it('skips older segments', async () => { diff --git a/test/media/drm_engine_unit.js b/test/media/drm_engine_unit.js index 68a7d22950..729ac68484 100644 --- a/test/media/drm_engine_unit.js +++ b/test/media/drm_engine_unit.js @@ -1514,7 +1514,7 @@ describe('DrmEngine', () => { // Not mocked. Run data through real data URI parser to ensure that it is // correctly formatted. - fakeNetEngine.request.and.callFake((type, request) => { + fakeNetEngine.request.and.callFake((type, request, advType) => { const requestType = shaka.net.NetworkingEngine.RequestType.LICENSE; // A dummy progress callback. diff --git a/test/media/streaming_engine_integration.js b/test/media/streaming_engine_integration.js index b95294c860..beae0db6eb 100644 --- a/test/media/streaming_engine_integration.js +++ b/test/media/streaming_engine_integration.js @@ -357,10 +357,12 @@ describe('StreamingEngine', () => { await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 305); const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT; + const segmentAdvType = + shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; // firstSegmentNumber = // [(segmentAvailabilityEnd - rebufferingGoal) / segmentDuration] + 1 - netEngine.expectRequest('0_video_29', segmentType); - netEngine.expectRequest('0_audio_29', segmentType); + netEngine.expectRequest('0_video_29', segmentType, segmentAdvType); + netEngine.expectRequest('0_audio_29', segmentType, segmentAdvType); }); it('can handle seeks ahead of availability window', async () => { diff --git a/test/media/streaming_engine_unit.js b/test/media/streaming_engine_unit.js index 446fc87357..a9f4d68741 100644 --- a/test/media/streaming_engine_unit.js +++ b/test/media/streaming_engine_unit.js @@ -546,40 +546,46 @@ describe('StreamingEngine', () => { netEngine.expectRangeRequest( '0_audio_init', initSegmentRanges[ContentType.AUDIO][0], - initSegmentRanges[ContentType.AUDIO][1]); + initSegmentRanges[ContentType.AUDIO][1], + /* isInit= */ true); netEngine.expectRangeRequest( '0_video_init', initSegmentRanges[ContentType.VIDEO][0], - initSegmentRanges[ContentType.VIDEO][1]); + initSegmentRanges[ContentType.VIDEO][1], + /* isInit= */ true); netEngine.expectRangeRequest( '1_audio_init', initSegmentRanges[ContentType.AUDIO][0], - initSegmentRanges[ContentType.AUDIO][1]); + initSegmentRanges[ContentType.AUDIO][1], + /* isInit= */ true); netEngine.expectRangeRequest( '1_video_init', initSegmentRanges[ContentType.VIDEO][0], - initSegmentRanges[ContentType.VIDEO][1]); + initSegmentRanges[ContentType.VIDEO][1], + /* isInit= */ true); const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT; + const segmentAdvType = + shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; - netEngine.expectRequest('0_audio_0', segmentType); - netEngine.expectRequest('0_video_0', segmentType); - netEngine.expectRequest('0_text_0', segmentType); + netEngine.expectRequest('0_audio_0', segmentType, segmentAdvType); + netEngine.expectRequest('0_video_0', segmentType, segmentAdvType); + netEngine.expectRequest('0_text_0', segmentType, segmentAdvType); - netEngine.expectRequest('0_audio_1', segmentType); - netEngine.expectRequest('0_video_1', segmentType); - netEngine.expectRequest('0_text_1', segmentType); + netEngine.expectRequest('0_audio_1', segmentType, segmentAdvType); + netEngine.expectRequest('0_video_1', segmentType, segmentAdvType); + netEngine.expectRequest('0_text_1', segmentType, segmentAdvType); - netEngine.expectRequest('1_audio_2', segmentType); - netEngine.expectRequest('1_video_2', segmentType); - netEngine.expectRequest('1_text_2', segmentType); + netEngine.expectRequest('1_audio_2', segmentType, segmentAdvType); + netEngine.expectRequest('1_video_2', segmentType, segmentAdvType); + netEngine.expectRequest('1_text_2', segmentType, segmentAdvType); - netEngine.expectRequest('1_audio_3', segmentType); - netEngine.expectRequest('1_video_3', segmentType); - netEngine.expectRequest('1_text_3', segmentType); + netEngine.expectRequest('1_audio_3', segmentType, segmentAdvType); + netEngine.expectRequest('1_video_3', segmentType, segmentAdvType); + netEngine.expectRequest('1_text_3', segmentType, segmentAdvType); }); describe('unloadTextStream', () => { @@ -597,16 +603,18 @@ describe('StreamingEngine', () => { // is sent. await runTest(() => { const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT; + const segmentAdvType = + shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; if (presentationTimeInSeconds == 1) { - netEngine.expectRequest('0_text_0', segmentType); + netEngine.expectRequest('0_text_0', segmentType, segmentAdvType); netEngine.request.calls.reset(); streamingEngine.unloadTextStream(); } else if (presentationTimeInSeconds == 35) { - netEngine.expectNoRequest('0_text_0', segmentType); - netEngine.expectNoRequest('0_text_1', segmentType); - netEngine.expectNoRequest('1_text_2', segmentType); - netEngine.expectNoRequest('1_text_3', segmentType); + netEngine.expectNoRequest('0_text_0', segmentType, segmentAdvType); + netEngine.expectNoRequest('0_text_1', segmentType, segmentAdvType); + netEngine.expectNoRequest('1_text_2', segmentType, segmentAdvType); + netEngine.expectNoRequest('1_text_3', segmentType, segmentAdvType); } }); }); @@ -858,22 +866,24 @@ describe('StreamingEngine', () => { expect(mediaSourceEngine.endOfStream).toHaveBeenCalled(); const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT; + const segmentAdvType = + shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; - netEngine.expectRequest('0_audio_0', segmentType); - netEngine.expectRequest('0_video_0', segmentType); - netEngine.expectRequest('0_text_0', segmentType); + netEngine.expectRequest('0_audio_0', segmentType, segmentAdvType); + netEngine.expectRequest('0_video_0', segmentType, segmentAdvType); + netEngine.expectRequest('0_text_0', segmentType, segmentAdvType); - netEngine.expectRequest('0_audio_1', segmentType); - netEngine.expectRequest('0_video_1', segmentType); - netEngine.expectRequest('0_text_1', segmentType); + netEngine.expectRequest('0_audio_1', segmentType, segmentAdvType); + netEngine.expectRequest('0_video_1', segmentType, segmentAdvType); + netEngine.expectRequest('0_text_1', segmentType, segmentAdvType); - netEngine.expectRequest('1_audio_2', segmentType); - netEngine.expectRequest('1_video_2', segmentType); - netEngine.expectRequest('1_text_2', segmentType); + netEngine.expectRequest('1_audio_2', segmentType, segmentAdvType); + netEngine.expectRequest('1_video_2', segmentType, segmentAdvType); + netEngine.expectRequest('1_text_2', segmentType, segmentAdvType); - netEngine.expectNoRequest('1_audio_3', segmentType); - netEngine.expectNoRequest('1_video_3', segmentType); - netEngine.expectNoRequest('1_text_3', segmentType); + netEngine.expectNoRequest('1_audio_3', segmentType, segmentAdvType); + netEngine.expectNoRequest('1_video_3', segmentType, segmentAdvType); + netEngine.expectNoRequest('1_text_3', segmentType, segmentAdvType); }); it('does not buffer one media type ahead of another', async () => { @@ -1148,10 +1158,13 @@ describe('StreamingEngine', () => { await Util.fakeEventLoop(5); const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT; + const segmentAdvType = + shaka.net.NetworkingEngine.AdvancedRequestType.INIT_SEGMENT; // Quickly switching back to text1, and text init segment should be // fetched again. - netEngine.expectRequest('text-20-init', segmentType); - netEngine.expectNoRequest('text-21-init', segmentType); + netEngine.expectRequest('text-20-init', segmentType, segmentAdvType); + netEngine.expectNoRequest('text-21-init', segmentType, segmentAdvType); + // TODO: huh? }); }); @@ -3087,7 +3100,7 @@ describe('StreamingEngine', () => { // For these tests, we don't care about specific data appended. // Just return any old ArrayBuffer for any requested segment. netEngine = new shaka.test.FakeNetworkingEngine(); - netEngine.request.and.callFake((requestType, request) => { + netEngine.request.and.callFake((requestType, request, advType) => { const buffer = new ArrayBuffer(0); const response = {uri: request.uris[0], data: buffer, headers: {}}; const bytes = new shaka.net.NetworkingEngine.NumBytesRemainingClass(); @@ -3409,7 +3422,7 @@ describe('StreamingEngine', () => { // For these tests, we don't care about specific data appended. // Just return any old ArrayBuffer for any requested segment. - netEngine.request.and.callFake((requestType, request) => { + netEngine.request.and.callFake((requestType, request, advType) => { const buffer = new ArrayBuffer(0); /** @type {shaka.extern.Response} */ const response = {uri: request.uris[0], data: buffer, headers: {}}; @@ -3649,7 +3662,7 @@ describe('StreamingEngine', () => { let isRequested = false; let isAborted = false; - netEngine.request.and.callFake((requestType, request) => { + netEngine.request.and.callFake((requestType, request, advType) => { isRequested = true; const abortOp = () => { @@ -3825,11 +3838,14 @@ describe('StreamingEngine', () => { '1_audio_3', '1_video_3', ]; + const segmentAdvType = + shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; + for (const request of requests) { if (hasRequest) { - netEngine.expectRequest(request, segmentType); + netEngine.expectRequest(request, segmentType, segmentAdvType); } else { - netEngine.expectNoRequest(request, segmentType); + netEngine.expectNoRequest(request, segmentType, segmentAdvType); } } } diff --git a/test/test/util/fake_networking_engine.js b/test/test/util/fake_networking_engine.js index 4a0cb293fd..370bc64762 100644 --- a/test/test/util/fake_networking_engine.js +++ b/test/test/util/fake_networking_engine.js @@ -174,9 +174,11 @@ shaka.test.FakeNetworkingEngine = class { * * @param {string} uri * @param {shaka.net.NetworkingEngine.RequestType} type + * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType */ - expectRequest(uri, type) { - shaka.test.FakeNetworkingEngine.expectRequest(this.request, uri, type); + expectRequest(uri, type, advType) { + shaka.test.FakeNetworkingEngine.expectRequest( + this.request, uri, type, advType); } /** @@ -184,9 +186,11 @@ shaka.test.FakeNetworkingEngine = class { * * @param {string} uri * @param {shaka.net.NetworkingEngine.RequestType} type + * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType */ - expectNoRequest(uri, type) { - shaka.test.FakeNetworkingEngine.expectNoRequest(this.request, uri, type); + expectNoRequest(uri, type, advType) { + shaka.test.FakeNetworkingEngine.expectNoRequest( + this.request, uri, type, advType); } /** @@ -195,10 +199,11 @@ shaka.test.FakeNetworkingEngine = class { * @param {string} uri * @param {number} startByte * @param {?number} endByte + * @param {boolean} isInit */ - expectRangeRequest(uri, startByte, endByte) { + expectRangeRequest(uri, startByte, endByte, isInit) { shaka.test.FakeNetworkingEngine.expectRangeRequest( - this.request, uri, startByte, endByte); + this.request, uri, startByte, endByte, isInit); } /** @@ -289,10 +294,17 @@ shaka.test.FakeNetworkingEngine = class { * @param {!Object} requestSpy * @param {string} uri * @param {shaka.net.NetworkingEngine.RequestType} type + * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType */ - static expectRequest(requestSpy, uri, type) { - expect(requestSpy).toHaveBeenCalledWith( - type, jasmine.objectContaining({uris: [uri]})); + static expectRequest(requestSpy, uri, type, advType) { + // Jasmine "toHaveBeenCalledWith" doesn't handle optional parameters well. + if (advType != undefined) { + expect(requestSpy).toHaveBeenCalledWith( + type, jasmine.objectContaining({uris: [uri]}), advType); + } else { + expect(requestSpy).toHaveBeenCalledWith( + type, jasmine.objectContaining({uris: [uri]})); + } } /** @@ -301,10 +313,17 @@ shaka.test.FakeNetworkingEngine = class { * @param {!Object} requestSpy * @param {string} uri * @param {shaka.net.NetworkingEngine.RequestType} type + * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType */ - static expectNoRequest(requestSpy, uri, type) { - expect(requestSpy).not.toHaveBeenCalledWith( - type, jasmine.objectContaining({uris: [uri]})); + static expectNoRequest(requestSpy, uri, type, advType) { + // Jasmine "toHaveBeenCalledWith" doesn't handle optional parameters well. + if (advType != undefined) { + expect(requestSpy).not.toHaveBeenCalledWith( + type, jasmine.objectContaining({uris: [uri]}), advType); + } else { + expect(requestSpy).not.toHaveBeenCalledWith( + type, jasmine.objectContaining({uris: [uri]})); + } } /** @@ -314,8 +333,9 @@ shaka.test.FakeNetworkingEngine = class { * @param {string} uri * @param {number} startByte * @param {?number} endByte + * @param {boolean} isInit */ - static expectRangeRequest(requestSpy, uri, startByte, endByte) { + static expectRangeRequest(requestSpy, uri, startByte, endByte, isInit) { const headers = {}; if (startByte == 0 && endByte == null) { // No header required. @@ -327,12 +347,17 @@ shaka.test.FakeNetworkingEngine = class { headers['Range'] = range; } + const advType = isInit ? + shaka.net.NetworkingEngine.AdvancedRequestType.INIT_SEGMENT : + shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; + expect(requestSpy).toHaveBeenCalledWith( shaka.net.NetworkingEngine.RequestType.SEGMENT, jasmine.objectContaining({ uris: [uri], headers: headers, - })); + }), + advType); } }; diff --git a/test/test/util/streaming_engine_util.js b/test/test/util/streaming_engine_util.js index 6366762f92..d288e02b9c 100644 --- a/test/test/util/streaming_engine_util.js +++ b/test/test/util/streaming_engine_util.js @@ -28,7 +28,7 @@ shaka.test.StreamingEngineUtil = class { static createFakeNetworkingEngine(getInitSegment, getSegment, delays) { const netEngine = new shaka.test.FakeNetworkingEngine(); - netEngine.request.and.callFake((requestType, request) => { + netEngine.request.and.callFake((requestType, request, advType) => { expect(requestType).toBeTruthy(); expect(request.uris.length).toBe(1);