getStats() {
    // If the Player is not in a fully-loaded state, then return an empty stats
    // blob so that this call will never fail.
    const loaded = this.loadMode_ == shaka.Player.LoadMode.MEDIA_SOURCE ||
                   this.loadMode_ == shaka.Player.LoadMode.SRC_EQUALS;
    if (!loaded) {
      return shaka.util.Stats.getEmptyBlob();
    }

    this.updateStateHistory_();

    goog.asserts.assert(this.video_, 'If we have stats, we should have video_');
    const element = /** @type {!HTMLVideoElement} */ (this.video_);

    const completionRatio = element.currentTime / element.duration;
    if (!isNaN(completionRatio) && !this.isLive()) {
      this.stats_.setCompletionPercent(Math.round(100 * completionRatio));
    }

    if (this.playhead_) {
      this.stats_.setGapsJumped(this.playhead_.getGapsJumped());
      this.stats_.setStallsDetected(this.playhead_.getStallsDetected());
    }

    if (element.getVideoPlaybackQuality) {
      const info = element.getVideoPlaybackQuality();

      this.stats_.setDroppedFrames(
          Number(info.droppedVideoFrames),
          Number(info.totalVideoFrames));
      this.stats_.setCorruptedFrames(Number(info.corruptedVideoFrames));
    }

    const licenseSeconds =
        this.drmEngine_ ? this.drmEngine_.getLicenseTime() : NaN;
    this.stats_.setLicenseTime(licenseSeconds);

    // Resolution fallback
    this.stats_.setResolution(
        /* width= */ element.videoWidth || NaN,
        /* height= */ element.videoHeight || NaN);

    this.stats_.setCodecs('');

    if (this.isLive()) {
      // Apple's native HLS gives us getStartDate(), which is only available
      // if EXT-X-PROGRAM-DATETIME is in the playlist.
      if (this.getPresentationStartTimeAsDate() != null) {
        const latency = this.getLiveLatency() || 0;
        this.stats_.setLiveLatency(latency / 1000);
      }
    }

    const variants = this.getVariantTracks();
    const variant = variants.find((t) => t.active);
    const textTracks = this.getTextTracks();
    const textTrack = textTracks.find((t) => t.active);
    if (variant) {
      if (variant.bandwidth) {
        const rate = this.playRateController_ ?
           this.playRateController_.getRealRate() : 1;
        const variantBandwidth = rate * variant.bandwidth;
        let currentStreamBandwidth = variantBandwidth;
        if (textTrack && textTrack.bandwidth) {
          currentStreamBandwidth += (rate * textTrack.bandwidth);
        }
        this.stats_.setCurrentStreamBandwidth(currentStreamBandwidth);
      }
      if (variant.width && variant.height) {
        this.stats_.setResolution(
            /* width= */ variant.width || NaN,
            /* height= */ variant.height || NaN);
      }
      let codecs = variant.codecs;
      if (textTrack) {
        codecs += ',' + (textTrack.codecs || textTrack.mimeType);
      }
      if (codecs) {
        this.stats_.setCodecs(codecs);
      }
    }

    if (this.loadMode_ == shaka.Player.LoadMode.MEDIA_SOURCE &&
        !this.isRemotePlayback()) {
      if (this.manifest_) {
        this.stats_.setManifestPeriodCount(this.manifest_.periodCount);
        this.stats_.setManifestGapCount(this.manifest_.gapCount);
        if (this.manifest_.presentationTimeline) {
          const maxSegmentDuration =
              this.manifest_.presentationTimeline.getMaxSegmentDuration();
          this.stats_.setMaxSegmentDuration(maxSegmentDuration);
        }
      }

      const estimate = this.abrManager_.getBandwidthEstimate();
      this.stats_.setBandwidthEstimate(estimate);
    }

    if (this.loadMode_ == shaka.Player.LoadMode.SRC_EQUALS) {
      this.stats_.addBytesDownloaded(NaN);
    }

    return this.stats_.getBlob();
  }
Get statistics for the current playback session. If the player is not
playing content, this will return an empty stats object.

@return {shaka.extern.Stats}
@export