processPendingSegments_() {
    let sortedSegments = {
      video: {
        segments: [],
        bytes: 0
      },
      audio: {
        segments: [],
        bytes: 0
      },
      captions: [],
      metadata: []
    };

    // Sort segments into separate video/audio arrays and
    // keep track of their total byte lengths
    sortedSegments = this.pendingBuffers_.reduce(function(segmentObj, segment) {
      let type = segment.type;
      let data = segment.data;
      let initSegment = segment.initSegment;

      segmentObj[type].segments.push(data);
      segmentObj[type].bytes += data.byteLength;

      segmentObj[type].initSegment = initSegment;

      // Gather any captions into a single array
      if (segment.captions) {
        segmentObj.captions = segmentObj.captions.concat(segment.captions);
      }

      if (segment.info) {
        segmentObj[type].info = segment.info;
      }

      // Gather any metadata into a single array
      if (segment.metadata) {
        segmentObj.metadata = segmentObj.metadata.concat(segment.metadata);
      }

      return segmentObj;
    }, sortedSegments);

    // Create the real source buffers if they don't exist by now since we
    // finally are sure what tracks are contained in the source
    if (!this.videoBuffer_ && !this.audioBuffer_) {
      // Remove any codecs that may have been specified by default but
      // are no longer applicable now
      if (sortedSegments.video.bytes === 0) {
        this.videoCodec_ = null;
      }
      if (sortedSegments.audio.bytes === 0) {
        this.audioCodec_ = null;
      }

      this.createRealSourceBuffers_();
    }

    if (sortedSegments.audio.info) {
      this.mediaSource_.trigger({type: 'audioinfo', info: sortedSegments.audio.info});
    }
    if (sortedSegments.video.info) {
      this.mediaSource_.trigger({type: 'videoinfo', info: sortedSegments.video.info});
    }

    if (this.appendAudioInitSegment_) {
      if (!this.audioDisabled_ && this.audioBuffer_) {
        sortedSegments.audio.segments.unshift(sortedSegments.audio.initSegment);
        sortedSegments.audio.bytes += sortedSegments.audio.initSegment.byteLength;
      }
      this.appendAudioInitSegment_ = false;
    }

    let triggerUpdateend = false;

    // Merge multiple video and audio segments into one and append
    if (this.videoBuffer_ && sortedSegments.video.bytes) {
      sortedSegments.video.segments.unshift(sortedSegments.video.initSegment);
      sortedSegments.video.bytes += sortedSegments.video.initSegment.byteLength;
      this.concatAndAppendSegments_(sortedSegments.video, this.videoBuffer_);
      // TODO: are video tracks the only ones with text tracks?
      addTextTrackData(this, sortedSegments.captions, sortedSegments.metadata);
    } else if (this.videoBuffer_ && (this.audioDisabled_ || !this.audioBuffer_)) {
      // The transmuxer did not return any bytes of video, meaning it was all trimmed
      // for gop alignment. Since we have a video buffer and audio is disabled, updateend
      // will never be triggered by this source buffer, which will cause contrib-hls
      // to be stuck forever waiting for updateend. If audio is not disabled, updateend
      // will be triggered by the audio buffer, which will be sent upwards since the video
      // buffer will not be in an updating state.
      triggerUpdateend = true;
    }

    if (!this.audioDisabled_ && this.audioBuffer_) {
      this.concatAndAppendSegments_(sortedSegments.audio, this.audioBuffer_);
    }

    this.pendingBuffers_.length = 0;

    if (triggerUpdateend) {
      this.trigger('updateend');
    }

    // We are no longer in the internal "updating" state
    this.bufferUpdating_ = false;
  }
/**
   * Process any segments that the muxer has output
   * Concatenate segments together based on type and append them into
   * their respective sourceBuffers
   *
   * @private
   */
Process any segments that the muxer has output
Concatenate segments together based on type and append them into
their respective sourceBuffers

