From 48626f2ae0187ed12e1edbd7d8ec0be6a1cf699a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Thu, 18 Jan 2024 08:31:06 +0100 Subject: [PATCH] fix: Change quality only when adding the last partial segment and it is fast switching (#6114) --- externs/shaka/abr_manager.js | 9 +++++++++ lib/abr/simple_abr_manager.js | 11 +++++++++++ lib/media/segment_prefetch.js | 4 ++++ lib/media/streaming_engine.js | 12 +++++------- lib/net/networking_engine.js | 2 +- lib/player.js | 15 +++++++++++++-- 6 files changed, 43 insertions(+), 10 deletions(-) diff --git a/externs/shaka/abr_manager.js b/externs/shaka/abr_manager.js index 89d9470e61..eb061ea076 100644 --- a/externs/shaka/abr_manager.js +++ b/externs/shaka/abr_manager.js @@ -96,6 +96,15 @@ shaka.extern.AbrManager = class { */ segmentDownloaded(deltaTimeMs, numBytes, allowSwitch) {} + /** + * Notifies the ABR that it is a time to suggest new streams. This is used by + * the Player when it finishes adding the last partial segment of a fast + * switching stream. + * + * @exportDoc + */ + trySuggestStreams() {} + /** * Gets an estimate of the current bandwidth in bit/sec. This is used by the * Player to generate stats. diff --git a/lib/abr/simple_abr_manager.js b/lib/abr/simple_abr_manager.js index af7410b2e9..99ccca75f4 100644 --- a/lib/abr/simple_abr_manager.js +++ b/lib/abr/simple_abr_manager.js @@ -320,6 +320,17 @@ shaka.abr.SimpleAbrManager = class { } + /** + * @override + * @export + */ + trySuggestStreams() { + if ((this.lastTimeChosenMs_ != null) && this.enabled_) { + this.suggestStreams_(); + } + } + + /** * @override * @export diff --git a/lib/media/segment_prefetch.js b/lib/media/segment_prefetch.js index 64a15be193..0e0b093150 100644 --- a/lib/media/segment_prefetch.js +++ b/lib/media/segment_prefetch.js @@ -97,6 +97,10 @@ shaka.media.SegmentPrefetch = class { this.segmentPrefetchMap_.set(reference, segmentPrefetchOperation); } this.prefetchPosTime_ = reference.startTime; + if (this.stream_.fastSwitching && reference.isPartial() && + reference.isLastPartial()) { + break; + } reference = iterator.next().value; } } diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index c2c2d1dc5a..09d984cce9 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -1488,8 +1488,7 @@ shaka.media.StreamingEngine = class { JSON.stringify(buffered)); if (!mediaState.waitingToClearBuffer) { - this.playerInterface_.onSegmentAppended( - reference.startTime, reference.endTime, mediaState.type); + this.playerInterface_.onSegmentAppended(reference, mediaState.stream); } // Update right away. @@ -2540,8 +2539,8 @@ shaka.media.StreamingEngine = class { * onError: function(!shaka.util.Error), * onEvent: function(!Event), * onManifestUpdate: function(), - * onSegmentAppended: function(number, number, - * !shaka.util.ManifestParserUtils.ContentType), + * onSegmentAppended: function(!shaka.media.SegmentReference, + * !shaka.extern.Stream), * onInitSegmentAppended: function(!number,!shaka.media.InitSegmentReference), * beforeAppendSegment: function( * shaka.util.ManifestParserUtils.ContentType,!BufferSource):Promise, @@ -2566,10 +2565,9 @@ shaka.media.StreamingEngine = class { * Called when an event occurs that should be sent to the app. * @property {function()} onManifestUpdate * Called when an embedded 'emsg' box should trigger a manifest update. - * @property {function(number, number, - * !shaka.util.ManifestParserUtils.ContentType)} onSegmentAppended + * @property {function(!shaka.media.SegmentReference, + * !shaka.extern.Stream)} onSegmentAppended * Called after a segment is successfully appended to a MediaSource. - * The parameters are the start and end time. * @property * {function(!number, !shaka.media.InitSegmentReference)} onInitSegmentAppended * Called when an init segment is appended to a MediaSource. diff --git a/lib/net/networking_engine.js b/lib/net/networking_engine.js index ab0d7b4f63..eb4e6ae34f 100644 --- a/lib/net/networking_engine.js +++ b/lib/net/networking_engine.js @@ -700,7 +700,7 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget { const segment = context.segment; const stream = context.stream; if (segment && stream && stream.fastSwitching) { - if (segment.isPartial() && !segment.isLastPartial()) { + if (segment.isPartial()) { return false; } } diff --git a/lib/player.js b/lib/player.js index caaf67d498..1bcbe2c58e 100644 --- a/lib/player.js +++ b/lib/player.js @@ -1858,6 +1858,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget { 'Please use an AbrManager with setCmsdManager function.'); this.abrManager_.setCmsdManager = () => {}; } + if (typeof this.abrManager_.trySuggestStreams != 'function') { + shaka.Deprecate.deprecateFeature(5, + 'AbrManager', + 'Please use an AbrManager with trySuggestStreams function.'); + this.abrManager_.trySuggestStreams = () => {}; + } this.abrManager_.configure(this.config_.abr); } @@ -2915,8 +2921,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget { onError: (error) => this.onError_(error), onEvent: (event) => this.dispatchEvent(event), onManifestUpdate: () => this.onManifestUpdate_(), - onSegmentAppended: (start, end, contentType) => { - this.onSegmentAppended_(start, end, contentType); + onSegmentAppended: (reference, stream) => { + this.onSegmentAppended_( + reference.startTime, reference.endTime, stream.type); + if (this.abrManager_ && stream.fastSwitching && + reference.isPartial() && reference.isLastPartial()) { + this.abrManager_.trySuggestStreams(); + } }, onInitSegmentAppended: (position, initSegment) => { const mediaQuality = initSegment.getMediaQuality();