Skip to content

Commit

Permalink
Reset MSE when switching codec if changeType is unstable or unavailab…
Browse files Browse the repository at this point in the history
…le (#4270)

* resetSourceBuffersForTrackSwitch
  • Loading branch information
matvp91 authored Sep 11, 2023
1 parent 39efb18 commit 455796d
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 3 deletions.
1 change: 1 addition & 0 deletions AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,4 @@
* @epiclabsDASH [Jesus Oliva, Epic Labs]
* @adripanico [Adrian Caballero, Epic Labs]
* @ahfarmer [Andrew Farmer, Rhombus Systems]
* @matvp91 [Matthias Van Parijs]
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,7 @@ declare namespace dashjs {
avoidCurrentTimeRangePruning?: boolean
useChangeTypeForTrackSwitch?: boolean
mediaSourceDurationInfinity?: boolean
resetSourceBuffersForTrackSwitch?: boolean
},
gaps?: {
jumpGaps?: boolean,
Expand Down
11 changes: 11 additions & 0 deletions samples/dash-if-reference-player/app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
$scope.calcSegmentAvailabilityRangeFromTimelineSelected = false;
$scope.reuseExistingSourceBuffersSelected = true;
$scope.mediaSourceDurationInfinitySelected = true;
$scope.resetSourceBuffersForTrackSwitch = false;
$scope.saveLastMediaSettingsSelected = true;
$scope.localStorageSelected = true;
$scope.jumpGapsSelected = true;
Expand Down Expand Up @@ -681,6 +682,15 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
});
};

$scope.toggleResetSourceBuffersForTrackSwitch = function () {
$scope.player.updateSettings({
streaming: {
buffer: {
resetSourceBuffersForTrackSwitch: $scope.resetSourceBuffersForTrackSwitch
}
}
})
};

