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