Hello hls.js!

First step: setup and support

First include https://cdn.jsdelivr.net/hls.js/latest/hls.min.js (or /hls.js for unminified) in your web page.

  <script src="https://cdn.jsdelivr.net/hls.js/latest/hls.min.js"></script>

Invoke the following static method: Hls.isSupported() to check whether your browser is supporting MediaSource Extensions.

  <script src="https://cdn.jsdelivr.net/hls.js/latest/hls.min.js"></script>
  <script>
    if (Hls.isSupported()) {
 	    console.log("hello hls.js!");
    }
  </script>

Second step: instantiate Hls object and bind it to <video> element

Let’s

  <script src="https://cdn.jsdelivr.net/hls.js/latest/hls.min.js"></script>

  <video id="video"></video>
  <script>
    if (Hls.isSupported()) {
      var video = document.getElementById('video');
      var hls = new Hls();
      // bind them together
      hls.attachMedia(video);
      // MEDIA_ATTACHED event is fired by hls object once MediaSource is ready
      hls.on(Hls.Events.MEDIA_ATTACHED, function () {
		    console.log("video and hls.js are now bound together !");
      });
    }
  </script>

Third step: load a manifest

You need to provide manifest URL as below:

  <script src="https://cdn.jsdelivr.net/hls.js/latest/hls.min.js"></script>

  <video id="video"></video>
  <script>
    if (Hls.isSupported()) {
      var video = document.getElementById('video');
      var hls = new Hls();
      // bind them together
      hls.attachMedia(video);
      hls.on(Hls.Events.MEDIA_ATTACHED, function () {
        console.log("video and hls.js are now bound together !");
        hls.loadSource("http://my.streamURL.com/playlist.m3u8");
        hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) {
          console.log("manifest loaded, found " + data.levels.length + " quality level");
        });
      });
    }
  </script>

Fourth step: control through <video> element

Video is controlled through HTML <video> element.

HTMLVideoElement control and events could be used seamlessly.

  video.play();

Fifth step: error handling

All errors are signalled through a unique single event.

Each error is categorized by:

Full details are described below

