/* AUTHOR Trek Hopton LICENSE This file is Copyright (C) 2020 the Australian Ocean Lab (AusOcean) It is free software: you can redistribute it and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License in gpl.txt. If not, see http://www.gnu.org/licenses. For hls.js Copyright notice and license, see LICENSE file. */ /* * Fragment Loader */ import Event from '../events.js'; import EventHandler from '../event-handler.js'; class FragmentLoader extends EventHandler { constructor(hls) { super(hls, Event.FRAG_LOADING); this.loaders = {}; } destroy() { let loaders = this.loaders; for (let loaderName in loaders) { let loader = loaders[loaderName]; if (loader) { loader.destroy(); } } this.loaders = {}; super.destroy(); } onFragLoading(data) { const frag = data.frag, type = frag.type, loaders = this.loaders, config = this.hls.config, FragmentILoader = config.fLoader, DefaultILoader = config.loader; // reset fragment state frag.loaded = 0; let loader = loaders[type]; if (loader) { console.warn(`abort previous fragment loader for type: ${type}`); loader.abort(); } loader = loaders[type] = frag.loader = config.fLoader ? new FragmentILoader(config) : new DefaultILoader(config); let loaderContext, loaderConfig, loaderCallbacks; loaderContext = { url: frag.url, frag: frag, responseType: 'arraybuffer', progressData: false }; let start = frag.byteRangeStartOffset, end = frag.byteRangeEndOffset; if (Number.isFinite(start) && Number.isFinite(end)) { loaderContext.rangeStart = start; loaderContext.rangeEnd = end; } loaderConfig = { timeout: config.fragLoadingTimeOut, maxRetry: 0, retryDelay: 0, maxRetryDelay: config.fragLoadingMaxRetryTimeout }; loaderCallbacks = { onSuccess: this.loadsuccess.bind(this), onError: this.loaderror.bind(this), onTimeout: this.loadtimeout.bind(this), onProgress: this.loadprogress.bind(this) }; loader.load(loaderContext, loaderConfig, loaderCallbacks); } loadsuccess(response, stats, context, networkDetails = null) { let payload = response.data, frag = context.frag; // detach fragment loader on load success frag.loader = undefined; this.loaders[frag.type] = undefined; this.hls.trigger(Event.FRAG_LOADED, { payload: payload, frag: frag, stats: stats, networkDetails: networkDetails }); } loaderror(response, context, networkDetails = null) { const frag = context.frag; let loader = frag.loader; if (loader) { loader.abort(); } this.loaders[frag.type] = undefined; this.hls.trigger(Event.ERROR, { type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.FRAG_LOAD_ERROR, fatal: false, frag: context.frag, response: response, networkDetails: networkDetails }); } loadtimeout(stats, context, networkDetails = null) { const frag = context.frag; let loader = frag.loader; if (loader) { loader.abort(); } this.loaders[frag.type] = undefined; this.hls.trigger(Event.ERROR, { type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.FRAG_LOAD_TIMEOUT, fatal: false, frag: context.frag, networkDetails: networkDetails }); } // data will be used for progressive parsing loadprogress(stats, context, data, networkDetails = null) { // jshint ignore:line let frag = context.frag; frag.loaded = stats.loaded; this.hls.trigger(Event.FRAG_LOAD_PROGRESS, { frag: frag, stats: stats, networkDetails: networkDetails }); } } export default FragmentLoader;