Skip to content

Commit

Permalink
feat: Add config to allow Media Source recoveries (#5938)
Browse files Browse the repository at this point in the history
  • Loading branch information
avelad committed Nov 28, 2023
1 parent c496aaf commit 0deb25b
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 10 deletions.
1 change: 1 addition & 0 deletions build/misspellings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@
r'(?i)deafult': 'default',
r'(?i)evication': 'eviction',
r'(?i)immidiately': 'immediately',
r'(?i)minimun': 'minimum',
}
6 changes: 5 additions & 1 deletion demo/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,11 @@ shakaDemo.Config = class {
.addNumberInput_('Min playback rate for live sync',
'streaming.liveSyncMinPlaybackRate',
/* canBeDecimal= */ true,
/* canBeZero= */ false);
/* canBeZero= */ false)
.addBoolInput_('Allow Media Source recoveries',
'streaming.allowMediaSourceRecoveries')
.addNumberInput_('Minimum time between recoveries',
'streaming.minTimeBetweenRecoveries');

if (!shakaDemoMain.getNativeControlsEnabled()) {
this.addBoolInput_('Always Stream Text', 'streaming.alwaysStreamText');
Expand Down
6 changes: 3 additions & 3 deletions externs/shaka/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ shaka.extern.InitDataOverride;
* }}
*
* @description
* Maximum and minimun latency and playback rate for a manifest. When max
* Maximum and minimum latency and playback rate for a manifest. When max
* latency is reached playbackrate is updated to maxPlaybackRate to decrease
* latency. When min latency is reached playbackrate is updated to
* minPlaybackRate to increase latency.
Expand All @@ -169,9 +169,9 @@ shaka.extern.InitDataOverride;
* @property {?number} maxPlaybackRate
* Maximum playback rate.
* @property {?number} minLatency
* Minimun latency in seconds.
* Minimum latency in seconds.
* @property {?number} minPlaybackRate
* Minimun playback rate.
* Minimum playback rate.
*
* @exportDoc
*/
Expand Down
15 changes: 12 additions & 3 deletions externs/shaka/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -1123,7 +1123,9 @@ shaka.extern.ManifestConfiguration;
* liveSyncMaxLatency: number,
* liveSyncPlaybackRate: number,
* liveSyncMinLatency: number,
* liveSyncMinPlaybackRate: number
* liveSyncMinPlaybackRate: number,
* allowMediaSourceRecoveries: boolean,
* minTimeBetweenRecoveries: number
* }}
*
* @description
Expand Down Expand Up @@ -1253,12 +1255,19 @@ shaka.extern.ManifestConfiguration;
* between 1 and 2. Effective only if liveSync is true. Defaults to
* <code>1.1</code>.
* @property {number} liveSyncMinLatency
* Minimun acceptable latency, in seconds. Effective only if liveSync is
* Minimum acceptable latency, in seconds. Effective only if liveSync is
* true. Defaults to <code>0</code>.
* @property {number} liveSyncMinPlaybackRate
* Minimun playback rate used for latency chasing. It is recommended to use a
* Minimum playback rate used for latency chasing. It is recommended to use a
* value between 0 and 1. Effective only if liveSync is true. Defaults to
* <code>1</code>.
* @property {boolean} allowMediaSourceRecoveries
* Indicate if we should recover from VIDEO_ERROR resetting Media Source.
* Defaults to <code>true</code>.
* @property {number} minTimeBetweenRecoveries
* The minimum time between recoveries when VIDEO_ERROR is reached, in
* seconds.
* Defaults to <code>5</code>.
* @exportDoc
*/
shaka.extern.StreamingConfiguration;
Expand Down
10 changes: 9 additions & 1 deletion lib/media/media_source_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ shaka.media.MediaSourceEngine = class {

/** @private {boolean} */
this.streamingAllowed_ = true;

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

/**
Expand Down Expand Up @@ -1241,6 +1244,7 @@ shaka.media.MediaSourceEngine = class {
}

this.mediaSource_.duration = duration;
this.lastDuration_ = duration;
});
}

Expand Down Expand Up @@ -1757,7 +1761,11 @@ shaka.media.MediaSourceEngine = class {
this.mediaSourceOpen_ = new shaka.util.PublicPromise();
this.mediaSource_ = this.createMediaSource(this.mediaSourceOpen_);
await this.mediaSourceOpen_;
this.mediaSource_.duration = previousDuration;
if (!isNaN(previousDuration) && previousDuration) {
this.mediaSource_.duration = previousDuration;
} else if (!isNaN(this.lastDuration_) && this.lastDuration_) {
this.mediaSource_.duration = this.lastDuration_;
}

const sourceBufferAdded = new shaka.util.PublicPromise();
const sourceBuffers =
Expand Down
44 changes: 44 additions & 0 deletions lib/media/streaming_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ shaka.media.StreamingEngine = class {

/** @private {!shaka.util.Destroyer} */
this.destroyer_ = new shaka.util.Destroyer(() => this.doDestroy_());

/** @private {number} */
this.lastMediaSourceReset_ = 0;
}

