From 7bee99911d15b509667ac74917274f0b62a2d3e7 Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Thu, 26 Jan 2023 15:43:03 -0800 Subject: [PATCH 01/19] fix: exclude "future" segments from presentation timeline calculations --- lib/media/presentation_timeline.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/media/presentation_timeline.js b/lib/media/presentation_timeline.js index ddcf997ee9..fcf10588e4 100644 --- a/lib/media/presentation_timeline.js +++ b/lib/media/presentation_timeline.js @@ -236,7 +236,16 @@ shaka.media.PresentationTimeline = class { let firstReferenceStartTime = references[0].startTime; let lastReferenceEndTime = references[0].endTime; + + // Date.now() is in milliseconds, from which we compute "now" in seconds. + const now = (Date.now() + this.clockOffset_) / 1000.0; + for (const reference of references) { + // Stop if we've reached segments that are in the "future". + if (now < reference.startTime) { + break; + } + firstReferenceStartTime = Math.min( firstReferenceStartTime, reference.startTime); lastReferenceEndTime = Math.max(lastReferenceEndTime, reference.endTime); @@ -251,8 +260,6 @@ shaka.media.PresentationTimeline = class { !this.startTimeLocked_) { // Since we have explicit segment end times, calculate a presentation // start based on them. This start time accounts for drift. - // Date.now() is in milliseconds, from which we compute "now" in seconds. - const now = (Date.now() + this.clockOffset_) / 1000.0; this.presentationStartTime_ = now - this.maxSegmentEndTime_ - this.maxSegmentDuration_; } From 172fb81baa3b237d5e00ea5dcccc5194fd5a808e Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Thu, 26 Jan 2023 15:46:25 -0800 Subject: [PATCH 02/19] Revert "fix: exclude "future" segments from presentation timeline calculations" This reverts commit 7bee99911d15b509667ac74917274f0b62a2d3e7. --- lib/media/presentation_timeline.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/media/presentation_timeline.js b/lib/media/presentation_timeline.js index fcf10588e4..ddcf997ee9 100644 --- a/lib/media/presentation_timeline.js +++ b/lib/media/presentation_timeline.js @@ -236,16 +236,7 @@ shaka.media.PresentationTimeline = class { let firstReferenceStartTime = references[0].startTime; let lastReferenceEndTime = references[0].endTime; - - // Date.now() is in milliseconds, from which we compute "now" in seconds. - const now = (Date.now() + this.clockOffset_) / 1000.0; - for (const reference of references) { - // Stop if we've reached segments that are in the "future". - if (now < reference.startTime) { - break; - } - firstReferenceStartTime = Math.min( firstReferenceStartTime, reference.startTime); lastReferenceEndTime = Math.max(lastReferenceEndTime, reference.endTime); @@ -260,6 +251,8 @@ shaka.media.PresentationTimeline = class { !this.startTimeLocked_) { // Since we have explicit segment end times, calculate a presentation // start based on them. This start time accounts for drift. + // Date.now() is in milliseconds, from which we compute "now" in seconds. + const now = (Date.now() + this.clockOffset_) / 1000.0; this.presentationStartTime_ = now - this.maxSegmentEndTime_ - this.maxSegmentDuration_; } From 127b183a412ed6cf7127ffd79fc64135d24ac509 Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Thu, 26 Jan 2023 15:52:40 -0800 Subject: [PATCH 03/19] fix: exclude "future" segments from presentation timeline calculations --- lib/media/presentation_timeline.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/media/presentation_timeline.js b/lib/media/presentation_timeline.js index ddcf997ee9..fcf10588e4 100644 --- a/lib/media/presentation_timeline.js +++ b/lib/media/presentation_timeline.js @@ -236,7 +236,16 @@ shaka.media.PresentationTimeline = class { let firstReferenceStartTime = references[0].startTime; let lastReferenceEndTime = references[0].endTime; + + // Date.now() is in milliseconds, from which we compute "now" in seconds. + const now = (Date.now() + this.clockOffset_) / 1000.0; + for (const reference of references) { + // Stop if we've reached segments that are in the "future". + if (now < reference.startTime) { + break; + } + firstReferenceStartTime = Math.min( firstReferenceStartTime, reference.startTime); lastReferenceEndTime = Math.max(lastReferenceEndTime, reference.endTime); @@ -251,8 +260,6 @@ shaka.media.PresentationTimeline = class { !this.startTimeLocked_) { // Since we have explicit segment end times, calculate a presentation // start based on them. This start time accounts for drift. - // Date.now() is in milliseconds, from which we compute "now" in seconds. - const now = (Date.now() + this.clockOffset_) / 1000.0; this.presentationStartTime_ = now - this.maxSegmentEndTime_ - this.maxSegmentDuration_; } From 7004b446a2840d337bac8c1b6d01cefd9a45d94b Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Thu, 26 Jan 2023 15:54:03 -0800 Subject: [PATCH 04/19] Revert "fix: exclude "future" segments from presentation timeline calculations" This reverts commit 127b183a412ed6cf7127ffd79fc64135d24ac509. --- lib/media/presentation_timeline.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/media/presentation_timeline.js b/lib/media/presentation_timeline.js index fcf10588e4..ddcf997ee9 100644 --- a/lib/media/presentation_timeline.js +++ b/lib/media/presentation_timeline.js @@ -236,16 +236,7 @@ shaka.media.PresentationTimeline = class { let firstReferenceStartTime = references[0].startTime; let lastReferenceEndTime = references[0].endTime; - - // Date.now() is in milliseconds, from which we compute "now" in seconds. - const now = (Date.now() + this.clockOffset_) / 1000.0; - for (const reference of references) { - // Stop if we've reached segments that are in the "future". - if (now < reference.startTime) { - break; - } - firstReferenceStartTime = Math.min( firstReferenceStartTime, reference.startTime); lastReferenceEndTime = Math.max(lastReferenceEndTime, reference.endTime); @@ -260,6 +251,8 @@ shaka.media.PresentationTimeline = class { !this.startTimeLocked_) { // Since we have explicit segment end times, calculate a presentation // start based on them. This start time accounts for drift. + // Date.now() is in milliseconds, from which we compute "now" in seconds. + const now = (Date.now() + this.clockOffset_) / 1000.0; this.presentationStartTime_ = now - this.maxSegmentEndTime_ - this.maxSegmentDuration_; } From 685107a1cfbc5efe35e86ae9950978f72b2bd484 Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Wed, 8 Mar 2023 12:18:10 -0500 Subject: [PATCH 05/19] fix: missing CMCD params in HEAD requests fixes #5067 --- lib/player.js | 9 ++++++-- lib/util/cmcd_manager.js | 38 ++++++++++++++++++++++++++++---- test/util/cmcd_manager_unit.js | 40 +++++++++++++++++++++++++++++++--- 3 files changed, 78 insertions(+), 9 deletions(-) diff --git a/lib/player.js b/lib/player.js index e0c2dd77cb..02a10f8a5d 100644 --- a/lib/player.js +++ b/lib/player.js @@ -901,7 +901,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.config_ = null; this.stats_ = null; this.videoContainer_ = null; - this.cmcdManager_ = null; + + if (this.cmcdManager_) { + await this.cmcdManager_.destroy(); + this.cmcdManager_ = null; + } if (this.networkingEngine_) { await this.networkingEngine_.destroy(); @@ -3089,8 +3093,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.abrManager_.getBandwidthEstimate() : NaN, getBufferedInfo: () => this.getBufferedInfo(), getCurrentTime: () => this.video_ ? this.video_.currentTime : 0, - getVariantTracks: () => this.getVariantTracks(), getPlaybackRate: () => this.getPlaybackRate(), + getNetworkingEngine: () => this.getNetworkingEngine(), + getVariantTracks: () => this.getVariantTracks(), isLive: () => this.isLive(), }; diff --git a/lib/util/cmcd_manager.js b/lib/util/cmcd_manager.js index 32d092437b..c53dd11f4d 100644 --- a/lib/util/cmcd_manager.js +++ b/lib/util/cmcd_manager.js @@ -8,12 +8,15 @@ goog.provide('shaka.util.CmcdManager'); goog.require('goog.Uri'); goog.require('shaka.log'); - +goog.require('shaka.net.NetworkingEngine'); +goog.require('shaka.util.IDestroyable'); /** * @summary * A CmcdManager maintains CMCD state as well as a collection of utility * functions. + * + * @implements {shaka.util.IDestroyable} */ shaka.util.CmcdManager = class { /** @@ -55,6 +58,30 @@ shaka.util.CmcdManager = class { * @private {boolean} */ this.starved_ = false; + + /** + * @private {shaka.extern.RequestFilter} + */ + this.requestFilter_ = (type, request) => { + if (!this.config_.enabled || request.method !== 'HEAD') { + return; + } + + this.apply_(request, {su: false}); + }; + + playerInterface.getNetworkingEngine() + .registerRequestFilter(this.requestFilter_); + } + + /** + * @override + */ + destroy() { + this.playerInterface_.getNetworkingEngine() + .unregisterRequestFilter(this.requestFilter_); + + return Promise.resolve(); } /** @@ -566,8 +593,9 @@ shaka.util.CmcdManager = class { * getBandwidthEstimate: function():number, * getBufferedInfo: function():shaka.extern.BufferedInfo, * getCurrentTime: function():number, - * getVariantTracks: function():Array., * getPlaybackRate: function():number, + * getNetworkingEngine: function():shaka.net.NetworkingEngine, + * getVariantTracks: function():Array., * isLive: function():boolean * }} * @@ -577,10 +605,12 @@ shaka.util.CmcdManager = class { * Get information about what the player has buffered. * @property {function():number} getCurrentTime * Get the current time - * @property {function():Array.} getVariantTracks - * Get the variant tracks * @property {function():number} getPlaybackRate * Get the playback rate + * @property {function():shaka.net.NetworkingEngine} getNetworkingEngine + * Get the networking engine + * @property {function():Array.} getVariantTracks + * Get the variant tracks * @property {function():boolean} isLive * Get if the player is playing live content. */ diff --git a/test/util/cmcd_manager_unit.js b/test/util/cmcd_manager_unit.js index a338f7d877..f2523d671e 100644 --- a/test/util/cmcd_manager_unit.js +++ b/test/util/cmcd_manager_unit.js @@ -67,9 +67,24 @@ describe('CmcdManager', () => { }); }); + const NetworkingEngine = shaka.net.NetworkingEngine; + + function createNetworkingEngine() { + const resolveScheme = jasmine.createSpy('resolve scheme').and.callFake( + () => shaka.util.AbortableOperation.completed( + {uri: '', data: new ArrayBuffer(5), headers: {}}, + )); + + NetworkingEngine.registerScheme( + 'resolve', shaka.test.Util.spyFunc(resolveScheme), + NetworkingEngine.PluginPriority.FALLBACK); + + return new NetworkingEngine(); + } + describe('CmcdManager instance', () => { const ObjectUtils = shaka.util.ObjectUtils; - + const networkingEngine = createNetworkingEngine(); const playerInterface = { isLive: () => false, getBandwidthEstimate: () => 10000000, @@ -80,6 +95,9 @@ describe('CmcdManager', () => { {start: 35, end: 40}, ], }), + getCurrentTime: () => 10, + getPlaybackRate: () => 1, + getNetworkingEngine: () => networkingEngine, getVariantTracks: () => /** @type {Array.} */([ { type: 'variant', @@ -94,8 +112,6 @@ describe('CmcdManager', () => { audioBandWidth: 1000000, }, ]), - getPlaybackRate: () => 1, - getCurrentTime: () => 10, }; const sid = '2ed2d1cd-970b-48f2-bfb3-50a79e87cfa3'; @@ -286,6 +302,24 @@ describe('CmcdManager', () => { cmcdManager.applySegmentData(r, segmentInfo); expect(r.headers['CMCD-Request']).not.toContain(',su'); }); + + it('applies core CMCD params to HEAD requests', async () => { + config.useHeaders = false; + cmcdManager = new CmcdManager(playerInterface, config); + + const uri = 'resolve://foo'; + const type = NetworkingEngine.RequestType.MANIFEST; + const retry = NetworkingEngine.defaultRetryParameters(); + const request = NetworkingEngine.makeRequest([uri], retry); + request.method = 'HEAD'; + await networkingEngine.request(type, request); + + const result = request.uris[0]; + expect(result).toContain('?CMCD='); + expect(result).toContain(encodeURIComponent('sid="')); + expect(result).toContain(encodeURIComponent('cid="testing"')); + expect(result).not.toContain(encodeURIComponent('sf=')); + }); }); }); }); From 4c21d66cd0271114b00cee18d27a48d77cb1dc7f Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Thu, 9 Mar 2023 23:17:13 -0800 Subject: [PATCH 06/19] Refactor to use IReleaseable instead of IDestroyable --- lib/player.js | 2 +- lib/util/cmcd_manager.js | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/player.js b/lib/player.js index 02a10f8a5d..414cdc977b 100644 --- a/lib/player.js +++ b/lib/player.js @@ -903,7 +903,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.videoContainer_ = null; if (this.cmcdManager_) { - await this.cmcdManager_.destroy(); + await this.cmcdManager_.release(); this.cmcdManager_ = null; } diff --git a/lib/util/cmcd_manager.js b/lib/util/cmcd_manager.js index c53dd11f4d..ae5d5662f4 100644 --- a/lib/util/cmcd_manager.js +++ b/lib/util/cmcd_manager.js @@ -9,14 +9,14 @@ goog.provide('shaka.util.CmcdManager'); goog.require('goog.Uri'); goog.require('shaka.log'); goog.require('shaka.net.NetworkingEngine'); -goog.require('shaka.util.IDestroyable'); +goog.require('shaka.util.IReleasable'); /** * @summary * A CmcdManager maintains CMCD state as well as a collection of utility * functions. * - * @implements {shaka.util.IDestroyable} + * @implements {shaka.util.IReleasable} */ shaka.util.CmcdManager = class { /** @@ -77,11 +77,9 @@ shaka.util.CmcdManager = class { /** * @override */ - destroy() { + release() { this.playerInterface_.getNetworkingEngine() .unregisterRequestFilter(this.requestFilter_); - - return Promise.resolve(); } /** From 19cfe303f94403c7decf53fef51ea7b208a9c486 Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Thu, 9 Mar 2023 23:17:33 -0800 Subject: [PATCH 07/19] remove su override --- lib/util/cmcd_manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util/cmcd_manager.js b/lib/util/cmcd_manager.js index ae5d5662f4..7add62fc89 100644 --- a/lib/util/cmcd_manager.js +++ b/lib/util/cmcd_manager.js @@ -67,7 +67,7 @@ shaka.util.CmcdManager = class { return; } - this.apply_(request, {su: false}); + this.apply_(request); }; playerInterface.getNetworkingEngine() From 5a78a5253a04ce0aa4bc76a1cab7d89df463079e Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Thu, 9 Mar 2023 23:27:31 -0800 Subject: [PATCH 08/19] Add comment to request filter --- lib/util/cmcd_manager.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/util/cmcd_manager.js b/lib/util/cmcd_manager.js index 7add62fc89..3fb4efbce4 100644 --- a/lib/util/cmcd_manager.js +++ b/lib/util/cmcd_manager.js @@ -60,6 +60,9 @@ shaka.util.CmcdManager = class { this.starved_ = false; /** + * Attach CMCD data to all HEAD requests so they can be + * associated with the playback session. + * * @private {shaka.extern.RequestFilter} */ this.requestFilter_ = (type, request) => { From ab887560399b3a56901382e652e61c692829580b Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Fri, 10 Mar 2023 12:55:07 -0800 Subject: [PATCH 09/19] Update player.js --- lib/player.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/player.js b/lib/player.js index 414cdc977b..813e9d1b98 100644 --- a/lib/player.js +++ b/lib/player.js @@ -903,7 +903,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.videoContainer_ = null; if (this.cmcdManager_) { - await this.cmcdManager_.release(); + this.cmcdManager_.release(); this.cmcdManager_ = null; } From ce5c955acd86c10632e3decb8817b7cf96deea28 Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Mon, 13 Mar 2023 16:35:22 -0700 Subject: [PATCH 10/19] Refactor CMCD and NetorkingEngine.request --- externs/shaka/manifest_parser.js | 10 -- externs/shaka/net.js | 18 +-- lib/dash/dash_parser.js | 13 +- lib/hls/hls_parser.js | 14 +- lib/media/streaming_engine.js | 31 ++--- lib/net/networking_engine.js | 75 +++++++++-- lib/offline/storage.js | 4 - lib/player.js | 31 ++--- lib/util/cmcd_manager.js | 147 +++++++++++++-------- test/dash/dash_parser_live_unit.js | 2 - test/hls/hls_live_unit.js | 2 - test/media/streaming_engine_integration.js | 1 - test/media/streaming_engine_unit.js | 1 - test/util/cmcd_manager_unit.js | 43 +++--- 14 files changed, 219 insertions(+), 173 deletions(-) diff --git a/externs/shaka/manifest_parser.js b/externs/shaka/manifest_parser.js index 6b297ec8eb..c3f8b6e592 100644 --- a/externs/shaka/manifest_parser.js +++ b/externs/shaka/manifest_parser.js @@ -100,10 +100,6 @@ shaka.extern.ManifestParser = class { /** * @typedef {{ * networkingEngine: !shaka.net.NetworkingEngine, - * modifyManifestRequest: function(!shaka.extern.Request, - * shaka.util.CmcdManager.ManifestInfo), - * modifySegmentRequest: function(!shaka.extern.Request, - * shaka.util.CmcdManager.SegmentInfo), * filter: function(shaka.extern.Manifest):!Promise, * makeTextStreamsForClosedCaptions: function(shaka.extern.Manifest), * onTimelineRegionAdded: function(shaka.extern.TimelineRegionInfo), @@ -124,12 +120,6 @@ shaka.extern.ManifestParser = class { * * @property {!shaka.net.NetworkingEngine} networkingEngine * The networking engine to use for network requests. - * @property {function(!shaka.extern.Request, - * shaka.util.CmcdManager.ManifestInfo)} modifyManifestRequest - * Modify a manifest request - * @property {function(!shaka.extern.Request, - * shaka.util.CmcdManager.SegmentInfo)} modifySegmentRequest - * Modify a segment request * @property {function(shaka.extern.Manifest):!Promise} filter * Should be called when new variants or text streams are added to the * Manifest. Note that this operation is asynchronous. diff --git a/externs/shaka/net.js b/externs/shaka/net.js index 4435ad8bc1..c5fd11847a 100644 --- a/externs/shaka/net.js +++ b/externs/shaka/net.js @@ -203,14 +203,14 @@ 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. + * etc). The optional RequestContext will be provided where applicable to + * provide additional infomation about the request. 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, - * shaka.net.NetworkingEngine.AdvancedRequestType=): + * shaka.net.NetworkingEngine.RequestContext=): * (Promise|undefined)} * @exportDoc */ @@ -221,13 +221,13 @@ 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. + * etc). The optional RequestContext will be provided where applicable to + * provide additional infomation about the request. A response filter can run + * asynchronously by returning a promise. * * @typedef {!function(shaka.net.NetworkingEngine.RequestType, * shaka.extern.Response, - * shaka.net.NetworkingEngine.AdvancedRequestType=): + * shaka.net.NetworkingEngine.RequestContext=): * (Promise|undefined)} * @exportDoc */ diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index 617fc94655..91bc0db408 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -19,7 +19,6 @@ goog.require('shaka.media.PresentationTimeline'); goog.require('shaka.media.SegmentIndex'); goog.require('shaka.net.NetworkingEngine'); goog.require('shaka.text.TextEngine'); -goog.require('shaka.util.CmcdManager'); goog.require('shaka.util.Error'); goog.require('shaka.util.Functional'); goog.require('shaka.util.LanguageUtils'); @@ -222,16 +221,13 @@ shaka.dash.DashParser = class { */ async requestManifest_() { const requestType = shaka.net.NetworkingEngine.RequestType.MANIFEST; - const advType = shaka.net.NetworkingEngine.AdvancedRequestType.MPD; + const type = shaka.net.NetworkingEngine.AdvancedRequestType.MPD; const request = shaka.net.NetworkingEngine.makeRequest( this.manifestUris_, this.config_.retryParameters); const networkingEngine = this.playerInterface_.networkingEngine; - - const format = shaka.util.CmcdManager.StreamingFormat.DASH; - this.playerInterface_.modifyManifestRequest(request, {format: format}); - const startTime = Date.now(); - const operation = networkingEngine.request(requestType, request, advType); + const operation = networkingEngine.request( + requestType, request, {type: type}); this.operationManager_.manage(operation); const response = await operation.promise; @@ -1848,7 +1844,8 @@ shaka.dash.DashParser = class { this.config_.retryParameters); const networkingEngine = this.playerInterface_.networkingEngine; - const operation = networkingEngine.request(requestType, request, advType); + const operation = networkingEngine.request( + requestType, request, {type: advType}); this.operationManager_.manage(operation); const response = await operation.promise; return response.data; diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js index 837a0b9f9c..e9f1b83027 100644 --- a/lib/hls/hls_parser.js +++ b/lib/hls/hls_parser.js @@ -26,7 +26,6 @@ goog.require('shaka.net.DataUriPlugin'); goog.require('shaka.net.NetworkingEngine'); goog.require('shaka.util.ArrayUtils'); goog.require('shaka.util.BufferUtils'); -goog.require('shaka.util.CmcdManager'); goog.require('shaka.util.Error'); goog.require('shaka.util.FakeEvent'); goog.require('shaka.util.Functional'); @@ -3273,13 +3272,10 @@ shaka.hls.HlsParser = class { const request = shaka.net.NetworkingEngine.makeRequest( [absoluteUri], this.config_.retryParameters); - const format = shaka.util.CmcdManager.StreamingFormat.HLS; - this.playerInterface_.modifyManifestRequest(request, {format: format}); - - const advType = isPlaylist ? + const type = isPlaylist ? shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_PLAYLIST : shaka.net.NetworkingEngine.AdvancedRequestType.MASTER_PLAYLIST; - return this.makeNetworkRequest_(request, requestType, advType); + return this.makeNetworkRequest_(request, requestType, {type}); } /** @@ -3379,11 +3375,11 @@ shaka.hls.HlsParser = class { * * @param {shaka.extern.Request} request * @param {shaka.net.NetworkingEngine.RequestType} type - * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType + * @param {shaka.net.NetworkingEngine.RequestContext=} context * @return {!Promise.} * @private */ - makeNetworkRequest_(request, type, advType) { + makeNetworkRequest_(request, type, context) { if (!this.operationManager_) { throw new shaka.util.Error( shaka.util.Error.Severity.CRITICAL, @@ -3392,7 +3388,7 @@ shaka.hls.HlsParser = class { } const op = this.playerInterface_.networkingEngine.request( - type, request, advType); + type, request, context); this.operationManager_.manage(op); return op.promise; diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index a40567182a..30622238c4 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -2112,7 +2112,8 @@ shaka.media.StreamingEngine = class { const advType = isInit ? shaka.net.NetworkingEngine.AdvancedRequestType.INIT_SEGMENT : shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; - + const segment = reference instanceof shaka.media.SegmentReference ? + reference : undefined; const request = shaka.util.Networking.createSegmentRequest( reference.getUris(), reference.startByte, @@ -2121,24 +2122,13 @@ shaka.media.StreamingEngine = class { streamDataCallback); shaka.log.v2('fetching: reference=', reference); - let duration = 0; - if (reference instanceof shaka.media.SegmentReference) { - // start and endTime are not defined in InitSegmentReference - duration = reference.endTime - reference.startTime; - } - this.playerInterface_.modifySegmentRequest( - request, - { - type: stream.type, - init: reference instanceof shaka.media.InitSegmentReference, - duration: duration, - mimeType: stream.mimeType, - codecs: stream.codecs, - bandwidth: stream.bandwidth, - }, - ); + return this.playerInterface_.netEngine.request( - requestType, request, advType); + requestType, request, { + type: advType, + stream: stream, + segment: segment, + }); } /** @@ -2304,8 +2294,6 @@ shaka.media.StreamingEngine = class { * @typedef {{ * getPresentationTime: function():number, * getBandwidthEstimate: function():number, - * modifySegmentRequest: function(shaka.extern.Request, - * shaka.util.CmcdManager.SegmentInfo), * mediaSourceEngine: !shaka.media.MediaSourceEngine, * netEngine: shaka.net.NetworkingEngine, * onError: function(!shaka.util.Error), @@ -2324,9 +2312,6 @@ shaka.media.StreamingEngine = class { * viewer is seeing on screen right now. * @property {function():number} getBandwidthEstimate * Get the estimated bandwidth in bits per second. - * @property {function(shaka.extern.Request, - * shaka.extern.Cmcd.SegmentInfo)} modifySegmentRequest - * The request modifier * @property {!shaka.media.MediaSourceEngine} mediaSourceEngine * The MediaSourceEngine. The caller retains ownership. * @property {shaka.net.NetworkingEngine} netEngine diff --git a/lib/net/networking_engine.js b/lib/net/networking_engine.js index 5354f454e3..af361d1972 100644 --- a/lib/net/networking_engine.js +++ b/lib/net/networking_engine.js @@ -10,6 +10,7 @@ goog.provide('shaka.net.NetworkingEngine.PendingRequest'); goog.require('goog.Uri'); goog.require('goog.asserts'); +goog.require('shaka.media.SegmentReference'); goog.require('shaka.net.Backoff'); goog.require('shaka.util.AbortableOperation'); goog.require('shaka.util.BufferUtils'); @@ -52,8 +53,11 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget { * Called when the headers are received for a download. * @param {shaka.net.NetworkingEngine.OnDownloadFailed=} onDownloadFailed * Called when a download fails, for any reason. + * @param {shaka.net.NetworkingEngine.OnRequest=} onRequest + * Called when a request is made */ - constructor(onProgressUpdated, onHeadersReceived, onDownloadFailed) { + constructor(onProgressUpdated, onHeadersReceived, onDownloadFailed, + onRequest) { super(); /** @private {boolean} */ @@ -77,6 +81,9 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget { /** @private {?shaka.net.NetworkingEngine.OnDownloadFailed} */ this.onDownloadFailed_ = onDownloadFailed || null; + /** @private {?shaka.net.NetworkingEngine.OnRequest} */ + this.onRequest_ = onRequest || null; + /** @private {boolean} */ this.forceHTTPS_ = false; } @@ -247,11 +254,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 + * @param {shaka.net.NetworkingEngine.RequestContext=} context * @return {!shaka.net.NetworkingEngine.PendingRequest} * @export */ - request(type, request, advType) { + request(type, request, context) { const ObjectUtils = shaka.util.ObjectUtils; const numBytesRemainingObj = new shaka.net.NetworkingEngine.NumBytesRemainingClass(); @@ -286,12 +293,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, advType); + const requestFilterOperation = this.filterRequest_(type, request, context); const requestOperation = requestFilterOperation.chain( () => this.makeRequestWithRetry_(type, request, numBytesRemainingObj)); const responseFilterOperation = requestOperation.chain( (responseAndGotProgress) => - this.filterResponse_(type, responseAndGotProgress, advType)); + this.filterResponse_(type, responseAndGotProgress, context)); // Keep track of time spent in filters. const requestFilterStartTime = Date.now(); @@ -342,15 +349,14 @@ 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 + * @param {shaka.net.NetworkingEngine.RequestContext=} context * @return {!shaka.util.AbortableOperation.} * @private */ - filterRequest_(type, request, advType) { + filterRequest_(type, request, context) { let filterOperation = shaka.util.AbortableOperation.completed(undefined); - for (const requestFilter of this.requestFilters_) { - // Request filters are run sequentially. + const applyFilter = (requestFilter) => { filterOperation = filterOperation.chain(() => { if (request.body) { // TODO: For v4.0 we should remove this or change to always pass a @@ -360,8 +366,17 @@ 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, advType); + return requestFilter(type, request, context); }); + }; + + if (this.onRequest_) { + applyFilter(this.onRequest_); + } + + for (const requestFilter of this.requestFilters_) { + // Request filters are run sequentially. + applyFilter(requestFilter); } // Catch any errors thrown by request filters, and substitute @@ -609,12 +624,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 + * @param {shaka.net.NetworkingEngine.RequestContext=} context * @return {!shaka.extern.IAbortableOperation.< * shaka.net.NetworkingEngine.ResponseAndGotProgress>} * @private */ - filterResponse_(type, responseAndGotProgress, advType) { + filterResponse_(type, responseAndGotProgress, context) { let filterOperation = shaka.util.AbortableOperation.completed(undefined); for (const responseFilter of this.responseFilters_) { // Response filters are run sequentially. @@ -624,7 +639,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, advType); + return responseFilter(type, resp, context); }); } // If successful, return the filtered response with whether it got @@ -829,6 +844,27 @@ shaka.net.NetworkingEngine.schemes_ = {}; shaka.net.NetworkingEngine.ResponseAndGotProgress; +/** + * @typedef {{ + * type: (shaka.net.NetworkingEngine.AdvancedRequestType|undefined), + * stream: (shaka.extern.Stream|undefined), + * segment: (shaka.media.SegmentReference|undefined), + * }} + * + * @description + * Defines contextual data about a request + * + * @property {shaka.net.NetworkingEngine.AdvancedRequestType=} type + * The advanced type + * @property {shaka.extern.Stream=} stream + * The duration of the segment in seconds + * @property {shaka.media.SegmentReference=} segment + * The request's segment reference + * @export + */ +shaka.net.NetworkingEngine.RequestContext; + + /** * @typedef {function( * !Object., @@ -856,3 +892,16 @@ shaka.net.NetworkingEngine.OnHeadersReceived; * @export */ shaka.net.NetworkingEngine.OnDownloadFailed; + + +/** + * @typedef {function( + * !shaka.net.NetworkingEngine.RequestType, + * !shaka.extern.Request, + * shaka.net.NetworkingEngine.RequestContext=)} + * + * @description + * A callback function called on every request + * @export + */ +shaka.net.NetworkingEngine.OnRequest; diff --git a/lib/offline/storage.js b/lib/offline/storage.js index c7620b7e04..10c4346be5 100644 --- a/lib/offline/storage.js +++ b/lib/offline/storage.js @@ -1147,10 +1147,6 @@ shaka.offline.Storage = class { const playerInterface = { networkingEngine: networkingEngine, - // No need to apply CMCD data for offline requests - modifyManifestRequest: (request, manifestInfo) => {}, - modifySegmentRequest: (request, segmentInfo) => {}, - // Don't bother filtering now. We will do that later when we have all the // information we need to filter. filter: () => Promise.resolve(), diff --git a/lib/player.js b/lib/player.js index 813e9d1b98..02698fc9a0 100644 --- a/lib/player.js +++ b/lib/player.js @@ -615,6 +615,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget { dependencyInjector(this); } + + // Create the CMCD manager so client data can be attached to all requests + this.cmcdManager_ = this.createCmcd_(); + this.networkingEngine_ = this.createNetworkingEngine(); this.networkingEngine_.setForceHTTPS(this.config_.streaming.forceHTTPS); @@ -901,11 +905,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.config_ = null; this.stats_ = null; this.videoContainer_ = null; - - if (this.cmcdManager_) { - this.cmcdManager_.release(); - this.cmcdManager_ = null; - } + this.cmcdManager_ = null; if (this.networkingEngine_) { await this.networkingEngine_.destroy(); @@ -1308,9 +1308,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { // before we allow calls to |updateStateHistory|. this.stats_ = new shaka.util.Stats(); - // Create the CMCD manager so client data can be attached to all requests - this.cmcdManager_ = this.createCmcd_(); - // Load's request is a little different, so we can't use our normal // listeners-to-promise method. It is the only request where we may skip the // request, so we need to set the on skip callback to reject with a specific @@ -1866,12 +1863,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { const playerInterface = { networkingEngine: networkingEngine, - modifyManifestRequest: (request, manifestInfo) => { - this.cmcdManager_.applyManifestData(request, manifestInfo); - }, - modifySegmentRequest: (request, segmentInfo) => { - this.cmcdManager_.applySegmentData(request, segmentInfo); - }, filter: (manifest) => this.filterManifest_(manifest), makeTextStreamsForClosedCaptions: (manifest) => { return this.makeTextStreamsForClosedCaptions_(manifest); @@ -2889,9 +2880,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget { .set('aborted', aborted); this.dispatchEvent(this.makeEvent_(name, data)); }; + /** @type {shaka.net.NetworkingEngine.OnRequest} */ + const onRequest_ = (type, request, context) => { + this.cmcdManager_.applyData(type, request, context); + }; return new shaka.net.NetworkingEngine( - onProgressUpdated_, onHeadersReceived_, onDownloadFailed_); + onProgressUpdated_, onHeadersReceived_, onDownloadFailed_, onRequest_); } /** @@ -3110,17 +3105,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget { */ createStreamingEngine() { goog.asserts.assert( - this.abrManager_ && this.mediaSourceEngine_ && - this.cmcdManager_ && this.manifest_, + this.abrManager_ && this.mediaSourceEngine_ && this.manifest_, 'Must not be destroyed'); /** @type {shaka.media.StreamingEngine.PlayerInterface} */ const playerInterface = { getPresentationTime: () => this.playhead_ ? this.playhead_.getTime() : 0, getBandwidthEstimate: () => this.abrManager_.getBandwidthEstimate(), - modifySegmentRequest: (request, segmentInfo) => { - this.cmcdManager_.applySegmentData(request, segmentInfo); - }, mediaSourceEngine: this.mediaSourceEngine_, netEngine: this.networkingEngine_, onError: (error) => this.onError_(error), diff --git a/lib/util/cmcd_manager.js b/lib/util/cmcd_manager.js index 3fb4efbce4..2c3822bcc6 100644 --- a/lib/util/cmcd_manager.js +++ b/lib/util/cmcd_manager.js @@ -9,14 +9,11 @@ goog.provide('shaka.util.CmcdManager'); goog.require('goog.Uri'); goog.require('shaka.log'); goog.require('shaka.net.NetworkingEngine'); -goog.require('shaka.util.IReleasable'); /** * @summary * A CmcdManager maintains CMCD state as well as a collection of utility * functions. - * - * @implements {shaka.util.IReleasable} */ shaka.util.CmcdManager = class { /** @@ -58,31 +55,6 @@ shaka.util.CmcdManager = class { * @private {boolean} */ this.starved_ = false; - - /** - * Attach CMCD data to all HEAD requests so they can be - * associated with the playback session. - * - * @private {shaka.extern.RequestFilter} - */ - this.requestFilter_ = (type, request) => { - if (!this.config_.enabled || request.method !== 'HEAD') { - return; - } - - this.apply_(request); - }; - - playerInterface.getNetworkingEngine() - .registerRequestFilter(this.requestFilter_); - } - - /** - * @override - */ - release() { - this.playerInterface_.getNetworkingEngine() - .unregisterRequestFilter(this.requestFilter_); } /** @@ -102,21 +74,58 @@ shaka.util.CmcdManager = class { this.buffering_ = buffering; } + /** + * Apply CMCD data to a request. + * + * @param {!shaka.net.NetworkingEngine.RequestType} type + * The request type + * @param {!shaka.extern.Request} request + * The request to apply CMCD data to + * @param {shaka.net.NetworkingEngine.RequestContext=} context + * The request context + */ + applyData(type, request, context) { + if (!this.config_.enabled) { + return; + } + + if (!context) { + if (request.method === 'HEAD') { + this.apply_(request); + } + return; + } + + const RequestType = shaka.net.NetworkingEngine.RequestType; + + switch (type) { + case RequestType.MANIFEST: + this.applyManifestData(request, context); + break; + + case RequestType.SEGMENT: + this.applySegmentData(request, context); + break; + } + } + /** * Apply CMCD data to a manifest request. * * @param {!shaka.extern.Request} request * The request to apply CMCD data to - * @param {shaka.util.CmcdManager.ManifestInfo} manifestInfo - * The manifest format + * @param {shaka.net.NetworkingEngine.RequestContext} context + * The request context */ - applyManifestData(request, manifestInfo) { + applyManifestData(request, context) { try { if (!this.config_.enabled) { return; } - this.sf_ = manifestInfo.format; + if (context.type) { + this.sf_ = this.getStreamFormat_(context.type); + } this.apply_(request, { ot: shaka.util.CmcdManager.ObjectType.MANIFEST, @@ -132,33 +141,42 @@ shaka.util.CmcdManager = class { * Apply CMCD data to a segment request * * @param {!shaka.extern.Request} request - * @param {shaka.util.CmcdManager.SegmentInfo} segmentInfo + * @param {shaka.net.NetworkingEngine.RequestContext} context + * The request context */ - applySegmentData(request, segmentInfo) { + applySegmentData(request, context) { try { if (!this.config_.enabled) { return; } + const stream = context.stream; + const segment = context.segment; + + let duration = 0; + if (segment) { + duration = segment.endTime - segment.startTime; + } + const data = { - d: segmentInfo.duration * 1000, + d: duration * 1000, st: this.getStreamType_(), }; - data.ot = this.getObjectType_(segmentInfo); + data.ot = this.getObjectType_(context); const ObjectType = shaka.util.CmcdManager.ObjectType; const isMedia = data.ot === ObjectType.VIDEO || - data.ot === ObjectType.AUDIO || - data.ot === ObjectType.MUXED || - data.ot === ObjectType.TIMED_TEXT; + data.ot === ObjectType.AUDIO || + data.ot === ObjectType.MUXED || + data.ot === ObjectType.TIMED_TEXT; if (isMedia) { - data.bl = this.getBufferLength_(segmentInfo.type); + data.bl = this.getBufferLength_(stream.type); } - if (segmentInfo.bandwidth) { - data.br = segmentInfo.bandwidth / 1000; + if (stream.bandwidth) { + data.br = stream.bandwidth / 1000; } if (isMedia && data.ot !== ObjectType.TIMED_TEXT) { @@ -284,7 +302,7 @@ shaka.util.CmcdManager = class { data.pr = this.playerInterface_.getPlaybackRate(); const isVideo = data.ot === shaka.util.CmcdManager.ObjectType.VIDEO || - data.ot === shaka.util.CmcdManager.ObjectType.MUXED; + data.ot === shaka.util.CmcdManager.ObjectType.MUXED; if (this.starved_ && isVideo) { data.bs = true; @@ -320,18 +338,21 @@ shaka.util.CmcdManager = class { /** * The CMCD object type. * - * @param {shaka.util.CmcdManager.SegmentInfo} segmentInfo + * @param {shaka.net.NetworkingEngine.RequestContext} context + * The request context * @private */ - getObjectType_(segmentInfo) { - const type = segmentInfo.type; - - if (segmentInfo.init) { + getObjectType_(context) { + if (context.type === + shaka.net.NetworkingEngine.AdvancedRequestType.INIT_SEGMENT) { return shaka.util.CmcdManager.ObjectType.INIT; } + const stream = context.stream; + const type = stream.type; + if (type == 'video') { - if (segmentInfo.codecs.includes(',')) { + if (stream.codecs.includes(',')) { return shaka.util.CmcdManager.ObjectType.MUXED; } return shaka.util.CmcdManager.ObjectType.VIDEO; @@ -342,7 +363,7 @@ shaka.util.CmcdManager = class { } if (type == 'text') { - if (segmentInfo.mimeType === 'application/mp4') { + if (stream.mimeType === 'application/mp4') { return shaka.util.CmcdManager.ObjectType.TIMED_TEXT; } return shaka.util.CmcdManager.ObjectType.CAPTION; @@ -396,6 +417,29 @@ shaka.util.CmcdManager = class { return (range.end - start) * 1000; } + /** + * Get the stream format + * + * @param {shaka.net.NetworkingEngine.AdvancedRequestType} type + * The request's advanced type + * @return {(shaka.util.CmcdManager.StreamingFormat|undefined)} + * @private + */ + getStreamFormat_(type) { + const AdvancedRequestType = shaka.net.NetworkingEngine.AdvancedRequestType; + + switch (type) { + case AdvancedRequestType.MPD: + return shaka.util.CmcdManager.StreamingFormat.DASH; + + case AdvancedRequestType.MASTER_PLAYLIST: + case AdvancedRequestType.MEDIA_PLAYLIST: + return shaka.util.CmcdManager.StreamingFormat.HLS; + } + + return undefined; + } + /** * Get the stream type * @@ -595,7 +639,6 @@ shaka.util.CmcdManager = class { * getBufferedInfo: function():shaka.extern.BufferedInfo, * getCurrentTime: function():number, * getPlaybackRate: function():number, - * getNetworkingEngine: function():shaka.net.NetworkingEngine, * getVariantTracks: function():Array., * isLive: function():boolean * }} @@ -608,8 +651,6 @@ shaka.util.CmcdManager = class { * Get the current time * @property {function():number} getPlaybackRate * Get the playback rate - * @property {function():shaka.net.NetworkingEngine} getNetworkingEngine - * Get the networking engine * @property {function():Array.} getVariantTracks * Get the variant tracks * @property {function():boolean} isLive diff --git a/test/dash/dash_parser_live_unit.js b/test/dash/dash_parser_live_unit.js index 1fe4ac86e8..6b2d20f65d 100644 --- a/test/dash/dash_parser_live_unit.js +++ b/test/dash/dash_parser_live_unit.js @@ -26,8 +26,6 @@ describe('DashParser Live', () => { parser.configure(shaka.util.PlayerConfiguration.createDefault().manifest); playerInterface = { networkingEngine: fakeNetEngine, - modifyManifestRequest: (request, manifestInfo) => {}, - modifySegmentRequest: (request, segmentInfo) => {}, filter: (manifest) => Promise.resolve(), makeTextStreamsForClosedCaptions: (manifest) => {}, onTimelineRegionAdded: fail, // Should not have any EventStream elements. diff --git a/test/hls/hls_live_unit.js b/test/hls/hls_live_unit.js index ae51076335..361abda0f5 100644 --- a/test/hls/hls_live_unit.js +++ b/test/hls/hls_live_unit.js @@ -66,8 +66,6 @@ describe('HlsParser live', () => { config = shaka.util.PlayerConfiguration.createDefault().manifest; playerInterface = { - modifyManifestRequest: (request, manifestInfo) => {}, - modifySegmentRequest: (request, segmentInfo) => {}, filter: () => Promise.resolve(), makeTextStreamsForClosedCaptions: (manifest) => {}, networkingEngine: fakeNetEngine, diff --git a/test/media/streaming_engine_integration.js b/test/media/streaming_engine_integration.js index beae0db6eb..559003660b 100644 --- a/test/media/streaming_engine_integration.js +++ b/test/media/streaming_engine_integration.js @@ -252,7 +252,6 @@ describe('StreamingEngine', () => { function createStreamingEngine() { const playerInterface = { - modifySegmentRequest: (request, segmentInfo) => {}, getPresentationTime: () => playhead.getTime(), getBandwidthEstimate: () => 1e6, mediaSourceEngine: mediaSourceEngine, diff --git a/test/media/streaming_engine_unit.js b/test/media/streaming_engine_unit.js index a9f4d68741..5bba8486f2 100644 --- a/test/media/streaming_engine_unit.js +++ b/test/media/streaming_engine_unit.js @@ -453,7 +453,6 @@ describe('StreamingEngine', () => { presentationTimeInSeconds != undefined, 'All tests should have defined an initial presentation time by now!'); const playerInterface = { - modifySegmentRequest: (request, segmentInfo) => {}, getPresentationTime: () => presentationTimeInSeconds, getBandwidthEstimate: Util.spyFunc(getBandwidthEstimate), mediaSourceEngine: mediaSourceEngine, diff --git a/test/util/cmcd_manager_unit.js b/test/util/cmcd_manager_unit.js index f2523d671e..4cc4dfa9f0 100644 --- a/test/util/cmcd_manager_unit.js +++ b/test/util/cmcd_manager_unit.js @@ -69,22 +69,23 @@ describe('CmcdManager', () => { const NetworkingEngine = shaka.net.NetworkingEngine; - function createNetworkingEngine() { - const resolveScheme = jasmine.createSpy('resolve scheme').and.callFake( + function createNetworkingEngine(cmcd) { + const resolveScheme = jasmine.createSpy('cmcd').and.callFake( () => shaka.util.AbortableOperation.completed( {uri: '', data: new ArrayBuffer(5), headers: {}}, )); NetworkingEngine.registerScheme( - 'resolve', shaka.test.Util.spyFunc(resolveScheme), + 'cmcd', shaka.test.Util.spyFunc(resolveScheme), NetworkingEngine.PluginPriority.FALLBACK); - return new NetworkingEngine(); + return new NetworkingEngine(null, null, null, (type, request, context) => { + cmcd.applyData(type, request, context); + }); } describe('CmcdManager instance', () => { const ObjectUtils = shaka.util.ObjectUtils; - const networkingEngine = createNetworkingEngine(); const playerInterface = { isLive: () => false, getBandwidthEstimate: () => 10000000, @@ -97,7 +98,6 @@ describe('CmcdManager', () => { }), getCurrentTime: () => 10, getPlaybackRate: () => 1, - getNetworkingEngine: () => networkingEngine, getVariantTracks: () => /** @type {Array.} */([ { type: 'variant', @@ -142,18 +142,25 @@ describe('CmcdManager', () => { streamDataCallback: null, }; - const manifestInfo = { - format: shaka.util.CmcdManager.StreamingFormat.DASH, + const createContext = (type) => { + return { + type: type, + stream: /** @type {shaka.extern.Stream} */ ({ + bandwidth: 5234167, + codecs: 'avc1.42001e', + mimeType: 'application/mp4', + type: 'video', + }), + segment: /** @type {shaka.media.SegmentReference} */ ({ + startTime: 0, + endTime: 3.33, + }), + }; }; - const segmentInfo = { - type: 'video', - init: false, - duration: 3.33, - mimeType: 'application/mp4', - codecs: 'avc1.42001e', - bandwidth: 5234167, - }; + const AdvancedRequestType = NetworkingEngine.AdvancedRequestType; + const manifestInfo = createContext(AdvancedRequestType.MPD); + const segmentInfo = createContext(AdvancedRequestType.MEDIA_SEGMENT); describe('configuration', () => { it('does not modify requests when disabled', () => { @@ -306,8 +313,8 @@ describe('CmcdManager', () => { it('applies core CMCD params to HEAD requests', async () => { config.useHeaders = false; cmcdManager = new CmcdManager(playerInterface, config); - - const uri = 'resolve://foo'; + const networkingEngine = createNetworkingEngine(cmcdManager); + const uri = 'cmcd://foo'; const type = NetworkingEngine.RequestType.MANIFEST; const retry = NetworkingEngine.defaultRetryParameters(); const request = NetworkingEngine.makeRequest([uri], retry); From daf16aea4004671361ccb1e1e51726bb2def4a8e Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Mon, 13 Mar 2023 17:08:11 -0700 Subject: [PATCH 11/19] lint fix --- test/util/cmcd_manager_unit.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/util/cmcd_manager_unit.js b/test/util/cmcd_manager_unit.js index 4cc4dfa9f0..9027df69ad 100644 --- a/test/util/cmcd_manager_unit.js +++ b/test/util/cmcd_manager_unit.js @@ -79,9 +79,19 @@ describe('CmcdManager', () => { 'cmcd', shaka.test.Util.spyFunc(resolveScheme), NetworkingEngine.PluginPriority.FALLBACK); - return new NetworkingEngine(null, null, null, (type, request, context) => { + + /** + * + * @param {shaka.net.NetworkingEngine.RequestType} type + * @param {shaka.extern.Request} request + * @param {shaka.net.NetworkingEngine.RequestContext=} context + */ + function onRequest(type, request, context) { cmcd.applyData(type, request, context); - }); + } + + return new NetworkingEngine(undefined, undefined, undefined, + onRequest); } describe('CmcdManager instance', () => { From 578c9e236c0b04da71360a9e7045e5db7a5993c2 Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Mon, 13 Mar 2023 18:10:47 -0700 Subject: [PATCH 12/19] build fixes and doc updates --- demo/common/asset.js | 2 +- 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 +- lib/dash/dash_parser.js | 4 +- lib/media/streaming_engine.js | 4 +- lib/net/networking_engine.js | 4 +- lib/util/fairplay_utils.js | 24 ++--- test/dash/dash_parser_live_unit.js | 24 +++-- test/dash/dash_parser_manifest_unit.js | 2 +- test/hls/hls_live_unit.js | 12 ++- test/media/drm_engine_unit.js | 2 +- test/media/streaming_engine_integration.js | 9 +- test/media/streaming_engine_unit.js | 99 ++++++++++--------- test/test/util/fake_networking_engine.js | 33 ++++--- test/test/util/streaming_engine_util.js | 2 +- test/util/cmcd_manager_unit.js | 7 +- 19 files changed, 132 insertions(+), 120 deletions(-) diff --git a/demo/common/asset.js b/demo/common/asset.js index bbd57e5532..201e9e0a84 100644 --- a/demo/common/asset.js +++ b/demo/common/asset.js @@ -373,7 +373,7 @@ const ShakaDemoAssetInfo = class { if (this.licenseRequestHeaders.size) { /** @type {!shaka.extern.RequestFilter} */ - const filter = (requestType, request, advType) => { + const filter = (requestType, request, context) => { return this.addLicenseRequestHeaders_(this.licenseRequestHeaders, requestType, request); diff --git a/docs/tutorials/ad_monetization.md b/docs/tutorials/ad_monetization.md index 8532792491..308826caec 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, advType) { + player.getNetworkingEngine().registerRequestFilter(function(type, request, context) { 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 58c602b03f..f45a68537e 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, advType) => { +player.getNetworkingEngine().registerResponseFilter(async (type, response, context) => { // 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 0bad7064b3..d00a10d1b2 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, advType) => { +player.getNetworkingEngine().registerRequestFilter((type, request, context) => { if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) { return; } @@ -103,7 +103,7 @@ player.getNetworkingEngine().registerRequestFilter((type, request, advType) => { request.body = shaka.util.StringUtils.toUTF8(encodeURIComponent(params)); }); -player.getNetworkingEngine().registerResponseFilter((type, response, advType) => { +player.getNetworkingEngine().registerResponseFilter((type, response, context) => { 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, advType) => { +player.getNetworkingEngine().registerRequestFilter((type, request, context) => { 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, advType) => { +player.getNetworkingEngine().registerRequestFilter((type, request, context) => { 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 be1ffa01cf..13331fb23e 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, advType) { + player.getNetworkingEngine().registerRequestFilter(function(type, request, context) { // 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, advType) { + player.getNetworkingEngine().registerRequestFilter(function(type, request, context) { // 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, advType) { + player.getNetworkingEngine().registerRequestFilter(function(type, request, context) { 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, advType) { + player.getNetworkingEngine().registerRequestFilter(function(type, request, context) { // 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 61011a6cfa..2ad502cca6 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, advType) { + player.getNetworkingEngine().registerRequestFilter(function(type, request, context) { // 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, advType) { + player.getNetworkingEngine().registerResponseFilter(function(type, response, context) { // Alias some utilities provided by the library. const StringUtils = shaka.util.StringUtils; const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils; diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index 91bc0db408..5c7c549168 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -1833,7 +1833,7 @@ shaka.dash.DashParser = class { */ async requestSegment_(uris, startByte, endByte, isInit) { const requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT; - const advType = isInit ? + const type = isInit ? shaka.net.NetworkingEngine.AdvancedRequestType.INIT_SEGMENT : shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; @@ -1845,7 +1845,7 @@ shaka.dash.DashParser = class { const networkingEngine = this.playerInterface_.networkingEngine; const operation = networkingEngine.request( - requestType, request, {type: advType}); + requestType, request, {type: type}); this.operationManager_.manage(operation); const response = await operation.promise; return response.data; diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index 30622238c4..e95ec8c63b 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -2109,7 +2109,7 @@ shaka.media.StreamingEngine = class { */ dispatchFetch_(reference, stream, streamDataCallback, isInit) { const requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT; - const advType = isInit ? + const type = isInit ? shaka.net.NetworkingEngine.AdvancedRequestType.INIT_SEGMENT : shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; const segment = reference instanceof shaka.media.SegmentReference ? @@ -2125,7 +2125,7 @@ shaka.media.StreamingEngine = class { return this.playerInterface_.netEngine.request( requestType, request, { - type: advType, + type: type, stream: stream, segment: segment, }); diff --git a/lib/net/networking_engine.js b/lib/net/networking_engine.js index af361d1972..4fc1207ddc 100644 --- a/lib/net/networking_engine.js +++ b/lib/net/networking_engine.js @@ -848,7 +848,7 @@ shaka.net.NetworkingEngine.ResponseAndGotProgress; * @typedef {{ * type: (shaka.net.NetworkingEngine.AdvancedRequestType|undefined), * stream: (shaka.extern.Stream|undefined), - * segment: (shaka.media.SegmentReference|undefined), + * segment: (shaka.media.SegmentReference|undefined) * }} * * @description @@ -898,7 +898,7 @@ shaka.net.NetworkingEngine.OnDownloadFailed; * @typedef {function( * !shaka.net.NetworkingEngine.RequestType, * !shaka.extern.Request, - * shaka.net.NetworkingEngine.RequestContext=)} + * (shaka.net.NetworkingEngine.RequestContext|undefined))} * * @description * A callback function called on every request diff --git a/lib/util/fairplay_utils.js b/lib/util/fairplay_utils.js index 22661f2b5b..e83b4e3443 100644 --- a/lib/util/fairplay_utils.js +++ b/lib/util/fairplay_utils.js @@ -233,10 +233,10 @@ shaka.util.FairPlayUtils = class { * * @param {shaka.net.NetworkingEngine.RequestType} type * @param {shaka.extern.Request} request - * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType + * @param {shaka.net.NetworkingEngine.RequestContext=} context * @export */ - static verimatrixFairPlayRequest(type, request, advType) { + static verimatrixFairPlayRequest(type, request, context) { if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) { return; } @@ -252,10 +252,10 @@ shaka.util.FairPlayUtils = class { * * @param {shaka.net.NetworkingEngine.RequestType} type * @param {shaka.extern.Request} request - * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType + * @param {shaka.net.NetworkingEngine.RequestContext=} context * @private */ - static octetStreamFairPlayRequest_(type, request, advType) { + static octetStreamFairPlayRequest_(type, request, context) { if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) { return; } @@ -267,10 +267,10 @@ shaka.util.FairPlayUtils = class { * * @param {shaka.net.NetworkingEngine.RequestType} type * @param {shaka.extern.Request} request - * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType + * @param {shaka.net.NetworkingEngine.RequestContext=} context * @export */ - static ezdrmFairPlayRequest(type, request, advType) { + static ezdrmFairPlayRequest(type, request, context) { shaka.util.FairPlayUtils.octetStreamFairPlayRequest_(type, request); } @@ -279,10 +279,10 @@ shaka.util.FairPlayUtils = class { * * @param {shaka.net.NetworkingEngine.RequestType} type * @param {shaka.extern.Request} request - * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType + * @param {shaka.net.NetworkingEngine.RequestContext=} context * @export */ - static conaxFairPlayRequest(type, request, advType) { + static conaxFairPlayRequest(type, request, context) { shaka.util.FairPlayUtils.octetStreamFairPlayRequest_(type, request); } @@ -291,10 +291,10 @@ shaka.util.FairPlayUtils = class { * * @param {shaka.net.NetworkingEngine.RequestType} type * @param {shaka.extern.Request} request - * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType + * @param {shaka.net.NetworkingEngine.RequestContext=} context * @export */ - static expressplayFairPlayRequest(type, request, advType) { + static expressplayFairPlayRequest(type, request, context) { shaka.util.FairPlayUtils.octetStreamFairPlayRequest_(type, request); } @@ -303,10 +303,10 @@ shaka.util.FairPlayUtils = class { * * @param {shaka.net.NetworkingEngine.RequestType} type * @param {shaka.extern.Response} response - * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType + * @param {shaka.net.NetworkingEngine.RequestContext=} context * @export */ - static commonFairPlayResponse(type, response, advType) { + static commonFairPlayResponse(type, response, context) { 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 6b2d20f65d..8837f0498b 100644 --- a/test/dash/dash_parser_live_unit.js +++ b/test/dash/dash_parser_live_unit.js @@ -706,19 +706,21 @@ describe('DashParser Live', () => { fakeNetEngine.setResponseText('dummy://foo', manifestText); const manifestRequest = shaka.net.NetworkingEngine.RequestType.MANIFEST; - const manifestAdv = shaka.net.NetworkingEngine.AdvancedRequestType.MPD; + const manifestContext = { + type: shaka.net.NetworkingEngine.AdvancedRequestType.MPD, + }; await parser.start('dummy://foo', playerInterface); expect(fakeNetEngine.request).toHaveBeenCalledTimes(1); - fakeNetEngine.expectRequest('dummy://foo', manifestRequest, manifestAdv); + fakeNetEngine.expectRequest('dummy://foo', manifestRequest, manifestContext); 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, advType) => { + fakeNetEngine.request.and.callFake((type, request, context) => { expect(type).toBe(manifestRequest); - expect(advType).toBe(manifestAdv); + expect(context).toBe(manifestContext); expect(request.uris).toEqual( ['http://foobar', 'http://foobar2', 'dummy://foo/foobar3']); const data = shaka.util.StringUtils.toUTF8(manifestText); @@ -951,7 +953,9 @@ describe('DashParser Live', () => { describe('stop', () => { const manifestRequestType = shaka.net.NetworkingEngine.RequestType.MANIFEST; - const manifestAdvType = shaka.net.NetworkingEngine.AdvancedRequestType.MPD; + const manifestContext = { + type: shaka.net.NetworkingEngine.AdvancedRequestType.MPD, + }; const dateRequestType = shaka.net.NetworkingEngine.RequestType.TIMING; const manifestUri = 'dummy://foo'; const dateUri = 'http://foo.bar/date'; @@ -984,7 +988,7 @@ describe('DashParser Live', () => { await parser.start(manifestUri, playerInterface); fakeNetEngine.expectRequest( - manifestUri, manifestRequestType, manifestAdvType); + manifestUri, manifestRequestType, manifestContext); fakeNetEngine.request.calls.reset(); parser.stop(); @@ -1003,7 +1007,7 @@ describe('DashParser Live', () => { await expectation; fakeNetEngine.expectRequest( - manifestUri, manifestRequestType, manifestAdvType); + manifestUri, manifestRequestType, manifestContext); fakeNetEngine.request.calls.reset(); await updateManifest(); // An update should not occur. @@ -1015,7 +1019,7 @@ describe('DashParser Live', () => { expect(manifest).toBeTruthy(); fakeNetEngine.expectRequest( - manifestUri, manifestRequestType, manifestAdvType); + manifestUri, manifestRequestType, manifestContext); fakeNetEngine.request.calls.reset(); /** @type {!shaka.util.PublicPromise} */ const delay = fakeNetEngine.delayNextRequest(); @@ -1024,7 +1028,7 @@ describe('DashParser Live', () => { // The request was made but should not be resolved yet. expect(fakeNetEngine.request).toHaveBeenCalledTimes(1); fakeNetEngine.expectRequest( - manifestUri, manifestRequestType, manifestAdvType); + manifestUri, manifestRequestType, manifestContext); fakeNetEngine.request.calls.reset(); parser.stop(); delay.resolve(); @@ -1046,7 +1050,7 @@ describe('DashParser Live', () => { // This is the initial manifest request. expect(fakeNetEngine.request).toHaveBeenCalledTimes(1); fakeNetEngine.expectRequest( - manifestUri, manifestRequestType, manifestAdvType); + manifestUri, manifestRequestType, manifestContext); 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 7c2b63a2f5..b261e2bdc2 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, advType) => { + fakeNetEngine.request.and.callFake((type, request, context) => { if (request.uris[0] == 'http://foo.bar/manifest') { const data = shaka.util.StringUtils.toUTF8(source); return shaka.util.AbortableOperation.completed({ diff --git a/test/hls/hls_live_unit.js b/test/hls/hls_live_unit.js index 361abda0f5..8b825274a5 100644 --- a/test/hls/hls_live_unit.js +++ b/test/hls/hls_live_unit.js @@ -371,10 +371,13 @@ describe('HlsParser live', () => { manifest, mediaWithAdditionalSegment + '#EXT-X-ENDLIST\n'); // We saw one request for the video playlist, which signalled "ENDLIST". + const type = + shaka.net.NetworkingEngine.AdvancedRequestType.MASTER_PLAYLIST; + fakeNetEngine.expectRequest( 'test:/video', shaka.net.NetworkingEngine.RequestType.MANIFEST, - shaka.net.NetworkingEngine.AdvancedRequestType.MASTER_PLAYLIST); + {type: type}); expect(manifest.presentationTimeline.isLive()).toBe(false); fakeNetEngine.request.calls.reset(); @@ -840,10 +843,12 @@ describe('HlsParser live', () => { // Only one request was made, and it was for the playlist. // No segment requests were needed to get the start time. expect(fakeNetEngine.request).toHaveBeenCalledTimes(1); + const type = + shaka.net.NetworkingEngine.AdvancedRequestType.MASTER_PLAYLIST; fakeNetEngine.expectRequest( 'test:/video', shaka.net.NetworkingEngine.RequestType.MANIFEST, - shaka.net.NetworkingEngine.AdvancedRequestType.MASTER_PLAYLIST); + {type: type}); }); it('request playlist delta updates to skip segments', async () => { @@ -886,7 +891,8 @@ describe('HlsParser live', () => { fakeNetEngine.expectRequest( 'test:/video?_HLS_skip=YES', shaka.net.NetworkingEngine.RequestType.MANIFEST, - shaka.net.NetworkingEngine.AdvancedRequestType.MASTER_PLAYLIST); + {type: + 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 729ac68484..f34c70deb1 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, advType) => { + fakeNetEngine.request.and.callFake((type, request, context) => { 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 559003660b..fcfe98c8ed 100644 --- a/test/media/streaming_engine_integration.js +++ b/test/media/streaming_engine_integration.js @@ -356,12 +356,13 @@ describe('StreamingEngine', () => { await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 305); const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT; - const segmentAdvType = - shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; + const segmentContext = { + type: shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT, + }; // firstSegmentNumber = // [(segmentAvailabilityEnd - rebufferingGoal) / segmentDuration] + 1 - netEngine.expectRequest('0_video_29', segmentType, segmentAdvType); - netEngine.expectRequest('0_audio_29', segmentType, segmentAdvType); + netEngine.expectRequest('0_video_29', segmentType, segmentContext); + netEngine.expectRequest('0_audio_29', segmentType, segmentContext); }); 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 5bba8486f2..e6100ffaff 100644 --- a/test/media/streaming_engine_unit.js +++ b/test/media/streaming_engine_unit.js @@ -567,24 +567,25 @@ describe('StreamingEngine', () => { /* isInit= */ true); const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT; - const segmentAdvType = - shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; + const segmentContext = { + type: shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT, + }; - 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_0', segmentType, segmentContext); + netEngine.expectRequest('0_video_0', segmentType, segmentContext); + netEngine.expectRequest('0_text_0', segmentType, segmentContext); - netEngine.expectRequest('0_audio_1', segmentType, segmentAdvType); - netEngine.expectRequest('0_video_1', segmentType, segmentAdvType); - netEngine.expectRequest('0_text_1', segmentType, segmentAdvType); + netEngine.expectRequest('0_audio_1', segmentType, segmentContext); + netEngine.expectRequest('0_video_1', segmentType, segmentContext); + netEngine.expectRequest('0_text_1', segmentType, segmentContext); - 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_2', segmentType, segmentContext); + netEngine.expectRequest('1_video_2', segmentType, segmentContext); + netEngine.expectRequest('1_text_2', segmentType, segmentContext); - netEngine.expectRequest('1_audio_3', segmentType, segmentAdvType); - netEngine.expectRequest('1_video_3', segmentType, segmentAdvType); - netEngine.expectRequest('1_text_3', segmentType, segmentAdvType); + netEngine.expectRequest('1_audio_3', segmentType, segmentContext); + netEngine.expectRequest('1_video_3', segmentType, segmentContext); + netEngine.expectRequest('1_text_3', segmentType, segmentContext); }); describe('unloadTextStream', () => { @@ -602,18 +603,19 @@ describe('StreamingEngine', () => { // is sent. await runTest(() => { const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT; - const segmentAdvType = - shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; + const segmentContext = { + type: shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT, + }; if (presentationTimeInSeconds == 1) { - netEngine.expectRequest('0_text_0', segmentType, segmentAdvType); + netEngine.expectRequest('0_text_0', segmentType, segmentContext); netEngine.request.calls.reset(); streamingEngine.unloadTextStream(); } else if (presentationTimeInSeconds == 35) { - 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); + netEngine.expectNoRequest('0_text_0', segmentType, segmentContext); + netEngine.expectNoRequest('0_text_1', segmentType, segmentContext); + netEngine.expectNoRequest('1_text_2', segmentType, segmentContext); + netEngine.expectNoRequest('1_text_3', segmentType, segmentContext); } }); }); @@ -865,24 +867,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, segmentAdvType); - netEngine.expectRequest('0_video_0', segmentType, segmentAdvType); - netEngine.expectRequest('0_text_0', segmentType, segmentAdvType); + const segmentContext = { + type: shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT, + }; + netEngine.expectRequest('0_audio_0', segmentType, segmentContext); + netEngine.expectRequest('0_video_0', segmentType, segmentContext); + netEngine.expectRequest('0_text_0', segmentType, segmentContext); - netEngine.expectRequest('0_audio_1', segmentType, segmentAdvType); - netEngine.expectRequest('0_video_1', segmentType, segmentAdvType); - netEngine.expectRequest('0_text_1', segmentType, segmentAdvType); + netEngine.expectRequest('0_audio_1', segmentType, segmentContext); + netEngine.expectRequest('0_video_1', segmentType, segmentContext); + netEngine.expectRequest('0_text_1', segmentType, segmentContext); - 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_2', segmentType, segmentContext); + netEngine.expectRequest('1_video_2', segmentType, segmentContext); + netEngine.expectRequest('1_text_2', segmentType, segmentContext); - netEngine.expectNoRequest('1_audio_3', segmentType, segmentAdvType); - netEngine.expectNoRequest('1_video_3', segmentType, segmentAdvType); - netEngine.expectNoRequest('1_text_3', segmentType, segmentAdvType); + netEngine.expectNoRequest('1_audio_3', segmentType, segmentContext); + netEngine.expectNoRequest('1_video_3', segmentType, segmentContext); + netEngine.expectNoRequest('1_text_3', segmentType, segmentContext); }); it('does not buffer one media type ahead of another', async () => { @@ -1157,12 +1159,14 @@ describe('StreamingEngine', () => { await Util.fakeEventLoop(5); const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT; - const segmentAdvType = - shaka.net.NetworkingEngine.AdvancedRequestType.INIT_SEGMENT; + const segmentContext = { + type: 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, segmentAdvType); - netEngine.expectNoRequest('text-21-init', segmentType, segmentAdvType); + netEngine.expectRequest('text-20-init', segmentType, segmentContext); + netEngine.expectNoRequest('text-21-init', segmentType, segmentContext); // TODO: huh? }); }); @@ -3099,7 +3103,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, advType) => { + netEngine.request.and.callFake((requestType, request, context) => { const buffer = new ArrayBuffer(0); const response = {uri: request.uris[0], data: buffer, headers: {}}; const bytes = new shaka.net.NetworkingEngine.NumBytesRemainingClass(); @@ -3421,7 +3425,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, advType) => { + netEngine.request.and.callFake((requestType, request, context) => { const buffer = new ArrayBuffer(0); /** @type {shaka.extern.Response} */ const response = {uri: request.uris[0], data: buffer, headers: {}}; @@ -3661,7 +3665,7 @@ describe('StreamingEngine', () => { let isRequested = false; let isAborted = false; - netEngine.request.and.callFake((requestType, request, advType) => { + netEngine.request.and.callFake((requestType, request, context) => { isRequested = true; const abortOp = () => { @@ -3837,14 +3841,15 @@ describe('StreamingEngine', () => { '1_audio_3', '1_video_3', ]; - const segmentAdvType = - shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; + const context = { + type: shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT, + }; for (const request of requests) { if (hasRequest) { - netEngine.expectRequest(request, segmentType, segmentAdvType); + netEngine.expectRequest(request, segmentType, context); } else { - netEngine.expectNoRequest(request, segmentType, segmentAdvType); + netEngine.expectNoRequest(request, segmentType, context); } } } diff --git a/test/test/util/fake_networking_engine.js b/test/test/util/fake_networking_engine.js index 370bc64762..aa9d084a59 100644 --- a/test/test/util/fake_networking_engine.js +++ b/test/test/util/fake_networking_engine.js @@ -174,11 +174,11 @@ shaka.test.FakeNetworkingEngine = class { * * @param {string} uri * @param {shaka.net.NetworkingEngine.RequestType} type - * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType + * @param {shaka.net.NetworkingEngine.RequestContext=} context */ - expectRequest(uri, type, advType) { + expectRequest(uri, type, context) { shaka.test.FakeNetworkingEngine.expectRequest( - this.request, uri, type, advType); + this.request, uri, type, context); } /** @@ -186,11 +186,11 @@ shaka.test.FakeNetworkingEngine = class { * * @param {string} uri * @param {shaka.net.NetworkingEngine.RequestType} type - * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType + * @param {shaka.net.NetworkingEngine.RequestContext=} context */ - expectNoRequest(uri, type, advType) { + expectNoRequest(uri, type, context) { shaka.test.FakeNetworkingEngine.expectNoRequest( - this.request, uri, type, advType); + this.request, uri, type, context); } /** @@ -294,13 +294,13 @@ shaka.test.FakeNetworkingEngine = class { * @param {!Object} requestSpy * @param {string} uri * @param {shaka.net.NetworkingEngine.RequestType} type - * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType + * @param {shaka.net.NetworkingEngine.RequestContext=} context */ - static expectRequest(requestSpy, uri, type, advType) { + static expectRequest(requestSpy, uri, type, context) { // Jasmine "toHaveBeenCalledWith" doesn't handle optional parameters well. - if (advType != undefined) { + if (context != undefined) { expect(requestSpy).toHaveBeenCalledWith( - type, jasmine.objectContaining({uris: [uri]}), advType); + type, jasmine.objectContaining({uris: [uri]}), context); } else { expect(requestSpy).toHaveBeenCalledWith( type, jasmine.objectContaining({uris: [uri]})); @@ -313,13 +313,14 @@ shaka.test.FakeNetworkingEngine = class { * @param {!Object} requestSpy * @param {string} uri * @param {shaka.net.NetworkingEngine.RequestType} type - * @param {shaka.net.NetworkingEngine.AdvancedRequestType=} advType + * @param {shaka.net.NetworkingEngine.RequestContext=} context */ - static expectNoRequest(requestSpy, uri, type, advType) { + static expectNoRequest(requestSpy, uri, type, context) { // Jasmine "toHaveBeenCalledWith" doesn't handle optional parameters well. - if (advType != undefined) { + if (context != undefined) { expect(requestSpy).not.toHaveBeenCalledWith( - type, jasmine.objectContaining({uris: [uri]}), advType); + type, jasmine.objectContaining({uris: [uri]}), + jasmine.objectContaining(context)); } else { expect(requestSpy).not.toHaveBeenCalledWith( type, jasmine.objectContaining({uris: [uri]})); @@ -347,7 +348,7 @@ shaka.test.FakeNetworkingEngine = class { headers['Range'] = range; } - const advType = isInit ? + const type = isInit ? shaka.net.NetworkingEngine.AdvancedRequestType.INIT_SEGMENT : shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT; @@ -357,7 +358,7 @@ shaka.test.FakeNetworkingEngine = class { uris: [uri], headers: headers, }), - advType); + {type: type}); } }; diff --git a/test/test/util/streaming_engine_util.js b/test/test/util/streaming_engine_util.js index d288e02b9c..4c95ccf627 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, advType) => { + netEngine.request.and.callFake((requestType, request, context) => { expect(requestType).toBeTruthy(); expect(request.uris.length).toBe(1); diff --git a/test/util/cmcd_manager_unit.js b/test/util/cmcd_manager_unit.js index 9027df69ad..07baa13ef6 100644 --- a/test/util/cmcd_manager_unit.js +++ b/test/util/cmcd_manager_unit.js @@ -80,12 +80,7 @@ describe('CmcdManager', () => { NetworkingEngine.PluginPriority.FALLBACK); - /** - * - * @param {shaka.net.NetworkingEngine.RequestType} type - * @param {shaka.extern.Request} request - * @param {shaka.net.NetworkingEngine.RequestContext=} context - */ + /** @type {shaka.net.NetworkingEngine.OnRequest} */ function onRequest(type, request, context) { cmcd.applyData(type, request, context); } From b7ea19d1845a6468df1599a2b46aa4084ff10252 Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Mon, 13 Mar 2023 18:37:25 -0700 Subject: [PATCH 13/19] fix unit test util --- test/test/util/fake_networking_engine.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test/util/fake_networking_engine.js b/test/test/util/fake_networking_engine.js index aa9d084a59..9cad25f3f6 100644 --- a/test/test/util/fake_networking_engine.js +++ b/test/test/util/fake_networking_engine.js @@ -320,7 +320,7 @@ shaka.test.FakeNetworkingEngine = class { if (context != undefined) { expect(requestSpy).not.toHaveBeenCalledWith( type, jasmine.objectContaining({uris: [uri]}), - jasmine.objectContaining(context)); + jasmine.objectContaining({type: context.type})); } else { expect(requestSpy).not.toHaveBeenCalledWith( type, jasmine.objectContaining({uris: [uri]})); From 270b93a7131bf8ba69a93d03c2ef5e788866a5a1 Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Mon, 13 Mar 2023 19:25:55 -0700 Subject: [PATCH 14/19] test improvements --- test/dash/dash_parser_live_unit.js | 2 +- test/test/util/fake_networking_engine.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test/dash/dash_parser_live_unit.js b/test/dash/dash_parser_live_unit.js index 8837f0498b..26ca68b9d7 100644 --- a/test/dash/dash_parser_live_unit.js +++ b/test/dash/dash_parser_live_unit.js @@ -720,7 +720,7 @@ describe('DashParser Live', () => { // absolute url. fakeNetEngine.request.and.callFake((type, request, context) => { expect(type).toBe(manifestRequest); - expect(context).toBe(manifestContext); + expect(context).toEqual(manifestContext); expect(request.uris).toEqual( ['http://foobar', 'http://foobar2', 'dummy://foo/foobar3']); const data = shaka.util.StringUtils.toUTF8(manifestText); diff --git a/test/test/util/fake_networking_engine.js b/test/test/util/fake_networking_engine.js index 9cad25f3f6..69810850bc 100644 --- a/test/test/util/fake_networking_engine.js +++ b/test/test/util/fake_networking_engine.js @@ -300,7 +300,8 @@ shaka.test.FakeNetworkingEngine = class { // Jasmine "toHaveBeenCalledWith" doesn't handle optional parameters well. if (context != undefined) { expect(requestSpy).toHaveBeenCalledWith( - type, jasmine.objectContaining({uris: [uri]}), context); + type, jasmine.objectContaining({uris: [uri]}), + jasmine.objectContaining({type: context.type})); } else { expect(requestSpy).toHaveBeenCalledWith( type, jasmine.objectContaining({uris: [uri]})); @@ -358,7 +359,7 @@ shaka.test.FakeNetworkingEngine = class { uris: [uri], headers: headers, }), - {type: type}); + jasmine.objectContaining({type: type})); } }; From 1fc16650602a6bfb490e20f3cdd2afe91ea094a7 Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Mon, 13 Mar 2023 20:23:33 -0700 Subject: [PATCH 15/19] PR suggestions --- externs/shaka/net.js | 2 +- lib/dash/dash_parser.js | 6 ++-- lib/net/networking_engine.js | 1 + lib/util/cmcd_manager.js | 44 ++---------------------- test/hls/hls_live_unit.js | 4 +-- test/test/util/fake_networking_engine.js | 2 +- 6 files changed, 10 insertions(+), 49 deletions(-) diff --git a/externs/shaka/net.js b/externs/shaka/net.js index c5fd11847a..2851f76a54 100644 --- a/externs/shaka/net.js +++ b/externs/shaka/net.js @@ -205,7 +205,7 @@ shaka.extern.HeadersReceived; * The RequestType describes the basic type of the request (manifest, segment, * etc). The optional RequestContext will be provided where applicable to * provide additional infomation about the request. A request filter can run - * asynchronously by returning a promise; in this case,the request will not be + * 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, diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index 5c7c549168..1b6e0c3eb1 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -226,8 +226,7 @@ shaka.dash.DashParser = class { this.manifestUris_, this.config_.retryParameters); const networkingEngine = this.playerInterface_.networkingEngine; const startTime = Date.now(); - const operation = networkingEngine.request( - requestType, request, {type: type}); + const operation = networkingEngine.request(requestType, request, {type}); this.operationManager_.manage(operation); const response = await operation.promise; @@ -1844,8 +1843,7 @@ shaka.dash.DashParser = class { this.config_.retryParameters); const networkingEngine = this.playerInterface_.networkingEngine; - const operation = networkingEngine.request( - requestType, request, {type: type}); + const operation = networkingEngine.request(requestType, request, {type}); this.operationManager_.manage(operation); const response = await operation.promise; return response.data; diff --git a/lib/net/networking_engine.js b/lib/net/networking_engine.js index 4fc1207ddc..9074449f0c 100644 --- a/lib/net/networking_engine.js +++ b/lib/net/networking_engine.js @@ -786,6 +786,7 @@ shaka.net.NetworkingEngine.AdvancedRequestType = { 'MEDIA_PLAYLIST': 2, 'MASTER_PLAYLIST': 3, 'MPD': 4, + 'MSS': 5, }; diff --git a/lib/util/cmcd_manager.js b/lib/util/cmcd_manager.js index 2c3822bcc6..99c1c5677b 100644 --- a/lib/util/cmcd_manager.js +++ b/lib/util/cmcd_manager.js @@ -435,6 +435,9 @@ shaka.util.CmcdManager = class { case AdvancedRequestType.MASTER_PLAYLIST: case AdvancedRequestType.MEDIA_PLAYLIST: return shaka.util.CmcdManager.StreamingFormat.HLS; + + case AdvancedRequestType.MSS: + return shaka.util.CmcdManager.StreamingFormat.SMOOTH; } return undefined; @@ -659,47 +662,6 @@ shaka.util.CmcdManager = class { shaka.util.CmcdManager.PlayerInterface; -/** - * @typedef {{ - * type: string, - * init: boolean, - * duration: number, - * mimeType: string, - * codecs: string, - * bandwidth: (number|undefined) - * }} - * - * @property {string} type - * The media type - * @property {boolean} init - * Flag indicating whether the segment is an init segment - * @property {number} duration - * The duration of the segment in seconds - * @property {string} mimeType - * The segment's mime type - * @property {string} codecs - * The segment's codecs - * @property {(number|undefined)} bandwidth - * The segment's variation bandwidth - * - * @export - */ -shaka.util.CmcdManager.SegmentInfo; - - -/** - * @typedef {{ - * format: shaka.util.CmcdManager.StreamingFormat - * }} - * - * @property {shaka.util.CmcdManager.StreamingFormat} format - * The manifest's stream format - * - * @export - */ -shaka.util.CmcdManager.ManifestInfo; - - /** * @enum {string} */ diff --git a/test/hls/hls_live_unit.js b/test/hls/hls_live_unit.js index 8b825274a5..a1bbb63460 100644 --- a/test/hls/hls_live_unit.js +++ b/test/hls/hls_live_unit.js @@ -377,7 +377,7 @@ describe('HlsParser live', () => { fakeNetEngine.expectRequest( 'test:/video', shaka.net.NetworkingEngine.RequestType.MANIFEST, - {type: type}); + {type}); expect(manifest.presentationTimeline.isLive()).toBe(false); fakeNetEngine.request.calls.reset(); @@ -848,7 +848,7 @@ describe('HlsParser live', () => { fakeNetEngine.expectRequest( 'test:/video', shaka.net.NetworkingEngine.RequestType.MANIFEST, - {type: type}); + {type}); }); it('request playlist delta updates to skip segments', async () => { diff --git a/test/test/util/fake_networking_engine.js b/test/test/util/fake_networking_engine.js index 69810850bc..632687ef71 100644 --- a/test/test/util/fake_networking_engine.js +++ b/test/test/util/fake_networking_engine.js @@ -359,7 +359,7 @@ shaka.test.FakeNetworkingEngine = class { uris: [uri], headers: headers, }), - jasmine.objectContaining({type: type})); + jasmine.objectContaining({type})); } }; From 2eff917baec6c005ac1156de5ccc9c775ae6386b Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:32:06 -0700 Subject: [PATCH 16/19] add "key" and "other" object types --- lib/util/cmcd_manager.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/util/cmcd_manager.js b/lib/util/cmcd_manager.js index 99c1c5677b..5039aada77 100644 --- a/lib/util/cmcd_manager.js +++ b/lib/util/cmcd_manager.js @@ -89,14 +89,13 @@ shaka.util.CmcdManager = class { return; } - if (!context) { - if (request.method === 'HEAD') { - this.apply_(request); - } + if (request.method === 'HEAD') { + this.apply_(request); return; } const RequestType = shaka.net.NetworkingEngine.RequestType; + const ObjectType = shaka.util.CmcdManager.ObjectType; switch (type) { case RequestType.MANIFEST: @@ -106,6 +105,16 @@ shaka.util.CmcdManager = class { case RequestType.SEGMENT: this.applySegmentData(request, context); break; + + case RequestType.LICENSE: + case RequestType.SERVER_CERTIFICATE: + case RequestType.KEY: + this.apply_(request, {ot: ObjectType.KEY}); + break; + + case RequestType.TIMING: + this.apply_(request, {ot: ObjectType.OTHER}); + break; } } From 6bb53169435d9b6b32585d24c4d6a327e6231dc1 Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Tue, 14 Mar 2023 16:12:05 -0700 Subject: [PATCH 17/19] type fix --- lib/util/cmcd_manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util/cmcd_manager.js b/lib/util/cmcd_manager.js index 5039aada77..490fd67cf6 100644 --- a/lib/util/cmcd_manager.js +++ b/lib/util/cmcd_manager.js @@ -84,7 +84,7 @@ shaka.util.CmcdManager = class { * @param {shaka.net.NetworkingEngine.RequestContext=} context * The request context */ - applyData(type, request, context) { + applyData(type, request, context = {}) { if (!this.config_.enabled) { return; } From 525e6e4b1d6012218e9a09a36c39474e6cc1df54 Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Tue, 14 Mar 2023 19:04:25 -0700 Subject: [PATCH 18/19] add more tests --- lib/util/cmcd_manager.js | 23 ++++--- test/util/cmcd_manager_unit.js | 121 +++++++++++++++++++++++++++++---- 2 files changed, 122 insertions(+), 22 deletions(-) diff --git a/lib/util/cmcd_manager.js b/lib/util/cmcd_manager.js index 490fd67cf6..2d26728b20 100644 --- a/lib/util/cmcd_manager.js +++ b/lib/util/cmcd_manager.js @@ -159,7 +159,6 @@ shaka.util.CmcdManager = class { return; } - const stream = context.stream; const segment = context.segment; let duration = 0; @@ -180,12 +179,15 @@ shaka.util.CmcdManager = class { data.ot === ObjectType.MUXED || data.ot === ObjectType.TIMED_TEXT; - if (isMedia) { - data.bl = this.getBufferLength_(stream.type); - } - - if (stream.bandwidth) { - data.br = stream.bandwidth / 1000; + const stream = context.stream; + if (stream) { + if (isMedia) { + data.bl = this.getBufferLength_(stream.type); + } + + if (stream.bandwidth) { + data.br = stream.bandwidth / 1000; + } } if (isMedia && data.ot !== ObjectType.TIMED_TEXT) { @@ -358,10 +360,15 @@ shaka.util.CmcdManager = class { } const stream = context.stream; + + if (!stream) { + return undefined; + } + const type = stream.type; if (type == 'video') { - if (stream.codecs.includes(',')) { + if (stream.codecs && stream.codecs.includes(',')) { return shaka.util.CmcdManager.ObjectType.MUXED; } return shaka.util.CmcdManager.ObjectType.VIDEO; diff --git a/test/util/cmcd_manager_unit.js b/test/util/cmcd_manager_unit.js index 07baa13ef6..9853809eec 100644 --- a/test/util/cmcd_manager_unit.js +++ b/test/util/cmcd_manager_unit.js @@ -68,6 +68,7 @@ describe('CmcdManager', () => { }); const NetworkingEngine = shaka.net.NetworkingEngine; + const RequestType = NetworkingEngine.RequestType; function createNetworkingEngine(cmcd) { const resolveScheme = jasmine.createSpy('cmcd').and.callFake( @@ -315,22 +316,114 @@ describe('CmcdManager', () => { expect(r.headers['CMCD-Request']).not.toContain(',su'); }); - it('applies core CMCD params to HEAD requests', async () => { - config.useHeaders = false; - cmcdManager = new CmcdManager(playerInterface, config); - const networkingEngine = createNetworkingEngine(cmcdManager); + describe('applies core CMCD params to networking engine requests', () => { + let networkingEngine; const uri = 'cmcd://foo'; - const type = NetworkingEngine.RequestType.MANIFEST; const retry = NetworkingEngine.defaultRetryParameters(); - const request = NetworkingEngine.makeRequest([uri], retry); - request.method = 'HEAD'; - await networkingEngine.request(type, request); - - const result = request.uris[0]; - expect(result).toContain('?CMCD='); - expect(result).toContain(encodeURIComponent('sid="')); - expect(result).toContain(encodeURIComponent('cid="testing"')); - expect(result).not.toContain(encodeURIComponent('sf=')); + + beforeAll(() => { + config.useHeaders = false; + cmcdManager = new CmcdManager(playerInterface, config); + networkingEngine = createNetworkingEngine(cmcdManager); + }); + + it('HEAD requests', async () => { + const request = NetworkingEngine.makeRequest([uri], retry); + request.method = 'HEAD'; + await networkingEngine.request(RequestType.MANIFEST, request); + + const result = request.uris[0]; + expect(result).toContain('?CMCD='); + expect(result).toContain(encodeURIComponent('sid="')); + expect(result).toContain(encodeURIComponent('cid="testing"')); + expect(result).not.toContain(encodeURIComponent('sf=')); + }); + + it('dash manifest requests', async () => { + const request = NetworkingEngine.makeRequest([uri], retry); + await networkingEngine.request(RequestType.MANIFEST, request, + {type: AdvancedRequestType.MPD}); + + const result = request.uris[0]; + expect(result).toContain(encodeURIComponent('ot=m')); + expect(result).toContain(encodeURIComponent('sf=d')); + }); + + it('hls manifest requests', async () => { + const request = NetworkingEngine.makeRequest([uri], retry); + await networkingEngine.request(RequestType.MANIFEST, request, + {type: AdvancedRequestType.MASTER_PLAYLIST}); + + const result = request.uris[0]; + expect(result).toContain(encodeURIComponent('ot=m')); + expect(result).toContain(encodeURIComponent('sf=h')); + }); + + it('hls playlist requests', async () => { + const request = NetworkingEngine.makeRequest([uri], retry); + await networkingEngine.request(RequestType.MANIFEST, request, + {type: AdvancedRequestType.MEDIA_PLAYLIST}); + + const result = request.uris[0]; + expect(result).toContain(encodeURIComponent('ot=m')); + expect(result).toContain(encodeURIComponent('sf=h')); + }); + + it('init segment requests', async () => { + const request = NetworkingEngine.makeRequest([uri], retry); + await networkingEngine.request(RequestType.SEGMENT, request, + {type: AdvancedRequestType.INIT_SEGMENT}); + + const result = request.uris[0]; + expect(result).toContain(encodeURIComponent('ot=i')); + }); + + it('media segment requests', async () => { + const request = NetworkingEngine.makeRequest([uri], retry); + await networkingEngine.request(RequestType.SEGMENT, request, + { + type: AdvancedRequestType.MEDIA_SEGMENT, + stream: { + type: 'video', + }, + }); + + const result = request.uris[0]; + expect(result).toContain(encodeURIComponent('ot=v')); + }); + + it('key requests', async () => { + const request = NetworkingEngine.makeRequest([uri], retry); + await networkingEngine.request(RequestType.KEY, request); + + const result = request.uris[0]; + expect(result).toContain(encodeURIComponent('ot=k')); + }); + + it('license requests', async () => { + const request = NetworkingEngine.makeRequest([uri], retry); + await networkingEngine.request(RequestType.LICENSE, request); + + const result = request.uris[0]; + expect(result).toContain(encodeURIComponent('ot=k')); + }); + + it('cert requests', async () => { + const request = NetworkingEngine.makeRequest([uri], retry); + await networkingEngine.request(RequestType.SERVER_CERTIFICATE, + request); + + const result = request.uris[0]; + expect(result).toContain(encodeURIComponent('ot=k')); + }); + + it('timing requests', async () => { + const request = NetworkingEngine.makeRequest([uri], retry); + await networkingEngine.request(RequestType.TIMING, request); + + const result = request.uris[0]; + expect(result).toContain(encodeURIComponent('ot=o')); + }); }); }); }); From 9f653e2ab8678acbead08f64d8bb49eb8342f098 Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Tue, 14 Mar 2023 23:51:38 -0700 Subject: [PATCH 19/19] dont apply filter when cmcd is disabled --- lib/player.js | 3 ++- test/util/cmcd_manager_unit.js | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/player.js b/lib/player.js index 02698fc9a0..b494c336ec 100644 --- a/lib/player.js +++ b/lib/player.js @@ -2886,7 +2886,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget { }; return new shaka.net.NetworkingEngine( - onProgressUpdated_, onHeadersReceived_, onDownloadFailed_, onRequest_); + onProgressUpdated_, onHeadersReceived_, onDownloadFailed_, + this.config_.cmcd.enabled ? onRequest_ : undefined); } /** diff --git a/test/util/cmcd_manager_unit.js b/test/util/cmcd_manager_unit.js index 9853809eec..704355a57d 100644 --- a/test/util/cmcd_manager_unit.js +++ b/test/util/cmcd_manager_unit.js @@ -424,6 +424,16 @@ describe('CmcdManager', () => { const result = request.uris[0]; expect(result).toContain(encodeURIComponent('ot=o')); }); + + it('not when enabled is false', async () => { + config.enabled = false; + cmcdManager = new CmcdManager(playerInterface, config); + const request = NetworkingEngine.makeRequest([uri], retry); + await networkingEngine.request(RequestType.TIMING, request); + + const result = request.uris[0]; + expect(result).not.toContain('?CMCD='); + }); }); }); });