Files
shaka-player/lib/media/region_observer.js
T
Joey Parrish f539147d48 fix: Correct license headers in compiled output
This fixes all the license headers in the main library, which corrects
the appearance of the main license in the compiled output.

It seems that the `!` in the header forces the compiler to keep it in
the output.  I believe older compiler releases did this purely based
on `@license`.

Issue #2638

Change-Id: I7f0e918caad10c9af689c9d07672b7fe9be7b2f3
2020-06-09 16:05:09 -07:00

210 lines
6.4 KiB
JavaScript

/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('shaka.media.RegionObserver');
goog.require('shaka.media.RegionTimeline');
/**
* The region observer watches a region timeline and playhead, and fires events
* (onEnter, onExit, and onSkip) as the playhead moves.
*
* @implements {shaka.media.IPlayheadObserver}
* @final
*/
shaka.media.RegionObserver = class {
/**
* Create a region observer for the given timeline. The observer does not
* own the timeline, only uses it. This means that the observer should NOT
* destroy the timeline.
*
* @param {!shaka.media.RegionTimeline} timeline
*/
constructor(timeline) {
/** @private {shaka.media.RegionTimeline} */
this.timeline_ = timeline;
/**
* A mapping between a region and where we previously were relative to it.
* When the value here differs from what we calculate, it means we moved and
* should fire an event.
*
* @private {!Map.<shaka.extern.TimelineRegionInfo,
* shaka.media.RegionObserver.RelativePosition_>}
*/
this.oldPosition_ = new Map();
/** @private {shaka.media.RegionObserver.EventListener} */
this.onEnter_ = (region, seeking) => {};
/** @private {shaka.media.RegionObserver.EventListener} */
this.onExit_ = (region, seeking) => {};
/** @private {shaka.media.RegionObserver.EventListener} */
this.onSkip_ = (region, seeking) => {};
// To make the rules easier to read, alias all the relative positions.
const RelativePosition = shaka.media.RegionObserver.RelativePosition_;
const BEFORE_THE_REGION = RelativePosition.BEFORE_THE_REGION;
const IN_THE_REGION = RelativePosition.IN_THE_REGION;
const AFTER_THE_REGION = RelativePosition.AFTER_THE_REGION;
/**
* A read-only collection of rules for what to do when we change position
* relative to a region.
*
* @private {!Iterable.<shaka.media.RegionObserver.Rule_>}
*/
this.rules_ = [
{
weWere: null,
weAre: IN_THE_REGION,
invoke: (region, seeking) => this.onEnter_(region, seeking),
},
{
weWere: BEFORE_THE_REGION,
weAre: IN_THE_REGION,
invoke: (region, seeking) => this.onEnter_(region, seeking),
},
{
weWere: AFTER_THE_REGION,
weAre: IN_THE_REGION,
invoke: (region, seeking) => this.onEnter_(region, seeking),
},
{
weWere: IN_THE_REGION,
weAre: BEFORE_THE_REGION,
invoke: (region, seeking) => this.onExit_(region, seeking),
},
{
weWere: IN_THE_REGION,
weAre: AFTER_THE_REGION,
invoke: (region, seeking) => this.onExit_(region, seeking),
},
{
weWere: BEFORE_THE_REGION,
weAre: AFTER_THE_REGION,
invoke: (region, seeking) => this.onSkip_(region, seeking),
},
{
weWere: AFTER_THE_REGION,
weAre: BEFORE_THE_REGION,
invoke: (region, seeking) => this.onSkip_(region, seeking),
},
];
}
/** @override */
release() {
this.timeline_ = null;
// Clear our maps so that we are not holding onto any more information than
// needed.
this.oldPosition_.clear();
// Clear the callbacks so that we don't hold onto any references external
// to this class.
this.onEnter_ = (region, seeking) => {};
this.onExit_ = (region, seeking) => {};
this.onSkip_ = (region, seeking) => {};
}
/** @override */
poll(positionInSeconds, wasSeeking) {
const RegionObserver = shaka.media.RegionObserver;
for (const region of this.timeline_.regions()) {
const previousPosition = this.oldPosition_.get(region);
const currentPosition = RegionObserver.determinePositionRelativeTo_(
region, positionInSeconds);
// We will only use |previousPosition| and |currentPosition|, so we can
// update our state now.
this.oldPosition_.set(region, currentPosition);
for (const rule of this.rules_) {
if (rule.weWere == previousPosition && rule.weAre == currentPosition) {
rule.invoke(region, wasSeeking);
}
}
}
}
/**
* Set all the listeners. This overrides any previous calls to |setListeners|.
*
* @param {shaka.media.RegionObserver.EventListener} onEnter
* The callback for when we move from outside a region to inside a region.
* @param {shaka.media.RegionObserver.EventListener} onExit
* The callback for when we move from inside a region to outside a region.
* @param {shaka.media.RegionObserver.EventListener} onSkip
* The callback for when we move from before to after a region or from
* after to before a region.
*/
setListeners(onEnter, onExit, onSkip) {
this.onEnter_ = onEnter;
this.onExit_ = onExit;
this.onSkip_ = onSkip;
}
/**
* Get the relative position of the playhead to |region| when the playhead is
* at |seconds|. We treat the region's start and end times as inclusive
* bounds.
*
* @param {shaka.extern.TimelineRegionInfo} region
* @param {number} seconds
* @return {shaka.media.RegionObserver.RelativePosition_}
* @private
*/
static determinePositionRelativeTo_(region, seconds) {
const RelativePosition = shaka.media.RegionObserver.RelativePosition_;
if (seconds < region.startTime) {
return RelativePosition.BEFORE_THE_REGION;
}
if (seconds > region.endTime) {
return RelativePosition.AFTER_THE_REGION;
}
return RelativePosition.IN_THE_REGION;
}
};
/**
* An enum of relative positions between the playhead and a region. Each is
* phrased so that it works in "The playhead is X" where "X" is any value in
* the enum.
*
* @enum {number}
* @private
*/
shaka.media.RegionObserver.RelativePosition_ = {
BEFORE_THE_REGION: 1,
IN_THE_REGION: 2,
AFTER_THE_REGION: 3,
};
/**
* All region observer events (onEnter, onExit, and onSkip) will be passed the
* region that the playhead is interacting with and whether or not the playhead
* moving is part of a seek event.
*
* @typedef {function(shaka.extern.TimelineRegionInfo, boolean)}
*/
shaka.media.RegionObserver.EventListener;
/**
* @typedef {{
* weWere: ?shaka.media.RegionObserver.RelativePosition_,
* weAre: ?shaka.media.RegionObserver.RelativePosition_,
* invoke: shaka.media.RegionObserver.EventListener
* }}
*
* @private
*/
shaka.media.RegionObserver.Rule_;