# All files / src/controller fps-controller.js

28.57% Statements 14/49
11.11% Branches 3/27
50% Functions 3/6
27.08% Lines 13/48

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81

    15x
    15x
    15x

    15x

    15x

    15x
    13x

    13x

    15x

    15x

    15x

    15x

    15x
     /*
     * FPS Controller
    */

    import Event from '../events';
    import EventHandler from '../event-handler';
    import { logger } from '../utils/logger';

    const { performance } = window;

    class FPSController extends EventHandler {
      constructor (hls) {
        super(hls, Event.MEDIA_ATTACHING);
      }

      destroy () {
        Iif (this.timer) {
          clearInterval(this.timer);
        }

        this.isVideoPlaybackQualityAvailable = false;
      }

      onMediaAttaching (data) {
        const config = this.hls.config;
        if (config.capLevelOnFPSDrop) {
          const video = this.video = data.media instanceof window.HTMLVideoElement ? data.media : null;
          if (typeof video.getVideoPlaybackQuality === 'function') {
            this.isVideoPlaybackQualityAvailable = true;
          }

          clearInterval(this.timer);
          this.timer = setInterval(this.checkFPSInterval.bind(this), config.fpsDroppedMonitoringPeriod);
        }
      }

      checkFPS (video, decodedFrames, droppedFrames) {
        let currentTime = performance.now();
        if (decodedFrames) {
          if (this.lastTime) {
            let currentPeriod = currentTime - this.lastTime,
              currentDropped = droppedFrames - this.lastDroppedFrames,
              currentDecoded = decodedFrames - this.lastDecodedFrames,
              droppedFPS = 1000 * currentDropped / currentPeriod,
              hls = this.hls;
            hls.trigger(Event.FPS_DROP, { currentDropped: currentDropped, currentDecoded: currentDecoded, totalDroppedFrames: droppedFrames });
            if (droppedFPS > 0) {
              // logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
              if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
                let currentLevel = hls.currentLevel;
                logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
                if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) {
                  currentLevel = currentLevel - 1;
                  hls.trigger(Event.FPS_DROP_LEVEL_CAPPING, { level: currentLevel, droppedLevel: hls.currentLevel });
                  hls.autoLevelCapping = currentLevel;
                  hls.streamController.nextLevelSwitch();
                }
              }
            }
          }
          this.lastTime = currentTime;
          this.lastDroppedFrames = droppedFrames;
          this.lastDecodedFrames = decodedFrames;
        }
      }

      checkFPSInterval () {
        const video = this.video;
        if (video) {
          if (this.isVideoPlaybackQualityAvailable) {
            let videoPlaybackQuality = video.getVideoPlaybackQuality();
            this.checkFPS(video, videoPlaybackQuality.totalVideoFrames, videoPlaybackQuality.droppedVideoFrames);
          } else {
            this.checkFPS(video, video.webkitDecodedFrameCount, video.webkitDroppedFrameCount);
          }
        }
      }
    }

    export default FPSController;