From 88056fcd52e5f2a273eb1080e3942313e7cda10e Mon Sep 17 00:00:00 2001 From: Tomohiro IKEDA Date: Sat, 19 May 2018 22:21:13 +0900 Subject: [PATCH 01/24] Removed `Array.prototype.slice.call` - Use rest parameters - Use `Array.from` --- src/remux/mp4-generator.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/remux/mp4-generator.js b/src/remux/mp4-generator.js index d59d19570eb..e38b2f40b83 100644 --- a/src/remux/mp4-generator.js +++ b/src/remux/mp4-generator.js @@ -142,9 +142,8 @@ class MP4 { MP4.DINF = MP4.box(MP4.types.dinf, MP4.box(MP4.types.dref, dref)); } - static box (type) { + static box (type, ...payload) { let - payload = Array.prototype.slice.call(arguments, 1), size = 8, i = payload.length, len = i, @@ -334,7 +333,13 @@ class MP4 { len = data.byteLength; sps.push((len >>> 8) & 0xFF); sps.push((len & 0xFF)); - sps = sps.concat(Array.prototype.slice.call(data)); // SPS + + // SPS + if (typeof Array.from === 'function') { + sps = sps.concat(Array.from(data)); + } else { + sps = sps.concat(Array.prototype.slice.call(data)); + } } // assemble the PPSs @@ -343,7 +348,12 @@ class MP4 { len = data.byteLength; pps.push((len >>> 8) & 0xFF); pps.push((len & 0xFF)); - pps = pps.concat(Array.prototype.slice.call(data)); + + if (typeof Array.from === 'function') { + pps = pps.concat(Array.from(data)); + } else { + pps = pps.concat(Array.prototype.slice.call(data)); + } } let avcc = MP4.box(MP4.types.avcC, new Uint8Array([ From 3e91c4eca0178245b5de85277243d249e1d4829e Mon Sep 17 00:00:00 2001 From: Tomohiro IKEDA Date: Sun, 20 May 2018 00:09:33 +0900 Subject: [PATCH 02/24] Revert `rest parameters` --- src/remux/mp4-generator.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/remux/mp4-generator.js b/src/remux/mp4-generator.js index e38b2f40b83..93ce894e112 100644 --- a/src/remux/mp4-generator.js +++ b/src/remux/mp4-generator.js @@ -142,8 +142,9 @@ class MP4 { MP4.DINF = MP4.box(MP4.types.dinf, MP4.box(MP4.types.dref, dref)); } - static box (type, ...payload) { + static box (type) { let + payload = Array.prototype.slice.call(arguments, 1), size = 8, i = payload.length, len = i, From 2306a46dad16a11dfd46668db4eb4c28c5954d4d Mon Sep 17 00:00:00 2001 From: Tomohiro IKEDA Date: Sun, 20 May 2018 13:06:56 +0900 Subject: [PATCH 03/24] Use wrapper function --- src/remux/mp4-generator.js | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/remux/mp4-generator.js b/src/remux/mp4-generator.js index 93ce894e112..9d8667c638d 100644 --- a/src/remux/mp4-generator.js +++ b/src/remux/mp4-generator.js @@ -6,6 +6,8 @@ const UINT32_MAX = Math.pow(2, 32) - 1; +const copyAsArray = typeof Array.from === 'function' ? Array.from : Array.prototype.slice.call; + class MP4 { static init () { MP4.types = { @@ -334,13 +336,7 @@ class MP4 { len = data.byteLength; sps.push((len >>> 8) & 0xFF); sps.push((len & 0xFF)); - - // SPS - if (typeof Array.from === 'function') { - sps = sps.concat(Array.from(data)); - } else { - sps = sps.concat(Array.prototype.slice.call(data)); - } + sps = sps.concat(copyAsArray(data)); // SPS } // assemble the PPSs @@ -349,12 +345,7 @@ class MP4 { len = data.byteLength; pps.push((len >>> 8) & 0xFF); pps.push((len & 0xFF)); - - if (typeof Array.from === 'function') { - pps = pps.concat(Array.from(data)); - } else { - pps = pps.concat(Array.prototype.slice.call(data)); - } + pps = pps.concat(copyAsArray(data)); } let avcc = MP4.box(MP4.types.avcC, new Uint8Array([ From 326926bdd67bc7a6b52b2279bc90824609b88005 Mon Sep 17 00:00:00 2001 From: alex-gusev Date: Mon, 4 Jun 2018 21:43:33 +0300 Subject: [PATCH 04/24] expose observer.once to public api --- docs/API.md | 12 +++++++++--- src/hls.js | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/API.md b/docs/API.md index 4c50798498f..ca69dc57b7d 100644 --- a/docs/API.md +++ b/docs/API.md @@ -1103,12 +1103,18 @@ get : position of live sync point (ie edge of live position minus safety delay d ## Runtime Events -Hls.js fires a bunch of events, that could be registered as below: +Hls.js fires a bunch of events, that could be registered and unregistered as below: ```js -hls.on(Hls.Events.LEVEL_LOADED,function(event,data) { +function onLevelLoaded (event, data) { var level_duration = data.details.totalduration; -}); +} +// subscribe event +hls.on(Hls.Events.LEVEL_LOADED, onLevelLoaded); +// unsubscribe event +hls.off(Hls.Events.LEVEL_LOADED, onLevelLoaded); +// subscribe for a single event call only +hls.once(Hls.Events.LEVEL_LOADED, onLevelLoaded); ``` Full list of Events is available below: diff --git a/src/hls.js b/src/hls.js index 5a7ddeed27e..8eaea5fdf83 100644 --- a/src/hls.js +++ b/src/hls.js @@ -123,6 +123,7 @@ export default class Hls { }; this.on = observer.on.bind(observer); this.off = observer.off.bind(observer); + this.once = observer.once.bind(observer); this.trigger = observer.trigger.bind(observer); // core controllers and network loaders From a9c81d7febf4bd5976ba9dc5e005c3b953283635 Mon Sep 17 00:00:00 2001 From: oldmtn Date: Tue, 5 Jun 2018 17:38:03 +0800 Subject: [PATCH 05/24] Event.ERROR is undefined if don't import Event object. --- src/demux/adts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/demux/adts.js b/src/demux/adts.js index ec4c2b33ac7..32e5a050859 100644 --- a/src/demux/adts.js +++ b/src/demux/adts.js @@ -2,6 +2,7 @@ * ADTS parser helper */ import { logger } from '../utils/logger'; +import Event from '../events'; import { ErrorTypes, ErrorDetails } from '../errors'; export function getAudioConfig (observer, data, offset, audioCodec) { From e131eda8764109759285b3350e9b68d96d790fdf Mon Sep 17 00:00:00 2001 From: Tomohiro IKEDA Date: Tue, 5 Jun 2018 21:30:03 +0900 Subject: [PATCH 06/24] Implement utility function for making an instance of Array --- src/remux/mp4-generator.js | 7 +++---- src/utils/make-array-from-array-like.js | 5 +++++ 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 src/utils/make-array-from-array-like.js diff --git a/src/remux/mp4-generator.js b/src/remux/mp4-generator.js index 9d8667c638d..a91b9f8d339 100644 --- a/src/remux/mp4-generator.js +++ b/src/remux/mp4-generator.js @@ -3,11 +3,10 @@ */ // import Hex from '../utils/hex'; +import makeArrayFromArrayLike from '../utils/make-array-from-array-like'; const UINT32_MAX = Math.pow(2, 32) - 1; -const copyAsArray = typeof Array.from === 'function' ? Array.from : Array.prototype.slice.call; - class MP4 { static init () { MP4.types = { @@ -336,7 +335,7 @@ class MP4 { len = data.byteLength; sps.push((len >>> 8) & 0xFF); sps.push((len & 0xFF)); - sps = sps.concat(copyAsArray(data)); // SPS + sps = sps.concat(makeArrayFromArrayLike(data)); // SPS } // assemble the PPSs @@ -345,7 +344,7 @@ class MP4 { len = data.byteLength; pps.push((len >>> 8) & 0xFF); pps.push((len & 0xFF)); - pps = pps.concat(copyAsArray(data)); + pps = pps.concat(makeArrayFromArrayLike(data)); } let avcc = MP4.box(MP4.types.avcC, new Uint8Array([ diff --git a/src/utils/make-array-from-array-like.js b/src/utils/make-array-from-array-like.js new file mode 100644 index 00000000000..f7bc646b6c7 --- /dev/null +++ b/src/utils/make-array-from-array-like.js @@ -0,0 +1,5 @@ +'use strict'; + +const MakeArrayFromArrayLike = typeof Array.from === 'function' ? Array.from : Array.prototype.slice.call; + +export default MakeArrayFromArrayLike; From 85e217caedd9760e443a055ae6a9464e4a1323af Mon Sep 17 00:00:00 2001 From: Tomohiro IKEDA Date: Tue, 5 Jun 2018 22:09:57 +0900 Subject: [PATCH 07/24] Change to named exports --- src/remux/mp4-generator.js | 2 +- src/utils/make-array-from-array-like.js | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/remux/mp4-generator.js b/src/remux/mp4-generator.js index a91b9f8d339..ba02ab1a0c1 100644 --- a/src/remux/mp4-generator.js +++ b/src/remux/mp4-generator.js @@ -3,7 +3,7 @@ */ // import Hex from '../utils/hex'; -import makeArrayFromArrayLike from '../utils/make-array-from-array-like'; +import { makeArrayFromArrayLike } from '../utils/make-array-from-array-like'; const UINT32_MAX = Math.pow(2, 32) - 1; diff --git a/src/utils/make-array-from-array-like.js b/src/utils/make-array-from-array-like.js index f7bc646b6c7..17ca96f9943 100644 --- a/src/utils/make-array-from-array-like.js +++ b/src/utils/make-array-from-array-like.js @@ -1,5 +1,3 @@ 'use strict'; -const MakeArrayFromArrayLike = typeof Array.from === 'function' ? Array.from : Array.prototype.slice.call; - -export default MakeArrayFromArrayLike; +export const makeArrayFromArrayLike = typeof Array.from === 'function' ? Array.from : Array.prototype.slice.call; From a64e67d77b9303889a13006b15693e784635b19e Mon Sep 17 00:00:00 2001 From: Tomohiro IKEDA Date: Tue, 5 Jun 2018 22:41:25 +0900 Subject: [PATCH 08/24] Remove 'use strict' --- src/utils/make-array-from-array-like.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/utils/make-array-from-array-like.js b/src/utils/make-array-from-array-like.js index 17ca96f9943..9bfd8f88d82 100644 --- a/src/utils/make-array-from-array-like.js +++ b/src/utils/make-array-from-array-like.js @@ -1,3 +1 @@ -'use strict'; - export const makeArrayFromArrayLike = typeof Array.from === 'function' ? Array.from : Array.prototype.slice.call; From 1d58572b7409924c1aeba3afc1fd3ab4418dd1be Mon Sep 17 00:00:00 2001 From: Stephan Hesse Date: Tue, 5 Jun 2018 13:26:28 +0200 Subject: [PATCH 09/24] eslintrc: don't have any explicit globals or env.browser preset globals This has us have wrong positives, like "Event" not defined in effect --- .eslintrc.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 041861db3b8..4307bacefad 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,19 +1,11 @@ module.exports = { 'env': { - 'browser': true, 'commonjs': true, 'es6': true }, 'globals': { // Allowed globals 'console': true, - // "MediaSource": true, - 'performance': true, - 'crypto': true, - 'fetch': true, - 'Request': true, - 'Headers': true, - 'escape': true, // Compile-time defines '__VERSION__': true, From 1f217840337729ccfd4306a603654c573e8b9b43 Mon Sep 17 00:00:00 2001 From: Stephan Hesse Date: Tue, 5 Jun 2018 13:26:45 +0200 Subject: [PATCH 10/24] use explicite window property for all previous globals --- src/controller/abr-controller.js | 2 ++ src/controller/audio-stream-controller.js | 2 ++ src/controller/buffer-controller.js | 4 ++-- src/controller/cap-level-controller.js | 2 +- src/controller/eme-controller.js | 2 ++ src/controller/fps-controller.js | 4 +++- src/controller/level-controller.js | 2 ++ src/controller/stream-controller.js | 2 ++ src/controller/subtitle-stream-controller.js | 2 ++ src/crypt/decrypter.js | 4 ++++ src/demux/adts.js | 2 ++ src/demux/demuxer-inline.js | 2 ++ src/demux/demuxer.js | 4 ++-- src/events.js | 1 + src/loader/playlist-loader.js | 2 ++ src/utils/codecs.js | 2 +- src/utils/fetch-loader.js | 2 ++ src/utils/xhr-loader.js | 2 ++ tests/unit/demuxer/demuxer.js | 2 +- 19 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/controller/abr-controller.js b/src/controller/abr-controller.js index 397be794ba6..1a9222ce21f 100644 --- a/src/controller/abr-controller.js +++ b/src/controller/abr-controller.js @@ -11,6 +11,8 @@ import { ErrorDetails } from '../errors'; import { logger } from '../utils/logger'; import EwmaBandWidthEstimator from '../utils/ewma-bandwidth-estimator'; +const { performance } = window; + class AbrController extends EventHandler { constructor (hls) { super(hls, Event.FRAG_LOADING, diff --git a/src/controller/audio-stream-controller.js b/src/controller/audio-stream-controller.js index 15b13c0806d..428f07b4e74 100644 --- a/src/controller/audio-stream-controller.js +++ b/src/controller/audio-stream-controller.js @@ -15,6 +15,8 @@ import TaskLoop from '../task-loop'; import { FragmentState } from './fragment-tracker'; import Fragment from '../loader/fragment'; +const { performance } = window; + const State = { STOPPED: 'STOPPED', STARTING: 'STARTING', diff --git a/src/controller/buffer-controller.js b/src/controller/buffer-controller.js index 1ff1f1261a0..c8760437576 100644 --- a/src/controller/buffer-controller.js +++ b/src/controller/buffer-controller.js @@ -109,7 +109,7 @@ class BufferController extends EventHandler { ms.addEventListener('sourceended', this.onmse); ms.addEventListener('sourceclose', this.onmsc); // link video and media Source - media.src = URL.createObjectURL(ms); + media.src = window.URL.createObjectURL(ms); // cache the locally generated object url this._objectUrl = media.src; } @@ -137,7 +137,7 @@ class BufferController extends EventHandler { // Detach properly the MediaSource from the HTMLMediaElement as // suggested in https://github.com/w3c/media-source/issues/53. if (this.media) { - URL.revokeObjectURL(this._objectUrl); + window.URL.revokeObjectURL(this._objectUrl); // clean up video tag src only if it's our own url. some external libraries might // hijack the video tag and change its 'src' without destroying the Hls instance first diff --git a/src/controller/cap-level-controller.js b/src/controller/cap-level-controller.js index f160437f6cd..6aaf8309442 100644 --- a/src/controller/cap-level-controller.js +++ b/src/controller/cap-level-controller.js @@ -36,7 +36,7 @@ class CapLevelController extends EventHandler { } onMediaAttaching (data) { - this.media = data.media instanceof HTMLVideoElement ? data.media : null; + this.media = data.media instanceof window.HTMLVideoElement ? data.media : null; } onManifestParsed (data) { diff --git a/src/controller/eme-controller.js b/src/controller/eme-controller.js index 2b2e1ff0699..d387ff9c487 100644 --- a/src/controller/eme-controller.js +++ b/src/controller/eme-controller.js @@ -10,6 +10,8 @@ import { ErrorTypes, ErrorDetails } from '../errors'; import { logger } from '../utils/logger'; +const { XMLHttpRequest } = window; + const MAX_LICENSE_REQUEST_FAILURES = 3; /** diff --git a/src/controller/fps-controller.js b/src/controller/fps-controller.js index 55ce89c4da8..3c9d0f6aba5 100644 --- a/src/controller/fps-controller.js +++ b/src/controller/fps-controller.js @@ -6,6 +6,8 @@ import Event from '../events'; import EventHandler from '../event-handler'; import { logger } from '../utils/logger'; +const { performance } = window; + class FPSController extends EventHandler { constructor (hls) { super(hls, Event.MEDIA_ATTACHING); @@ -22,7 +24,7 @@ class FPSController extends EventHandler { onMediaAttaching (data) { const config = this.hls.config; if (config.capLevelOnFPSDrop) { - const video = this.video = data.media instanceof HTMLVideoElement ? data.media : null; + const video = this.video = data.media instanceof window.HTMLVideoElement ? data.media : null; if (typeof video.getVideoPlaybackQuality === 'function') { this.isVideoPlaybackQualityAvailable = true; } diff --git a/src/controller/level-controller.js b/src/controller/level-controller.js index 418be8e933d..6d17c43fa36 100644 --- a/src/controller/level-controller.js +++ b/src/controller/level-controller.js @@ -8,6 +8,8 @@ import { logger } from '../utils/logger'; import { ErrorTypes, ErrorDetails } from '../errors'; import { isCodecSupportedInMp4 } from '../utils/codecs'; +const { performance } = window; + export default class LevelController extends EventHandler { constructor (hls) { super(hls, diff --git a/src/controller/stream-controller.js b/src/controller/stream-controller.js index 155fe623990..fb56b9ccf7d 100644 --- a/src/controller/stream-controller.js +++ b/src/controller/stream-controller.js @@ -17,6 +17,8 @@ import { alignDiscontinuities } from '../utils/discontinuities'; import TaskLoop from '../task-loop'; import { calculateNextPDT, findFragmentByPDT, findFragmentBySN, fragmentWithinToleranceTest } from './fragment-finders'; +const { performance } = window; + export const State = { STOPPED: 'STOPPED', IDLE: 'IDLE', diff --git a/src/controller/subtitle-stream-controller.js b/src/controller/subtitle-stream-controller.js index 837faa839e7..0ff050ffa3c 100644 --- a/src/controller/subtitle-stream-controller.js +++ b/src/controller/subtitle-stream-controller.js @@ -7,6 +7,8 @@ import { logger } from '../utils/logger'; import Decrypter from '../crypt/decrypter'; import TaskLoop from '../task-loop'; +const { performance } = window; + const State = { STOPPED: 'STOPPED', IDLE: 'IDLE', diff --git a/src/crypt/decrypter.js b/src/crypt/decrypter.js index 03396d5388c..f0ada4fc705 100644 --- a/src/crypt/decrypter.js +++ b/src/crypt/decrypter.js @@ -5,6 +5,10 @@ import AESDecryptor from './aes-decryptor'; import { ErrorTypes, ErrorDetails } from '../errors'; import { logger } from '../utils/logger'; +import Event from '../events'; + +const { performance, crypto } = window; + /* globals self: false */ class Decrypter { diff --git a/src/demux/adts.js b/src/demux/adts.js index 32e5a050859..1ad509a8c83 100644 --- a/src/demux/adts.js +++ b/src/demux/adts.js @@ -5,6 +5,8 @@ import { logger } from '../utils/logger'; import Event from '../events'; import { ErrorTypes, ErrorDetails } from '../errors'; +import Event from '../events'; + export function getAudioConfig (observer, data, offset, audioCodec) { let adtsObjectType, // :int adtsSampleingIndex, // :int diff --git a/src/demux/demuxer-inline.js b/src/demux/demuxer-inline.js index d3614668f51..fc9c59fd961 100644 --- a/src/demux/demuxer-inline.js +++ b/src/demux/demuxer-inline.js @@ -12,6 +12,8 @@ import MP3Demuxer from '../demux/mp3demuxer'; import MP4Remuxer from '../remux/mp4-remuxer'; import PassThroughRemuxer from '../remux/passthrough-remuxer'; +const { performance } = window; + class DemuxerInline { constructor (observer, typeSupported, config, vendor) { this.observer = observer; diff --git a/src/demux/demuxer.js b/src/demux/demuxer.js index 8720849ab36..89bcde396f7 100644 --- a/src/demux/demuxer.js +++ b/src/demux/demuxer.js @@ -64,7 +64,7 @@ class Demuxer { logger.error('error while initializing DemuxerWorker, fallback on DemuxerInline'); if (w) { // revoke the Object URL that was used to create demuxer worker, so as not to leak it - URL.revokeObjectURL(w.objectURL); + window.URL.revokeObjectURL(w.objectURL); } this.demuxer = new DemuxerInline(observer, typeSupported, config, vendor); this.w = undefined; @@ -129,7 +129,7 @@ class Demuxer { switch (data.event) { case 'init': // revoke the Object URL that was used to create demuxer worker, so as not to leak it - URL.revokeObjectURL(this.w.objectURL); + window.URL.revokeObjectURL(this.w.objectURL); break; // special case for FRAG_PARSING_DATA: data1 and data2 are transferable objects case Event.FRAG_PARSING_DATA: diff --git a/src/events.js b/src/events.js index ce7c5122788..823141175a7 100644 --- a/src/events.js +++ b/src/events.js @@ -106,4 +106,5 @@ const HlsEvents = { // fired upon stream controller state transitions - data: { previousState, nextState } STREAM_STATE_TRANSITION: 'hlsStreamStateTransition' }; + export default HlsEvents; diff --git a/src/loader/playlist-loader.js b/src/loader/playlist-loader.js index d395ae3b758..37e74102f75 100644 --- a/src/loader/playlist-loader.js +++ b/src/loader/playlist-loader.js @@ -18,6 +18,8 @@ import { logger } from '../utils/logger'; import MP4Demuxer from '../demux/mp4demuxer'; import M3U8Parser from './m3u8-parser'; +const { performance } = window; + /** * `type` property values for this loaders' context object * @enum diff --git a/src/utils/codecs.js b/src/utils/codecs.js index 4f620a560b1..e814f647fc3 100644 --- a/src/utils/codecs.js +++ b/src/utils/codecs.js @@ -69,7 +69,7 @@ function isCodecType (codec, type) { } function isCodecSupportedInMp4 (codec, type) { - return MediaSource.isTypeSupported(`${type || 'video'}/mp4;codecs="${codec}"`); + return window.MediaSource.isTypeSupported(`${type || 'video'}/mp4;codecs="${codec}"`); } export { isCodecType, isCodecSupportedInMp4 }; diff --git a/src/utils/fetch-loader.js b/src/utils/fetch-loader.js index 34c96ca9f0c..ad3b94f25f5 100644 --- a/src/utils/fetch-loader.js +++ b/src/utils/fetch-loader.js @@ -5,6 +5,8 @@ * but still it is not bullet proof as it fails to avoid data waste.... */ +const { Request, Headers, fetch, performance } = window; + class FetchLoader { constructor (config) { this.fetchSetup = config.fetchSetup; diff --git a/src/utils/xhr-loader.js b/src/utils/xhr-loader.js index b2e08840656..ecd2f849ce6 100644 --- a/src/utils/xhr-loader.js +++ b/src/utils/xhr-loader.js @@ -4,6 +4,8 @@ import { logger } from '../utils/logger'; +const { performance, XMLHttpRequest } = window; + class XhrLoader { constructor (config) { if (config && config.xhrSetup) { diff --git a/tests/unit/demuxer/demuxer.js b/tests/unit/demuxer/demuxer.js index 512a2fa2053..23060ce30ea 100644 --- a/tests/unit/demuxer/demuxer.js +++ b/tests/unit/demuxer/demuxer.js @@ -217,7 +217,7 @@ describe('Demuxer tests', function () { } }; - let spy = sinon.spy(URL, 'revokeObjectURL'); + let spy = sinon.spy(window.URL, 'revokeObjectURL'); demux.onWorkerMessage(evt); From 1baef802699e0506e3e10f748f7cc27cdf2143de Mon Sep 17 00:00:00 2001 From: Stephan Hesse Date: Tue, 5 Jun 2018 13:27:41 +0200 Subject: [PATCH 11/24] lint script: add quiet mode (only show fatal errors) --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 620aa3959e2..ee002164ef5 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "docs:release": "npm run docs:clean && npm run docs:generate && npm run docs:update", "lint": "npm run lint:src && npm run lint:tests", "lint:fix": "eslint src/ tests/ --fix", + "lint:quiet": "eslint src/ tests/ --quiet", "lint:src": "eslint src/", "lint:tests": "eslint tests/", "lint:demo": "eslint demo/", From b58112e9ce60c204d2d3c253852a6b39be57cf56 Mon Sep 17 00:00:00 2001 From: Stephan Hesse Date: Tue, 5 Jun 2018 14:19:46 +0200 Subject: [PATCH 12/24] Globals: Fix accessing worker window global scope --- src/crypt/decrypter.js | 8 +++++--- src/demux/demuxer-inline.js | 11 +++++++++-- src/demux/demuxer.js | 4 ++++ src/utils/logger.js | 9 +++++---- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/crypt/decrypter.js b/src/crypt/decrypter.js index f0ada4fc705..5c5d111fbe9 100644 --- a/src/crypt/decrypter.js +++ b/src/crypt/decrypter.js @@ -7,9 +7,11 @@ import { logger } from '../utils/logger'; import Event from '../events'; -const { performance, crypto } = window; +// see https://stackoverflow.com/a/11237259/589493 +/* eslint-disable-next-line no-undef */ +const window = self; // safeguard for code that might run both on worker and main thread -/* globals self: false */ +const { performance, crypto } = window; class Decrypter { constructor (observer, config, { removePKCS7Padding = true } = {}) { @@ -20,7 +22,7 @@ class Decrypter { // built in decryptor expects PKCS7 padding if (removePKCS7Padding) { try { - const browserCrypto = crypto || self.crypto; + const browserCrypto = crypto || window.crypto; this.subtle = browserCrypto.subtle || browserCrypto.webkitSubtle; } catch (e) {} } diff --git a/src/demux/demuxer-inline.js b/src/demux/demuxer-inline.js index fc9c59fd961..d2c4a99d1ea 100644 --- a/src/demux/demuxer-inline.js +++ b/src/demux/demuxer-inline.js @@ -1,5 +1,8 @@ -/* inline demuxer. - * probe fragments and instantiate appropriate demuxer depending on content type (TSDemuxer, AACDemuxer, ...) +/** + * + * inline demuxer: probe fragments and instantiate + * appropriate demuxer depending on content type (TSDemuxer, AACDemuxer, ...) + * */ import Event from '../events'; @@ -12,6 +15,10 @@ import MP3Demuxer from '../demux/mp3demuxer'; import MP4Remuxer from '../remux/mp4-remuxer'; import PassThroughRemuxer from '../remux/passthrough-remuxer'; +// see https://stackoverflow.com/a/11237259/589493 +/* eslint-disable-next-line no-undef */ +const window = self; // safeguard for code that might run both on worker and main thread + const { performance } = window; class DemuxerInline { diff --git a/src/demux/demuxer.js b/src/demux/demuxer.js index 89bcde396f7..7757b04c1e6 100644 --- a/src/demux/demuxer.js +++ b/src/demux/demuxer.js @@ -7,6 +7,10 @@ import { logger } from '../utils/logger'; import { ErrorTypes, ErrorDetails } from '../errors'; import { getMediaSource } from '../utils/mediasource-helper'; +// see https://stackoverflow.com/a/11237259/589493 +/* eslint-disable-next-line no-undef */ +const window = self; // safeguard for code that might run both on worker and main thread + const MediaSource = getMediaSource(); class Demuxer { diff --git a/src/utils/logger.js b/src/utils/logger.js index 505f6e3eaae..2e7bc3e326f 100644 --- a/src/utils/logger.js +++ b/src/utils/logger.js @@ -11,8 +11,6 @@ const fakeLogger = { let exportedLogger = fakeLogger; -/* globals self: false */ - // let lastCallTime; // function formatMsgWithTimeInfo(type, msg) { // const now = Date.now(); @@ -27,15 +25,18 @@ function formatMsg (type, msg) { return msg; } +/* eslint-disable-next-line no-undef */ +const window = self; + function consolePrintFn (type) { - const func = self.console[type]; + const func = window.console[type]; if (func) { return function (...args) { if (args[0]) { args[0] = formatMsg(type, args[0]); } - func.apply(self.console, args); + func.apply(window.console, args); }; } return noop; From ec44fb0a61914f10d3270d411fcf610846a309e8 Mon Sep 17 00:00:00 2001 From: Stephan Hesse Date: Tue, 5 Jun 2018 17:05:07 +0200 Subject: [PATCH 13/24] Rever changes from #1755 since we did them in #1756 now --- src/demux/adts.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/demux/adts.js b/src/demux/adts.js index 1ad509a8c83..6109a6f05c2 100644 --- a/src/demux/adts.js +++ b/src/demux/adts.js @@ -2,7 +2,6 @@ * ADTS parser helper */ import { logger } from '../utils/logger'; -import Event from '../events'; import { ErrorTypes, ErrorDetails } from '../errors'; import Event from '../events'; From 40bd49ceeccfb6013d5cc71325bcaba6aa49e55a Mon Sep 17 00:00:00 2001 From: Stephan Hesse Date: Tue, 5 Jun 2018 17:27:10 +0200 Subject: [PATCH 14/24] add getSelfScope to get global window/worker scope --- src/crypt/decrypter.js | 4 +++- src/demux/adts.js | 2 ++ src/demux/demuxer-inline.js | 4 +++- src/demux/demuxer.js | 3 ++- src/utils/logger.js | 4 +++- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/crypt/decrypter.js b/src/crypt/decrypter.js index 5c5d111fbe9..84e123960df 100644 --- a/src/crypt/decrypter.js +++ b/src/crypt/decrypter.js @@ -7,9 +7,11 @@ import { logger } from '../utils/logger'; import Event from '../events'; +import { getSelfScope } from '../utils/get-self-scope'; + // see https://stackoverflow.com/a/11237259/589493 /* eslint-disable-next-line no-undef */ -const window = self; // safeguard for code that might run both on worker and main thread +const window = getSelfScope(); // safeguard for code that might run both on worker and main thread const { performance, crypto } = window; diff --git a/src/demux/adts.js b/src/demux/adts.js index 6109a6f05c2..c4d7db5dd61 100644 --- a/src/demux/adts.js +++ b/src/demux/adts.js @@ -6,6 +6,8 @@ import { ErrorTypes, ErrorDetails } from '../errors'; import Event from '../events'; +import { getSelfScope } from '../utils/get-self-scope'; + export function getAudioConfig (observer, data, offset, audioCodec) { let adtsObjectType, // :int adtsSampleingIndex, // :int diff --git a/src/demux/demuxer-inline.js b/src/demux/demuxer-inline.js index d2c4a99d1ea..53cd09ff3de 100644 --- a/src/demux/demuxer-inline.js +++ b/src/demux/demuxer-inline.js @@ -15,9 +15,11 @@ import MP3Demuxer from '../demux/mp3demuxer'; import MP4Remuxer from '../remux/mp4-remuxer'; import PassThroughRemuxer from '../remux/passthrough-remuxer'; +import { getSelfScope } from '../utils/get-self-scope'; + // see https://stackoverflow.com/a/11237259/589493 /* eslint-disable-next-line no-undef */ -const window = self; // safeguard for code that might run both on worker and main thread +const window = getSelfScope(); // safeguard for code that might run both on worker and main thread const { performance } = window; diff --git a/src/demux/demuxer.js b/src/demux/demuxer.js index 7757b04c1e6..bca3b2106be 100644 --- a/src/demux/demuxer.js +++ b/src/demux/demuxer.js @@ -6,10 +6,11 @@ import DemuxerInline from '../demux/demuxer-inline'; import { logger } from '../utils/logger'; import { ErrorTypes, ErrorDetails } from '../errors'; import { getMediaSource } from '../utils/mediasource-helper'; +import { getSelfScope } from '../utils/get-self-scope'; // see https://stackoverflow.com/a/11237259/589493 /* eslint-disable-next-line no-undef */ -const window = self; // safeguard for code that might run both on worker and main thread +const window = getSelfScope(); // safeguard for code that might run both on worker and main thread const MediaSource = getMediaSource(); diff --git a/src/utils/logger.js b/src/utils/logger.js index 2e7bc3e326f..10155936ab3 100644 --- a/src/utils/logger.js +++ b/src/utils/logger.js @@ -1,3 +1,5 @@ +import { getSelfScope } from './get-self-scope'; + function noop () {} const fakeLogger = { @@ -26,7 +28,7 @@ function formatMsg (type, msg) { } /* eslint-disable-next-line no-undef */ -const window = self; +const window = getSelfScope(); function consolePrintFn (type) { const func = window.console[type]; From 4b262a87c8c38bc931b7f2db0106a1790087609d Mon Sep 17 00:00:00 2001 From: Alexey Gusev Date: Thu, 7 Jun 2018 13:51:00 +0300 Subject: [PATCH 15/24] jsdoc misprint `booelan` -> `boolean` --- src/hls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hls.js b/src/hls.js index 5a7ddeed27e..1338e06529e 100644 --- a/src/hls.js +++ b/src/hls.js @@ -608,7 +608,7 @@ export default class Hls { } /** - * @type {booelan} + * @type {boolean} */ get subtitleDisplay () { const subtitleTrackController = this.subtitleTrackController; From 461d220cd68b9950c015ab22f406729a38cfb607 Mon Sep 17 00:00:00 2001 From: Stephan Hesse Date: Thu, 7 Jun 2018 13:34:24 +0200 Subject: [PATCH 16/24] add getSelfScope to abstract from window/worker global scopes explicitely --- src/utils/get-self-scope.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/utils/get-self-scope.js diff --git a/src/utils/get-self-scope.js b/src/utils/get-self-scope.js new file mode 100644 index 00000000000..faf57403ee8 --- /dev/null +++ b/src/utils/get-self-scope.js @@ -0,0 +1,14 @@ +export function getSelfScope () { + let window; + if (typeof self === 'undefined') { + // workaround for Node.js bundling apps + // @see https://github.com/video-dev/hls.js/pull/1642 + window = {}; // a Node app can not expect any DOM features if it doesn't define `self` + // as common scope for Window and Worker. + } else { + // see https://stackoverflow.com/a/11237259/589493 + /* eslint-disable-next-line no-undef */ + window = self; // safeguard for code that might run both on worker and main thread + } + return window; +} From 18be7d8aecc8b203166b544e7451594fe755d67b Mon Sep 17 00:00:00 2001 From: Stephan Hesse Date: Thu, 7 Jun 2018 13:34:35 +0200 Subject: [PATCH 17/24] decrypter: lint fix --- src/crypt/decrypter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypt/decrypter.js b/src/crypt/decrypter.js index 84e123960df..cb352f6b459 100644 --- a/src/crypt/decrypter.js +++ b/src/crypt/decrypter.js @@ -11,7 +11,7 @@ import { getSelfScope } from '../utils/get-self-scope'; // see https://stackoverflow.com/a/11237259/589493 /* eslint-disable-next-line no-undef */ -const window = getSelfScope(); // safeguard for code that might run both on worker and main thread +const window = getSelfScope(); // safeguard for code that might run both on worker and main thread const { performance, crypto } = window; From 8d12a9a6471f15b9e8978b02a0d1689ecc9d6c0f Mon Sep 17 00:00:00 2001 From: Stephan Hesse Date: Thu, 7 Jun 2018 13:53:40 +0200 Subject: [PATCH 18/24] simplify get-self-scope module --- src/utils/get-self-scope.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/utils/get-self-scope.js b/src/utils/get-self-scope.js index faf57403ee8..4c25c476379 100644 --- a/src/utils/get-self-scope.js +++ b/src/utils/get-self-scope.js @@ -1,14 +1,9 @@ export function getSelfScope () { - let window; - if (typeof self === 'undefined') { - // workaround for Node.js bundling apps - // @see https://github.com/video-dev/hls.js/pull/1642 - window = {}; // a Node app can not expect any DOM features if it doesn't define `self` - // as common scope for Window and Worker. - } else { - // see https://stackoverflow.com/a/11237259/589493 + // see https://stackoverflow.com/a/11237259/589493 + if (typeof window === 'undefined') { /* eslint-disable-next-line no-undef */ - window = self; // safeguard for code that might run both on worker and main thread + return self; + } else { + return window; } - return window; } From a4bdebff4ceb35340fbafd1a6702aef38829b843 Mon Sep 17 00:00:00 2001 From: Stephan Hesse Date: Thu, 7 Jun 2018 13:53:58 +0200 Subject: [PATCH 19/24] travis script: remove check for node require --- scripts/travis.sh | 7 ------- 1 file changed, 7 deletions(-) diff --git a/scripts/travis.sh b/scripts/travis.sh index 72efe902b77..52e543f07bb 100755 --- a/scripts/travis.sh +++ b/scripts/travis.sh @@ -2,18 +2,11 @@ # https://docs.travis-ci.com/user/customizing-the-build/#Implementing-Complex-Build-Steps set -ev -function testNodeRequire { - # check that hls.js doesn't error if requiring in node - # see https://github.com/video-dev/hls.js/pull/1642 - node -e 'require("./" + require("./package.json").main)' -} - npm install if [ "${TRAVIS_MODE}" = "build" ]; then npm run lint npm run build - testNodeRequire elif [ "${TRAVIS_MODE}" = "unitTests" ]; then npm run test:unit elif [ "${TRAVIS_MODE}" = "funcTests" ]; then From 4ac542012b9bf9e09351e86410d6e47c47bb138e Mon Sep 17 00:00:00 2001 From: Stephan Hesse Date: Thu, 7 Jun 2018 15:11:32 +0200 Subject: [PATCH 20/24] fix stream-controller unit-test not liking to grab performance ref on module def --- src/controller/stream-controller.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/controller/stream-controller.js b/src/controller/stream-controller.js index fb56b9ccf7d..e1f26b8bcba 100644 --- a/src/controller/stream-controller.js +++ b/src/controller/stream-controller.js @@ -17,8 +17,6 @@ import { alignDiscontinuities } from '../utils/discontinuities'; import TaskLoop from '../task-loop'; import { calculateNextPDT, findFragmentByPDT, findFragmentBySN, fragmentWithinToleranceTest } from './fragment-finders'; -const { performance } = window; - export const State = { STOPPED: 'STOPPED', IDLE: 'IDLE', @@ -144,7 +142,7 @@ class StreamController extends TaskLoop { break; case State.FRAG_LOADING_WAITING_RETRY: - var now = performance.now(); + var now = window.performance.now(); var retryDate = this.retryDate; // if current time is gt than retryDate, or if media seeking let's switch to IDLE state to retry loading if (!retryDate || (now >= retryDate) || (this.media && this.media.seeking)) { @@ -955,12 +953,12 @@ class StreamController extends TaskLoop { // switch back to IDLE state ... we just loaded a fragment to determine adequate start bitrate and initialize autoswitch algo this.state = State.IDLE; this.startFragRequested = false; - stats.tparsed = stats.tbuffered = performance.now(); + stats.tparsed = stats.tbuffered = window.performance.now(); this.hls.trigger(Event.FRAG_BUFFERED, { stats: stats, frag: fragCurrent, id: 'main' }); this.tick(); } else if (fragLoaded.sn === 'initSegment') { this.state = State.IDLE; - stats.tparsed = stats.tbuffered = performance.now(); + stats.tparsed = stats.tbuffered = window.performance.now(); details.initSegment.data = data.payload; this.hls.trigger(Event.FRAG_BUFFERED, { stats: stats, frag: fragCurrent, id: 'main' }); this.tick(); @@ -1159,7 +1157,7 @@ class StreamController extends TaskLoop { fragNew.sn === fragCurrent.sn && fragNew.level === fragCurrent.level && this.state === State.PARSING) { - this.stats.tparsed = performance.now(); + this.stats.tparsed = window.performance.now(); this.state = State.PARSED; this._checkAppendedParsed(); } @@ -1258,7 +1256,7 @@ class StreamController extends TaskLoop { logger.log(`main buffered : ${TimeRanges.toString(media.buffered)}`); this.fragPrevious = frag; const stats = this.stats; - stats.tbuffered = performance.now(); + stats.tbuffered = window.performance.now(); // we should get rid of this.fragLastKbps this.fragLastKbps = Math.round(8 * stats.total / (stats.tbuffered - stats.tfirst)); this.hls.trigger(Event.FRAG_BUFFERED, { stats: stats, frag: frag, id: 'main' }); @@ -1289,7 +1287,7 @@ class StreamController extends TaskLoop { // exponential backoff capped to config.fragLoadingMaxRetryTimeout let delay = Math.min(Math.pow(2, this.fragLoadError) * this.config.fragLoadingRetryDelay, this.config.fragLoadingMaxRetryTimeout); logger.warn(`mediaController: frag loading failed, retry in ${delay} ms`); - this.retryDate = performance.now() + delay; + this.retryDate = window.performance.now() + delay; // retry loading state // if loadedmetadata is not set, it means that we are emergency switch down on first frag // in that case, reset startFragRequested flag @@ -1381,7 +1379,7 @@ class StreamController extends TaskLoop { const expectedPlaying = !((media.paused && media.readyState > 1) || // not playing when media is paused and sufficiently buffered media.ended || // not playing when media is ended media.buffered.length === 0); // not playing if nothing buffered - const tnow = performance.now(); + const tnow = window.performance.now(); if (currentTime !== this.lastCurrentTime) { // The playhead is now moving, but was previously stalled From 77166d9ca6f82e14e41a3e2b00f049a7f46fc9cf Mon Sep 17 00:00:00 2001 From: Stephan Hesse Date: Thu, 7 Jun 2018 15:11:49 +0200 Subject: [PATCH 21/24] stream controller test cosmetics --- tests/unit/controller/check-buffer.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/unit/controller/check-buffer.js b/tests/unit/controller/check-buffer.js index 6538234cdf1..3eb5f105b77 100644 --- a/tests/unit/controller/check-buffer.js +++ b/tests/unit/controller/check-buffer.js @@ -1,9 +1,13 @@ import assert from 'assert'; import sinon from 'sinon'; + +import Hls from '../../../src/hls'; + import StreamController from '../../../src/controller/stream-controller'; import { FragmentTracker } from '../../../src/controller/fragment-tracker'; -import Hls from '../../../src/hls'; + import Event from '../../../src/events'; + import { ErrorTypes, ErrorDetails } from '../../../src/errors'; describe('checkBuffer', function () { From b1085a9d5712d9b990081213a34de8eaeb4ea07f Mon Sep 17 00:00:00 2001 From: Stephan Hesse Date: Fri, 8 Jun 2018 14:02:09 +0200 Subject: [PATCH 22/24] rm tests/tests.webpack.js (not needed) --- tests/tests.webpack.js | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 tests/tests.webpack.js diff --git a/tests/tests.webpack.js b/tests/tests.webpack.js deleted file mode 100644 index da5f985ed6e..00000000000 --- a/tests/tests.webpack.js +++ /dev/null @@ -1,7 +0,0 @@ -const tests = require.context('./unit/', true, /\.js$/); - -tests.keys().forEach(tests); - -const components = require.context('../src/', true, /\.js$/); - -components.keys().forEach(components); From 2b6623ac639a61b68e8dad9ec7e6cc2ab20864b6 Mon Sep 17 00:00:00 2001 From: Stephan Hesse Date: Fri, 8 Jun 2018 14:04:27 +0200 Subject: [PATCH 23/24] karma conf: glob input files and apply preprocessor on all paths (makes source-maps actually work, and using 'eval' mode) --- karma.conf.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index 038163b61ab..ca1f959b8a3 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -15,7 +15,9 @@ module.exports = function(config) { frameworks: ['mocha', 'sinon', 'should'], // list of files / patterns to load in the browser - files: ['tests/tests.webpack.js'], + files: [ + 'tests/unit/**/*.js' + ], // list of files to exclude exclude: [], @@ -23,7 +25,7 @@ module.exports = function(config) { // preprocess matching files before serving them to the browser // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor preprocessors: { - 'tests/tests.webpack.js': ['webpack', 'sourcemap'] + '**/*.js': ['webpack', 'sourcemap'] }, // test results reporter to use @@ -37,7 +39,7 @@ module.exports = function(config) { }, webpack: { - devtool: 'inline-source-map', + devtool: 'eval', module: { rules: [ // instrument only testing sources with Istanbul From 224254a346d2fc2b0d6cd78686c4156c613509f9 Mon Sep 17 00:00:00 2001 From: Stephan Hesse Date: Fri, 8 Jun 2018 14:04:42 +0200 Subject: [PATCH 24/24] require sinon explicitely in unit tests --- tests/mocks/hls.mock.js | 2 ++ tests/unit/controller/eme-controller.js | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/mocks/hls.mock.js b/tests/mocks/hls.mock.js index 03b6fde61e3..d44258c3382 100644 --- a/tests/mocks/hls.mock.js +++ b/tests/mocks/hls.mock.js @@ -1,5 +1,7 @@ import Hls from '../../src/hls'; +const sinon = require('sinon'); + /** * All public methods of Hls instance */ diff --git a/tests/unit/controller/eme-controller.js b/tests/unit/controller/eme-controller.js index fc166e29c39..0a41ad78493 100644 --- a/tests/unit/controller/eme-controller.js +++ b/tests/unit/controller/eme-controller.js @@ -1,9 +1,12 @@ import EMEController from '../../../src/controller/eme-controller'; -import assert from 'assert'; import HlsMock from '../../mocks/hls.mock'; import EventEmitter from 'events'; import { ErrorTypes, ErrorDetails } from '../../../src/errors'; +const sinon = require('sinon'); + +import assert from 'assert'; + const MediaMock = function () { let media = new EventEmitter(); media.setMediaKeys = sinon.spy();