mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-17 16:26:39 +03:00
f539147d48
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
210 lines
6.4 KiB
JavaScript
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_;
|