Skip to content

Commit

Permalink
feat: Simplify the use of low latency (#7748)
Browse files Browse the repository at this point in the history
The autoLowLatencyMode config is removed because it's no longer
necessary. Now lowLatencyMode only enable low latency if the stream is
low latency.

A new method is added (configurationForLowLatency) to allow configure
the Low Latency config more easily
  • Loading branch information
avelad authored Dec 20, 2024
1 parent 0313375 commit 6616ff2
Show file tree
Hide file tree
Showing 24 changed files with 99 additions and 208 deletions.
1 change: 0 additions & 1 deletion demo/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,6 @@ shakaDemo.Config = class {
'streaming.inaccurateManifestTolerance',
/* canBeDecimal= */ true)
.addBoolInput_('Low Latency Mode', 'streaming.lowLatencyMode')
.addBoolInput_('Auto Low Latency Mode', 'streaming.autoLowLatencyMode')
.addBoolInput_('Force HTTP', 'streaming.forceHTTP')
.addBoolInput_('Force HTTPS', 'streaming.forceHTTPS')
.addNumberInput_('Min bytes for progress events',
Expand Down
8 changes: 4 additions & 4 deletions docs/tutorials/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ buffering settings) while some will not have any effect until the next call to

#### Low latency streaming

With `.streaming.lowLatencyMode` set to true,
With `.streaming.lowLatencyMode` set to true and the manifest is Low Latency,
Shaka uses a Low Latency config:
`.streaming.inaccurateManifestTolerance` is set to 0 by default,
`.streaming.segmentPrefetchLimit` is set to 2 by default,
`.streaming.updateIntervalSeconds` is set to 0.1 by default,
Expand All @@ -134,11 +135,10 @@ With `.streaming.lowLatencyMode` set to true,

To customize the values of inaccurateManifestTolerance, rebufferingGoal,
segmentPrefetchLimit, updateIntervalSeconds and baseDelay with low latency
mode, you can set the fields in the same or subsequent call to configure().
mode, you can set the fields in the call to configurationForLowLatency().
```js
player.configure({
player.configurationForLowLatency({
streaming: {
lowLatencyMode: true,
inaccurateManifestTolerance: 0,
segmentPrefetchLimit: 2,
updateIntervalSeconds: 0.1,
Expand Down
6 changes: 0 additions & 6 deletions externs/shaka/manifest_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,6 @@ shaka.extern.ManifestParser = class {
* onEvent: function(!Event),
* onError: function(!shaka.util.Error),
* isLowLatencyMode: function():boolean,
* isAutoLowLatencyMode: function():boolean,
* enableLowLatencyMode: function(),
* updateDuration: function(),
* newDrmInfo: function(shaka.extern.Stream),
* onManifestUpdated: function(),
Expand Down Expand Up @@ -167,10 +165,6 @@ shaka.extern.ManifestParser = class {
* Should be called when an error occurs.
* @property {function():boolean} isLowLatencyMode
* Return true if low latency streaming mode is enabled.
* @property {function():boolean} isAutoLowLatencyMode
* Return true if auto low latency streaming mode is enabled.
* @property {function()} enableLowLatencyMode
* Enable low latency streaming mode.
* @property {function()} updateDuration
* Update the presentation duration based on PresentationTimeline.
* @property {function(shaka.extern.Stream)} newDrmInfo
Expand Down
8 changes: 0 additions & 8 deletions externs/shaka/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -1560,7 +1560,6 @@ shaka.extern.LiveSyncConfiguration;
* useNativeHlsForFairPlay: boolean,
* inaccurateManifestTolerance: number,
* lowLatencyMode: boolean,
* autoLowLatencyMode: boolean,
* forceHTTP: boolean,
* forceHTTPS: boolean,
* minBytesForProgressEvents: number,
Expand Down Expand Up @@ -1719,13 +1718,6 @@ shaka.extern.LiveSyncConfiguration;
* other things, see: docs/tutorials/config.md
* <br>
* Defaults to <code>false</code>.
* @property {boolean} autoLowLatencyMode
* If the stream is low latency and the user has not configured the
* lowLatencyMode, but if it has been configured to activate the
* lowLatencyMode if a stream of this type is detected, we automatically
* activate the lowLatencyMode.
* <br>
* Defaults to <code>false</code>.
* @property {boolean} forceHTTP
* If true, if the protocol is HTTPs change it to HTTP.
* If both forceHTTP and forceHTTPS are set, forceHTTPS wins.
Expand Down
9 changes: 8 additions & 1 deletion lib/cast/cast_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ shaka.cast.CastUtils.LargePlayerGetterMethods = {
// NOTE: The 'getSharedConfiguration' property is not proxied as it would
// not be possible to share a reference.
'getConfiguration': 4,
'getConfigurationForLowLatency': 4,
'getStats': 5,
'getTextTracks': 2,
'getVariantTracks': 2,
Expand All @@ -368,7 +369,12 @@ shaka.cast.CastUtils.PlayerGetterMethodsThatRequireLive = {
* @const {!Array.<!Array.<string>>}
*/
shaka.cast.CastUtils.PlayerInitState = [
['getConfiguration', 'configure'],
[
'getConfiguration',
'configure',
'getConfigurationForLowLatency',
'configurationForLowLatency',
],
];


Expand All @@ -392,6 +398,7 @@ shaka.cast.CastUtils.PlayerVoidMethods = [
'addThumbnailsTrack',
'cancelTrickPlay',
'configure',
'configurationForLowLatency',
'getChapters',
'getChaptersTracks',
'resetConfiguration',
Expand Down
17 changes: 2 additions & 15 deletions lib/dash/dash_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -772,20 +772,7 @@ shaka.dash.DashParser = class {
presentationTimeline.setDuration(duration || Infinity);
}

// The segments are available earlier than the availability start time.
// If the stream is low latency and the user has not configured the
// lowLatencyMode, but if it has been configured to activate the
// lowLatencyMode if a stream of this type is detected, we automatically
// activate the lowLatencyMode.
if (this.isLowLatency_ && !this.lowLatencyMode_) {
const autoLowLatencyMode = this.playerInterface_.isAutoLowLatencyMode();
if (autoLowLatencyMode) {
this.playerInterface_.enableLowLatencyMode();
this.lowLatencyMode_ = this.playerInterface_.isLowLatencyMode();
}
}

if (this.lowLatencyMode_) {
if (this.isLowLatency_ && this.lowLatencyMode_) {
presentationTimeline.setAvailabilityTimeOffset(
this.minTotalAvailabilityTimeOffset_);
}
Expand All @@ -798,7 +785,7 @@ shaka.dash.DashParser = class {

await contentSteeringPromise;

if (this.lowLatencyMode_) {
if (this.isLowLatency_ && this.lowLatencyMode_) {
const presentationDelay = suggestedPresentationDelay != null ?
suggestedPresentationDelay : this.config_.defaultPresentationDelay;
presentationTimeline.setDelay(presentationDelay);
Expand Down
12 changes: 0 additions & 12 deletions lib/hls/hls_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -4216,18 +4216,6 @@ shaka.hls.HlsParser = class {
initSegmentRef = this.getInitSegmentReference_(playlist,
item.tags, getUris, variables);

// If the stream is low latency and the user has not configured the
// lowLatencyMode, but if it has been configured to activate the
// lowLatencyMode if a stream of this type is detected, we automatically
// activate the lowLatencyMode.
if (!this.lowLatencyMode_) {
const autoLowLatencyMode = this.playerInterface_.isAutoLowLatencyMode();
if (autoLowLatencyMode) {
this.playerInterface_.enableLowLatencyMode();
this.lowLatencyMode_ = this.playerInterface_.isLowLatencyMode();
}
}

const reference = this.createSegmentReference_(
initSegmentRef,
previousReference,
Expand Down
2 changes: 0 additions & 2 deletions lib/offline/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -1210,8 +1210,6 @@ shaka.offline.Storage = class {
error = e;
},
isLowLatencyMode: () => false,
isAutoLowLatencyMode: () => false,
enableLowLatencyMode: () => {},
updateDuration: () => {},
newDrmInfo: (stream) => {},
onManifestUpdated: () => {},
Expand Down
110 changes: 43 additions & 67 deletions lib/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
/** @private {?shaka.extern.PlayerConfiguration} */
this.config_ = this.defaultConfig_();

/** @private {!Object} */
this.lowLatencyConfig_ =
shaka.util.PlayerConfiguration.createDefaultForLL();

/** @private {?number} */
this.currentTargetLatency_ = null;

Expand Down Expand Up @@ -2077,14 +2081,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
}
};

const setConfig = (name, value) => {
if (getPreloadManager()) {
preloadManager.configure(name, value);
} else {
this.configure(name, value);
}
};

// Avoid having to detect the resolution again if it has already been
// detected or set
if (this.maxHwRes_.width == Infinity &&
Expand Down Expand Up @@ -2124,10 +2120,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
onEvent: (event) => preloadManager.dispatchEvent(event),
onError: (error) => preloadManager.onError(error),
isLowLatencyMode: () => getConfig().streaming.lowLatencyMode,
isAutoLowLatencyMode: () => getConfig().streaming.autoLowLatencyMode,
enableLowLatencyMode: () => {
setConfig('streaming.lowLatencyMode', true);
},
updateDuration: () => {
if (this.streamingEngine_ && preloadManager.hasBeenAttached()) {
this.streamingEngine_.updateDuration();
Expand Down Expand Up @@ -2638,11 +2630,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
this.parser_.onInitialVariantChosen(toLazyLoad);
}

if (this.manifest_.isLowLatency && !this.config_.streaming.lowLatencyMode) {
shaka.log.alwaysWarn('Low-latency live stream detected, but ' +
'low-latency streaming mode is not enabled in Shaka Player. ' +
'Set streaming.lowLatencyMode configuration to true, and see ' +
'https://bit.ly/3clctcj for details.');
if (this.manifest_.isLowLatency) {
if (this.config_.streaming.lowLatencyMode) {
this.configure(this.lowLatencyConfig_);
} else {
shaka.log.alwaysWarn('Low-latency live stream detected, but ' +
'low-latency streaming mode is not enabled in Shaka Player. ' +
'Set streaming.lowLatencyMode configuration to true, and see ' +
'https://bit.ly/3clctcj for details.');
}
}

if (this.cmcdManager_) {
Expand Down Expand Up @@ -4042,56 +4038,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
delete config['streaming']['dispatchAllEmsgBoxes'];
}

// If lowLatencyMode is enabled, and inaccurateManifestTolerance and
// segmentPrefetchLimit and baseDelay and
// autoCorrectDrift and maxDisabledTime are not specified, set
// inaccurateManifestTolerance to 0 and and
// segmentPrefetchLimit to 2 and updateIntervalSeconds to 0.1 and and
// baseDelay to 100 and autoCorrectDrift to false and maxDisabledTime
// to 1 by default for low latency streaming.
if (config['streaming'] && config['streaming']['lowLatencyMode']) {
if (config['streaming']['inaccurateManifestTolerance'] == undefined) {
config['streaming']['inaccurateManifestTolerance'] = 0;
}
if (config['streaming']['segmentPrefetchLimit'] == undefined) {
config['streaming']['segmentPrefetchLimit'] = 2;
}
if (config['streaming']['updateIntervalSeconds'] == undefined) {
config['streaming']['updateIntervalSeconds'] = 0.1;
}
if (config['streaming']['maxDisabledTime'] == undefined) {
config['streaming']['maxDisabledTime'] = 1;
}
if (config['streaming']['retryParameters'] == undefined) {
config['streaming']['retryParameters'] = {};
}
if (config['streaming']['retryParameters']['baseDelay'] == undefined) {
config['streaming']['retryParameters']['baseDelay'] = 100;
}
if (config['manifest'] == undefined) {
config['manifest'] = {};
}
if (config['manifest']['dash'] == undefined) {
config['manifest']['dash'] = {};
}
if (config['manifest']['dash']['autoCorrectDrift'] == undefined) {
config['manifest']['dash']['autoCorrectDrift'] = false;
}
if (config['manifest']['retryParameters'] == undefined) {
config['manifest']['retryParameters'] = {};
}
if (config['manifest']['retryParameters']['baseDelay'] == undefined) {
config['manifest']['retryParameters']['baseDelay'] = 100;
}
if (config['drm'] == undefined) {
config['drm'] = {};
}
if (config['drm']['retryParameters'] == undefined) {
config['drm']['retryParameters'] = {};
}
if (config['drm']['retryParameters']['baseDelay'] == undefined) {
config['drm']['retryParameters']['baseDelay'] = 100;
}
// Deprecate 'streaming.autoLowLatencyMode' configuration.
if (config['streaming'] && 'autoLowLatencyMode' in config['streaming']) {
shaka.Deprecate.deprecateFeature(5,
'streaming.autoLowLatencyMode configuration',
'Please Use streaming.lowLatencyMode instead.');
config['streaming']['lowLatencyMode'] =
config['streaming']['autoLowLatencyMode'];
delete config['streaming']['autoLowLatencyMode'];
}
const ret = shaka.util.PlayerConfiguration.mergeConfigObjects(
this.config_, config, this.defaultConfig_());
Expand All @@ -4100,6 +4054,18 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
return ret;
}

/**
* Changes low latency configuration settings on the Player.
*
* @param {!Object} config This object should follow the
* {@link shaka.extern.PlayerConfiguration} object. Not all fields
* need to be set; unset fields retain their old values.
* @export
*/
configurationForLowLatency(config) {
this.lowLatencyConfig_ = config;
}

/**
* Apply config changes.
* @private
Expand Down Expand Up @@ -4255,6 +4221,16 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
return ret;
}

/**
* Return a copy of the current configuration for low latency.
*
* @return {!Object}
* @export
*/
getConfigurationForLowLatency() {
return this.lowLatencyConfig_;
}

/**
* Return a copy of the current non default configuration. Modifications of
* the returned value will not affect the Player's active configuration.
Expand Down
32 changes: 31 additions & 1 deletion lib/util/player_configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,6 @@ shaka.util.PlayerConfiguration = class {
// will default to 0 if not specified.
inaccurateManifestTolerance: 2,
lowLatencyMode: false,
autoLowLatencyMode: false,
forceHTTP: false,
forceHTTPS: false,
minBytesForProgressEvents: minBytes,
Expand Down Expand Up @@ -492,6 +491,37 @@ shaka.util.PlayerConfiguration = class {
return config;
}

/**
* @return {!Object}
* @export
*/
static createDefaultForLL() {
return {
streaming: {
inaccurateManifestTolerance: 0,
segmentPrefetchLimit: 2,
updateIntervalSeconds: 0.1,
maxDisabledTime: 1,
retryParameters: {
baseDelay: 100,
},
},
manifest: {
dash: {
autoCorrectDrift: false,
},
retryParameters: {
baseDelay: 100,
},
},
drm: {
retryParameters: {
baseDelay: 100,
},
},
};
}

/**
* Merges the given configuration changes into the given destination. This
* uses the default Player configurations as the template.
Expand Down
2 changes: 0 additions & 2 deletions test/dash/dash_parser_content_protection_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ describe('DashParser ContentProtection', () => {
onEvent: fail,
onError: fail,
isLowLatencyMode: () => false,
isAutoLowLatencyMode: () => false,
enableLowLatencyMode: () => {},
updateDuration: () => {},
newDrmInfo: (stream) => {},
onManifestUpdated: () => {},
Expand Down
2 changes: 0 additions & 2 deletions test/dash/dash_parser_live_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ describe('DashParser Live', () => {
onEvent: fail,
onError: fail,
isLowLatencyMode: () => false,
isAutoLowLatencyMode: () => false,
enableLowLatencyMode: () => {},
updateDuration: () => {},
newDrmInfo: (stream) => {},
onManifestUpdated: () => {},
Expand Down
2 changes: 0 additions & 2 deletions test/dash/dash_parser_manifest_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ describe('DashParser Manifest', () => {
onEvent: shaka.test.Util.spyFunc(onEventSpy),
onError: fail,
isLowLatencyMode: () => false,
isAutoLowLatencyMode: () => false,
enableLowLatencyMode: () => {},
updateDuration: () => {},
newDrmInfo: (stream) => {},
onManifestUpdated: () => {},
Expand Down
Loading

0 comments on commit 6616ff2

Please sign in to comment.