All files / src/controller audio-track-controller.js

5.88% Statements 4/68
3.85% Branches 2/52
13.33% Functions 2/15
5.97% Lines 4/67

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155                      28x       28x 28x                                                             37x                                                                                                                                                                                                                      
/*
 * audio track controller
*/
 
import Event from '../events';
import EventHandler from '../event-handler';
import { logger } from '../utils/logger';
import { ErrorTypes } from '../errors';
 
class AudioTrackController extends EventHandler {
  constructor (hls) {
    super(hls, Event.MANIFEST_LOADING,
      Event.MANIFEST_PARSED,
      Event.AUDIO_TRACK_LOADED,
      Event.ERROR);
    this.ticks = 0;
    this.ontick = this.tick.bind(this);
  }
 
  destroy () {
    this.cleanTimer();
    EventHandler.prototype.destroy.call(this);
  }
 
  cleanTimer () {
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }
  }
 
  tick () {
    this.ticks++;
    if (this.ticks === 1) {
      this.doTick();
      if (this.ticks > 1)
        setTimeout(this.tick, 1);
 
      this.ticks = 0;
    }
  }
 
  doTick () {
    this.updateTrack(this.trackId);
  }
 
  onError (data) {
    Iif (data.fatal && data.type === ErrorTypes.NETWORK_ERROR)
      this.cleanTimer();
  }
 
  onManifestLoading () {
    // reset audio tracks on manifest loading
    this.tracks = [];
    this.trackId = -1;
  }
 
  onManifestParsed (data) {
    let tracks = data.audioTracks || [];
    let defaultFound = false;
    this.tracks = tracks;
    this.hls.trigger(Event.AUDIO_TRACKS_UPDATED, { audioTracks: tracks });
    // loop through available audio tracks and autoselect default if needed
    let id = 0;
    tracks.forEach(track => {
      if (track.default && !defaultFound) {
        this.audioTrack = id;
        defaultFound = true;
        return;
      }
      id++;
    });
    if (defaultFound === false && tracks.length) {
      logger.log('no default audio track defined, use first audio track as default');
      this.audioTrack = 0;
    }
  }
 
  onAudioTrackLoaded (data) {
    if (data.id < this.tracks.length) {
      logger.log(`audioTrack ${data.id} loaded`);
      this.tracks[data.id].details = data.details;
      // check if current playlist is a live playlist
      if (data.details.live && !this.timer) {
        // if live playlist we will have to reload it periodically
        // set reload period to playlist target duration
        this.timer = setInterval(this.ontick, 1000 * data.details.targetduration);
      }
      if (!data.details.live && this.timer) {
        // playlist is not live and timer is armed : stopping it
        this.cleanTimer();
      }
    }
  }
 
  /** get alternate audio tracks list from playlist **/
  get audioTracks () {
    return this.tracks;
  }
 
  /** get index of the selected audio track (index in audio track lists) **/
  get audioTrack () {
    return this.trackId;
  }
 
  /** select an audio track, based on its index in audio track lists**/
  set audioTrack (audioTrackId) {
    if (this.trackId !== audioTrackId || this.tracks[audioTrackId].details === undefined)
      this.setAudioTrackInternal(audioTrackId);
  }
 
  setAudioTrackInternal (newId) {
    // check if level idx is valid
    if (newId >= 0 && newId < this.tracks.length) {
      // stopping live reloading timer if any
      this.cleanTimer();
      this.trackId = newId;
      logger.log(`switching to audioTrack ${newId}`);
      let audioTrack = this.tracks[newId],
        hls = this.hls,
        type = audioTrack.type,
        url = audioTrack.url,
        eventObj = { id: newId, type: type, url: url };
      hls.trigger(Event.AUDIO_TRACK_SWITCHING, eventObj);
      // check if we need to load playlist for this audio Track
      let details = audioTrack.details;
      if (url && (details === undefined || details.live === true)) {
        // track not retrieved yet, or live playlist we need to (re)load it
        logger.log(`(re)loading playlist for audioTrack ${newId}`);
        hls.trigger(Event.AUDIO_TRACK_LOADING, { url: url, id: newId });
      }
    }
  }
 
  updateTrack (newId) {
    // check if level idx is valid
    if (newId >= 0 && newId < this.tracks.length) {
      // stopping live reloading timer if any
      this.cleanTimer();
      this.trackId = newId;
      logger.log(`updating audioTrack ${newId}`);
      let audioTrack = this.tracks[newId], url = audioTrack.url;
      // check if we need to load playlist for this audio Track
      let details = audioTrack.details;
      if (url && (details === undefined || details.live === true)) {
        // track not retrieved yet, or live playlist we need to (re)load it
        logger.log(`(re)loading playlist for audioTrack ${newId}`);
        this.hls.trigger(Event.AUDIO_TRACK_LOADING, { url: url, id: newId });
      }
    }
  }
}
 
export default AudioTrackController;