See sample code below to listen to errors:

  hls.on(Hls.Events.ERROR, function (event, data) {
    var errorType = data.type;
    var errorDetails = data.details;
    var errorFatal = data.fatal;

    switch(data.details) {
      case hls.ErrorDetails.FRAG_LOAD_ERROR:
        // ....
        break;
      default:
        break;
    }
  }

Fatal Error Recovery

Hls.js provides means to ‘try to’ recover fatal network and media errors, through these 2 methods:

hls.startLoad()

Should be invoked to recover network error.

hls.recoverMediaError()

Should be invoked to recover media error.

Error recovery sample code
  hls.on(Hls.Events.ERROR, function (event, data) {
    if (data.fatal) {
      switch(data.type) {
      case Hls.ErrorTypes.NETWORK_ERROR:
      // try to recover network error
        console.log("fatal network error encountered, try to recover");
        hls.startLoad();
        break;
      case Hls.ErrorTypes.MEDIA_ERROR:
        console.log("fatal media error encountered, try to recover");
        hls.recoverMediaError();
        break;
      default:
      // cannot recover
        hls.destroy();
        break;
      }
    }
  });
hls.swapAudioCodec()

If media error are still raised after calling hls.recoverMediaError(), calling this method, could be useful to workaround audio codec mismatch. the workflow should be:

on First Media Error : call hls.recoverMediaError()

if another Media Error is raised ‘quickly’ after this first Media Error : first call hls.swapAudioCodec(), then call hls.recoverMediaError().

Final step: destroying, switching between streams

hls.destroy() should be called to free used resources and destroy hls context.

Fine Tuning

Configuration parameters could be provided to hls.js upon instantiation of Hls object.

   var config = {
      autoStartLoad: true,
  	  startPosition : -1,
      capLevelToPlayerSize: false,
      debug: false,
      defaultAudioCodec: undefined,
      maxBufferLength: 30,
      maxMaxBufferLength: 600,
      maxBufferSize: 60*1000*1000,
      maxBufferHole: 0.5,
      maxSeekHole: 2,
      seekHoleNudgeDuration: 0.01,
      maxFragLookUpTolerance: 0.2,
      liveSyncDurationCount: 3,
      liveMaxLatencyDurationCount: 10,
      enableWorker: true,
      enableSoftwareAES: true,
      manifestLoadingTimeOut: 10000,
      manifestLoadingMaxRetry: 6,
      manifestLoadingRetryDelay: 500,
      levelLoadingTimeOut: 10000,
      levelLoadingMaxRetry: 6,
      levelLoadingRetryDelay: 500,
      fragLoadingTimeOut: 20000,
      fragLoadingMaxRetry: 6,
      fragLoadingRetryDelay: 500,
      startFragPrefech: false,
      appendErrorMaxRetry: 3,
      loader: customLoader,
      fLoader: customFragmentLoader,
      pLoader: customPlaylistLoader,
      xhrSetup: XMLHttpRequestSetupCallback,
      abrController: customAbrController,
      timelineController: TimelineController,
      enableCEA708Captions: true,
      stretchShortVideoTrack: false,
      forceKeyFrameOnDiscontinuity: true,
      abrEwmaFastLive: 5.0,
      abrEwmaSlowLive: 9.0,
      abrEwmaFastVoD: 4.0,
      abrEwmaSlowVoD: 15.0,
      abrEwmaDefaultEstimate: 500000,
      abrBandWidthFactor: 0.8,
      abrBandWidthUpFactor: 0.7
  };

  var hls = new Hls(config);

Hls.DefaultConfig get/set

This getter/setter allows to retrieve and override Hls default configuration. This configuration will be applied by default to all instances.

capLevelToPlayerSize

(default: false)

debug

(default: false)

Setting config.debug = true; will turn on debug logs on JS console.

A logger object could also be provided for custom logging: config.debug = customLogger;.

autoStartLoad

(default: true)

startPosition

(default -1)

defaultAudioCodec

(default: undefined)

If audio codec is not signaled in variant manifest, or if only a stream manifest is provided, hls.js tries to guess audio codec by parsing audio sampling rate in ADTS header. If sampling rate is less or equal than 22050 Hz, then hls.js assumes it is HE-AAC, otherwise it assumes it is AAC-LC. This could result in bad guess, leading to audio decode error, ending up in media error. It is possible to hint default audiocodec to hls.js by configuring this value as below: - mp4a.40.2 (AAC-LC) or - mp4a.40.5 (HE-AAC) or - undefined (guess based on sampling rate)

maxBufferLength

(default: 30 seconds)

Maximum buffer length in seconds. If buffer length is/become less than this value, a new fragment will be loaded. This is the guaranteed buffer length hls.js will try to reach, regardless of maxBufferSize.

maxBufferSize

(default: 60 MB)

‘Minimum’ maximum buffer size in bytes. If buffer size upfront is bigger than this value, no fragment will be loaded.

maxBufferHole

(default: 0.5 seconds)

‘Maximum’ inter-fragment buffer hole tolerance that hls.js can cope with when searching for the next fragment to load. When switching between quality level, fragments might not be perfectly aligned. This could result in small overlapping or hole in media buffer. This tolerance factor helps cope with this.

maxSeekHole

(default: 2 seconds)

In case playback is stalled, and a buffered range is available upfront, less than maxSeekHole seconds from current media position, hls.js will jump over this buffer hole to reach the beginning of this following buffered range. maxSeekHole allows to configure this jumpable threshold.

seekHoleNudgeDuration

(default 0.01s)

In case playback is still stalling although a seek over buffer hole just occured, hls.js will seek to next buffer start + (number of consecutive stalls * seekHoleNudgeDuration) to try to restore playback.

maxFragLookUpTolerance

(default 0.2s)

This tolerance factor is used during fragment lookup. Instead of checking whether buffered.end is located within [start, end] range, frag lookup will be done by checking within [start-maxFragLookUpTolerance, end-maxFragLookUpTolerance] range.

This tolerance factor is used to cope with situations like: buffered.end = 9.991 frag[0] : [0,10] frag[1] : [10,20] buffered.end is within frag[0] range, but as we are close to frag[1], frag[1] should be choosen instead

If maxFragLookUpTolerance = 0.2, this lookup will be adjusted to frag[0] : [-0.2,9.8] frag[1] : [9.8,19.8] This time, buffered.end is within frag[1] range, and frag[1] will be the next fragment to be loaded, as expected.

maxMaxBufferLength

(default 600s)

Maximum buffer length in seconds. Hls.js will never exceed this value, even if maxBufferSize is not reached yet.

hls.js tries to buffer up to a maximum number of bytes (60 MB by default) rather than to buffer up to a maximum nb of seconds. this is to mimic the browser behaviour (the buffer eviction algorithm is starting after the browser detects that video buffer size reaches a limit in bytes)

maxBufferLength is the minimum guaranteed buffer length that hls.js will try to achieve, even if that value exceeds the amount of bytes 60 MB of memory. maxMaxBufferLength acts as a capping value, as if bitrate is really low, you could need more than one hour of buffer to fill 60 MB.

liveSyncDurationCount

(default: 3)

edge of live delay, expressed in multiple of EXT-X-TARGETDURATION. if set to 3, playback will start from fragment N-3, N being the last fragment of the live playlist. decreasing this value is likely to cause playback stalls.

liveMaxLatencyDurationCount

(default: Infinity)

maximum delay allowed from edge of live, expressed in multiple of EXT-X-TARGETDURATION. if set to 10, the player will seek back to liveSyncDurationCount whenever the next fragment to be loaded is older than N-10, N being the last fragment of the live playlist. If set, this value must be stricly superior to liveSyncDurationCount a value too close from liveSyncDurationCount is likely to cause playback stalls.

liveSyncDuration

(default: undefined)

Alternative parameter to liveSyncDurationCount, expressed in seconds vs number of segments. If defined in the configuration object, liveSyncDuration will take precedence over the default liveSyncDurationCount. You can’t define this parameter and either liveSyncDurationCount or liveMaxLatencyDurationCount in your configuration object at the same time. A value too low (inferior to ~3 segment durations) is likely to cause playback stalls.

liveMaxLatencyDuration

(default: undefined)

Alternative parameter to liveMaxLatencyDurationCount, expressed in seconds vs number of segments. If defined in the configuration object, liveMaxLatencyDuration will take precedence over the default liveMaxLatencyDurationCount. If set, this value must be stricly superior to liveSyncDuration which must be defined as well. You can’t define this parameter and either liveSyncDurationCount or liveMaxLatencyDurationCount in your configuration object at the same time. A value too close from liveSyncDuration is likely to cause playback stalls.

enableWorker

(default: true)

Enable WebWorker (if available on browser) for TS demuxing/MP4 remuxing, to improve performance and avoid lag/frame drops.

enableSoftwareAES

(default: true)

Enable to use JavaScript version AES decryption for fallback of WebCrypto API.

fragLoadingTimeOut / manifestLoadingTimeOut / levelLoadingTimeOut

(default: 60000ms for fragment / 10000ms for level and manifest)

URL Loader timeout. A timeout callback will be triggered if loading duration exceeds this timeout. no further action will be done : the load operation will not be cancelled/aborted. It is up to the application to catch this event and treat it as needed.

fragLoadingMaxRetry / manifestLoadingMaxRetry / levelLoadingMaxRetry

(default: 3)

Max number of load retries.

fragLoadingRetryDelay / manifestLoadingRetryDelay / levelLoadingRetryDelay

(default: 1000 ms)

Initial delay between XMLHttpRequest error and first load retry (in ms). Any I/O error will trigger retries every 500ms,1s,2s,4s,8s, … capped to 64s (exponential backoff).

Prefetch start fragment although media not attached.

startFragPrefetch

(default: false)

Start prefetching start fragment although media not attached yet. Max number of append retries.

appendErrorMaxRetry

(default: 3)

Max number of sourceBuffer.appendBuffer() retry upon error. Such error could happen in loop with UHD streams, when internal buffer is full. (Quota Exceeding Error will be triggered). In that case we need to wait for the browser to evict some data before being able to append buffer correctly.

loader

(default: standard XMLHttpRequest-based URL loader)

Override standard URL loader by a custom one. Could be useful for P2P or stubbing (testing).

Use this, if you want to overwrite both the fragment and the playlist loader.

Note: If fLoader or pLoader are used, they overwrite loader!

  var customLoader = function () {
    /**
     * Calling load() will start retrieving content at given URL (HTTP GET).
     *
     * @param {string} url URL to load.
     * @param {string} responseType XHR response type (arraybuffer or default response type for playlist).
     * @param {Function} onSuccess Callback triggered upon successful loading of URL.
     *                             It should return XHR event and load stats object `{ trequest, tfirst, tload }`.
     * @param {Function} onError Callback triggered if any I/O error is met while loading fragment.
     * @param {Function} onTimeOut Callback triggered if loading is still not finished after a certain duration.
     * @param {number} timeout Timeout after which `onTimeOut` callback will be triggered (if loading is still not finished after that delay).
     * @param {number} maxRetry Max number of load retries.
     * @param {number} retryDelay Delay between an I/O error and following connection retry (ms). This to avoid spamming the server.
     */
    this.load = function (url, responseType, onSuccess, onError, onTimeOut, timeout, maxRetry, retryDelay) {};

    /** Abort any loading in progress. */
    this.abort = function () {};

    /** Destroy loading context. */
    this.destroy = function () {};
  }

fLoader

(default: undefined)

This enables the manipulation of the fragment loader. Note: This will overwrite the default loader, as well as your own loader function (see above).

  var customFragmentLoader = function() {
    // See `loader` for details.
  }

pLoader

(default: undefined)

This enables the manipulation of the playlist loader. Note: This will overwrite the default loader, as well as your own loader function (see above).

  var customPlaylistLoader = function() {
    // See `loader` for details.
  }

xhrSetup

(default: undefined)

XMLHttpRequest customization callback for default XHR based loader.

Parameter should be a function with one single argument (of type XMLHttpRequest). If xhrSetup is specified, default loader will invoke it before calling xhr.send(). This allows user to easily modify/setup XHR. See example below.

  var config = {
    xhrSetup: function(xhr, url) {
      xhr.withCredentials = true; // do send cookies
    }
  }

abrController

(default: internal ABR controller)

Customized Adaptive Bitrate Streaming Controller.

Parameter should be a class providing 2 getters, 2 setters and a destroy() method:

timelineController

(default: internal track timeline controller)

Customized text track syncronization controller.

Parameter should be a class with a destroy() method:

enableCEA708Captions

(default: true)

whether or not to enable CEA-708 captions

parameter should be a boolean

stretchShortVideoTrack

(default: false)

If a segment’s video track is shorter than its audio track by > min(maxSeekHole, maxBufferHole), extend the final video frame’s duration to match the audio track’s duration. This helps playback continue in certain cases that might otherwise get stuck.

parameter should be a boolean

forceKeyFrameOnDiscontinuity

(default: true)

Whether or not to force having a key frame in the first AVC sample after a discontinuity. If set to true, after a discontinuity, the AVC samples without any key frame will be dropped until finding one that contains a key frame. If set to false, all AVC samples will be kept, which can help avoid holes in the stream. Setting this parameter to false can also generate decoding weirdness when switching level or seeking.

parameter should be a boolean

abrEwmaFastLive

(default: 5.0)

Fast bitrate Exponential moving average half-life, used to compute average bitrate for Live streams. Half of the estimate is based on the last abrEwmaFastLive seconds of sample history. Each of the sample is weighted by the fragment loading duration.

parameter should be a float greater than 0

abrEwmaSlowLive

(default: 9.0)

Slow bitrate Exponential moving average half-life, used to compute average bitrate for Live streams. Half of the estimate is based on the last abrEwmaSlowLive seconds of sample history. Each of the sample is weighted by the fragment loading duration.

parameter should be a float greater than abrEwmaFastLive

abrEwmaFastVoD

(default: 4.0)

Fast bitrate Exponential moving average half-life, used to compute average bitrate for VoD streams. Half of the estimate is based on the last abrEwmaFastVoD seconds of sample history. Each of the sample is weighted by the fragment loading duration.

parameter should be a float greater than 0

abrEwmaSlowVoD

(default: 15.0)

Slow bitrate Exponential moving average half-life, used to compute average bitrate for VoD streams. Half of the estimate is based on the last abrEwmaSlowVoD seconds of sample history. Each of the sample is weighted by the fragment loading duration.

parameter should be a float greater than abrEwmaFastVoD

abrEwmaDefaultEstimate

(default: 500000)

Default bandwidth estimate in bits/second prior to collecting fragment bandwidth samples.

parameter should be a float

abrBandWidthFactor

(default: 0.8)

Scale factor to be applied against measured bandwidth average, to determine whether we can stay on current or lower quality level. If abrBandWidthFactor * bandwidth average < level.bitrate then ABR can switch to that level providing that it is equal or less than current level.

abrBandWidthUpFactor

(default: 0.7)

Scale factor to be applied against measured bandwidth average, to determine whether we can switch up to a higher quality level. If abrBandWidthUpFactor * bandwidth average < level.bitrate then ABR can switch up to that quality level.

Video Binding/Unbinding API

hls.attachMedia(videoElement)

Calling this method will:

hls.detachMedia()

Calling this method will:

Quality switch Control API

By default, hls.js handles quality switch automatically, using heuristics based on fragment loading bitrate and quality level bandwidth exposed in the variant manifest. It is also possible to manually control quality swith using below API.

hls.levels

hls.currentLevel

Set to -1 for automatic level selection.

hls.nextLevel

Set to -1 for automatic level selection.

hls.loadLevel

Set to -1 for automatic level selection.

hls.nextLoadLevel

hls.firstLevel

hls.startLevel

Default value is hls.firstLevel.

hls.autoLevelEnabled

hls.autoLevelCapping

Default value is -1 (no level capping).

Version Control

Hls.version

Static getter: return hls.js dist version number.

Network Loading Control API

By default, hls.js will automatically start loading quality level playlists, and fragments after Hls.Events.MANIFEST_PARSED event has been triggered (and video element has been attached).

However if config.autoStartLoad is set to false, the following method needs to be called to manually start playlist and fragments loading:

hls.startLoad(startPosition=-1)

Start/restart playlist/fragment loading. this is only effective if MANIFEST_PARSED event has been triggered and video element has been attached to hls object.

startPosition is the initial position in the playlist. If startPosition is not set to -1, it allows to override default startPosition to the one you want (it will bypass hls.config.liveSync* config params for Live for example, so that user can start playback from whatever position)

hls.stopLoad()

stop playlist/fragment loading. could be resumed later on by calling hls.startLoad()

Audio Tracks Control API

hls.audioTracks

get : array of audio tracks exposed in manifest

hls.audioTrack

get/set : audio track id (returned by)

Runtime Events

Hls.js fires a bunch of events, that could be registered as below:

hls.on(Hls.Events.LEVEL_LOADED,function(event,data) {
  var level_duration = data.details.totalduration;
});

Full list of Events is available below:

Errors

Full list of errors is described below:

Network Errors

Media Errors

Objects

Level

A Level object represents a given quality level. It contains quality level related info, retrieved from manifest, such as:

See sample Level object below:

{
  url: [ 'http://levelURL.com', 'http://levelURLfailover.com' ],
  bitrate: 246440,
  name: "240",
  codecs: "mp4a.40.5,avc1.42000d",
  width: 320,
  height: 136,
}

LevelDetails

A LevelDetails object contains level details retrieved after level playlist parsing, they are specified below:

See sample object below, available after corresponding LEVEL_LOADED event has been fired:

{
  version: 3,
  type: 'VOD', // null if EXT-X-PLAYLIST-TYPE not present
  startSN: 0,
  endSN: 50,
  totalduration: 510,
  targetduration: 10,
  fragments: Array(51),
  live: false
}

Fragment

The Fragment object contains fragment related info, such as:

See sample object below:

{
  duration: 10,
  level: 3,
  sn: 35,
  start: 30,
  url: 'http://fragURL.com'
}