@private
Process any segments that the muxer has output Concatenate segments together based on type and append them into their respective sourceBuffers @private
processPendingSegments_() {
    let sortedSegments = {
      video: {
        segments: [],
        bytes: 0
      },
      audio: {
        segments: [],
        bytes: 0
      },
      captions: [],
      metadata: []
    };
    sortedSegments = this.pendingBuffers_.reduce(function(segmentObj, segment) {
      let type = segment.type;
      let data = segment.data;
      let initSegment = segment.initSegment;
      segmentObj[type].segments.push(data);
      segmentObj[type].bytes += data.byteLength;
      segmentObj[type].initSegment = initSegment;
      if (segment.captions) {
        segmentObj.captions = segmentObj.captions.concat(segment.captions);
      }
      if (segment.info) {
        segmentObj[type].info = segment.info;
      }
      if (segment.metadata) {
        segmentObj.metadata = segmentObj.metadata.concat(segment.metadata);
      }
      return segmentObj;
    }, sortedSegments);
    if (!this.videoBuffer_ && !this.audioBuffer_) {
      if (sortedSegments.video.bytes === 0) {
        this.videoCodec_ = null;
      }
      if (sortedSegments.audio.bytes === 0) {
        this.audioCodec_ = null;
      }
      this.createRealSourceBuffers_();
    }
    if (sortedSegments.audio.info) {
      this.mediaSource_.trigger({type: 'audioinfo', info: sortedSegments.audio.info});
    }
    if (sortedSegments.video.info) {
      this.mediaSource_.trigger({type: 'videoinfo', info: sortedSegments.video.info});
    }
    if (this.appendAudioInitSegment_) {
      if (!this.audioDisabled_ && this.audioBuffer_) {
        sortedSegments.audio.segments.unshift(sortedSegments.audio.initSegment);
        sortedSegments.audio.bytes += sortedSegments.audio.initSegment.byteLength;
      }
      this.appendAudioInitSegment_ = false;
    }
    let triggerUpdateend = false;
    if (this.videoBuffer_ && sortedSegments.video.bytes) {
      sortedSegments.video.segments.unshift(sortedSegments.video.initSegment);
      sortedSegments.video.bytes += sortedSegments.video.initSegment.byteLength;
      this.concatAndAppendSegments_(sortedSegments.video, this.videoBuffer_);
      addTextTrackData(this, sortedSegments.captions, sortedSegments.metadata);
    } else if (this.videoBuffer_ && (this.audioDisabled_ || !this.audioBuffer_)) {
      triggerUpdateend = true;
    }
    if (!this.audioDisabled_ && this.audioBuffer_) {
      this.concatAndAppendSegments_(sortedSegments.audio, this.audioBuffer_);
    }
    this.pendingBuffers_.length = 0;
    if (triggerUpdateend) {
      this.trigger('updateend');
    }
    this.bufferUpdating_ = false;
  }
processPendingSegments_ ( ) { let sortedSegments = { video : { segments : [ ] , bytes : 0 } , audio : { segments : [ ] , bytes : 0 } , captions : [ ] , metadata : [ ] } ; sortedSegments = this . pendingBuffers_ . reduce ( function ( segmentObj , segment ) { let type = segment . type ; let data = segment . data ; let initSegment = segment . initSegment ; segmentObj [ type ] . segments . push ( data ) ; segmentObj [ type ] . bytes += data . byteLength ; segmentObj [ type ] . initSegment = initSegment ; if ( segment . captions ) { segmentObj . captions = segmentObj . captions . concat ( segment . captions ) ; } if ( segment . info ) { segmentObj [ type ] . info = segment . info ; } if ( segment . metadata ) { segmentObj . metadata = segmentObj . metadata . concat ( segment . metadata ) ; } return segmentObj ; } , sortedSegments ) ; if ( ! this . videoBuffer_ && ! this . audioBuffer_ ) { if ( sortedSegments . video . bytes === 0 ) { this . videoCodec_ = null ; } if ( sortedSegments . audio . bytes === 0 ) { this . audioCodec_ = null ; } this . createRealSourceBuffers_ ( ) ; } if ( sortedSegments . audio . info ) { this . mediaSource_ . trigger ( { type : 'audioinfo' , info : sortedSegments . audio . info } ) ; } if ( sortedSegments . video . info ) { this . mediaSource_ . trigger ( { type : 'videoinfo' , info : sortedSegments . video . info } ) ; } if ( this . appendAudioInitSegment_ ) { if ( ! this . audioDisabled_ && this . audioBuffer_ ) { sortedSegments . audio . segments . unshift ( sortedSegments . audio . initSegment ) ; sortedSegments . audio . bytes += sortedSegments . audio . initSegment . byteLength ; } this . appendAudioInitSegment_ = false ; } let triggerUpdateend = false ; if ( this . videoBuffer_ && sortedSegments . video . bytes ) { sortedSegments . video . segments . unshift ( sortedSegments . video . initSegment ) ; sortedSegments . video . bytes += sortedSegments . video . initSegment . byteLength ; this . concatAndAppendSegments_ ( sortedSegments . video , this . videoBuffer_ ) ; addTextTrackData ( this , sortedSegments . captions , sortedSegments . metadata ) ; } else if ( this . videoBuffer_ && ( this . audioDisabled_ || ! this . audioBuffer_ ) ) { triggerUpdateend = true ; } if ( ! this . audioDisabled_ && this . audioBuffer_ ) { this . concatAndAppendSegments_ ( sortedSegments . audio , this . audioBuffer_ ) ; } this . pendingBuffers_ . length = 0 ; if ( triggerUpdateend ) { this . trigger ( 'updateend' ) ; } this . bufferUpdating_ = false ; }
Process any segments that the muxer has output
 Concatenate segments together based on type and append them into
 their respective sourceBuffers
Process any segments that the muxer has output Concatenate segments together based on type and append them into their respective sourceBuffers
// Sort segments into separate video/audio arrays and // keep track of their total byte lengths // Gather any captions into a single array // Gather any metadata into a single array // Create the real source buffers if they don't exist by now since we // finally are sure what tracks are contained in the source // Remove any codecs that may have been specified by default but // are no longer applicable now // Merge multiple video and audio segments into one and append // TODO: are video tracks the only ones with text tracks? // The transmuxer did not return any bytes of video, meaning it was all trimmed // for gop alignment. Since we have a video buffer and audio is disabled, updateend // will never be triggered by this source buffer, which will cause contrib-hls // to be stuck forever waiting for updateend. If audio is not disabled, updateend // will be triggered by the audio buffer, which will be sent upwards since the video // buffer will not be in an updating state. // We are no longer in the internal "updating" state