UNPKG

shaka-player

Version:
161 lines (139 loc) 3.61 kB
/*! @license * Shaka Player * Copyright 2016 Google LLC * SPDX-License-Identifier: Apache-2.0 */ goog.provide('shaka.util.StateHistory'); goog.require('goog.asserts'); goog.require('shaka.log'); /** * This class is used to track the time spent in arbitrary states. When told of * a state, it will assume that state was active until a new state is provided. * When provided with identical states back-to-back, the existing entry will be * updated. * * @final */ shaka.util.StateHistory = class { /** */ constructor() { /** * The state that we think is still the current change. It is "open" for * updating. * * @private {?shaka.extern.StateChange} */ this.open_ = null; /** * The stats that are "closed" for updating. The "open" state becomes closed * once we move to a new state. * * @private {!Array<shaka.extern.StateChange>} */ this.closed_ = []; } /** * @param {string} state * @return {boolean} True if this changed the state */ update(state) { // |open_| will only be |null| when we first call |update|. if (this.open_ == null) { this.start_(state); return true; } else { return this.update_(state); } } /** * Go through all entries in the history and count how much time was spend in * the given state. * * @param {string} state * @return {number} */ getTimeSpentIn(state) { let sum = 0; if (this.open_ && this.open_.state == state) { sum += this.open_.duration; } for (const entry of this.closed_) { sum += entry.state == state ? entry.duration : 0; } return sum; } /** * Get a copy of each state change entry in the history. A copy of each entry * is created to break the reference to the internal data. * * @return {!Array<shaka.extern.StateChange>} */ getCopy() { const clone = (entry) => { return { timestamp: entry.timestamp, state: entry.state, duration: entry.duration, }; }; const copy = []; for (const entry of this.closed_) { copy.push(clone(entry)); } if (this.open_) { copy.push(clone(this.open_)); } return copy; } /** * @param {string} state * @private */ start_(state) { goog.asserts.assert( this.open_ == null, 'There must be no open entry in order when we start'); shaka.log.v1('Changing Player state to', state); this.open_ = { timestamp: this.getNowInSeconds_(), state: state, duration: 0, }; } /** * @param {string} state * @return {boolean} True if this changed the state * @private */ update_(state) { goog.asserts.assert( this.open_, 'There must be an open entry in order to update it'); const currentTimeSeconds = this.getNowInSeconds_(); // Always update the duration so that it can always be as accurate as // possible. this.open_.duration = currentTimeSeconds - this.open_.timestamp; // If the state has not changed, there is no need to add a new entry. if (this.open_.state == state) { return false; } // We have changed states, so "close" the open state. shaka.log.v1('Changing Player state to', state); this.closed_.push(this.open_); this.open_ = { timestamp: currentTimeSeconds, state: state, duration: 0, }; return true; } /** * Get the system time in seconds. * * @return {number} * @private */ getNowInSeconds_() { return Date.now() / 1000; } };