Home Reference Source

src/loader/fragment-loader.js

  1. /*
  2. * Fragment Loader
  3. */
  4.  
  5. import Event from '../events';
  6. import EventHandler from '../event-handler';
  7. import { ErrorTypes, ErrorDetails } from '../errors';
  8. import { logger } from '../utils/logger';
  9.  
  10. class FragmentLoader extends EventHandler {
  11. constructor (hls) {
  12. super(hls, Event.FRAG_LOADING);
  13. this.loaders = {};
  14. }
  15.  
  16. destroy () {
  17. let loaders = this.loaders;
  18. for (let loaderName in loaders) {
  19. let loader = loaders[loaderName];
  20. if (loader) {
  21. loader.destroy();
  22. }
  23. }
  24. this.loaders = {};
  25.  
  26. super.destroy();
  27. }
  28.  
  29. onFragLoading (data) {
  30. const frag = data.frag,
  31. type = frag.type,
  32. loaders = this.loaders,
  33. config = this.hls.config,
  34. FragmentILoader = config.fLoader,
  35. DefaultILoader = config.loader;
  36.  
  37. // reset fragment state
  38. frag.loaded = 0;
  39.  
  40. let loader = loaders[type];
  41. if (loader) {
  42. logger.warn(`abort previous fragment loader for type: ${type}`);
  43. loader.abort();
  44. }
  45.  
  46. loader = loaders[type] = frag.loader =
  47. config.fLoader ? new FragmentILoader(config) : new DefaultILoader(config);
  48.  
  49. let loaderContext, loaderConfig, loaderCallbacks;
  50.  
  51. loaderContext = { url: frag.url, frag: frag, responseType: 'arraybuffer', progressData: false };
  52.  
  53. let start = frag.byteRangeStartOffset,
  54. end = frag.byteRangeEndOffset;
  55.  
  56. if (Number.isFinite(start) && Number.isFinite(end)) {
  57. loaderContext.rangeStart = start;
  58. loaderContext.rangeEnd = end;
  59. }
  60.  
  61. loaderConfig = {
  62. timeout: config.fragLoadingTimeOut,
  63. maxRetry: 0,
  64. retryDelay: 0,
  65. maxRetryDelay: config.fragLoadingMaxRetryTimeout
  66. };
  67.  
  68. loaderCallbacks = {
  69. onSuccess: this.loadsuccess.bind(this),
  70. onError: this.loaderror.bind(this),
  71. onTimeout: this.loadtimeout.bind(this),
  72. onProgress: this.loadprogress.bind(this)
  73. };
  74.  
  75. loader.load(loaderContext, loaderConfig, loaderCallbacks);
  76. }
  77.  
  78. loadsuccess (response, stats, context, networkDetails = null) {
  79. let payload = response.data, frag = context.frag;
  80. // detach fragment loader on load success
  81. frag.loader = undefined;
  82. this.loaders[frag.type] = undefined;
  83. this.hls.trigger(Event.FRAG_LOADED, { payload: payload, frag: frag, stats: stats, networkDetails: networkDetails });
  84. }
  85.  
  86. loaderror (response, context, networkDetails = null) {
  87. const frag = context.frag;
  88. let loader = frag.loader;
  89. if (loader) {
  90. loader.abort();
  91. }
  92.  
  93. this.loaders[frag.type] = undefined;
  94. this.hls.trigger(Event.ERROR, { type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.FRAG_LOAD_ERROR, fatal: false, frag: context.frag, response: response, networkDetails: networkDetails });
  95. }
  96.  
  97. loadtimeout (stats, context, networkDetails = null) {
  98. const frag = context.frag;
  99. let loader = frag.loader;
  100. if (loader) {
  101. loader.abort();
  102. }
  103.  
  104. this.loaders[frag.type] = undefined;
  105. this.hls.trigger(Event.ERROR, { type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.FRAG_LOAD_TIMEOUT, fatal: false, frag: context.frag, networkDetails: networkDetails });
  106. }
  107.  
  108. // data will be used for progressive parsing
  109. loadprogress (stats, context, data, networkDetails = null) { // jshint ignore:line
  110. let frag = context.frag;
  111. frag.loaded = stats.loaded;
  112. this.hls.trigger(Event.FRAG_LOAD_PROGRESS, { frag: frag, stats: stats, networkDetails: networkDetails });
  113. }
  114. }
  115.  
  116. export default FragmentLoader;