$scope.toggleSaveLastMediaSettings = function () {
$scope.player.updateSettings({
Expand Down Expand Up @@ -2147,6 +2157,7 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
$scope.calcSegmentAvailabilityRangeFromTimelineSelected = currentConfig.streaming.timeShiftBuffer.calcFromSegmentTimeline;
$scope.reuseExistingSourceBuffersSelected = currentConfig.streaming.buffer.reuseExistingSourceBuffers;
$scope.mediaSourceDurationInfinitySelected = currentConfig.streaming.buffer.mediaSourceDurationInfinity;
$scope.resetSourceBuffersForTrackSwitch = currentConfig.streaming.buffer.resetSourceBuffersForTrackSwitch;
$scope.saveLastMediaSettingsSelected = currentConfig.streaming.saveLastMediaSettingsForCurrentStreamingSession;
$scope.localStorageSelected = currentConfig.streaming.lastBitrateCachingInfo.enabled;
$scope.jumpGapsSelected = currentConfig.streaming.gaps.jumpGaps;
Expand Down
7 changes: 7 additions & 0 deletions samples/dash-if-reference-player/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,13 @@
ng-checked="mediaSourceDurationInfinitySelected">
MediaSource duration Infinity
</label>
<label class="topcoat-checkbox" data-toggle="tooltip" data-placement="right"
title="Reset existing MediaSource Sourcebuffers when switching incompatible track.">
<input type="checkbox" ng-model="resetSourceBuffersForTrackSwitch"
ng-change="toggleResetSourceBuffersForTrackSwitch()"
ng-checked="resetSourceBuffersForTrackSwitch">
Reset SourceBuffers on incompatible track switch
</label>
<label class="topcoat-checkbox" data-toggle="tooltip" data-placement="right"
title="Enable media settings from last selected track to be used for incoming track selection.">
<input type="checkbox" ng-model="saveLastMediaSettingsSelected"
Expand Down
9 changes: 7 additions & 2 deletions src/core/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ import Events from './events/Events';
* setStallState: true,
* avoidCurrentTimeRangePruning: false,
* useChangeTypeForTrackSwitch: true,
* mediaSourceDurationInfinity: true
* mediaSourceDurationInfinity: true,
* resetSourceBuffersForTrackSwitch: false
* },
* gaps: {
* jumpGaps: true,
Expand Down Expand Up @@ -333,6 +334,9 @@ import Events from './events/Events';
* @property {boolean} [mediaSourceDurationInfinity=true]
* If this flag is set to true then dash.js will allow `Infinity` to be set as the MediaSource duration otherwise the duration will be set to `Math.pow(2,32)` instead of `Infinity` to allow appending segments indefinitely.
* Some platforms such as WebOS 4.x have issues with seeking when duration is set to `Infinity`, setting this flag to false resolve this.
* @property {boolean} [resetSourceBuffersForTrackSwitch=false]
* When switching to a track that is not compatible with the currently active MSE SourceBuffers, MSE will be reset. This happens when we switch codecs on a system
* that does not properly implement "changeType()", such as webOS 4.0 and before.
*/

/**
Expand Down Expand Up @@ -880,7 +884,8 @@ function Settings() {
setStallState: true,
avoidCurrentTimeRangePruning: false,
useChangeTypeForTrackSwitch: true,
mediaSourceDurationInfinity: true
mediaSourceDurationInfinity: true,
resetSourceBuffersForTrackSwitch: false
},
gaps: {
jumpGaps: true,
Expand Down
6 changes: 6 additions & 0 deletions src/streaming/controllers/BufferController.js
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,9 @@ function BufferController(config) {
* @private
*/
function _appendToBuffer(chunk, request = null) {
if (!sourceBufferSink) {
return;
}
sourceBufferSink.append(chunk, request)
.then((e) => {
_onAppended(e);
Expand Down Expand Up @@ -761,6 +764,9 @@ function BufferController(config) {
}

function getRangeAt(time, tolerance) {
if (!sourceBufferSink) {
return null;
}
const ranges = sourceBufferSink.getAllBufferRanges();
let start = 0;
let end = 0;
Expand Down
13 changes: 12 additions & 1 deletion src/streaming/controllers/MediaController.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ function MediaController() {

if (!settings) {
settings = domStorage.getSavedMediaSettings(type);
if (settings) {
// If the settings are defined locally, do not take codec into account or it'll be too strict.
// eg: An audio track should not be selected by codec but merely by lang.
delete settings.codec;
}
setInitialSettings(type, settings);
}

Expand All @@ -83,6 +88,7 @@ function MediaController() {
}
tracks = filterTracksBySettings(tracks, matchSettingsAccessibility, settings);
tracks = filterTracksBySettings(tracks, matchSettingsAudioChannelConfig, settings);
tracks = filterTracksBySettings(tracks, matchSettingsCodec, settings);
}

if (tracks.length === 0) {
Expand Down Expand Up @@ -311,7 +317,8 @@ function MediaController() {
viewpoint: mediaInfo.viewpoint,
roles: mediaInfo.roles,
accessibility: mediaInfo.accessibility,
audioChannelConfiguration: mediaInfo.audioChannelConfiguration
audioChannelConfiguration: mediaInfo.audioChannelConfiguration,
codec: mediaInfo.codec
};
let notEmpty = settings.lang || settings.viewpoint || (settings.role && settings.role.length > 0) ||
(settings.accessibility && settings.accessibility.length > 0) || (settings.audioChannelConfiguration && settings.audioChannelConfiguration.length > 0);
Expand Down Expand Up @@ -378,6 +385,10 @@ function MediaController() {
return matchAudioChannelConfiguration;
}

function matchSettingsCodec(settings, track) {
return !settings.codec || (settings.codec === track.codec);
}

function matchSettings(settings, track, isTrackActive = false) {
try {
let matchLang = false;
Expand Down
7 changes: 7 additions & 0 deletions src/streaming/controllers/StreamController.js
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,13 @@ function StreamController() {
// If the track was changed in the active stream we need to stop preloading and remove the already prebuffered stuff. Since we do not support preloading specific handling of specific AdaptationSets yet.
_deactivateAllPreloadingStreams();

if (settings.get().streaming.buffer.resetSourceBuffersForTrackSwitch && e.oldMediaInfo && e.oldMediaInfo.codec !== e.newMediaInfo.codec) {
const time = playbackController.getTime();
activeStream.deactivate(false);
_openMediaSource(time, false, false);
return;
}

activeStream.prepareTrackChange(e);
}

Expand Down

0 comments on commit 455796d

Please sign in to comment.