/** @override */
Expand Down Expand Up @@ -2459,6 +2462,47 @@ shaka.media.StreamingEngine = class {
return this.config_.maxDisabledTime;
}

/**
* Reset Media Source
*
* @return {!Promise.<boolean>}
*/
async resetMediaSource() {
const now = (Date.now() / 1000);
const minTimeBetweenRecoveries = this.config_.minTimeBetweenRecoveries;
if (!this.config_.allowMediaSourceRecoveries ||
(now - this.lastMediaSourceReset_) < minTimeBetweenRecoveries) {
return false;
}
this.lastMediaSourceReset_ = now;
const ContentType = shaka.util.ManifestParserUtils.ContentType;
const audioMediaState = this.mediaStates_.get(ContentType.AUDIO);
if (audioMediaState) {
audioMediaState.lastInitSegmentReference = null;
this.forceClearBuffer_(audioMediaState);
this.abortOperations_(audioMediaState).catch(() => {});
}
const videoMediaState = this.mediaStates_.get(ContentType.VIDEO);
if (videoMediaState) {
videoMediaState.lastInitSegmentReference = null;
this.forceClearBuffer_(videoMediaState);
this.abortOperations_(videoMediaState).catch(() => {});
}
/**
* @type {!Map.<shaka.util.ManifestParserUtils.ContentType,
* shaka.extern.Stream>}
*/
const streamsByType = new Map();
if (this.currentVariant_.audio) {
streamsByType.set(ContentType.AUDIO, this.currentVariant_.audio);
}
if (this.currentVariant_.video) {
streamsByType.set(ContentType.VIDEO, this.currentVariant_.video);
}
await this.playerInterface_.mediaSourceEngine.reset(streamsByType);
return true;
}

/**
* @param {shaka.media.StreamingEngine.MediaState_} mediaState
* @return {string} A log prefix of the form ($CONTENT_TYPE:$STREAM_ID), e.g.,
Expand Down
15 changes: 13 additions & 2 deletions lib/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -6373,12 +6373,23 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
* @param {!Event} event
* @private
*/
onVideoError_(event) {
async onVideoError_(event) {
const error = this.videoErrorToShakaError_();
if (!error) {
return;
}
this.onError_(error);
let fireError = true;
if (this.fullyLoaded_ && this.manifest_ && this.streamingEngine_) {
try {
const ret = await this.streamingEngine_.resetMediaSource();
fireError = !ret;
} catch (e) {
fireError = true;
}
}
if (fireError) {
this.onError_(error);
}
}

/**
Expand Down
2 changes: 2 additions & 0 deletions lib/util/player_configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ shaka.util.PlayerConfiguration = class {
liveSyncPlaybackRate: 1.1,
liveSyncMinLatency: 0,
liveSyncMinPlaybackRate: 1,
allowMediaSourceRecoveries: true,
minTimeBetweenRecoveries: 5,
};

// WebOS, Tizen, Chromecast and Hisense have long hardware pipelines
Expand Down

0 comments on commit 0deb25b

Please sign in to comment.