1 |
|
2 |
|
3 | import QUnit from 'qunit';
|
4 | import RenditionMixin from '../src/rendition-mixin.js';
|
5 | import videojs from 'video.js';
|
6 |
|
7 | const makeMockPlaylist = function(options) {
|
8 | options = options || {};
|
9 |
|
10 | let playlist = {
|
11 | segments: [],
|
12 | attributes: {}
|
13 | };
|
14 |
|
15 | playlist.attributes.BANDWIDTH = options.bandwidth;
|
16 |
|
17 | if ('width' in options) {
|
18 | playlist.attributes.RESOLUTION = playlist.attributes.RESOLUTION || {};
|
19 |
|
20 | playlist.attributes.RESOLUTION.width = options.width;
|
21 | }
|
22 |
|
23 | if ('height' in options) {
|
24 | playlist.attributes.RESOLUTION = playlist.attributes.RESOLUTION || {};
|
25 |
|
26 | playlist.attributes.RESOLUTION.height = options.height;
|
27 | }
|
28 |
|
29 | if ('excludeUntil' in options) {
|
30 | playlist.excludeUntil = options.excludeUntil;
|
31 | }
|
32 |
|
33 | if ('uri' in options) {
|
34 | playlist.uri = options.uri;
|
35 | }
|
36 |
|
37 | if ('disabled' in options) {
|
38 | playlist.disabled = options.disabled;
|
39 | }
|
40 |
|
41 | return playlist;
|
42 | };
|
43 |
|
44 | const makeMockHlsHandler = function(playlistOptions) {
|
45 | let mcp = {
|
46 | fastQualityChange_: () => {
|
47 | mcp.fastQualityChange_.calls++;
|
48 | }
|
49 | };
|
50 |
|
51 | mcp.fastQualityChange_.calls = 0;
|
52 |
|
53 | let hlsHandler = {
|
54 | masterPlaylistController_: mcp
|
55 | };
|
56 |
|
57 | hlsHandler.playlists = new videojs.EventTarget();
|
58 | hlsHandler.playlists.master = { playlists: [] };
|
59 |
|
60 | playlistOptions.forEach((playlist, i) => {
|
61 | hlsHandler.playlists.master.playlists[i] = makeMockPlaylist(playlist);
|
62 |
|
63 | if (playlist.uri) {
|
64 | hlsHandler.playlists.master.playlists[playlist.uri] =
|
65 | hlsHandler.playlists.master.playlists[i];
|
66 | }
|
67 | });
|
68 |
|
69 | return hlsHandler;
|
70 | };
|
71 |
|
72 | QUnit.module('Rendition Selector API Mixin');
|
73 |
|
74 | QUnit.test('adds the representations API to HlsHandler', function(assert) {
|
75 | let hlsHandler = makeMockHlsHandler([
|
76 | {}
|
77 | ]);
|
78 |
|
79 | RenditionMixin(hlsHandler);
|
80 |
|
81 | assert.equal(typeof hlsHandler.representations, 'function',
|
82 | 'added the representations API');
|
83 | });
|
84 |
|
85 | QUnit.test('returns proper number of representations', function(assert) {
|
86 | let hlsHandler = makeMockHlsHandler([
|
87 | {}, {}, {}
|
88 | ]);
|
89 |
|
90 | RenditionMixin(hlsHandler);
|
91 |
|
92 | let renditions = hlsHandler.representations();
|
93 |
|
94 | assert.equal(renditions.length, 3, 'number of renditions is 3');
|
95 | });
|
96 |
|
97 | QUnit.test('returns representations in playlist order', function(assert) {
|
98 | let hlsHandler = makeMockHlsHandler([
|
99 | {
|
100 | bandwidth: 10
|
101 | },
|
102 | {
|
103 | bandwidth: 20
|
104 | },
|
105 | {
|
106 | bandwidth: 30
|
107 | }
|
108 | ]);
|
109 |
|
110 | RenditionMixin(hlsHandler);
|
111 |
|
112 | let renditions = hlsHandler.representations();
|
113 |
|
114 | assert.equal(renditions[0].bandwidth, 10, 'rendition has bandwidth 10');
|
115 | assert.equal(renditions[1].bandwidth, 20, 'rendition has bandwidth 20');
|
116 | assert.equal(renditions[2].bandwidth, 30, 'rendition has bandwidth 30');
|
117 | });
|
118 |
|
119 | QUnit.test('returns representations with width and height if present', function(assert) {
|
120 | let hlsHandler = makeMockHlsHandler([
|
121 | {
|
122 | bandwidth: 10,
|
123 | width: 100,
|
124 | height: 200
|
125 | },
|
126 | {
|
127 | bandwidth: 20,
|
128 | width: 500,
|
129 | height: 600
|
130 | },
|
131 | {
|
132 | bandwidth: 30
|
133 | }
|
134 | ]);
|
135 |
|
136 | RenditionMixin(hlsHandler);
|
137 |
|
138 | let renditions = hlsHandler.representations();
|
139 |
|
140 | assert.equal(renditions[0].width, 100, 'rendition has a width of 100');
|
141 | assert.equal(renditions[0].height, 200, 'rendition has a height of 200');
|
142 | assert.equal(renditions[1].width, 500, 'rendition has a width of 500');
|
143 | assert.equal(renditions[1].height, 600, 'rendition has a height of 600');
|
144 | assert.equal(renditions[2].width, undefined, 'rendition has a width of undefined');
|
145 | assert.equal(renditions[2].height, undefined, 'rendition has a height of undefined');
|
146 | });
|
147 |
|
148 | QUnit.test('incompatible playlists are not included in the representations list',
|
149 | function(assert) {
|
150 | let hlsHandler = makeMockHlsHandler([
|
151 | {
|
152 | bandwidth: 0,
|
153 | excludeUntil: Infinity,
|
154 | uri: 'media0.m3u8'
|
155 | },
|
156 | {
|
157 | bandwidth: 0,
|
158 | excludeUntil: 0,
|
159 | uri: 'media1.m3u8'
|
160 | },
|
161 | {
|
162 | bandwidth: 0,
|
163 | excludeUntil: Date.now() + 999999,
|
164 | uri: 'media2.m3u8'
|
165 | },
|
166 | {
|
167 | bandwidth: 0,
|
168 | excludeUntil: 1,
|
169 | uri: 'media3.m3u8'
|
170 | },
|
171 | {
|
172 | bandwidth: 0,
|
173 | uri: 'media4.m3u8'
|
174 | }
|
175 | ]);
|
176 |
|
177 | RenditionMixin(hlsHandler);
|
178 |
|
179 | let renditions = hlsHandler.representations();
|
180 |
|
181 | assert.equal(renditions.length, 4, 'incompatible rendition not added');
|
182 | assert.equal(renditions[0].id, 'media1.m3u8', 'rendition is enabled');
|
183 | assert.equal(renditions[1].id, 'media2.m3u8', 'rendition is enabled');
|
184 | assert.equal(renditions[2].id, 'media3.m3u8', 'rendition is enabled');
|
185 | assert.equal(renditions[3].id, 'media4.m3u8', 'rendition is enabled');
|
186 | });
|
187 |
|
188 | QUnit.test('setting a representation to disabled sets disabled to true',
|
189 | function(assert) {
|
190 | let renditiondisabled = 0;
|
191 | let hlsHandler = makeMockHlsHandler([
|
192 | {
|
193 | bandwidth: 0,
|
194 | excludeUntil: 0,
|
195 | uri: 'media0.m3u8'
|
196 | },
|
197 | {
|
198 | bandwidth: 0,
|
199 | excludeUntil: 0,
|
200 | uri: 'media1.m3u8'
|
201 | }
|
202 | ]);
|
203 | let playlists = hlsHandler.playlists.master.playlists;
|
204 |
|
205 | hlsHandler.playlists.on('renditiondisabled', function() {
|
206 | renditiondisabled++;
|
207 | });
|
208 |
|
209 | RenditionMixin(hlsHandler);
|
210 |
|
211 | let renditions = hlsHandler.representations();
|
212 |
|
213 | assert.equal(renditiondisabled, 0, 'renditiondisabled event has not been triggered');
|
214 | renditions[0].enabled(false);
|
215 |
|
216 | assert.equal(renditiondisabled, 1, 'renditiondisabled event has been triggered');
|
217 | assert.equal(playlists[0].disabled, true, 'rendition has been disabled');
|
218 | assert.equal(playlists[1].disabled, undefined, 'rendition has not been disabled');
|
219 | assert.equal(playlists[0].excludeUntil, 0,
|
220 | 'excludeUntil not touched when disabling a rendition');
|
221 | assert.equal(playlists[1].excludeUntil, 0,
|
222 | 'excludeUntil not touched when disabling a rendition');
|
223 | });
|
224 |
|
225 | QUnit.test('changing the enabled state of a representation calls fastQualityChange_',
|
226 | function(assert) {
|
227 | let renditionEnabledEvents = 0;
|
228 | let hlsHandler = makeMockHlsHandler([
|
229 | {
|
230 | bandwidth: 0,
|
231 | disabled: true,
|
232 | uri: 'media0.m3u8'
|
233 | },
|
234 | {
|
235 | bandwidth: 0,
|
236 | uri: 'media1.m3u8'
|
237 | }
|
238 | ]);
|
239 | let mpc = hlsHandler.masterPlaylistController_;
|
240 |
|
241 | hlsHandler.playlists.on('renditionenabled', function() {
|
242 | renditionEnabledEvents++;
|
243 | });
|
244 |
|
245 | RenditionMixin(hlsHandler);
|
246 |
|
247 | let renditions = hlsHandler.representations();
|
248 |
|
249 | assert.equal(mpc.fastQualityChange_.calls, 0, 'fastQualityChange_ was never called');
|
250 | assert.equal(renditionEnabledEvents, 0,
|
251 | 'renditionenabled event has not been triggered');
|
252 |
|
253 | renditions[0].enabled(true);
|
254 |
|
255 | assert.equal(mpc.fastQualityChange_.calls, 1, 'fastQualityChange_ was called once');
|
256 | assert.equal(renditionEnabledEvents, 1,
|
257 | 'renditionenabled event has been triggered once');
|
258 |
|
259 | renditions[1].enabled(false);
|
260 |
|
261 | assert.equal(mpc.fastQualityChange_.calls, 2, 'fastQualityChange_ was called twice');
|
262 | });
|