Hls.js: startLoad after 404 network error is quietly stopping

Created on 10 Jun 2016  路  7Comments  路  Source: video-dev/hls.js

Steps to reproduce:

  1. simulate a 404 playlist (http://www.streambox.fr/playlists/x36xhzz/404.m3u8)
  2. try to recover from it ( onError(e, data) data.fatal && data.type == NETWORK_ERROR and then startLoad())
  3. I was expecting another Events.ERROR but instead it seems that hls just state itself as stopped and silently stopped.

Summarizing, it tries (after the 404) to recovery player.startLoad and then on stream controller.startLoad it checks the levels (undefined) and then it stops.

Is this intentional?

Bug Wontfix

Most helpful comment

I just looked at this and it appears to be a bit more complicated because the user might have autoStartLoad set to false, in which case they'd need to call startLoad(), and then startLoad() again once they get the MAINFEST_PARSED event. It seems a bit strange to me for the same method to be doing different things depending on when it is called.

Also calling startLoad() when the MANIFEST_PARSED event hasn't happened yet will cause the immediate warning in StreamController and move to the STOPPED state because the manifest isn't parsed.

I think maybe instead of the user calling startLoad() then should instead call loadSource(url) again if the error was because the manifest failed to load? I think detecting this is also already possible by checking if the error event is MANIFEST_LOAD_ERROR/MANIFEST_LOAD_TIMEOUT vs the other errors?

E.g. untested

_onHLSJSError(evt, data) {
    // only report/handle errors if they are fatal
    // hlsjs should automatically handle non fatal errors
    if (data.fatal) {
      if (this._recoverAttemptsRemaining > 0) {
        this._recoverAttemptsRemaining -= 1
        switch (data.type) {
        case HLSJS.ErrorTypes.NETWORK_ERROR:=
          Log.warn(`hlsjs: trying to recover from network error, evt ${evt}, data ${data} `)
          if (data.details === HLSJS.ErrorDetails.MANIFEST_LOAD_ERROR || data.details === Hls.ErrorDetails.MANIFEST_LOAD_TIMEOUT || data.details === Hls.ErrorDetails.MANIFEST_PARSING_ERROR) {
            this._hls.loadSource(this.options.src)
          }
          else {
            this._hls.startLoad()
          }
          break
        case HLSJS.ErrorTypes.MEDIA_ERROR:
          Log.warn(`hlsjs: trying to recover from media error, evt ${evt}, data ${data} `)
          this._recover(evt, data)
          break
        default:
          Log.error(`hlsjs: trying to recover from error, evt ${evt}, data ${data} `)
          this.trigger(Events.PLAYBACK_ERROR, `hlsjs: could not recover from error, evt ${evt}, data ${data} `, this.name)
          break
        }
      } else {
        Log.error(`hlsjs: could not recover from error after maximum number of attempts, evt ${evt}, data ${data} `)
        this.trigger(Events.PLAYBACK_ERROR, {evt, data}, this.name)
      }
    }

All 7 comments

Hi @leandromoreira
it is not intentional, just not implemented :-)
a good place to force a manifest reload on hls.startLoad() would be in levelController.startLoad():

if (this._levels === undefined) {
   this.hls.trigger(Event.MANIFEST_LOADING, {url: this.hls.url});
}

PR welcome

Thanks @mangui

I just looked at this and it appears to be a bit more complicated because the user might have autoStartLoad set to false, in which case they'd need to call startLoad(), and then startLoad() again once they get the MAINFEST_PARSED event. It seems a bit strange to me for the same method to be doing different things depending on when it is called.

Also calling startLoad() when the MANIFEST_PARSED event hasn't happened yet will cause the immediate warning in StreamController and move to the STOPPED state because the manifest isn't parsed.

I think maybe instead of the user calling startLoad() then should instead call loadSource(url) again if the error was because the manifest failed to load? I think detecting this is also already possible by checking if the error event is MANIFEST_LOAD_ERROR/MANIFEST_LOAD_TIMEOUT vs the other errors?

E.g. untested

_onHLSJSError(evt, data) {
    // only report/handle errors if they are fatal
    // hlsjs should automatically handle non fatal errors
    if (data.fatal) {
      if (this._recoverAttemptsRemaining > 0) {
        this._recoverAttemptsRemaining -= 1
        switch (data.type) {
        case HLSJS.ErrorTypes.NETWORK_ERROR:=
          Log.warn(`hlsjs: trying to recover from network error, evt ${evt}, data ${data} `)
          if (data.details === HLSJS.ErrorDetails.MANIFEST_LOAD_ERROR || data.details === Hls.ErrorDetails.MANIFEST_LOAD_TIMEOUT || data.details === Hls.ErrorDetails.MANIFEST_PARSING_ERROR) {
            this._hls.loadSource(this.options.src)
          }
          else {
            this._hls.startLoad()
          }
          break
        case HLSJS.ErrorTypes.MEDIA_ERROR:
          Log.warn(`hlsjs: trying to recover from media error, evt ${evt}, data ${data} `)
          this._recover(evt, data)
          break
        default:
          Log.error(`hlsjs: trying to recover from error, evt ${evt}, data ${data} `)
          this.trigger(Events.PLAYBACK_ERROR, `hlsjs: could not recover from error, evt ${evt}, data ${data} `, this.name)
          break
        }
      } else {
        Log.error(`hlsjs: could not recover from error after maximum number of attempts, evt ${evt}, data ${data} `)
        this.trigger(Events.PLAYBACK_ERROR, {evt, data}, this.name)
      }
    }

We are really needed this to be implemented too, there should be a possibility to handle network loading errors.

any news about this integration ?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

any news regarding this issue?

Was this page helpful?
0 / 5 - 0 ratings