# All files / src/utils discontinuities.js

82.61% Statements 38/46
77.5% Branches 31/40
75% Functions 6/8
82.61% Lines 38/46

    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
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97

    3x

    3x
    5x
    5x
    1x
    1x

    3x

    7x
    7x
    4x
    3x

    7x

    5x
    5x

    5x
    2x
    2x

    3x

    3x
    2x
    2x

    1x

    2x
    6x
    6x
    6x
    6x

    2x

    1x
    1x
    1x

    1x

    1x
    1x

    1x
    1x
    1x
    1x

     import BinarySearch from './binary-search';
    import {logger} from '../utils/logger';

    export function findFirstFragWithCC(fragments, cc) {
      let firstFrag = null;

      for (let i = 0; i < fragments.length; i += 1) {
        const currentFrag = fragments[i];
        if (currentFrag && currentFrag.cc === cc) {
          firstFrag = currentFrag;
          break;
        }
      }

      return firstFrag;
    }

    export function findFragWithCC(fragments, CC) {
      return BinarySearch.search(fragments, (candidate) => {
        if (candidate.cc < CC) {
          return 1;
        } else if (candidate.cc > CC) {
          return -1;
        } else {
          return 0;
        }
      });
    }

    export function shouldAlignOnDiscontinuities(lastFrag, lastLevel, details) {
      let shouldAlign = false;
      if (lastLevel && lastLevel.details && details) {
        if (details.endCC > details.startCC || (lastFrag && lastFrag.cc < details.startCC)) {
          shouldAlign = true;
        }
      }
      return shouldAlign;
    }

    // Find the first frag in the previous level which matches the CC of the first frag of the new level
    export function findDiscontinuousReferenceFrag(prevDetails, curDetails) {
      const prevFrags = prevDetails.fragments;
      const curFrags = curDetails.fragments;

      if (!curFrags.length || !prevFrags.length) {
        logger.log('No fragments to align');
        return;
      }

      const prevStartFrag = findFirstFragWithCC(prevFrags, curFrags[0].cc);

      if (!prevStartFrag || (prevStartFrag && !prevStartFrag.startPTS)) {
        logger.log('No frag in previous level to align on');
        return;
      }

      return prevStartFrag;
    }

    export function adjustPts(sliding, details) {
      details.fragments.forEach((frag) => {
        Eif (frag) {
          let start = frag.start + sliding;
          frag.start = frag.startPTS = start;
          frag.endPTS = start + frag.duration;
        }
      });
      details.PTSKnown = true;
    }

    // If a change in CC is detected, the PTS can no longer be relied upon
    // Attempt to align the level by using the last level - find the last frag matching the current CC and use it's PTS
    // as a reference
    export function alignDiscontinuities(lastFrag, lastLevel, details) {
      Eif (shouldAlignOnDiscontinuities(lastFrag, lastLevel, details)) {
        const referenceFrag = findDiscontinuousReferenceFrag(lastLevel.details, details);
        Iif (referenceFrag) {
          logger.log('Adjusting PTS using last level due to CC increase within current level');
          adjustPts(referenceFrag.start, details);
        }
      }
      // try to align using programDateTime attribute (if available)
      Eif (details.PTSKnown === false && lastLevel && lastLevel.details) {
        // if last level sliding is 1000 and its first frag PROGRAM-DATE-TIME is 2017-08-20 1:10:00 AM
        // and if new details first frag PROGRAM DATE-TIME is 2017-08-20 1:10:08 AM
        // then we can deduce that playlist B sliding is 1000+8 = 1008s
        let lastPDT = lastLevel.details.programDateTime;
        let newPDT = details.programDateTime;
        // date diff is in ms. frag.start is in seconds
        let sliding = (newPDT - lastPDT)/1000 + lastLevel.details.fragments[0].start;
        Eif (!isNaN(sliding)) {
          logger.log(`adjusting PTS using programDateTime delta, sliding:${sliding.toFixed(3)}`);
          adjustPts(sliding,details);
        }
      }
    }