@clappr/hlsjs-playback 3.0.3 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -36
- package/dist/hlsjs-playback.esm.js +101 -383
- package/dist/hlsjs-playback.esm.js.map +1 -1
- package/dist/hlsjs-playback.js +185 -442
- package/dist/hlsjs-playback.js.map +1 -1
- package/dist/hlsjs-playback.min.js +1 -2
- package/dist/hlsjs-playback.min.js.map +1 -1
- package/package.json +11 -12
- package/src/dist.smoke.test.js +14 -7
- package/src/hls.js +2 -1
- package/src/hls.test.js +140 -62
package/package.json
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clappr/hlsjs-playback",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.1",
|
|
4
4
|
"description": "HLS Playback based on hls.js",
|
|
5
5
|
"main": "./dist/hlsjs-playback.js",
|
|
6
6
|
"module": "./dist/hlsjs-playback.esm.js",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"start": "
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"test": "
|
|
15
|
-
"test:
|
|
16
|
-
"
|
|
17
|
-
"lint": "eslint *.js ./src",
|
|
8
|
+
"start": "vite",
|
|
9
|
+
"build": "vite build",
|
|
10
|
+
"watch": "vite build --watch",
|
|
11
|
+
"bundle-check": "ANALYZE_BUNDLE=true vite build",
|
|
12
|
+
"release": "rm -rf dist && vite build && vite build --mode minify",
|
|
13
|
+
"test": "vitest run --coverage",
|
|
14
|
+
"test:smoke": "vitest run src/dist.smoke.test.js",
|
|
15
|
+
"test:watch": "vitest",
|
|
16
|
+
"lint": "eslint --no-error-on-unmatched-pattern *.js ./src",
|
|
18
17
|
"lint:fix": "yarn lint -- --fix",
|
|
19
18
|
"prepublishOnly": "lerna run release --scope=@clappr/hlsjs-playback"
|
|
20
19
|
},
|
|
@@ -41,7 +40,7 @@
|
|
|
41
40
|
"hls.js": "^1"
|
|
42
41
|
},
|
|
43
42
|
"devDependencies": {
|
|
44
|
-
"@clappr/core": "^0.
|
|
43
|
+
"@clappr/core": "^0.17.1",
|
|
45
44
|
"hls.js": "^1"
|
|
46
45
|
}
|
|
47
46
|
}
|
package/src/dist.smoke.test.js
CHANGED
|
@@ -12,7 +12,7 @@ const { TextEncoder, TextDecoder } = require('util')
|
|
|
12
12
|
global.TextEncoder = global.TextEncoder || TextEncoder
|
|
13
13
|
global.TextDecoder = global.TextDecoder || TextDecoder
|
|
14
14
|
const { JSDOM } = require('jsdom')
|
|
15
|
-
const {
|
|
15
|
+
const { expectEs5Syntax, expectSourcemapFromSrc } = require('../../../test/dist-contract')
|
|
16
16
|
|
|
17
17
|
const DIST = path.join(__dirname, '..', 'dist')
|
|
18
18
|
|
|
@@ -29,7 +29,7 @@ function readArtifact(name) {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
function loadArtifact(name) {
|
|
32
|
-
|
|
32
|
+
vi.resetModules()
|
|
33
33
|
return require(path.join(DIST, name))
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -68,8 +68,8 @@ function assertPlaybackContract(HlsjsPlaybackExport) {
|
|
|
68
68
|
expect(typeof HLSJS.version).toBe('string')
|
|
69
69
|
expect(HLSJS.version.length).toBeGreaterThan(0)
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
vi.spyOn(HLSJS, 'isSupported').mockReturnValue(true)
|
|
72
|
+
vi.spyOn(window.HTMLMediaElement.prototype, 'load').mockImplementation(() => {})
|
|
73
73
|
|
|
74
74
|
expect(Playback.canPlay('http://example.com/video.m3u8')).toBe(true)
|
|
75
75
|
expect(Playback.canPlay('http://example.com/video.m3u8?token=1')).toBe(true)
|
|
@@ -81,6 +81,7 @@ function assertPlaybackContract(HlsjsPlaybackExport) {
|
|
|
81
81
|
|
|
82
82
|
function assertSourceMappingURL(filename) {
|
|
83
83
|
expect(readArtifact(filename)).toContain(`sourceMappingURL=${filename}.map`)
|
|
84
|
+
expectSourcemapFromSrc(readArtifact(`${filename}.map`), filename)
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
const EXPECTED_SOURCEMAPS = Object.values(ARTIFACTS)
|
|
@@ -88,7 +89,7 @@ const EXPECTED_SOURCEMAPS = Object.values(ARTIFACTS)
|
|
|
88
89
|
.sort()
|
|
89
90
|
|
|
90
91
|
afterEach(() => {
|
|
91
|
-
|
|
92
|
+
vi.restoreAllMocks()
|
|
92
93
|
})
|
|
93
94
|
|
|
94
95
|
describe.each([
|
|
@@ -105,7 +106,7 @@ describe.each([
|
|
|
105
106
|
})
|
|
106
107
|
|
|
107
108
|
test('does not emit native class syntax', () => {
|
|
108
|
-
|
|
109
|
+
expectEs5Syntax(readArtifact(filename), filename)
|
|
109
110
|
})
|
|
110
111
|
})
|
|
111
112
|
|
|
@@ -120,10 +121,16 @@ describe('dist sourcemap inventory', () => {
|
|
|
120
121
|
})
|
|
121
122
|
|
|
122
123
|
describe('hls.js peer identity', () => {
|
|
123
|
-
test.each(
|
|
124
|
+
test.each(UMD_ARTIFACTS)('%s defers to the consumer hls.js', filename => {
|
|
124
125
|
const Playback = resolvePlayback(loadArtifact(filename))
|
|
125
126
|
expect(Playback.HLSJS).toBe(require('hls.js'))
|
|
126
127
|
})
|
|
128
|
+
|
|
129
|
+
test(`${ARTIFACTS.esm} defers to the consumer hls.js`, async () => {
|
|
130
|
+
const Playback = resolvePlayback(loadArtifact(ARTIFACTS.esm))
|
|
131
|
+
const { default: hls } = await import('hls.js')
|
|
132
|
+
expect(Playback.HLSJS).toBe(hls)
|
|
133
|
+
})
|
|
127
134
|
})
|
|
128
135
|
|
|
129
136
|
describe('UMD global.Hls branch', () => {
|
package/src/hls.js
CHANGED
|
@@ -415,7 +415,7 @@ export default class HlsjsPlayback extends HTML5Video {
|
|
|
415
415
|
}
|
|
416
416
|
let formattedError
|
|
417
417
|
if (data.response) error.description += `, response: ${JSON.stringify(data.response)}`
|
|
418
|
-
// only
|
|
418
|
+
// only handle errors if they are fatal
|
|
419
419
|
// hlsjs should automatically handle non fatal errors
|
|
420
420
|
if (data.fatal) {
|
|
421
421
|
if (this._recoverAttemptsRemaining > 0) {
|
|
@@ -479,6 +479,7 @@ export default class HlsjsPlayback extends HTML5Video {
|
|
|
479
479
|
|
|
480
480
|
error.level = PlayerError.Levels.WARN
|
|
481
481
|
Log.warn('hlsjs: non-fatal error occurred', { evt, data })
|
|
482
|
+
this.trigger(Events.PLAYBACK_WARNING, error, this.name)
|
|
482
483
|
}
|
|
483
484
|
}
|
|
484
485
|
|
package/src/hls.test.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Core, Events, Log, Playback } from '@clappr/core'
|
|
1
|
+
import { Core, Events, Log, Playback, PlayerError } from '@clappr/core'
|
|
2
2
|
import HlsjsPlayback from './hls.js'
|
|
3
3
|
import HLSJS from 'hls.js'
|
|
4
4
|
|
|
@@ -25,17 +25,17 @@ const makeLevelData = ({
|
|
|
25
25
|
|
|
26
26
|
const stubHls = playback => {
|
|
27
27
|
playback._hls = {
|
|
28
|
-
startLoad:
|
|
29
|
-
recoverMediaError:
|
|
30
|
-
swapAudioCodec:
|
|
31
|
-
destroy:
|
|
28
|
+
startLoad: vi.fn(),
|
|
29
|
+
recoverMediaError: vi.fn(),
|
|
30
|
+
swapAudioCodec: vi.fn(),
|
|
31
|
+
destroy: vi.fn()
|
|
32
32
|
}
|
|
33
33
|
return playback._hls
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
const freezeNow = (playback, initialMs = 1000000) => {
|
|
37
37
|
let current = initialMs
|
|
38
|
-
|
|
38
|
+
vi.spyOn(playback, '_now', 'get').mockImplementation(() => current)
|
|
39
39
|
return {
|
|
40
40
|
advance(ms) {
|
|
41
41
|
current += ms
|
|
@@ -45,12 +45,13 @@ const freezeNow = (playback, initialMs = 1000000) => {
|
|
|
45
45
|
|
|
46
46
|
describe('HlsjsPlayback', () => {
|
|
47
47
|
beforeEach(() => {
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
vi.spyOn(window.HTMLMediaElement.prototype, 'play').mockImplementation(() => {})
|
|
49
|
+
vi.spyOn(window.HTMLMediaElement.prototype, 'load').mockImplementation(() => {})
|
|
50
50
|
})
|
|
51
51
|
|
|
52
52
|
afterEach(() => {
|
|
53
|
-
|
|
53
|
+
vi.restoreAllMocks()
|
|
54
|
+
vi.clearAllTimers()
|
|
54
55
|
})
|
|
55
56
|
|
|
56
57
|
test('have a getter called defaultOptions', () => {
|
|
@@ -83,7 +84,7 @@ describe('HlsjsPlayback', () => {
|
|
|
83
84
|
})
|
|
84
85
|
|
|
85
86
|
test('should be able to identify it can play resources independently of the file extension case', () => {
|
|
86
|
-
|
|
87
|
+
vi.spyOn(HLSJS, 'isSupported').mockImplementation(() => true)
|
|
87
88
|
expect(HlsjsPlayback.canPlay('/relative/video.m3u8')).toBeTruthy()
|
|
88
89
|
expect(HlsjsPlayback.canPlay('/relative/VIDEO.M3U8')).toBeTruthy()
|
|
89
90
|
expect(HlsjsPlayback.canPlay('/relative/video.m3u8?foobarQuery=1234#somefragment')).toBeTruthy()
|
|
@@ -102,7 +103,7 @@ describe('HlsjsPlayback', () => {
|
|
|
102
103
|
})
|
|
103
104
|
|
|
104
105
|
test('can play regardless of any mime type letter case', () => {
|
|
105
|
-
|
|
106
|
+
vi.spyOn(HLSJS, 'isSupported').mockImplementation(() => true)
|
|
106
107
|
expect(HlsjsPlayback.canPlay('/path/list.m3u8', 'APPLICATION/VND.APPLE.MPEGURL')).toBeTruthy()
|
|
107
108
|
expect(
|
|
108
109
|
HlsjsPlayback.canPlay(
|
|
@@ -154,9 +155,7 @@ describe('HlsjsPlayback', () => {
|
|
|
154
155
|
})
|
|
155
156
|
|
|
156
157
|
test('registers PLAYBACK_FRAGMENT_PARSING_METADATA event', () => {
|
|
157
|
-
expect(Events.Custom.PLAYBACK_FRAGMENT_PARSING_METADATA).toEqual(
|
|
158
|
-
'playbackFragmentParsingMetadata'
|
|
159
|
-
)
|
|
158
|
+
expect(Events.Custom.PLAYBACK_FRAGMENT_PARSING_METADATA).toEqual('playbackFragmentParsingMetadata')
|
|
160
159
|
})
|
|
161
160
|
|
|
162
161
|
test('levels supports specifying the level', () => {
|
|
@@ -237,14 +236,14 @@ describe('HlsjsPlayback', () => {
|
|
|
237
236
|
hlsPlayback: { preload: false }
|
|
238
237
|
})
|
|
239
238
|
playback._setup()
|
|
240
|
-
|
|
239
|
+
vi.spyOn(playback._hls, 'loadSource')
|
|
241
240
|
playback._hls.trigger(HLSJS.Events.MEDIA_ATTACHED, { media: playback.el })
|
|
242
241
|
|
|
243
242
|
expect(playback._hls.loadSource).not.toHaveBeenCalled()
|
|
244
243
|
|
|
245
244
|
playback.options.hlsPlayback.preload = true
|
|
246
245
|
playback._setup()
|
|
247
|
-
|
|
246
|
+
vi.spyOn(playback._hls, 'loadSource')
|
|
248
247
|
playback._hls.trigger(HLSJS.Events.MEDIA_ATTACHED, { media: playback.el })
|
|
249
248
|
|
|
250
249
|
expect(playback._hls.loadSource).toHaveBeenCalledTimes(1)
|
|
@@ -264,7 +263,7 @@ describe('HlsjsPlayback', () => {
|
|
|
264
263
|
|
|
265
264
|
test('calls bindCustomListeners method', () => {
|
|
266
265
|
const playback = new HlsjsPlayback({ src: 'http://clappr.io/foo.m3u8' })
|
|
267
|
-
|
|
266
|
+
vi.spyOn(playback, 'bindCustomListeners')
|
|
268
267
|
playback._setup()
|
|
269
268
|
|
|
270
269
|
expect(playback.bindCustomListeners).toHaveBeenCalledTimes(1)
|
|
@@ -275,7 +274,7 @@ describe('HlsjsPlayback', () => {
|
|
|
275
274
|
test('avoid to run internal logic if _isReadyState flag is true', () => {
|
|
276
275
|
const playback = new HlsjsPlayback({ src: 'http://clappr.io/video.m3u8' })
|
|
277
276
|
playback._isReadyState = true
|
|
278
|
-
|
|
277
|
+
vi.spyOn(playback, '_setup')
|
|
279
278
|
playback._ready()
|
|
280
279
|
|
|
281
280
|
expect(playback._setup).not.toHaveBeenCalled()
|
|
@@ -283,7 +282,7 @@ describe('HlsjsPlayback', () => {
|
|
|
283
282
|
|
|
284
283
|
test("call _setup method if HLS.JS internal don't exists", () => {
|
|
285
284
|
const playback = new HlsjsPlayback({ src: 'http://clappr.io/video.m3u8' })
|
|
286
|
-
|
|
285
|
+
vi.spyOn(playback, '_setup')
|
|
287
286
|
playback._ready()
|
|
288
287
|
|
|
289
288
|
expect(playback._setup).toHaveBeenCalledTimes(1)
|
|
@@ -302,8 +301,8 @@ describe('HlsjsPlayback', () => {
|
|
|
302
301
|
expect(playback._isReadyState).toBeTruthy()
|
|
303
302
|
})
|
|
304
303
|
|
|
305
|
-
test('triggers PLAYBACK_READY event', done => {
|
|
306
|
-
const cb =
|
|
304
|
+
test('triggers PLAYBACK_READY event', () => new Promise(done => {
|
|
305
|
+
const cb = vi.fn()
|
|
307
306
|
const playback = new HlsjsPlayback({ src: 'http://clappr.io/video.m3u8' })
|
|
308
307
|
|
|
309
308
|
playback.listenTo(playback, Events.PLAYBACK_READY, cb)
|
|
@@ -312,12 +311,12 @@ describe('HlsjsPlayback', () => {
|
|
|
312
311
|
done()
|
|
313
312
|
})
|
|
314
313
|
playback._ready()
|
|
315
|
-
})
|
|
314
|
+
}))
|
|
316
315
|
})
|
|
317
316
|
|
|
318
317
|
describe('play method', () => {
|
|
319
318
|
test('calls this._hls.loadSource once if _manifestLoading flag and options.hlsPlayback.preload are falsy', () => {
|
|
320
|
-
|
|
319
|
+
vi.spyOn(HLSJS.prototype, 'loadSource').mockImplementation()
|
|
321
320
|
const src = 'http://clappr.io/foo.m3u8'
|
|
322
321
|
const playback = new HlsjsPlayback({ src, hlsPlayback: { preload: false } })
|
|
323
322
|
playback._setup()
|
|
@@ -350,7 +349,7 @@ describe('HlsjsPlayback', () => {
|
|
|
350
349
|
})
|
|
351
350
|
const url = 'http://clappr.io/foo2.m3u8'
|
|
352
351
|
playback.load(url)
|
|
353
|
-
|
|
352
|
+
vi.spyOn(playback._hls, 'loadSource')
|
|
354
353
|
playback._hls.trigger(HLSJS.Events.MEDIA_ATTACHED, { media: playback.el })
|
|
355
354
|
expect(playback.options.src).toBe(url)
|
|
356
355
|
expect(playback._hls.loadSource).toHaveBeenCalledWith(url)
|
|
@@ -359,7 +358,7 @@ describe('HlsjsPlayback', () => {
|
|
|
359
358
|
|
|
360
359
|
describe('bindCustomListeners method', () => {
|
|
361
360
|
test('creates listeners for each item configured on customListeners array', () => {
|
|
362
|
-
const cb =
|
|
361
|
+
const cb = vi.fn()
|
|
363
362
|
const playback = new HlsjsPlayback({
|
|
364
363
|
src: 'http://clappr.io/foo.m3u8',
|
|
365
364
|
hlsPlayback: {
|
|
@@ -376,7 +375,7 @@ describe('HlsjsPlayback', () => {
|
|
|
376
375
|
})
|
|
377
376
|
|
|
378
377
|
test("don't add one listener without a valid configuration", () => {
|
|
379
|
-
const cb =
|
|
378
|
+
const cb = vi.fn()
|
|
380
379
|
const playback = new HlsjsPlayback({ src: 'http://clappr.io/foo.m3u8' })
|
|
381
380
|
playback._setup()
|
|
382
381
|
|
|
@@ -398,7 +397,7 @@ describe('HlsjsPlayback', () => {
|
|
|
398
397
|
})
|
|
399
398
|
|
|
400
399
|
test('adds a listener for one time when the customListeners array item is configured with the "once" param', () => {
|
|
401
|
-
const cb =
|
|
400
|
+
const cb = vi.fn()
|
|
402
401
|
const playback = new HlsjsPlayback({
|
|
403
402
|
src: 'http://clappr.io/foo.m3u8',
|
|
404
403
|
hlsPlayback: {
|
|
@@ -417,7 +416,7 @@ describe('HlsjsPlayback', () => {
|
|
|
417
416
|
|
|
418
417
|
describe('unbindCustomListeners method', () => {
|
|
419
418
|
test('remove listeners for each item configured on customListeners array', () => {
|
|
420
|
-
const cb =
|
|
419
|
+
const cb = vi.fn()
|
|
421
420
|
const playback = new HlsjsPlayback({
|
|
422
421
|
src: 'http://clappr.io/foo.m3u8',
|
|
423
422
|
hlsPlayback: {
|
|
@@ -459,9 +458,9 @@ describe('HlsjsPlayback', () => {
|
|
|
459
458
|
playback._hls = {
|
|
460
459
|
levels: [{ height: 1080, width: 1920, bitrate: 4000000 }]
|
|
461
460
|
}
|
|
462
|
-
const onSwitch =
|
|
463
|
-
const onHd =
|
|
464
|
-
const onBitrate =
|
|
461
|
+
const onSwitch = vi.fn()
|
|
462
|
+
const onHd = vi.fn()
|
|
463
|
+
const onBitrate = vi.fn()
|
|
465
464
|
playback.on(Events.PLAYBACK_LEVEL_SWITCH, onSwitch)
|
|
466
465
|
playback.on(Events.PLAYBACK_HIGHDEFINITIONUPDATE, onHd)
|
|
467
466
|
playback.on(Events.PLAYBACK_BITRATE, onBitrate)
|
|
@@ -479,8 +478,8 @@ describe('HlsjsPlayback', () => {
|
|
|
479
478
|
|
|
480
479
|
test('_onFragmentLoaded and _onFragmentBuffered forward playback events', () => {
|
|
481
480
|
const playback = createPlayback()
|
|
482
|
-
const onLoaded =
|
|
483
|
-
const onBuffered =
|
|
481
|
+
const onLoaded = vi.fn()
|
|
482
|
+
const onBuffered = vi.fn()
|
|
484
483
|
playback.on(Events.PLAYBACK_FRAGMENT_LOADED, onLoaded)
|
|
485
484
|
playback.on(Events.PLAYBACK_FRAGMENT_BUFFERED, onBuffered)
|
|
486
485
|
const data = { frag: { sn: 1 } }
|
|
@@ -778,8 +777,8 @@ describe('HlsjsPlayback', () => {
|
|
|
778
777
|
const playback = createPlayback()
|
|
779
778
|
playback._playbackType = Playback.LIVE
|
|
780
779
|
freezeNow(playback)
|
|
781
|
-
|
|
782
|
-
|
|
780
|
+
vi.spyOn(playback, '_onDurationChange').mockImplementation(() => {})
|
|
781
|
+
vi.spyOn(playback, '_onProgress').mockImplementation(() => {})
|
|
783
782
|
|
|
784
783
|
playback._onLevelUpdated(
|
|
785
784
|
'levelUpdated',
|
|
@@ -836,7 +835,7 @@ describe('HlsjsPlayback', () => {
|
|
|
836
835
|
playback._playbackType = Playback.VOD
|
|
837
836
|
playback._playableRegionStartTime = 0
|
|
838
837
|
playback._playableRegionDuration = 80
|
|
839
|
-
|
|
838
|
+
vi.spyOn(Log, 'warn').mockImplementation(() => {})
|
|
840
839
|
|
|
841
840
|
playback.seek(-1)
|
|
842
841
|
|
|
@@ -884,7 +883,7 @@ describe('HlsjsPlayback', () => {
|
|
|
884
883
|
playback._playableRegionDuration = 100
|
|
885
884
|
playback.el.currentTime = 1
|
|
886
885
|
freezeNow(playback, 1000000)
|
|
887
|
-
const onTimeUpdate =
|
|
886
|
+
const onTimeUpdate = vi.fn()
|
|
888
887
|
playback.on(Events.PLAYBACK_TIMEUPDATE, onTimeUpdate)
|
|
889
888
|
|
|
890
889
|
playback._onTimeUpdate()
|
|
@@ -899,7 +898,7 @@ describe('HlsjsPlayback', () => {
|
|
|
899
898
|
playback._playableRegionDuration = 100
|
|
900
899
|
playback.el.currentTime = 1
|
|
901
900
|
const clock = freezeNow(playback, 1000000)
|
|
902
|
-
const onTimeUpdate =
|
|
901
|
+
const onTimeUpdate = vi.fn()
|
|
903
902
|
playback.on(Events.PLAYBACK_TIMEUPDATE, onTimeUpdate)
|
|
904
903
|
|
|
905
904
|
playback._onTimeUpdate()
|
|
@@ -915,7 +914,7 @@ describe('HlsjsPlayback', () => {
|
|
|
915
914
|
playback._playableRegionDuration = 100
|
|
916
915
|
playback.el.currentTime = 1
|
|
917
916
|
const clock = freezeNow(playback, 1000000)
|
|
918
|
-
const onTimeUpdate =
|
|
917
|
+
const onTimeUpdate = vi.fn()
|
|
919
918
|
playback.on(Events.PLAYBACK_TIMEUPDATE, onTimeUpdate)
|
|
920
919
|
|
|
921
920
|
playback._onTimeUpdate()
|
|
@@ -931,7 +930,7 @@ describe('HlsjsPlayback', () => {
|
|
|
931
930
|
playback._playableRegionDuration = 100
|
|
932
931
|
playback.el.currentTime = 1
|
|
933
932
|
const clock = freezeNow(playback, 1000000)
|
|
934
|
-
const onTimeUpdate =
|
|
933
|
+
const onTimeUpdate = vi.fn()
|
|
935
934
|
playback.on(Events.PLAYBACK_TIMEUPDATE, onTimeUpdate)
|
|
936
935
|
|
|
937
936
|
playback._onTimeUpdate()
|
|
@@ -949,7 +948,7 @@ describe('HlsjsPlayback', () => {
|
|
|
949
948
|
playback._programDateTime = 1000
|
|
950
949
|
playback.el.currentTime = 1
|
|
951
950
|
const clock = freezeNow(playback, 1000000)
|
|
952
|
-
const onTimeUpdate =
|
|
951
|
+
const onTimeUpdate = vi.fn()
|
|
953
952
|
playback.on(Events.PLAYBACK_TIMEUPDATE, onTimeUpdate)
|
|
954
953
|
|
|
955
954
|
playback._onTimeUpdate()
|
|
@@ -973,14 +972,14 @@ describe('HlsjsPlayback', () => {
|
|
|
973
972
|
cores.push(core)
|
|
974
973
|
const playback = createPlayback(options, core.playerError)
|
|
975
974
|
stubHls(playback)
|
|
976
|
-
|
|
977
|
-
|
|
975
|
+
vi.spyOn(playback, 'play').mockImplementation(() => {})
|
|
976
|
+
vi.spyOn(playback, 'stop').mockImplementation(() => {})
|
|
978
977
|
return playback
|
|
979
978
|
}
|
|
980
979
|
|
|
981
980
|
test('recoverable network fatal error calls startLoad', () => {
|
|
982
981
|
const playback = createErrorPlayback()
|
|
983
|
-
|
|
982
|
+
vi.spyOn(Log, 'warn').mockImplementation(() => {})
|
|
984
983
|
|
|
985
984
|
playback._onHLSJSError('hlsError', {
|
|
986
985
|
fatal: true,
|
|
@@ -1001,8 +1000,8 @@ describe('HlsjsPlayback', () => {
|
|
|
1001
1000
|
HLSJS.ErrorDetails.LEVEL_LOAD_TIMEOUT
|
|
1002
1001
|
])('unrecoverable network fatal %s triggers error and stop', details => {
|
|
1003
1002
|
const playback = createErrorPlayback()
|
|
1004
|
-
|
|
1005
|
-
const onError =
|
|
1003
|
+
vi.spyOn(Log, 'error').mockImplementation(() => {})
|
|
1004
|
+
const onError = vi.fn()
|
|
1006
1005
|
playback.on(Events.PLAYBACK_ERROR, onError)
|
|
1007
1006
|
|
|
1008
1007
|
playback._onHLSJSError('hlsError', {
|
|
@@ -1018,9 +1017,9 @@ describe('HlsjsPlayback', () => {
|
|
|
1018
1017
|
|
|
1019
1018
|
test('media fatal error recovers via recoverMediaError then swapAudioCodec then fails', () => {
|
|
1020
1019
|
const playback = createErrorPlayback()
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
const onError =
|
|
1020
|
+
vi.spyOn(Log, 'warn').mockImplementation(() => {})
|
|
1021
|
+
vi.spyOn(Log, 'error').mockImplementation(() => {})
|
|
1022
|
+
const onError = vi.fn()
|
|
1024
1023
|
playback.on(Events.PLAYBACK_ERROR, onError)
|
|
1025
1024
|
const mediaError = {
|
|
1026
1025
|
fatal: true,
|
|
@@ -1046,8 +1045,8 @@ describe('HlsjsPlayback', () => {
|
|
|
1046
1045
|
|
|
1047
1046
|
test('other fatal error types trigger error and stop', () => {
|
|
1048
1047
|
const playback = createErrorPlayback()
|
|
1049
|
-
|
|
1050
|
-
const onError =
|
|
1048
|
+
vi.spyOn(Log, 'error').mockImplementation(() => {})
|
|
1049
|
+
const onError = vi.fn()
|
|
1051
1050
|
playback.on(Events.PLAYBACK_ERROR, onError)
|
|
1052
1051
|
|
|
1053
1052
|
playback._onHLSJSError('hlsError', {
|
|
@@ -1062,8 +1061,8 @@ describe('HlsjsPlayback', () => {
|
|
|
1062
1061
|
|
|
1063
1062
|
test('exhausted recover attempts trigger error and stop', () => {
|
|
1064
1063
|
const playback = createErrorPlayback({ hlsRecoverAttempts: 0 })
|
|
1065
|
-
|
|
1066
|
-
const onError =
|
|
1064
|
+
vi.spyOn(Log, 'error').mockImplementation(() => {})
|
|
1065
|
+
const onError = vi.fn()
|
|
1067
1066
|
playback.on(Events.PLAYBACK_ERROR, onError)
|
|
1068
1067
|
|
|
1069
1068
|
playback._onHLSJSError('hlsError', {
|
|
@@ -1081,8 +1080,8 @@ describe('HlsjsPlayback', () => {
|
|
|
1081
1080
|
const playback = createErrorPlayback({
|
|
1082
1081
|
playback: { triggerFatalErrorOnResourceDenied: true }
|
|
1083
1082
|
})
|
|
1084
|
-
|
|
1085
|
-
const onError =
|
|
1083
|
+
vi.spyOn(Log, 'error').mockImplementation(() => {})
|
|
1084
|
+
const onError = vi.fn()
|
|
1086
1085
|
playback.on(Events.PLAYBACK_ERROR, onError)
|
|
1087
1086
|
|
|
1088
1087
|
playback._onHLSJSError('hlsError', {
|
|
@@ -1098,8 +1097,8 @@ describe('HlsjsPlayback', () => {
|
|
|
1098
1097
|
|
|
1099
1098
|
test('non-fatal key denial without option only warns', () => {
|
|
1100
1099
|
const playback = createErrorPlayback()
|
|
1101
|
-
|
|
1102
|
-
const onError =
|
|
1100
|
+
vi.spyOn(Log, 'warn').mockImplementation(() => {})
|
|
1101
|
+
const onError = vi.fn()
|
|
1103
1102
|
playback.on(Events.PLAYBACK_ERROR, onError)
|
|
1104
1103
|
|
|
1105
1104
|
playback._onHLSJSError('hlsError', {
|
|
@@ -1118,8 +1117,8 @@ describe('HlsjsPlayback', () => {
|
|
|
1118
1117
|
const playback = createErrorPlayback({
|
|
1119
1118
|
playback: { triggerFatalErrorOnResourceDenied: true }
|
|
1120
1119
|
})
|
|
1121
|
-
|
|
1122
|
-
const onError =
|
|
1120
|
+
vi.spyOn(Log, 'warn').mockImplementation(() => {})
|
|
1121
|
+
const onError = vi.fn()
|
|
1123
1122
|
playback.on(Events.PLAYBACK_ERROR, onError)
|
|
1124
1123
|
|
|
1125
1124
|
playback._onHLSJSError('hlsError', {
|
|
@@ -1135,8 +1134,8 @@ describe('HlsjsPlayback', () => {
|
|
|
1135
1134
|
|
|
1136
1135
|
test('includes response in error description when present', () => {
|
|
1137
1136
|
const playback = createErrorPlayback()
|
|
1138
|
-
|
|
1139
|
-
const onError =
|
|
1137
|
+
vi.spyOn(Log, 'error').mockImplementation(() => {})
|
|
1138
|
+
const onError = vi.fn()
|
|
1140
1139
|
playback.on(Events.PLAYBACK_ERROR, onError)
|
|
1141
1140
|
|
|
1142
1141
|
playback._onHLSJSError('hlsError', {
|
|
@@ -1148,6 +1147,85 @@ describe('HlsjsPlayback', () => {
|
|
|
1148
1147
|
|
|
1149
1148
|
expect(onError.mock.calls[0][0].description).toContain('response:')
|
|
1150
1149
|
})
|
|
1150
|
+
|
|
1151
|
+
test('triggers PLAYBACK_WARNING for a non-fatal error', () => {
|
|
1152
|
+
const playback = createErrorPlayback()
|
|
1153
|
+
vi.spyOn(Log, 'warn').mockImplementation(() => {})
|
|
1154
|
+
const onWarning = vi.fn()
|
|
1155
|
+
playback.on(Events.PLAYBACK_WARNING, onWarning)
|
|
1156
|
+
|
|
1157
|
+
playback._onHLSJSError('hlsError', {
|
|
1158
|
+
fatal: false,
|
|
1159
|
+
type: HLSJS.ErrorTypes.NETWORK_ERROR,
|
|
1160
|
+
details: HLSJS.ErrorDetails.FRAG_LOAD_ERROR,
|
|
1161
|
+
response: { code: 500 }
|
|
1162
|
+
})
|
|
1163
|
+
|
|
1164
|
+
expect(onWarning).toHaveBeenCalledTimes(1)
|
|
1165
|
+
expect(onWarning.mock.calls[0][0]).toMatchObject({
|
|
1166
|
+
code: `${HLSJS.ErrorTypes.NETWORK_ERROR}_${HLSJS.ErrorDetails.FRAG_LOAD_ERROR}`,
|
|
1167
|
+
level: PlayerError.Levels.WARN,
|
|
1168
|
+
raw: { response: { code: 500 } }
|
|
1169
|
+
})
|
|
1170
|
+
})
|
|
1171
|
+
|
|
1172
|
+
test('does not trigger PLAYBACK_WARNING for a fatal error', () => {
|
|
1173
|
+
const playback = createErrorPlayback()
|
|
1174
|
+
vi.spyOn(Log, 'error').mockImplementation(() => {})
|
|
1175
|
+
const onWarning = vi.fn()
|
|
1176
|
+
const onError = vi.fn()
|
|
1177
|
+
playback.on(Events.PLAYBACK_WARNING, onWarning)
|
|
1178
|
+
playback.on(Events.PLAYBACK_ERROR, onError)
|
|
1179
|
+
|
|
1180
|
+
playback._onHLSJSError('hlsError', {
|
|
1181
|
+
fatal: true,
|
|
1182
|
+
type: HLSJS.ErrorTypes.NETWORK_ERROR,
|
|
1183
|
+
details: HLSJS.ErrorDetails.MANIFEST_LOAD_TIMEOUT,
|
|
1184
|
+
response: { code: 504 }
|
|
1185
|
+
})
|
|
1186
|
+
|
|
1187
|
+
expect(onWarning).not.toHaveBeenCalled()
|
|
1188
|
+
expect(onError).toHaveBeenCalledTimes(1)
|
|
1189
|
+
expect(playback.stop).toHaveBeenCalled()
|
|
1190
|
+
})
|
|
1191
|
+
|
|
1192
|
+
test('does not trigger PLAYBACK_WARNING when non-fatal key denial escalates to fatal', () => {
|
|
1193
|
+
const playback = createErrorPlayback({
|
|
1194
|
+
playback: { triggerFatalErrorOnResourceDenied: true }
|
|
1195
|
+
})
|
|
1196
|
+
vi.spyOn(Log, 'error').mockImplementation(() => {})
|
|
1197
|
+
const onWarning = vi.fn()
|
|
1198
|
+
const onError = vi.fn()
|
|
1199
|
+
playback.on(Events.PLAYBACK_WARNING, onWarning)
|
|
1200
|
+
playback.on(Events.PLAYBACK_ERROR, onError)
|
|
1201
|
+
|
|
1202
|
+
playback._onHLSJSError('hlsError', {
|
|
1203
|
+
fatal: false,
|
|
1204
|
+
type: HLSJS.ErrorTypes.NETWORK_ERROR,
|
|
1205
|
+
details: HLSJS.ErrorDetails.KEY_LOAD_ERROR,
|
|
1206
|
+
response: { code: 403 }
|
|
1207
|
+
})
|
|
1208
|
+
|
|
1209
|
+
expect(onWarning).not.toHaveBeenCalled()
|
|
1210
|
+
expect(onError).toHaveBeenCalledTimes(1)
|
|
1211
|
+
})
|
|
1212
|
+
|
|
1213
|
+
test('triggers PLAYBACK_WARNING for a non-fatal key denial that does not escalate', () => {
|
|
1214
|
+
const playback = createErrorPlayback()
|
|
1215
|
+
vi.spyOn(Log, 'warn').mockImplementation(() => {})
|
|
1216
|
+
const onWarning = vi.fn()
|
|
1217
|
+
playback.on(Events.PLAYBACK_WARNING, onWarning)
|
|
1218
|
+
|
|
1219
|
+
playback._onHLSJSError('hlsError', {
|
|
1220
|
+
fatal: false,
|
|
1221
|
+
type: HLSJS.ErrorTypes.NETWORK_ERROR,
|
|
1222
|
+
details: HLSJS.ErrorDetails.KEY_LOAD_ERROR,
|
|
1223
|
+
response: { code: 403 }
|
|
1224
|
+
})
|
|
1225
|
+
|
|
1226
|
+
expect(onWarning).toHaveBeenCalledTimes(1)
|
|
1227
|
+
expect(onWarning.mock.calls[0][0].level).toBe(PlayerError.Levels.WARN)
|
|
1228
|
+
})
|
|
1151
1229
|
})
|
|
1152
1230
|
|
|
1153
1231
|
describe('dvrEnabled and settings', () => {
|
|
@@ -1190,7 +1268,7 @@ describe('HlsjsPlayback', () => {
|
|
|
1190
1268
|
|
|
1191
1269
|
test('_updateSettings chooses left controls from playback type and dvr', () => {
|
|
1192
1270
|
const playback = createPlayback({ hlsMinimumDvrSize: 60 })
|
|
1193
|
-
const onSettings =
|
|
1271
|
+
const onSettings = vi.fn()
|
|
1194
1272
|
playback.on(Events.PLAYBACK_SETTINGSUPDATE, onSettings)
|
|
1195
1273
|
|
|
1196
1274
|
playback._playbackType = Playback.VOD
|