Skip to content

Commit

Permalink
feat: Add video progress events (#5850)
Browse files Browse the repository at this point in the history
Closes #2656
  • Loading branch information
avelad authored Nov 7, 2023
1 parent 9777c52 commit c3beee6
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 2 deletions.
113 changes: 111 additions & 2 deletions lib/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,56 @@ goog.requireType('shaka.media.PresentationTimeline');
*/


/**
* @event shaka.Player.Started
* @description Fires when the content starts playing.
* Only for VoD.
* @property {string} type
* 'started'
* @exportDoc
*/


/**
* @event shaka.Player.FirstQuartile
* @description Fires when the content playhead crosses first quartile.
* Only for VoD.
* @property {string} type
* 'firstquartile'
* @exportDoc
*/


/**
* @event shaka.Player.Midpoint
* @description Fires when the content playhead crosses midpoint.
* Only for VoD.
* @property {string} type
* 'midpoint'
* @exportDoc
*/


/**
* @event shaka.Player.ThirdQuartile
* @description Fires when the content playhead crosses third quartile.
* Only for VoD.
* @property {string} type
* 'thirdquartile'
* @exportDoc
*/


/**
* @event shaka.Player.Complete
* @description Fires when the content completes playing.
* Only for VoD.
* @property {string} type
* 'complete'
* @exportDoc
*/


/**
* @summary The main player object for Shaka Player.
*
Expand Down Expand Up @@ -599,6 +649,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
/** @private {!Array.<shaka.extern.Stream>} */
this.externalSrcEqualsThumbnailsStreams_ = [];

/** @private {number} */
this.completionPercent_ = NaN;

/** @private {?shaka.extern.PlayerConfiguration} */
this.config_ = this.defaultConfig_();

Expand Down Expand Up @@ -1213,6 +1266,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {

this.externalSrcEqualsThumbnailsStreams_ = [];

this.completionPercent_ = NaN;

// Make sure that the app knows of the new buffering state.
this.updateBufferState_();
} finally {
Expand Down Expand Up @@ -1956,6 +2011,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
this.manifest_.serviceDescription)) {
const onTimeUpdate = () => this.onTimeUpdate_();
this.loadEventManager_.listen(mediaElement, 'timeupdate', onTimeUpdate);
} else if (!isLive) {
const onVideoProgress = () => this.onVideoProgress_();
this.loadEventManager_.listen(
mediaElement, 'timeupdate', onVideoProgress);
this.onVideoProgress_();
}

if (this.adManager_) {
Expand Down Expand Up @@ -2277,13 +2337,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {

await fullyLoaded;

if (this.isLive() && this.config_.streaming.liveSync) {
const isLive = this.isLive();

if (isLive && this.config_.streaming.liveSync) {
const onTimeUpdate = () => this.onTimeUpdate_();
this.loadEventManager_.listen(mediaElement, 'timeupdate', onTimeUpdate);
} else if (!isLive) {
const onVideoProgress = () => this.onVideoProgress_();
this.loadEventManager_.listen(
mediaElement, 'timeupdate', onVideoProgress);
this.onVideoProgress_();
}

if (this.adManager_) {
const isLive = this.isLive();
this.adManager_.onManifestUpdated(isLive);
// There is no good way to detect when the manifest has been updated,
// so we use seekRange().end so we can tell when it has been updated.
Expand Down Expand Up @@ -5489,6 +5555,49 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
}
}

/**
* Callback for video progress events
*
* @private
*/
onVideoProgress_() {
if (!this.video_) {
return;
}
let hasNewCompletionPercent = false;
const completionRatio = this.video_.currentTime / this.video_.duration;
if (!isNaN(completionRatio)) {
const percent = Math.round(100 * completionRatio);
if (isNaN(this.completionPercent_)) {
this.completionPercent_ = percent;
hasNewCompletionPercent = true;
} else {
const newCompletionPercent = Math.max(this.completionPercent_, percent);
if (this.completionPercent_ != newCompletionPercent) {
this.completionPercent_ = newCompletionPercent;
hasNewCompletionPercent = true;
}
}
}
if (hasNewCompletionPercent) {
let event;
if (this.completionPercent_ == 0) {
event = this.makeEvent_(shaka.util.FakeEvent.EventName.Started);
} else if (this.completionPercent_ == 25) {
event = this.makeEvent_(shaka.util.FakeEvent.EventName.FirstQuartile);
} else if (this.completionPercent_ == 50) {
event = this.makeEvent_(shaka.util.FakeEvent.EventName.Midpoint);
} else if (this.completionPercent_ == 75) {
event = this.makeEvent_(shaka.util.FakeEvent.EventName.ThirdQuartile);
} else if (this.completionPercent_ == 100) {
event = this.makeEvent_(shaka.util.FakeEvent.EventName.Complete);
}
if (event) {
this.dispatchEvent(event);
}
}
}

/**
* Callback from Playhead.
*
Expand Down
5 changes: 5 additions & 0 deletions lib/util/fake_event.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,15 @@ shaka.util.FakeEvent.EventName = {
AbrStatusChanged: 'abrstatuschanged',
Adaptation: 'adaptation',
Buffering: 'buffering',
Complete: 'complete',
DownloadFailed: 'downloadfailed',
DownloadHeadersReceived: 'downloadheadersreceived',
DrmSessionUpdate: 'drmsessionupdate',
Emsg: 'emsg',
Prft: 'prft',
Error: 'error',
ExpirationUpdated: 'expirationupdated',
FirstQuartile: 'firstquartile',
GapJumped: 'gapjumped',
KeyStatusChanged: 'keystatuschanged',
Loaded: 'loaded',
Expand All @@ -171,15 +173,18 @@ shaka.util.FakeEvent.EventName = {
ManifestUpdated: 'manifestupdated',
MediaQualityChanged: 'mediaqualitychanged',
Metadata: 'metadata',
Midpoint: 'midpoint',
OnStateChange: 'onstatechange',
RateChange: 'ratechange',
SegmentAppended: 'segmentappended',
SessionDataEvent: 'sessiondata',
StallDetected: 'stalldetected',
Started: 'started',
StateChanged: 'statechanged',
Streaming: 'streaming',
TextChanged: 'textchanged',
TextTrackVisibility: 'texttrackvisibility',
ThirdQuartile: 'thirdquartile',
TimelineRegionAdded: 'timelineregionadded',
TimelineRegionEnter: 'timelineregionenter',
TimelineRegionExit: 'timelineregionexit',
Expand Down

0 comments on commit c3beee6

Please sign in to comment.