Skip to content

Commit 43628a4

Browse files
committed
Delay manual quality switches for partial segments
1 parent 79d9197 commit 43628a4

File tree

5 files changed

+129
-63
lines changed

5 files changed

+129
-63
lines changed

src/dash/controllers/RepresentationController.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ function RepresentationController(config) {
9494

9595

9696
if (type !== Constants.VIDEO && type !== Constants.AUDIO && (type !== Constants.TEXT || !isFragmented)) {
97-
endDataUpdate();
97+
_endDataUpdate();
9898
resolve();
9999
return;
100100
}
@@ -123,7 +123,7 @@ function RepresentationController(config) {
123123
dashMetrics.updateManifestUpdateInfo({ latency: dvrInfo.range.end - playbackController.getTime() });
124124
}
125125

126-
endDataUpdate();
126+
_endDataUpdate();
127127
}
128128

129129
function _updateRepresentation(currentRep) {
@@ -242,7 +242,7 @@ function RepresentationController(config) {
242242
return null;
243243
}
244244

245-
function endDataUpdate(error) {
245+
function _endDataUpdate(error) {
246246
eventBus.trigger(events.DATA_UPDATE_COMPLETED,
247247
{
248248
currentRepresentation: currentVoRepresentation,

src/streaming/MediaPlayer.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,7 +1604,7 @@ function MediaPlayer() {
16041604
} else {
16051605
const representation = activeStream.getRepresentationForTypeById(type, id);
16061606
if (representation) {
1607-
abrController.setPlaybackQuality(type, streamController.getActiveStreamInfo(), representation, { forceReplace });
1607+
abrController.manuallySetPlaybackQuality(type, streamController.getActiveStreamInfo(), representation, { forceReplace });
16081608
}
16091609
}
16101610
}
@@ -1641,7 +1641,7 @@ function MediaPlayer() {
16411641
} else {
16421642
const representation = activeStream.getRepresentationForTypeByIndex(type, index);
16431643
if (representation) {
1644-
abrController.setPlaybackQuality(type, streamController.getActiveStreamInfo(), representation, { forceReplace });
1644+
abrController.manuallySetPlaybackQuality(type, streamController.getActiveStreamInfo(), representation, { forceReplace });
16451645
}
16461646
}
16471647
}

src/streaming/StreamProcessor.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ function StreamProcessor(config) {
331331
scheduleController.setInitSegmentRequired(true);
332332

333333
// Right after a seek we should not immediately check the playback quality
334-
scheduleController.setCheckPlaybackQuality(false);
334+
scheduleController.setShouldCheckPlaybackQuality(false);
335335
scheduleController.startScheduleTimer();
336336
resolve();
337337
});
@@ -868,7 +868,7 @@ function StreamProcessor(config) {
868868
streamId: streamInfo.id
869869
}, { mediaType: type, streamId: streamInfo.id });
870870

871-
scheduleController.setCheckPlaybackQuality(false);
871+
scheduleController.setShouldCheckPlaybackQuality(false);
872872

873873
// Abort appending segments to the buffer. Also adjust the appendWindow as we might have been in the progress of prebuffering stuff.
874874
bufferController.prepareForForceReplacementQualitySwitch(newPresentation, oldRepresentation)
@@ -899,7 +899,7 @@ function StreamProcessor(config) {
899899
function _abandonQualitySwitchPreparationDone() {
900900
fragmentModel.abortRequests();
901901
shouldRepeatRequest = true;
902-
scheduleController.setCheckPlaybackQuality(false);
902+
scheduleController.setShouldCheckPlaybackQuality(false);
903903
scheduleController.startScheduleTimer();
904904
qualityChangeInProgress = false;
905905
}
@@ -945,7 +945,7 @@ function StreamProcessor(config) {
945945
fragmentModel.abortRequests();
946946
const targetTime = time + safeBufferLevel;
947947
setExplicitBufferingTime(targetTime);
948-
scheduleController.setCheckPlaybackQuality(false);
948+
scheduleController.setShouldCheckPlaybackQuality(false);
949949
scheduleController.startScheduleTimer();
950950
qualityChangeInProgress = false;
951951
}
@@ -971,7 +971,7 @@ function StreamProcessor(config) {
971971
}
972972

973973
function _defaultQualitySwitchPreparationDone() {
974-
scheduleController.setCheckPlaybackQuality(false);
974+
scheduleController.setShouldCheckPlaybackQuality(false);
975975
if (currentMediaInfo.segmentAlignment || currentMediaInfo.subSegmentAlignment) {
976976
scheduleController.startScheduleTimer();
977977
} else {

src/streaming/controllers/AbrController.js

Lines changed: 96 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -52,27 +52,28 @@ function AbrController() {
5252
const debug = Debug(context).getInstance();
5353
const eventBus = EventBus(context).getInstance();
5454

55-
let instance,
56-
logger,
57-
abrRulesCollection,
58-
streamController,
59-
capabilities,
60-
streamProcessorDict,
61-
abandonmentStateDict,
55+
let abandonmentStateDict,
6256
abandonmentTimeout,
63-
windowResizeEventCalled,
57+
abrRulesCollection,
6458
adapter,
65-
videoModel,
66-
mediaPlayerModel,
67-
customParametersModel,
59+
capabilities,
6860
cmsdModel,
69-
domStorage,
7061
currentRepresentationId,
71-
switchRequestHistory,
62+
customParametersModel,
63+
dashMetrics,
64+
domStorage,
7265
droppedFramesHistory,
66+
instance,
67+
logger,
68+
mediaPlayerModel,
69+
queuedManualQualitySwitches,
70+
settings,
71+
streamController,
72+
streamProcessorDict,
73+
switchRequestHistory,
7374
throughputController,
74-
dashMetrics,
75-
settings;
75+
videoModel,
76+
windowResizeEventCalled;
7677

7778
function setup() {
7879
logger = debug.getLogger(instance);
@@ -149,6 +150,7 @@ function AbrController() {
149150
function resetInitialSettings() {
150151
abandonmentStateDict = {};
151152
streamProcessorDict = {};
153+
queuedManualQualitySwitches = new Map();
152154

153155
if (windowResizeEventCalled === undefined) {
154156
windowResizeEventCalled = false;
@@ -538,19 +540,25 @@ function AbrController() {
538540
return;
539541
}
540542

541-
const rulesContext = RulesContext(context).create({
543+
const rulesContext = _createRulesContext(streamProcessor, e.request);
544+
const switchRequest = abrRulesCollection.shouldAbandonFragment(rulesContext);
545+
546+
if (switchRequest && switchRequest.representation !== SwitchRequest.NO_CHANGE) {
547+
_onSegmentDownloadShouldBeAbandoned(e, streamId, type, streamProcessor, switchRequest);
548+
}
549+
}
550+
551+
function _createRulesContext(streamProcessor, currentRequest) {
552+
return RulesContext(context).create({
542553
abrController: instance,
543554
streamProcessor,
544-
currentRequest: e.request,
555+
currentRequest,
556+
switchRequestHistory,
557+
droppedFramesHistory,
545558
throughputController,
546559
adapter,
547560
videoModel
548561
});
549-
const switchRequest = abrRulesCollection.shouldAbandonFragment(rulesContext);
550-
551-
if (switchRequest && switchRequest.representation !== SwitchRequest.NO_CHANGE) {
552-
_onSegmentDownloadShouldBeAbandoned(e, streamId, type, streamProcessor, switchRequest);
553-
}
554562
}
555563

556564
function _canAbandonRequest(lastSegment) {
@@ -669,17 +677,8 @@ function AbrController() {
669677
return false;
670678
}
671679

672-
673680
const currentRepresentation = streamProcessor.getRepresentation();
674-
const rulesContext = RulesContext(context).create({
675-
abrController: instance,
676-
throughputController,
677-
switchRequestHistory,
678-
droppedFramesHistory,
679-
streamProcessor,
680-
adapter,
681-
videoModel
682-
});
681+
const rulesContext = _createRulesContext(streamProcessor);
683682
const switchRequest = abrRulesCollection.getBestPossibleSwitchRequest(rulesContext);
684683

685684
if (!switchRequest || !switchRequest.representation) {
@@ -739,16 +738,74 @@ function AbrController() {
739738
*/
740739
function setPlaybackQuality(type, streamInfo, representation, reason = {}) {
741740
if (!streamInfo || !streamInfo.id || !type || !streamProcessorDict || !streamProcessorDict[streamInfo.id] || !streamProcessorDict[streamInfo.id][type] || !representation) {
742-
return;
741+
return false;
743742
}
744743

745744
const streamProcessor = streamProcessorDict[streamInfo.id][type];
746745
const currentRepresentation = streamProcessor.getRepresentation();
747746

748-
749747
if (!currentRepresentation || representation.id !== currentRepresentation.id) {
750-
_changeQuality(currentRepresentation, representation, reason);
748+
return _changeQuality(currentRepresentation, representation, reason);
749+
}
750+
751+
return false;
752+
}
753+
754+
function manuallySetPlaybackQuality(type, streamInfo, representation, reason = {}) {
755+
const streamProcessor = streamProcessorDict[streamInfo.id][type];
756+
const lastSegment = streamProcessor.getLastSegment();
757+
const canPerformQualitySwitch = _canPerformQualitySwitch(lastSegment);
758+
759+
if (!canPerformQualitySwitch) {
760+
_queueManualQualitySwitch(type, streamInfo, representation, reason);
761+
return;
751762
}
763+
764+
return setPlaybackQuality(type, streamInfo, representation, reason);
765+
}
766+
767+
function _queueManualQualitySwitch(type, streamInfo, representation, reason) {
768+
try {
769+
logger.debug(`[AbrController] Queuing manual quality switch for stream ${streamInfo.id} and type ${type} to representation ${representation.id}`);
770+
const key = _getManualQualitySwitchKey(streamInfo.id, type);
771+
queuedManualQualitySwitches.set(key, { type, streamInfo, representation, reason });
772+
} catch (e) {
773+
logger.error(`Can not queue manual quality switch: ${e}`);
774+
}
775+
}
776+
777+
function handlePendingManualQualitySwitch(streamId, mediaType) {
778+
try {
779+
const streamProcessor = streamProcessorDict[streamId][mediaType];
780+
const lastSegment = streamProcessor.getLastSegment();
781+
const canPerformQualitySwitch = _canPerformQualitySwitch(lastSegment);
782+
783+
if (!canPerformQualitySwitch) {
784+
return false
785+
}
786+
787+
const key = _getManualQualitySwitchKey(streamId, mediaType);
788+
let switchRequest = null;
789+
if (queuedManualQualitySwitches.has(key)) {
790+
switchRequest = queuedManualQualitySwitches.get(key);
791+
}
792+
793+
if (!switchRequest) {
794+
return false
795+
}
796+
797+
const { type, streamInfo, representation, reason } = switchRequest;
798+
799+
queuedManualQualitySwitches.delete(key);
800+
setPlaybackQuality(type, streamInfo, representation, reason);
801+
return true;
802+
} catch (e) {
803+
logger.error(`Can not handle pending manual quality switch: ${e}`);
804+
}
805+
}
806+
807+
function _getManualQualitySwitchKey(streamId, mediaType) {
808+
return `${streamId}-${mediaType}`
752809
}
753810

754811
/**
@@ -778,7 +835,7 @@ function AbrController() {
778835
const type = newRepresentation.mediaInfo.type;
779836

780837
if (!type || !streamProcessorDict[streamId] || !streamProcessorDict[streamId][type]) {
781-
return
838+
return false
782839
}
783840

784841
const streamInfo = streamProcessorDict[streamId][type].getStreamInfo();
@@ -800,6 +857,7 @@ function AbrController() {
800857
);
801858

802859
_saveBitrateSettings(type)
860+
return true
803861
}
804862

805863
function _saveBitrateSettings(type) {
@@ -908,9 +966,11 @@ function AbrController() {
908966
getPossibleVoRepresentationsFilteredBySettings,
909967
getRepresentationByAbsoluteIndex,
910968
handleNewMediaInfo,
969+
handlePendingManualQualitySwitch,
911970
initialize,
912971
isPlayingAtLowestQuality,
913972
isPlayingAtTopQuality,
973+
manuallySetPlaybackQuality,
914974
registerStreamType,
915975
reset,
916976
setConfig,

0 commit comments

Comments
 (0)