Source: player/stats.js

/**
 * @license
 * Copyright 2015 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

goog.provide('shaka.player.Stats');

goog.require('shaka.asserts');
goog.require('shaka.media.StreamInfo');
goog.require('shaka.util.Clock');



/**
 * Creates a Stats object.
 *
 * @constructor
 * @struct
 */
shaka.player.Stats = function() {
  /**
   * @type {shaka.player.Stats.StreamStats}
   * @expose
   */
  this.streamStats = null;

  /**
   * Number of frames decoded.  NaN if not available.
   *
   * @type {number}
   * @expose
   */
  this.decodedFrames = NaN;

  /**
   * Number of frames dropped.  NaN if not available.
   *
   * @type {number}
   * @expose
   */
  this.droppedFrames = NaN;

  /**
   * Estimated bandwidth in bits per second.
   *
   * @type {number}
   * @expose
   */
  this.estimatedBandwidth = 0;

  /**
   * Time in playback state in seconds.
   *
   * @type {number}
   * @expose
   */
  this.playTime = 0;

  /**
   * Time in buffering state in seconds.
   *
   * @type {number}
   * @expose
   */
  this.bufferingTime = 0;

  /**
   * Playback latency in seconds.  NaN if autoplay is not used.
   *
   * @type {number}
   * @expose
   */
  this.playbackLatency = NaN;

  /**
   * Buffering history.  Each number is a timestamp when the player entered a
   * buffering state.
   *
   * @type {!Array.<number>}
   * @expose
   */
  this.bufferingHistory = [];

  /**
   * Bandwidth history.  Each timestamped value is a bandwidth measurement, in
   * bits per second.
   *
   * @type {!Array.<!shaka.player.Stats.TimedValue.<number>>}
   * @expose
   */
  this.bandwidthHistory = [];

  /**
   * StreamInfo history.  Each timestamped value is a stream chosen
   * by the player.
   *
   * @type {!Array.<!shaka.player.Stats.TimedValue.<
   *            !shaka.player.Stats.StreamStats>>}
   * @expose
   */
  this.streamHistory = [];
};


/**
 * Updates video stats from the video tag.
 *
 * @param {HTMLVideoElement} video
 */
shaka.player.Stats.prototype.updateVideoStats = function(video) {
  // Quality metrics may not be supported in all browsers yet.
  if (video.getVideoPlaybackQuality) {
    var quality = video.getVideoPlaybackQuality();
    this.decodedFrames = quality.totalVideoFrames;
    this.droppedFrames = quality.droppedVideoFrames;
  }
};


/**
 * Logs a buffering event.
 */
shaka.player.Stats.prototype.logBufferingEvent = function() {
  this.bufferingHistory.push(shaka.util.Clock.now() / 1000.0);
};


/**
 * Logs play time.
 *
 * @param {number} t Milliseconds the player has been in a playback state.
 */
shaka.player.Stats.prototype.logPlayTime = function(t) {
  this.playTime += t / 1000.0;
};


/**
 * Logs buffering time.
 *
 * @param {number} t Milliseconds the player has been in a buffering state.
 */
shaka.player.Stats.prototype.logBufferingTime = function(t) {
  this.bufferingTime += t / 1000.0;
};


/**
 * Logs a stream change.
 *
 * @param {!shaka.media.StreamInfo} streamInfo
 */
shaka.player.Stats.prototype.logStreamChange = function(streamInfo) {
  // Record all stream stats to the history.
  var streamStats = new shaka.player.Stats.StreamStats(streamInfo);
  this.streamHistory.push(new shaka.player.Stats.TimedValue(streamStats));

  // Prefer video stats in this.streamStats.
  if (streamStats.videoHeight || !this.streamStats) {
    this.streamStats = streamStats;
  }
};


/**
 * Logs bandwidth stats.
 *
 * @param {number} bandwidth in bits per second.
 */
shaka.player.Stats.prototype.logBandwidth = function(bandwidth) {
  this.estimatedBandwidth = bandwidth;
  this.bandwidthHistory.push(
      new shaka.player.Stats.TimedValue(bandwidth));
};


/**
 * Logs playback latency.
 *
 * @param {number} latency in milliseconds.
 */
shaka.player.Stats.prototype.logPlaybackLatency = function(latency) {
  this.playbackLatency = latency / 1000.0;
};



/**
 * A collection of stream stats.
 *
 * @param {!shaka.media.StreamInfo} streamInfo
 *
 * @constructor
 * @struct
 */
shaka.player.Stats.StreamStats = function(streamInfo) {
  /**
   * StreamInfo width in pixels, if a video stream.
   *
   * @type {?number}
   * @expose
   */
  this.videoWidth = streamInfo.width;

  /**
   * StreamInfo height in pixels, if an audio stream.
   *
   * @type {?number}
   * @expose
   */
  this.videoHeight = streamInfo.height;

  /**
   * StreamInfo MIME type.
   *
   * @type {?string}
   * @expose
   */
  this.videoMimeType = streamInfo.mimeType;

  /**
   * StreamInfo bandwidth requirement in bits per second.
   *
   * @type {?number}
   * @expose
   */
  this.videoBandwidth = streamInfo.bandwidth;
};



/**
 * A value associated with a timestamp.
 *
 * @param {T} value
 *
 * @template T
 * @constructor
 * @struct
 */
shaka.player.Stats.TimedValue = function(value) {
  /**
   * Seconds since 1970.
   *
   * @type {number}
   * @const
   * @expose
   */
  this.timestamp = shaka.util.Clock.now() / 1000.0;

  /**
   * @const {T}
   * @expose
   */
  this.value = value;
};