Skip to content
This repository was archived by the owner on Sep 28, 2025. It is now read-only.

Commit d4d3023

Browse files
Merge pull request #15 from clappr/decouple-setup-from-load-source
Decouple setup playback process from the load source process
2 parents 5baf051 + b90c5ae commit d4d3023

File tree

4 files changed

+144
-47
lines changed

4 files changed

+144
-47
lines changed

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ var player = new Clappr.Player(
4444
hlsUseNextLevel: false,
4545
hlsMinimumDvrSize: 60,
4646
hlsRecoverAttempts: 16,
47+
hlsPlayback: {
48+
preload: true,
49+
},
4750
playback: {
4851
extrapolatedWindowNumSegments: 2,
4952
triggerFatalErrorOnResourceDenied: false,
@@ -83,6 +86,26 @@ The `hls.js` have recover approaches for some fatal errors. This option sets the
8386
8487
If this option is set to true, the playback will triggers fatal error event if decrypt key http response code is greater than or equal to 400. This option is used to attempt to reproduce iOS devices behaviour which internally use html5 video playback.
8588

89+
#### hlsPlayback
90+
> Soon (in a new breaking change version), all options related to this playback that are declared in the scope of the `options` object will have to be declared necessarily within this new scope!
91+
92+
Groups all options related directly to `HlsjsPlayback` configs.
93+
94+
```javascript
95+
var player = new Clappr.Player(
96+
{
97+
...
98+
hlsPlayback: {
99+
preload: true,
100+
},
101+
});
102+
```
103+
104+
#### `hlsPlayback.preload`
105+
> Default value: `true`
106+
107+
Configures whether the source should be loaded as soon as the `HLS.JS` internal reference is setup or only after the first play.
108+
86109
#### hlsjsConfig
87110

88111
As `HlsjsPlayback` is based on `hls.js`, it's possible to use the available `hls.js` configs too. You can check them out [here](https://github.com/video-dev/hls.js/blob/master/docs/API.md#fine-tuning).

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"watch": "rollup --config --watch",
1212
"bundle-check": "ANALYZE_BUNDLE=true rollup --config",
1313
"release": "MINIMIZE=true rollup --config",
14-
"test": "jest ./src --coverage",
14+
"test": "jest ./src --coverage --silent",
1515
"test:debug": "node --inspect node_modules/.bin/jest ./src --runInBand",
1616
"test:watch": "jest ./src --watch",
1717
"lint": "eslint *.js ./src",

src/hls.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ export default class HlsjsPlayback extends HTML5Video {
109109
return this._hls && this._hls.bandwidthEstimate
110110
}
111111

112+
get defaultOptions() {
113+
return { preload: true }
114+
}
115+
112116
static get HLSJS() {
113117
return HLSJS
114118
}
@@ -117,6 +121,7 @@ export default class HlsjsPlayback extends HTML5Video {
117121
super(...args)
118122
// backwards compatibility (TODO: remove on 0.3.0)
119123
this.options.playback = { ...this.options, ...this.options.playback }
124+
this.options.hlsPlayback = { ...this.defaultOptions, ...this.options.hlsPlayback }
120125
this._minDvrSize = typeof (this.options.hlsMinimumDvrSize) === 'undefined' ? 60 : this.options.hlsMinimumDvrSize
121126
// The size of the start time extrapolation window measured as a multiple of segments.
122127
// Should be 2 or higher, or 0 to disable. Should only need to be increased above 2 if more than one segment is
@@ -158,11 +163,13 @@ export default class HlsjsPlayback extends HTML5Video {
158163
}
159164

160165
_setup() {
166+
this._manifestParsed = false
161167
this._ccIsSetup = false
162168
this._ccTracksUpdated = false
163169
this._hls && this._hls.destroy()
164170
this._hls = new HLSJS(assign({}, this.options.playback.hlsjsConfig))
165-
this._hls.once(HLSJS.Events.MEDIA_ATTACHED, () => this._hls.loadSource(this.options.src))
171+
this._hls.once(HLSJS.Events.MEDIA_ATTACHED, () => { this.options.hlsPlayback.preload && this._hls.loadSource(this.options.src) })
172+
this._hls.on(HLSJS.Events.MANIFEST_PARSED, () => this._manifestParsed = true)
166173
this._hls.on(HLSJS.Events.LEVEL_LOADED, (evt, data) => this._updatePlaybackType(evt, data))
167174
this._hls.on(HLSJS.Events.LEVEL_UPDATED, (evt, data) => this._onLevelUpdated(evt, data))
168175
this._hls.on(HLSJS.Events.LEVEL_SWITCHING, (evt,data) => this._onLevelSwitch(evt, data))
@@ -416,8 +423,8 @@ export default class HlsjsPlayback extends HTML5Video {
416423
}
417424

418425
play() {
419-
if (!this._hls)
420-
this._setup()
426+
!this._hls && this._setup()
427+
!this._manifestParsed && !this.options.hlsPlayback.preload && this._hls.loadSource(this.options.src)
421428

422429
super.play()
423430
this._startTimeUpdateTimer()

src/hls.test.js

Lines changed: 110 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,17 @@ import { Core, Events } from '@clappr/core'
22
import HlsjsPlayback from './hls.js'
33
import HLSJS from 'hls.js'
44

5-
describe('HLS playback', () => {
5+
const simplePlaybackMock = new HlsjsPlayback({ src: 'http://clappr.io/video.m3u8' })
6+
7+
describe('HlsjsPlayback', () => {
8+
test('have a getter called template', () => {
9+
expect(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(simplePlaybackMock), 'defaultOptions').get).toBeTruthy()
10+
})
11+
12+
test('defaultOptions getter returns all the default options values into one object', () => {
13+
expect(simplePlaybackMock.defaultOptions).toEqual({ preload: true })
14+
})
15+
616
test('should be able to identify it can play resources independently of the file extension case', () => {
717
jest.spyOn(HLSJS, 'isSupported').mockImplementation(() => true)
818
expect(HlsjsPlayback.canPlay('/relative/video.m3u8')).toBeTruthy()
@@ -33,48 +43,6 @@ describe('HLS playback', () => {
3343
expect(playback.tagName).toEqual('audio')
3444
})
3545

36-
describe('options backwards compatibility', () => {
37-
// backwards compatibility (TODO: remove on 0.3.0)
38-
test('should set options.playback as a reference to options if options.playback not set', () => {
39-
let options = { src: 'http://clappr.io/video.m3u8' },
40-
hls = new HlsjsPlayback(options)
41-
expect(hls.options.playback).toEqual(hls.options)
42-
options = { src: 'http://clappr.io/video.m3u8', playback: { test: true } }
43-
hls = new HlsjsPlayback(options)
44-
expect(hls.options.playback.test).toEqual(true)
45-
})
46-
})
47-
48-
describe('HlsjsPlayback.js configuration', () => {
49-
test('should use hlsjsConfig from playback options', () => {
50-
const options = {
51-
src: 'http://clappr.io/video.m3u8',
52-
playback: {
53-
hlsMinimumDvrSize: 1,
54-
hlsjsConfig: {
55-
someHlsjsOption: 'value'
56-
}
57-
}
58-
}
59-
const playback = new HlsjsPlayback(options)
60-
playback._setup()
61-
expect(playback._hls.config.someHlsjsOption).toEqual('value')
62-
})
63-
64-
test('should use hlsjsConfig from player options as fallback', () => {
65-
const options = {
66-
src: 'http://clappr.io/video.m3u8',
67-
hlsMinimumDvrSize: 1,
68-
hlsjsConfig: {
69-
someHlsjsOption: 'value'
70-
}
71-
}
72-
const playback = new HlsjsPlayback(options)
73-
playback._setup()
74-
expect(playback._hls.config.someHlsjsOption).toEqual('value')
75-
})
76-
})
77-
7846
test('should trigger a playback error if source load failed', () => {
7947
jest.spyOn(window.HTMLMediaElement.prototype, 'play').mockImplementation(() => {})
8048
let resolveFn = undefined
@@ -127,4 +95,103 @@ describe('HLS playback', () => {
12795
expect(playback.currentLevel).toEqual(1)
12896
expect(playback._hls.currentLevel).toEqual(1)
12997
})
98+
99+
describe('constructor', () => {
100+
test('should use hlsjsConfig from playback options', () => {
101+
const options = {
102+
src: 'http://clappr.io/video.m3u8',
103+
playback: {
104+
hlsMinimumDvrSize: 1,
105+
hlsjsConfig: {
106+
someHlsjsOption: 'value'
107+
}
108+
}
109+
}
110+
const playback = new HlsjsPlayback(options)
111+
playback._setup()
112+
expect(playback._hls.config.someHlsjsOption).toEqual('value')
113+
})
114+
115+
test('should use hlsjsConfig from player options as fallback', () => {
116+
const options = {
117+
src: 'http://clappr.io/video.m3u8',
118+
hlsMinimumDvrSize: 1,
119+
hlsjsConfig: {
120+
someHlsjsOption: 'value'
121+
}
122+
}
123+
const playback = new HlsjsPlayback(options)
124+
playback._setup()
125+
expect(playback._hls.config.someHlsjsOption).toEqual('value')
126+
})
127+
128+
test('merges defaultOptions with received options.hlsPlayback', () => {
129+
const options = {
130+
src: 'http://clappr.io/foo.m3u8',
131+
hlsPlayback: { foo: 'bar' },
132+
}
133+
const playback = new HlsjsPlayback(options)
134+
expect(playback.options.hlsPlayback).toEqual({ ...options.hlsPlayback, ...playback.defaultOptions })
135+
})
136+
})
137+
138+
describe('_setup method', () => {
139+
test('sets _manifestParsed flag to false', () => {
140+
const playback = new HlsjsPlayback({ src: 'http://clappr.io/foo.m3u8' })
141+
expect(playback._manifestParsed).toBeUndefined()
142+
143+
playback._setup()
144+
145+
expect(playback._manifestParsed).toBeFalsy()
146+
})
147+
148+
test('calls this._hls.loadSource when MEDIA_ATTACHED event is triggered and hlsPlayback.preload is true', () => {
149+
const playback = new HlsjsPlayback({ src: 'http://clappr.io/foo.m3u8', hlsPlayback: { preload: false } })
150+
playback._setup()
151+
jest.spyOn(playback._hls, 'loadSource')
152+
playback._hls.trigger(HLSJS.Events.MEDIA_ATTACHED)
153+
154+
expect(playback._hls.loadSource).not.toHaveBeenCalled()
155+
156+
playback.options.hlsPlayback.preload = true
157+
playback._setup()
158+
jest.spyOn(playback._hls, 'loadSource')
159+
playback._hls.trigger(HLSJS.Events.MEDIA_ATTACHED)
160+
161+
expect(playback._hls.loadSource).toHaveBeenCalledTimes(1)
162+
})
163+
164+
test('updates _manifestParsed flag value to true if MANIFEST_PARSED event is triggered', () => {
165+
const playback = new HlsjsPlayback({ src: 'http://clappr.io/foo.m3u8' })
166+
167+
expect(playback._manifestParsed).toBeUndefined()
168+
169+
playback._setup()
170+
playback._hls.trigger(HLSJS.Events.MANIFEST_PARSED)
171+
172+
expect(playback._manifestParsed).toBeTruthy()
173+
})
174+
})
175+
176+
describe('play method', () => {
177+
test('calls this._hls.loadSource if _manifestParsed flag and options.hlsPlayback.preload are falsy', () => {
178+
const playback = new HlsjsPlayback({ src: 'http://clappr.io/foo.m3u8', hlsPlayback: { preload: true } })
179+
playback._setup()
180+
jest.spyOn(playback._hls, 'loadSource')
181+
playback.play()
182+
183+
expect(playback._hls.loadSource).not.toHaveBeenCalled()
184+
185+
playback.options.hlsPlayback.preload = false
186+
playback._manifestParsed = true
187+
playback.play()
188+
189+
expect(playback._hls.loadSource).not.toHaveBeenCalled()
190+
191+
playback._manifestParsed = false
192+
playback.play()
193+
194+
expect(playback._hls.loadSource).toHaveBeenCalledTimes(1)
195+
})
196+
})
130197
})

0 commit comments

Comments
 (0)