Added bandwidth stats to HLS (#685)
* Added bandwidth stats to HLS * moved bandwidth stats to reside on segment loaders * added accessors for stats on master playlist controller * added getters for stats using master playlist controller on hls * updated tests to check for stats
Showing
6 changed files
with
386 additions
and
6 deletions
... | @@ -170,6 +170,40 @@ export default class MasterPlaylistController extends videojs.EventTarget { | ... | @@ -170,6 +170,40 @@ export default class MasterPlaylistController extends videojs.EventTarget { |
170 | } | 170 | } |
171 | 171 | ||
172 | /** | 172 | /** |
173 | * get the total number of media requests from the `audiosegmentloader_` | ||
174 | * and the `mainSegmentLoader_` | ||
175 | * | ||
176 | * @private | ||
177 | */ | ||
178 | mediaRequests_() { | ||
179 | return this.audioSegmentLoader_.mediaRequests + | ||
180 | this.mainSegmentLoader_.mediaRequests; | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * get the total time that media requests have spent trnasfering | ||
185 | * from the `audiosegmentloader_` and the `mainSegmentLoader_` | ||
186 | * | ||
187 | * @private | ||
188 | */ | ||
189 | mediaTransferDuration_() { | ||
190 | return this.audioSegmentLoader_.mediaTransferDuration + | ||
191 | this.mainSegmentLoader_.mediaTransferDuration; | ||
192 | |||
193 | } | ||
194 | |||
195 | /** | ||
196 | * get the total number of bytes transfered during media requests | ||
197 | * from the `audiosegmentloader_` and the `mainSegmentLoader_` | ||
198 | * | ||
199 | * @private | ||
200 | */ | ||
201 | mediaBytesTransferred_() { | ||
202 | return this.audioSegmentLoader_.mediaBytesTransferred + | ||
203 | this.mainSegmentLoader_.mediaBytesTransferred; | ||
204 | } | ||
205 | |||
206 | /** | ||
173 | * fill our internal list of HlsAudioTracks with data from | 207 | * fill our internal list of HlsAudioTracks with data from |
174 | * the master playlist or use a default | 208 | * the master playlist or use a default |
175 | * | 209 | * |
... | @@ -350,7 +384,8 @@ export default class MasterPlaylistController extends videojs.EventTarget { | ... | @@ -350,7 +384,8 @@ export default class MasterPlaylistController extends videojs.EventTarget { |
350 | 384 | ||
351 | if (media !== this.masterPlaylistLoader_.media()) { | 385 | if (media !== this.masterPlaylistLoader_.media()) { |
352 | this.masterPlaylistLoader_.media(media); | 386 | this.masterPlaylistLoader_.media(media); |
353 | this.mainSegmentLoader_.sourceUpdater_.remove(this.tech_.currentTime() + 5, Infinity); | 387 | this.mainSegmentLoader_.sourceUpdater_.remove(this.tech_.currentTime() + 5, |
388 | Infinity); | ||
354 | } | 389 | } |
355 | } | 390 | } |
356 | 391 | ... | ... |
... | @@ -131,7 +131,7 @@ export default class SegmentLoader extends videojs.EventTarget { | ... | @@ -131,7 +131,7 @@ export default class SegmentLoader extends videojs.EventTarget { |
131 | this.state = 'INIT'; | 131 | this.state = 'INIT'; |
132 | this.bandwidth = settings.bandwidth; | 132 | this.bandwidth = settings.bandwidth; |
133 | this.roundTrip = NaN; | 133 | this.roundTrip = NaN; |
134 | this.bytesReceived = 0; | 134 | this.resetStats_(); |
135 | 135 | ||
136 | // private properties | 136 | // private properties |
137 | this.hasPlayed_ = settings.hasPlayed; | 137 | this.hasPlayed_ = settings.hasPlayed; |
... | @@ -153,6 +153,17 @@ export default class SegmentLoader extends videojs.EventTarget { | ... | @@ -153,6 +153,17 @@ export default class SegmentLoader extends videojs.EventTarget { |
153 | } | 153 | } |
154 | 154 | ||
155 | /** | 155 | /** |
156 | * reset all of our media stats | ||
157 | * | ||
158 | * @private | ||
159 | */ | ||
160 | resetStats_() { | ||
161 | this.mediaBytesTransferred = 0; | ||
162 | this.mediaRequests = 0; | ||
163 | this.mediaTransferDuration = 0; | ||
164 | } | ||
165 | |||
166 | /** | ||
156 | * dispose of the SegmentLoader and reset to the default state | 167 | * dispose of the SegmentLoader and reset to the default state |
157 | */ | 168 | */ |
158 | dispose() { | 169 | dispose() { |
... | @@ -161,6 +172,7 @@ export default class SegmentLoader extends videojs.EventTarget { | ... | @@ -161,6 +172,7 @@ export default class SegmentLoader extends videojs.EventTarget { |
161 | if (this.sourceUpdater_) { | 172 | if (this.sourceUpdater_) { |
162 | this.sourceUpdater_.dispose(); | 173 | this.sourceUpdater_.dispose(); |
163 | } | 174 | } |
175 | this.resetStats_(); | ||
164 | } | 176 | } |
165 | 177 | ||
166 | /** | 178 | /** |
... | @@ -625,7 +637,9 @@ export default class SegmentLoader extends videojs.EventTarget { | ... | @@ -625,7 +637,9 @@ export default class SegmentLoader extends videojs.EventTarget { |
625 | // calculate the download bandwidth based on segment request | 637 | // calculate the download bandwidth based on segment request |
626 | this.roundTrip = request.roundTripTime; | 638 | this.roundTrip = request.roundTripTime; |
627 | this.bandwidth = request.bandwidth; | 639 | this.bandwidth = request.bandwidth; |
628 | this.bytesReceived += request.bytesReceived || 0; | 640 | this.mediaBytesTransferred += request.bytesReceived || 0; |
641 | this.mediaRequests += 1; | ||
642 | this.mediaTransferDuration += request.roundTripTime || 0; | ||
629 | 643 | ||
630 | if (segment.key) { | 644 | if (segment.key) { |
631 | segmentInfo.encryptedBytes = new Uint8Array(request.response); | 645 | segmentInfo.encryptedBytes = new Uint8Array(request.response); | ... | ... |
... | @@ -301,12 +301,16 @@ class HlsHandler extends Component { | ... | @@ -301,12 +301,16 @@ class HlsHandler extends Component { |
301 | 301 | ||
302 | this.tech_ = tech; | 302 | this.tech_ = tech; |
303 | this.source_ = source; | 303 | this.source_ = source; |
304 | this.stats = {}; | ||
304 | 305 | ||
305 | // handle global & Source Handler level options | 306 | // handle global & Source Handler level options |
306 | this.options_ = videojs.mergeOptions(videojs.options.hls || {}, options.hls); | 307 | this.options_ = videojs.mergeOptions(videojs.options.hls || {}, options.hls); |
307 | this.setOptions_(); | 308 | this.setOptions_(); |
308 | 309 | ||
309 | this.bytesReceived = 0; | 310 | // start playlist selection at a reasonable bandwidth for |
311 | // broadband internet | ||
312 | // 0.5 Mbps | ||
313 | this.bandwidth = this.options_.bandwidth || 4194304; | ||
310 | 314 | ||
311 | // listen for fullscreenchange events for this player so that we | 315 | // listen for fullscreenchange events for this player so that we |
312 | // can adjust our quality selection quickly | 316 | // can adjust our quality selection quickly |
... | @@ -406,6 +410,19 @@ class HlsHandler extends Component { | ... | @@ -406,6 +410,19 @@ class HlsHandler extends Component { |
406 | } | 410 | } |
407 | }); | 411 | }); |
408 | 412 | ||
413 | Object.defineProperty(this.stats, 'bandwidth', { | ||
414 | get: () => this.bandwidth || 0 | ||
415 | }); | ||
416 | Object.defineProperty(this.stats, 'mediaRequests', { | ||
417 | get: () => this.masterPlaylistController_.mediaRequests_() || 0 | ||
418 | }); | ||
419 | Object.defineProperty(this.stats, 'mediaTransferDuration', { | ||
420 | get: () => this.masterPlaylistController_.mediaTransferDuration_() || 0 | ||
421 | }); | ||
422 | Object.defineProperty(this.stats, 'mediaBytesTransferred', { | ||
423 | get: () => this.masterPlaylistController_.mediaBytesTransferred_() || 0 | ||
424 | }); | ||
425 | |||
409 | this.tech_.one('canplay', | 426 | this.tech_.one('canplay', |
410 | this.masterPlaylistController_.setupFirstPlay.bind(this.masterPlaylistController_)); | 427 | this.masterPlaylistController_.setupFirstPlay.bind(this.masterPlaylistController_)); |
411 | 428 | ||
... | @@ -527,7 +544,6 @@ class HlsHandler extends Component { | ... | @@ -527,7 +544,6 @@ class HlsHandler extends Component { |
527 | this.masterPlaylistController_.dispose(); | 544 | this.masterPlaylistController_.dispose(); |
528 | } | 545 | } |
529 | this.tech_.audioTracks().removeEventListener('change', this.audioTrackChange_); | 546 | this.tech_.audioTracks().removeEventListener('change', this.audioTrackChange_); |
530 | |||
531 | super.dispose(); | 547 | super.dispose(); |
532 | } | 548 | } |
533 | } | 549 | } | ... | ... |
... | @@ -64,6 +64,9 @@ QUnit.test('obeys none preload option', function() { | ... | @@ -64,6 +64,9 @@ QUnit.test('obeys none preload option', function() { |
64 | openMediaSource(this.player, this.clock); | 64 | openMediaSource(this.player, this.clock); |
65 | 65 | ||
66 | QUnit.equal(this.requests.length, 0, 'no segment requests'); | 66 | QUnit.equal(this.requests.length, 0, 'no segment requests'); |
67 | |||
68 | // verify stats | ||
69 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default bandwidth'); | ||
67 | }); | 70 | }); |
68 | 71 | ||
69 | QUnit.test('obeys auto preload option', function() { | 72 | QUnit.test('obeys auto preload option', function() { |
... | @@ -76,6 +79,9 @@ QUnit.test('obeys auto preload option', function() { | ... | @@ -76,6 +79,9 @@ QUnit.test('obeys auto preload option', function() { |
76 | openMediaSource(this.player, this.clock); | 79 | openMediaSource(this.player, this.clock); |
77 | 80 | ||
78 | QUnit.equal(this.requests.length, 1, '1 segment request'); | 81 | QUnit.equal(this.requests.length, 1, '1 segment request'); |
82 | |||
83 | // verify stats | ||
84 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default bandwidth'); | ||
79 | }); | 85 | }); |
80 | 86 | ||
81 | QUnit.test('obeys metadata preload option', function() { | 87 | QUnit.test('obeys metadata preload option', function() { |
... | @@ -88,6 +94,9 @@ QUnit.test('obeys metadata preload option', function() { | ... | @@ -88,6 +94,9 @@ QUnit.test('obeys metadata preload option', function() { |
88 | openMediaSource(this.player, this.clock); | 94 | openMediaSource(this.player, this.clock); |
89 | 95 | ||
90 | QUnit.equal(this.requests.length, 1, '1 segment request'); | 96 | QUnit.equal(this.requests.length, 1, '1 segment request'); |
97 | |||
98 | // verify stats | ||
99 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default bandwidth'); | ||
91 | }); | 100 | }); |
92 | 101 | ||
93 | QUnit.test('clears some of the buffer for a fast quality change', function() { | 102 | QUnit.test('clears some of the buffer for a fast quality change', function() { |
... | @@ -114,6 +123,9 @@ QUnit.test('clears some of the buffer for a fast quality change', function() { | ... | @@ -114,6 +123,9 @@ QUnit.test('clears some of the buffer for a fast quality change', function() { |
114 | QUnit.equal(removes.length, 1, 'removed buffered content'); | 123 | QUnit.equal(removes.length, 1, 'removed buffered content'); |
115 | QUnit.equal(removes[0].start, 7 + 5, 'removed from a bit after current time'); | 124 | QUnit.equal(removes[0].start, 7 + 5, 'removed from a bit after current time'); |
116 | QUnit.equal(removes[0].end, Infinity, 'removed to the end'); | 125 | QUnit.equal(removes[0].end, Infinity, 'removed to the end'); |
126 | |||
127 | // verify stats | ||
128 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default bandwidth'); | ||
117 | }); | 129 | }); |
118 | 130 | ||
119 | QUnit.test('does not clear the buffer when no fast quality change occurs', function() { | 131 | QUnit.test('does not clear the buffer when no fast quality change occurs', function() { |
... | @@ -134,6 +146,8 @@ QUnit.test('does not clear the buffer when no fast quality change occurs', funct | ... | @@ -134,6 +146,8 @@ QUnit.test('does not clear the buffer when no fast quality change occurs', funct |
134 | this.masterPlaylistController.fastQualityChange_(); | 146 | this.masterPlaylistController.fastQualityChange_(); |
135 | 147 | ||
136 | QUnit.equal(removes.length, 0, 'did not remove content'); | 148 | QUnit.equal(removes.length, 0, 'did not remove content'); |
149 | // verify stats | ||
150 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default bandwidth'); | ||
137 | }); | 151 | }); |
138 | 152 | ||
139 | QUnit.test('if buffered, will request second segment byte range', function() { | 153 | QUnit.test('if buffered, will request second segment byte range', function() { |
... | @@ -163,6 +177,13 @@ QUnit.test('if buffered, will request second segment byte range', function() { | ... | @@ -163,6 +177,13 @@ QUnit.test('if buffered, will request second segment byte range', function() { |
163 | this.masterPlaylistController.mediaSource.sourceBuffers[0].trigger('updateend'); | 177 | this.masterPlaylistController.mediaSource.sourceBuffers[0].trigger('updateend'); |
164 | this.clock.tick(10 * 1000); | 178 | this.clock.tick(10 * 1000); |
165 | QUnit.equal(this.requests[2].headers.Range, 'bytes=1823412-2299991'); | 179 | QUnit.equal(this.requests[2].headers.Range, 'bytes=1823412-2299991'); |
180 | |||
181 | // verify stats | ||
182 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, Infinity, 'Live stream'); | ||
183 | QUnit.equal(this.player.tech_.hls.stats.mediaRequests, 1, '1 segment request'); | ||
184 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, | ||
185 | 16, | ||
186 | '16 bytes downloaded'); | ||
166 | }); | 187 | }); |
167 | 188 | ||
168 | QUnit.test('re-initializes the combined playlist loader when switching sources', | 189 | QUnit.test('re-initializes the combined playlist loader when switching sources', |
... | @@ -218,6 +239,8 @@ QUnit.test('updates the combined segment loader on live playlist refreshes', fun | ... | @@ -218,6 +239,8 @@ QUnit.test('updates the combined segment loader on live playlist refreshes', fun |
218 | 239 | ||
219 | this.masterPlaylistController.masterPlaylistLoader_.trigger('loadedplaylist'); | 240 | this.masterPlaylistController.masterPlaylistLoader_.trigger('loadedplaylist'); |
220 | QUnit.equal(updates.length, 1, 'updated the segment list'); | 241 | QUnit.equal(updates.length, 1, 'updated the segment list'); |
242 | // verify stats | ||
243 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default bandwidth'); | ||
221 | }); | 244 | }); |
222 | 245 | ||
223 | QUnit.test( | 246 | QUnit.test( |
... | @@ -240,6 +263,13 @@ function() { | ... | @@ -240,6 +263,13 @@ function() { |
240 | standardXHRResponse(this.requests.shift()); | 263 | standardXHRResponse(this.requests.shift()); |
241 | this.masterPlaylistController.mainSegmentLoader_.trigger('progress'); | 264 | this.masterPlaylistController.mainSegmentLoader_.trigger('progress'); |
242 | QUnit.equal(progressCount, 1, 'fired a progress event'); | 265 | QUnit.equal(progressCount, 1, 'fired a progress event'); |
266 | |||
267 | // verify stats | ||
268 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, Infinity, 'Live stream'); | ||
269 | QUnit.equal(this.player.tech_.hls.stats.mediaRequests, 1, '1 segment request'); | ||
270 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, | ||
271 | 16, | ||
272 | '16 bytes downloaded'); | ||
243 | }); | 273 | }); |
244 | 274 | ||
245 | QUnit.test('blacklists switching from video+audio playlists to audio only', function() { | 275 | QUnit.test('blacklists switching from video+audio playlists to audio only', function() { |
... | @@ -264,6 +294,9 @@ QUnit.test('blacklists switching from video+audio playlists to audio only', func | ... | @@ -264,6 +294,9 @@ QUnit.test('blacklists switching from video+audio playlists to audio only', func |
264 | 'selected video+audio'); | 294 | 'selected video+audio'); |
265 | audioPlaylist = this.masterPlaylistController.masterPlaylistLoader_.master.playlists[0]; | 295 | audioPlaylist = this.masterPlaylistController.masterPlaylistLoader_.master.playlists[0]; |
266 | QUnit.equal(audioPlaylist.excludeUntil, Infinity, 'excluded incompatible playlist'); | 296 | QUnit.equal(audioPlaylist.excludeUntil, Infinity, 'excluded incompatible playlist'); |
297 | |||
298 | // verify stats | ||
299 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 1e10, 'bandwidth we set above'); | ||
267 | }); | 300 | }); |
268 | 301 | ||
269 | QUnit.test('blacklists switching from audio-only playlists to video+audio', function() { | 302 | QUnit.test('blacklists switching from audio-only playlists to video+audio', function() { |
... | @@ -290,6 +323,9 @@ QUnit.test('blacklists switching from audio-only playlists to video+audio', func | ... | @@ -290,6 +323,9 @@ QUnit.test('blacklists switching from audio-only playlists to video+audio', func |
290 | QUnit.equal(videoAudioPlaylist.excludeUntil, | 323 | QUnit.equal(videoAudioPlaylist.excludeUntil, |
291 | Infinity, | 324 | Infinity, |
292 | 'excluded incompatible playlist'); | 325 | 'excluded incompatible playlist'); |
326 | |||
327 | // verify stats | ||
328 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 1, 'bandwidth we set above'); | ||
293 | }); | 329 | }); |
294 | 330 | ||
295 | QUnit.test('blacklists switching from video-only playlists to video+audio', function() { | 331 | QUnit.test('blacklists switching from video-only playlists to video+audio', function() { |
... | @@ -317,6 +353,9 @@ QUnit.test('blacklists switching from video-only playlists to video+audio', func | ... | @@ -317,6 +353,9 @@ QUnit.test('blacklists switching from video-only playlists to video+audio', func |
317 | QUnit.equal(videoAudioPlaylist.excludeUntil, | 353 | QUnit.equal(videoAudioPlaylist.excludeUntil, |
318 | Infinity, | 354 | Infinity, |
319 | 'excluded incompatible playlist'); | 355 | 'excluded incompatible playlist'); |
356 | |||
357 | // verify stats | ||
358 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 1, 'bandwidth we set above'); | ||
320 | }); | 359 | }); |
321 | 360 | ||
322 | QUnit.test('blacklists switching between playlists with incompatible audio codecs', | 361 | QUnit.test('blacklists switching between playlists with incompatible audio codecs', |
... | @@ -343,6 +382,8 @@ function() { | ... | @@ -343,6 +382,8 @@ function() { |
343 | alternatePlaylist = | 382 | alternatePlaylist = |
344 | this.masterPlaylistController.masterPlaylistLoader_.master.playlists[1]; | 383 | this.masterPlaylistController.masterPlaylistLoader_.master.playlists[1]; |
345 | QUnit.equal(alternatePlaylist.excludeUntil, Infinity, 'excluded incompatible playlist'); | 384 | QUnit.equal(alternatePlaylist.excludeUntil, Infinity, 'excluded incompatible playlist'); |
385 | // verify stats | ||
386 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 1, 'bandwidth we set above'); | ||
346 | }); | 387 | }); |
347 | 388 | ||
348 | QUnit.test('updates the combined segment loader on media changes', function() { | 389 | QUnit.test('updates the combined segment loader on media changes', function() { |
... | @@ -369,6 +410,14 @@ QUnit.test('updates the combined segment loader on media changes', function() { | ... | @@ -369,6 +410,14 @@ QUnit.test('updates the combined segment loader on media changes', function() { |
369 | // media | 410 | // media |
370 | standardXHRResponse(this.requests.shift()); | 411 | standardXHRResponse(this.requests.shift()); |
371 | QUnit.equal(updates.length, 1, 'updated the segment list'); | 412 | QUnit.equal(updates.length, 1, 'updated the segment list'); |
413 | |||
414 | // verify stats | ||
415 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, Infinity, 'Live stream'); | ||
416 | QUnit.equal(this.player.tech_.hls.stats.mediaRequests, 1, '1 segment request'); | ||
417 | QUnit.equal( | ||
418 | this.player.tech_.hls.stats.mediaBytesTransferred, | ||
419 | 16, | ||
420 | '16 bytes downloaded'); | ||
372 | }); | 421 | }); |
373 | 422 | ||
374 | QUnit.test('selects a playlist after main/combined segment downloads', function() { | 423 | QUnit.test('selects a playlist after main/combined segment downloads', function() { |
... | @@ -392,6 +441,8 @@ QUnit.test('selects a playlist after main/combined segment downloads', function( | ... | @@ -392,6 +441,8 @@ QUnit.test('selects a playlist after main/combined segment downloads', function( |
392 | // and another | 441 | // and another |
393 | this.masterPlaylistController.mainSegmentLoader_.trigger('progress'); | 442 | this.masterPlaylistController.mainSegmentLoader_.trigger('progress'); |
394 | QUnit.strictEqual(calls, 3, 'selects after additional segments'); | 443 | QUnit.strictEqual(calls, 3, 'selects after additional segments'); |
444 | // verify stats | ||
445 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default bandwidth'); | ||
395 | }); | 446 | }); |
396 | 447 | ||
397 | QUnit.test('updates the duration after switching playlists', function() { | 448 | QUnit.test('updates the duration after switching playlists', function() { |
... | @@ -424,6 +475,13 @@ QUnit.test('updates the duration after switching playlists', function() { | ... | @@ -424,6 +475,13 @@ QUnit.test('updates the duration after switching playlists', function() { |
424 | QUnit.ok(selectedPlaylist, 'selected playlist'); | 475 | QUnit.ok(selectedPlaylist, 'selected playlist'); |
425 | QUnit.ok(this.masterPlaylistController.mediaSource.duration !== 0, | 476 | QUnit.ok(this.masterPlaylistController.mediaSource.duration !== 0, |
426 | 'updates the duration'); | 477 | 'updates the duration'); |
478 | |||
479 | // verify stats | ||
480 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, Infinity, 'Live stream'); | ||
481 | QUnit.equal(this.player.tech_.hls.stats.mediaRequests, 1, '1 segment request'); | ||
482 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, | ||
483 | 16, | ||
484 | '16 bytes downloaded'); | ||
427 | }); | 485 | }); |
428 | 486 | ||
429 | QUnit.test('seekable uses the intersection of alternate audio and combined tracks', | 487 | QUnit.test('seekable uses the intersection of alternate audio and combined tracks', | ... | ... |
... | @@ -105,6 +105,11 @@ QUnit.test('calling load is idempotent', function() { | ... | @@ -105,6 +105,11 @@ QUnit.test('calling load is idempotent', function() { |
105 | this.requests.shift().respond(200, null, ''); | 105 | this.requests.shift().respond(200, null, ''); |
106 | loader.load(); | 106 | loader.load(); |
107 | QUnit.equal(this.requests.length, 0, 'load has no effect'); | 107 | QUnit.equal(this.requests.length, 0, 'load has no effect'); |
108 | |||
109 | // verify stats | ||
110 | QUnit.equal(loader.mediaBytesTransferred, 10, '10 bytes'); | ||
111 | QUnit.equal(loader.mediaTransferDuration, 100, '100 ms (clock above)'); | ||
112 | QUnit.equal(loader.mediaRequests, 1, '1 request'); | ||
108 | }); | 113 | }); |
109 | 114 | ||
110 | QUnit.test('calling load should unpause', function() { | 115 | QUnit.test('calling load should unpause', function() { |
... | @@ -135,6 +140,11 @@ QUnit.test('calling load should unpause', function() { | ... | @@ -135,6 +140,11 @@ QUnit.test('calling load should unpause', function() { |
135 | 140 | ||
136 | loader.load(); | 141 | loader.load(); |
137 | QUnit.equal(loader.paused(), false, 'unpaused'); | 142 | QUnit.equal(loader.paused(), false, 'unpaused'); |
143 | |||
144 | // verify stats | ||
145 | QUnit.equal(loader.mediaBytesTransferred, 10, '10 bytes'); | ||
146 | QUnit.equal(loader.mediaTransferDuration, 1, '1 ms (clock above)'); | ||
147 | QUnit.equal(loader.mediaRequests, 1, '1 request'); | ||
138 | }); | 148 | }); |
139 | 149 | ||
140 | QUnit.test('regularly checks the buffer while unpaused', function() { | 150 | QUnit.test('regularly checks the buffer while unpaused', function() { |
... | @@ -159,6 +169,11 @@ QUnit.test('regularly checks the buffer while unpaused', function() { | ... | @@ -159,6 +169,11 @@ QUnit.test('regularly checks the buffer while unpaused', function() { |
159 | currentTime = Config.GOAL_BUFFER_LENGTH; | 169 | currentTime = Config.GOAL_BUFFER_LENGTH; |
160 | this.clock.tick(10 * 1000); | 170 | this.clock.tick(10 * 1000); |
161 | QUnit.equal(this.requests.length, 1, 'requested another segment'); | 171 | QUnit.equal(this.requests.length, 1, 'requested another segment'); |
172 | |||
173 | // verify stats | ||
174 | QUnit.equal(loader.mediaBytesTransferred, 10, '10 bytes'); | ||
175 | QUnit.equal(loader.mediaTransferDuration, 1, '1 ms (clock above)'); | ||
176 | QUnit.equal(loader.mediaRequests, 1, '1 request'); | ||
162 | }); | 177 | }); |
163 | 178 | ||
164 | QUnit.test('does not check the buffer while paused', function() { | 179 | QUnit.test('does not check the buffer while paused', function() { |
... | @@ -177,6 +192,11 @@ QUnit.test('does not check the buffer while paused', function() { | ... | @@ -177,6 +192,11 @@ QUnit.test('does not check the buffer while paused', function() { |
177 | 192 | ||
178 | this.clock.tick(10 * 1000); | 193 | this.clock.tick(10 * 1000); |
179 | QUnit.equal(this.requests.length, 0, 'did not make a request'); | 194 | QUnit.equal(this.requests.length, 0, 'did not make a request'); |
195 | |||
196 | // verify stats | ||
197 | QUnit.equal(loader.mediaBytesTransferred, 10, '10 bytes'); | ||
198 | QUnit.equal(loader.mediaTransferDuration, 1, '1 ms (clock above)'); | ||
199 | QUnit.equal(loader.mediaRequests, 1, '1 request'); | ||
180 | }); | 200 | }); |
181 | 201 | ||
182 | QUnit.test('calculates bandwidth after downloading a segment', function() { | 202 | QUnit.test('calculates bandwidth after downloading a segment', function() { |
... | @@ -191,7 +211,12 @@ QUnit.test('calculates bandwidth after downloading a segment', function() { | ... | @@ -191,7 +211,12 @@ QUnit.test('calculates bandwidth after downloading a segment', function() { |
191 | 211 | ||
192 | QUnit.equal(loader.bandwidth, (10 / 100) * 8 * 1000, 'calculated bandwidth'); | 212 | QUnit.equal(loader.bandwidth, (10 / 100) * 8 * 1000, 'calculated bandwidth'); |
193 | QUnit.equal(loader.roundTrip, 100, 'saves request round trip time'); | 213 | QUnit.equal(loader.roundTrip, 100, 'saves request round trip time'); |
194 | QUnit.equal(loader.bytesReceived, 10, 'saves bytes received'); | 214 | |
215 | // TODO: Bandwidth Stat will be stale?? | ||
216 | // verify stats | ||
217 | QUnit.equal(loader.mediaBytesTransferred, 10, '10 bytes'); | ||
218 | QUnit.equal(loader.mediaTransferDuration, 100, '100 ms (clock above)'); | ||
219 | QUnit.equal(loader.mediaRequests, 1, '1 request'); | ||
195 | }); | 220 | }); |
196 | 221 | ||
197 | QUnit.test('segment request timeouts reset bandwidth', function() { | 222 | QUnit.test('segment request timeouts reset bandwidth', function() { |
... | @@ -223,6 +248,10 @@ QUnit.test('appending a segment triggers progress', function() { | ... | @@ -223,6 +248,10 @@ QUnit.test('appending a segment triggers progress', function() { |
223 | mediaSource.sourceBuffers[0].trigger('updateend'); | 248 | mediaSource.sourceBuffers[0].trigger('updateend'); |
224 | 249 | ||
225 | QUnit.equal(progresses, 1, 'fired progress'); | 250 | QUnit.equal(progresses, 1, 'fired progress'); |
251 | |||
252 | // verify stats | ||
253 | QUnit.equal(loader.mediaBytesTransferred, 10, '10 bytes'); | ||
254 | QUnit.equal(loader.mediaRequests, 1, '1 request'); | ||
226 | }); | 255 | }); |
227 | 256 | ||
228 | QUnit.test('only requests one segment at a time', function() { | 257 | QUnit.test('only requests one segment at a time', function() { |
... | @@ -251,6 +280,11 @@ QUnit.test('only appends one segment at a time', function() { | ... | @@ -251,6 +280,11 @@ QUnit.test('only appends one segment at a time', function() { |
251 | QUnit.equal(mediaSource.sourceBuffers[0].updates_.filter( | 280 | QUnit.equal(mediaSource.sourceBuffers[0].updates_.filter( |
252 | update => update.append).length, 1, 'only one append'); | 281 | update => update.append).length, 1, 'only one append'); |
253 | QUnit.equal(this.requests.length, 0, 'only made one request'); | 282 | QUnit.equal(this.requests.length, 0, 'only made one request'); |
283 | |||
284 | // verify stats | ||
285 | QUnit.equal(loader.mediaBytesTransferred, 10, '10 bytes'); | ||
286 | QUnit.equal(loader.mediaTransferDuration, 100, '100 ms (clock above)'); | ||
287 | QUnit.equal(loader.mediaRequests, 1, '1 request'); | ||
254 | }); | 288 | }); |
255 | 289 | ||
256 | QUnit.test('adjusts the playlist offset if no buffering progress is made', function() { | 290 | QUnit.test('adjusts the playlist offset if no buffering progress is made', function() { |
... | @@ -288,6 +322,11 @@ QUnit.test('adjusts the playlist offset if no buffering progress is made', funct | ... | @@ -288,6 +322,11 @@ QUnit.test('adjusts the playlist offset if no buffering progress is made', funct |
288 | 322 | ||
289 | // so the loader should try the next segment | 323 | // so the loader should try the next segment |
290 | QUnit.equal(this.requests[0].url, '1.ts', 'moved ahead a segment'); | 324 | QUnit.equal(this.requests[0].url, '1.ts', 'moved ahead a segment'); |
325 | |||
326 | // verify stats | ||
327 | QUnit.equal(loader.mediaBytesTransferred, 20, '20 bytes'); | ||
328 | QUnit.equal(loader.mediaTransferDuration, 2, '2 ms (clocks above)'); | ||
329 | QUnit.equal(loader.mediaRequests, 2, '2 requests'); | ||
291 | }); | 330 | }); |
292 | 331 | ||
293 | QUnit.test('never attempt to load a segment that ' + | 332 | QUnit.test('never attempt to load a segment that ' + |
... | @@ -319,6 +358,11 @@ QUnit.test('never attempt to load a segment that ' + | ... | @@ -319,6 +358,11 @@ QUnit.test('never attempt to load a segment that ' + |
319 | 358 | ||
320 | // the loader should move on to the next segment | 359 | // the loader should move on to the next segment |
321 | QUnit.equal(this.requests[0].url, '1.ts', 'moved ahead a segment'); | 360 | QUnit.equal(this.requests[0].url, '1.ts', 'moved ahead a segment'); |
361 | |||
362 | // verify stats | ||
363 | QUnit.equal(loader.mediaBytesTransferred, 10, '10 bytes'); | ||
364 | QUnit.equal(loader.mediaTransferDuration, 1, '1 ms (clocks above)'); | ||
365 | QUnit.equal(loader.mediaRequests, 1, '1 requests'); | ||
322 | }); | 366 | }); |
323 | 367 | ||
324 | QUnit.test('adjusts the playlist offset if no buffering progress is made', function() { | 368 | QUnit.test('adjusts the playlist offset if no buffering progress is made', function() { |
... | @@ -356,6 +400,11 @@ QUnit.test('adjusts the playlist offset if no buffering progress is made', funct | ... | @@ -356,6 +400,11 @@ QUnit.test('adjusts the playlist offset if no buffering progress is made', funct |
356 | 400 | ||
357 | // so the loader should try the next segment | 401 | // so the loader should try the next segment |
358 | QUnit.equal(this.requests[0].url, '1.ts', 'moved ahead a segment'); | 402 | QUnit.equal(this.requests[0].url, '1.ts', 'moved ahead a segment'); |
403 | |||
404 | // verify stats | ||
405 | QUnit.equal(loader.mediaBytesTransferred, 20, '20 bytes'); | ||
406 | QUnit.equal(loader.mediaTransferDuration, 2, '2 ms (clocks above)'); | ||
407 | QUnit.equal(loader.mediaRequests, 2, '2 requests'); | ||
359 | }); | 408 | }); |
360 | 409 | ||
361 | QUnit.test('adjusts the playlist offset even when segment.end is set if no' + | 410 | QUnit.test('adjusts the playlist offset even when segment.end is set if no' + |
... | @@ -453,6 +502,10 @@ QUnit.test('abort does not cancel segment processing in progress', function() { | ... | @@ -453,6 +502,10 @@ QUnit.test('abort does not cancel segment processing in progress', function() { |
453 | 502 | ||
454 | loader.abort(); | 503 | loader.abort(); |
455 | QUnit.equal(loader.state, 'APPENDING', 'still appending'); | 504 | QUnit.equal(loader.state, 'APPENDING', 'still appending'); |
505 | |||
506 | // verify stats | ||
507 | QUnit.equal(loader.mediaBytesTransferred, 10, '10 bytes'); | ||
508 | QUnit.equal(loader.mediaRequests, 1, '1 request'); | ||
456 | }); | 509 | }); |
457 | 510 | ||
458 | QUnit.test('sets the timestampOffset on timeline change', function() { | 511 | QUnit.test('sets the timestampOffset on timeline change', function() { |
... | @@ -474,6 +527,10 @@ QUnit.test('sets the timestampOffset on timeline change', function() { | ... | @@ -474,6 +527,10 @@ QUnit.test('sets the timestampOffset on timeline change', function() { |
474 | this.requests[0].response = new Uint8Array(10).buffer; | 527 | this.requests[0].response = new Uint8Array(10).buffer; |
475 | this.requests.shift().respond(200, null, ''); | 528 | this.requests.shift().respond(200, null, ''); |
476 | QUnit.equal(mediaSource.sourceBuffers[0].timestampOffset, 10, 'set timestampOffset'); | 529 | QUnit.equal(mediaSource.sourceBuffers[0].timestampOffset, 10, 'set timestampOffset'); |
530 | |||
531 | // verify stats | ||
532 | QUnit.equal(loader.mediaBytesTransferred, 20, '20 bytes'); | ||
533 | QUnit.equal(loader.mediaRequests, 2, '2 requests'); | ||
477 | }); | 534 | }); |
478 | 535 | ||
479 | QUnit.test('tracks segment end times as they are buffered', function() { | 536 | QUnit.test('tracks segment end times as they are buffered', function() { |
... | @@ -491,6 +548,10 @@ QUnit.test('tracks segment end times as they are buffered', function() { | ... | @@ -491,6 +548,10 @@ QUnit.test('tracks segment end times as they are buffered', function() { |
491 | ]); | 548 | ]); |
492 | mediaSource.sourceBuffers[0].trigger('updateend'); | 549 | mediaSource.sourceBuffers[0].trigger('updateend'); |
493 | QUnit.equal(playlist.segments[0].end, 9.5, 'updated duration'); | 550 | QUnit.equal(playlist.segments[0].end, 9.5, 'updated duration'); |
551 | |||
552 | // verify stats | ||
553 | QUnit.equal(loader.mediaBytesTransferred, 10, '10 bytes'); | ||
554 | QUnit.equal(loader.mediaRequests, 1, '1 request'); | ||
494 | }); | 555 | }); |
495 | 556 | ||
496 | QUnit.test('segment 404s should trigger an error', function() { | 557 | QUnit.test('segment 404s should trigger an error', function() { |
... | @@ -548,6 +609,10 @@ QUnit.test('fires ended at the end of a playlist', function() { | ... | @@ -548,6 +609,10 @@ QUnit.test('fires ended at the end of a playlist', function() { |
548 | mediaSource.sourceBuffers[0].buffered = videojs.createTimeRanges([[0, 10]]); | 609 | mediaSource.sourceBuffers[0].buffered = videojs.createTimeRanges([[0, 10]]); |
549 | mediaSource.sourceBuffers[0].trigger('updateend'); | 610 | mediaSource.sourceBuffers[0].trigger('updateend'); |
550 | QUnit.equal(endOfStreams, 1, 'triggered ended'); | 611 | QUnit.equal(endOfStreams, 1, 'triggered ended'); |
612 | |||
613 | // verify stats | ||
614 | QUnit.equal(loader.mediaBytesTransferred, 10, '10 bytes'); | ||
615 | QUnit.equal(loader.mediaRequests, 1, '1 request'); | ||
551 | }); | 616 | }); |
552 | 617 | ||
553 | QUnit.test('live playlists do not trigger ended', function() { | 618 | QUnit.test('live playlists do not trigger ended', function() { |
... | @@ -572,6 +637,10 @@ QUnit.test('live playlists do not trigger ended', function() { | ... | @@ -572,6 +637,10 @@ QUnit.test('live playlists do not trigger ended', function() { |
572 | mediaSource.sourceBuffers[0].buffered = videojs.createTimeRanges([[0, 10]]); | 637 | mediaSource.sourceBuffers[0].buffered = videojs.createTimeRanges([[0, 10]]); |
573 | mediaSource.sourceBuffers[0].trigger('updateend'); | 638 | mediaSource.sourceBuffers[0].trigger('updateend'); |
574 | QUnit.equal(endOfStreams, 0, 'did not trigger ended'); | 639 | QUnit.equal(endOfStreams, 0, 'did not trigger ended'); |
640 | |||
641 | // verify stats | ||
642 | QUnit.equal(loader.mediaBytesTransferred, 10, '10 bytes'); | ||
643 | QUnit.equal(loader.mediaRequests, 1, '1 request'); | ||
575 | }); | 644 | }); |
576 | 645 | ||
577 | QUnit.test('respects the global withCredentials option', function() { | 646 | QUnit.test('respects the global withCredentials option', function() { |
... | @@ -781,6 +850,10 @@ QUnit.test('the key is saved to the segment in the correct format', function() { | ... | @@ -781,6 +850,10 @@ QUnit.test('the key is saved to the segment in the correct format', function() { |
781 | QUnit.deepEqual(segment.key.bytes, | 850 | QUnit.deepEqual(segment.key.bytes, |
782 | new Uint32Array([0, 0x01000000, 0x02000000, 0x03000000]), | 851 | new Uint32Array([0, 0x01000000, 0x02000000, 0x03000000]), |
783 | 'passed the specified segment key'); | 852 | 'passed the specified segment key'); |
853 | |||
854 | // verify stats | ||
855 | QUnit.equal(loader.mediaBytesTransferred, 10, '10 bytes'); | ||
856 | QUnit.equal(loader.mediaRequests, 1, '1 request was completed'); | ||
784 | }); | 857 | }); |
785 | 858 | ||
786 | QUnit.test('supplies media sequence of current segment as the IV by default, if no IV ' + | 859 | QUnit.test('supplies media sequence of current segment as the IV by default, if no IV ' + |
... | @@ -811,6 +884,10 @@ function() { | ... | @@ -811,6 +884,10 @@ function() { |
811 | 884 | ||
812 | QUnit.deepEqual(segment.key.iv, new Uint32Array([0, 0, 0, 5]), | 885 | QUnit.deepEqual(segment.key.iv, new Uint32Array([0, 0, 0, 5]), |
813 | 'the IV for the segment is the media sequence'); | 886 | 'the IV for the segment is the media sequence'); |
887 | |||
888 | // verify stats | ||
889 | QUnit.equal(loader.mediaBytesTransferred, 10, '10 bytes'); | ||
890 | QUnit.equal(loader.mediaRequests, 1, '1 request'); | ||
814 | }); | 891 | }); |
815 | 892 | ||
816 | QUnit.test('segment with key has decrypted bytes appended during processing', function() { | 893 | QUnit.test('segment with key has decrypted bytes appended during processing', function() { |
... | @@ -839,6 +916,10 @@ QUnit.test('segment with key has decrypted bytes appended during processing', fu | ... | @@ -839,6 +916,10 @@ QUnit.test('segment with key has decrypted bytes appended during processing', fu |
839 | // Allow the decrypter's async stream to run the callback | 916 | // Allow the decrypter's async stream to run the callback |
840 | this.clock.tick(1); | 917 | this.clock.tick(1); |
841 | QUnit.ok(loader.pendingSegment_.bytes, 'decrypted bytes in segment'); | 918 | QUnit.ok(loader.pendingSegment_.bytes, 'decrypted bytes in segment'); |
919 | |||
920 | // verify stats | ||
921 | QUnit.equal(loader.mediaBytesTransferred, 8, '8 bytes'); | ||
922 | QUnit.equal(loader.mediaRequests, 1, '1 request'); | ||
842 | }); | 923 | }); |
843 | 924 | ||
844 | QUnit.test('calling load with an encrypted segment waits for both key and segment ' + | 925 | QUnit.test('calling load with an encrypted segment waits for both key and segment ' + |
... | @@ -864,6 +945,10 @@ QUnit.test('calling load with an encrypted segment waits for both key and segmen | ... | @@ -864,6 +945,10 @@ QUnit.test('calling load with an encrypted segment waits for both key and segmen |
864 | keyRequest.response = new Uint32Array([0, 0, 0, 0]).buffer; | 945 | keyRequest.response = new Uint32Array([0, 0, 0, 0]).buffer; |
865 | keyRequest.respond(200, null, ''); | 946 | keyRequest.respond(200, null, ''); |
866 | QUnit.equal(loader.state, 'DECRYPTING', 'moves to decrypting state'); | 947 | QUnit.equal(loader.state, 'DECRYPTING', 'moves to decrypting state'); |
948 | |||
949 | // verify stats | ||
950 | QUnit.equal(loader.mediaBytesTransferred, 10, '10 bytes'); | ||
951 | QUnit.equal(loader.mediaRequests, 1, '1 request'); | ||
867 | }); | 952 | }); |
868 | 953 | ||
869 | QUnit.test('key request timeouts reset bandwidth', function() { | 954 | QUnit.test('key request timeouts reset bandwidth', function() { | ... | ... |
... | @@ -139,6 +139,25 @@ QUnit.test('starts playing if autoplay is specified', function() { | ... | @@ -139,6 +139,25 @@ QUnit.test('starts playing if autoplay is specified', function() { |
139 | QUnit.ok(!this.player.paused(), 'not paused'); | 139 | QUnit.ok(!this.player.paused(), 'not paused'); |
140 | }); | 140 | }); |
141 | 141 | ||
142 | QUnit.test('stats are reset on each new source', function() { | ||
143 | this.player.src({ | ||
144 | src: 'manifest/playlist.m3u8', | ||
145 | type: 'application/vnd.apple.mpegurl' | ||
146 | }); | ||
147 | |||
148 | // make sure play() is called *after* the media source opens | ||
149 | openMediaSource(this.player, this.clock); | ||
150 | standardXHRResponse(this.requests.shift()); | ||
151 | standardXHRResponse(this.requests.shift()); | ||
152 | |||
153 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, 16, 'stat is set'); | ||
154 | this.player.src({ | ||
155 | src: 'manifest/master.m3u8', | ||
156 | type: 'application/vnd.apple.mpegurl' | ||
157 | }); | ||
158 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, 0, 'stat is reset'); | ||
159 | }); | ||
160 | |||
142 | QUnit.test('XHR requests first byte range on play', function() { | 161 | QUnit.test('XHR requests first byte range on play', function() { |
143 | this.player.src({ | 162 | this.player.src({ |
144 | src: 'manifest/playlist.m3u8', | 163 | src: 'manifest/playlist.m3u8', |
... | @@ -359,6 +378,10 @@ QUnit.test('starts downloading a segment on loadedmetadata', function() { | ... | @@ -359,6 +378,10 @@ QUnit.test('starts downloading a segment on loadedmetadata', function() { |
359 | QUnit.strictEqual(this.requests[1].url, | 378 | QUnit.strictEqual(this.requests[1].url, |
360 | absoluteUrl('manifest/media-00001.ts'), | 379 | absoluteUrl('manifest/media-00001.ts'), |
361 | 'the first segment is requested'); | 380 | 'the first segment is requested'); |
381 | |||
382 | // verify stats | ||
383 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, 16, '16 bytes'); | ||
384 | QUnit.equal(this.player.tech_.hls.stats.mediaRequests, 1, '1 request'); | ||
362 | }); | 385 | }); |
363 | 386 | ||
364 | QUnit.test('re-initializes the handler for each source', function() { | 387 | QUnit.test('re-initializes the handler for each source', function() { |
... | @@ -433,6 +456,10 @@ QUnit.test('downloads media playlists after loading the master', function() { | ... | @@ -433,6 +456,10 @@ QUnit.test('downloads media playlists after loading the master', function() { |
433 | QUnit.strictEqual(this.requests[2].url, | 456 | QUnit.strictEqual(this.requests[2].url, |
434 | absoluteUrl('manifest/media2-00001.ts'), | 457 | absoluteUrl('manifest/media2-00001.ts'), |
435 | 'first segment requested'); | 458 | 'first segment requested'); |
459 | |||
460 | // verify stats | ||
461 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, 16, '16 bytes'); | ||
462 | QUnit.equal(this.player.tech_.hls.stats.mediaRequests, 1, '1 request'); | ||
436 | }); | 463 | }); |
437 | 464 | ||
438 | QUnit.test('upshifts if the initial bandwidth hint is high', function() { | 465 | QUnit.test('upshifts if the initial bandwidth hint is high', function() { |
... | @@ -462,6 +489,10 @@ QUnit.test('upshifts if the initial bandwidth hint is high', function() { | ... | @@ -462,6 +489,10 @@ QUnit.test('upshifts if the initial bandwidth hint is high', function() { |
462 | absoluteUrl('manifest/media2-00001.ts'), | 489 | absoluteUrl('manifest/media2-00001.ts'), |
463 | 'first segment requested' | 490 | 'first segment requested' |
464 | ); | 491 | ); |
492 | |||
493 | // verify stats | ||
494 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, 16, '16 bytes'); | ||
495 | QUnit.equal(this.player.tech_.hls.stats.mediaRequests, 1, '1 request'); | ||
465 | }); | 496 | }); |
466 | 497 | ||
467 | QUnit.test('downshifts if the initial bandwidth hint is low', function() { | 498 | QUnit.test('downshifts if the initial bandwidth hint is low', function() { |
... | @@ -485,6 +516,10 @@ QUnit.test('downshifts if the initial bandwidth hint is low', function() { | ... | @@ -485,6 +516,10 @@ QUnit.test('downshifts if the initial bandwidth hint is low', function() { |
485 | QUnit.strictEqual(this.requests[2].url, | 516 | QUnit.strictEqual(this.requests[2].url, |
486 | absoluteUrl('manifest/media1-00001.ts'), | 517 | absoluteUrl('manifest/media1-00001.ts'), |
487 | 'first segment requested'); | 518 | 'first segment requested'); |
519 | |||
520 | // verify stats | ||
521 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, 16, '16 bytes'); | ||
522 | QUnit.equal(this.player.tech_.hls.stats.mediaRequests, 1, '1 request'); | ||
488 | }); | 523 | }); |
489 | 524 | ||
490 | QUnit.test('buffer checks are noops until a media playlist is ready', function() { | 525 | QUnit.test('buffer checks are noops until a media playlist is ready', function() { |
... | @@ -499,6 +534,7 @@ QUnit.test('buffer checks are noops until a media playlist is ready', function() | ... | @@ -499,6 +534,7 @@ QUnit.test('buffer checks are noops until a media playlist is ready', function() |
499 | QUnit.strictEqual(this.requests[0].url, | 534 | QUnit.strictEqual(this.requests[0].url, |
500 | 'manifest/media.m3u8', | 535 | 'manifest/media.m3u8', |
501 | 'media playlist requested'); | 536 | 'media playlist requested'); |
537 | |||
502 | }); | 538 | }); |
503 | 539 | ||
504 | QUnit.test('buffer checks are noops when only the master is ready', function() { | 540 | QUnit.test('buffer checks are noops when only the master is ready', function() { |
... | @@ -533,6 +569,9 @@ QUnit.test('buffer checks are noops when only the master is ready', function() { | ... | @@ -533,6 +569,9 @@ QUnit.test('buffer checks are noops when only the master is ready', function() { |
533 | QUnit.strictEqual(this.requests[0].url, | 569 | QUnit.strictEqual(this.requests[0].url, |
534 | absoluteUrl('manifest/media1.m3u8'), | 570 | absoluteUrl('manifest/media1.m3u8'), |
535 | 'media playlist requested'); | 571 | 'media playlist requested'); |
572 | |||
573 | // verify stats | ||
574 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 1, 'bandwidth set above'); | ||
536 | }); | 575 | }); |
537 | 576 | ||
538 | QUnit.test('selects a playlist below the current bandwidth', function() { | 577 | QUnit.test('selects a playlist below the current bandwidth', function() { |
... | @@ -556,6 +595,9 @@ QUnit.test('selects a playlist below the current bandwidth', function() { | ... | @@ -556,6 +595,9 @@ QUnit.test('selects a playlist below the current bandwidth', function() { |
556 | QUnit.strictEqual(playlist, | 595 | QUnit.strictEqual(playlist, |
557 | this.player.tech_.hls.playlists.master.playlists[1], | 596 | this.player.tech_.hls.playlists.master.playlists[1], |
558 | 'the low bitrate stream is selected'); | 597 | 'the low bitrate stream is selected'); |
598 | |||
599 | // verify stats | ||
600 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 10, 'bandwidth set above'); | ||
559 | }); | 601 | }); |
560 | 602 | ||
561 | QUnit.test('allows initial bandwidth to be provided', function() { | 603 | QUnit.test('allows initial bandwidth to be provided', function() { |
... | @@ -574,6 +616,9 @@ QUnit.test('allows initial bandwidth to be provided', function() { | ... | @@ -574,6 +616,9 @@ QUnit.test('allows initial bandwidth to be provided', function() { |
574 | QUnit.equal(this.player.tech_.hls.bandwidth, | 616 | QUnit.equal(this.player.tech_.hls.bandwidth, |
575 | 500, | 617 | 500, |
576 | 'prefers user-specified initial bandwidth'); | 618 | 'prefers user-specified initial bandwidth'); |
619 | |||
620 | // verify stats | ||
621 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 500, 'bandwidth set above'); | ||
577 | }); | 622 | }); |
578 | 623 | ||
579 | QUnit.test('raises the minimum bitrate for a stream proportionially', function() { | 624 | QUnit.test('raises the minimum bitrate for a stream proportionially', function() { |
... | @@ -598,6 +643,9 @@ QUnit.test('raises the minimum bitrate for a stream proportionially', function() | ... | @@ -598,6 +643,9 @@ QUnit.test('raises the minimum bitrate for a stream proportionially', function() |
598 | QUnit.strictEqual(playlist, | 643 | QUnit.strictEqual(playlist, |
599 | this.player.tech_.hls.playlists.master.playlists[1], | 644 | this.player.tech_.hls.playlists.master.playlists[1], |
600 | 'a lower bitrate stream is selected'); | 645 | 'a lower bitrate stream is selected'); |
646 | |||
647 | // verify stats | ||
648 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 11, 'bandwidth set above'); | ||
601 | }); | 649 | }); |
602 | 650 | ||
603 | QUnit.test('uses the lowest bitrate if no other is suitable', function() { | 651 | QUnit.test('uses the lowest bitrate if no other is suitable', function() { |
... | @@ -619,6 +667,9 @@ QUnit.test('uses the lowest bitrate if no other is suitable', function() { | ... | @@ -619,6 +667,9 @@ QUnit.test('uses the lowest bitrate if no other is suitable', function() { |
619 | QUnit.strictEqual(playlist, | 667 | QUnit.strictEqual(playlist, |
620 | this.player.tech_.hls.playlists.master.playlists[1], | 668 | this.player.tech_.hls.playlists.master.playlists[1], |
621 | 'the lowest bitrate stream is selected'); | 669 | 'the lowest bitrate stream is selected'); |
670 | |||
671 | // verify stats | ||
672 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 1, 'bandwidth set above'); | ||
622 | }); | 673 | }); |
623 | 674 | ||
624 | QUnit.test('selects the correct rendition by tech dimensions', function() { | 675 | QUnit.test('selects the correct rendition by tech dimensions', function() { |
... | @@ -683,6 +734,9 @@ QUnit.test('selects the correct rendition by tech dimensions', function() { | ... | @@ -683,6 +734,9 @@ QUnit.test('selects the correct rendition by tech dimensions', function() { |
683 | QUnit.equal(playlist.attributes.BANDWIDTH, | 734 | QUnit.equal(playlist.attributes.BANDWIDTH, |
684 | 440000, | 735 | 440000, |
685 | 'should have the expected bandwidth in case of multiple, if exact match'); | 736 | 'should have the expected bandwidth in case of multiple, if exact match'); |
737 | |||
738 | // verify stats | ||
739 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 3000000, 'bandwidth set above'); | ||
686 | }); | 740 | }); |
687 | 741 | ||
688 | QUnit.test('selects the highest bitrate playlist when the player dimensions are ' + | 742 | QUnit.test('selects the highest bitrate playlist when the player dimensions are ' + |
... | @@ -713,6 +767,9 @@ QUnit.test('selects the highest bitrate playlist when the player dimensions are | ... | @@ -713,6 +767,9 @@ QUnit.test('selects the highest bitrate playlist when the player dimensions are |
713 | QUnit.equal(playlist.attributes.BANDWIDTH, | 767 | QUnit.equal(playlist.attributes.BANDWIDTH, |
714 | 1000, | 768 | 1000, |
715 | 'selected the highest bandwidth variant'); | 769 | 'selected the highest bandwidth variant'); |
770 | |||
771 | // verify stats | ||
772 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 1e10, 'bandwidth set above'); | ||
716 | }); | 773 | }); |
717 | 774 | ||
718 | QUnit.test('filters playlists that are currently excluded', function() { | 775 | QUnit.test('filters playlists that are currently excluded', function() { |
... | @@ -748,6 +805,9 @@ QUnit.test('filters playlists that are currently excluded', function() { | ... | @@ -748,6 +805,9 @@ QUnit.test('filters playlists that are currently excluded', function() { |
748 | QUnit.equal(playlist, | 805 | QUnit.equal(playlist, |
749 | this.player.tech_.hls.playlists.master.playlists[0], | 806 | this.player.tech_.hls.playlists.master.playlists[0], |
750 | 'expired the exclusion'); | 807 | 'expired the exclusion'); |
808 | |||
809 | // verify stats | ||
810 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 1e10, 'bandwidth set above'); | ||
751 | }); | 811 | }); |
752 | 812 | ||
753 | QUnit.test('does not blacklist compatible H.264 codec strings', function() { | 813 | QUnit.test('does not blacklist compatible H.264 codec strings', function() { |
... | @@ -778,6 +838,9 @@ QUnit.test('does not blacklist compatible H.264 codec strings', function() { | ... | @@ -778,6 +838,9 @@ QUnit.test('does not blacklist compatible H.264 codec strings', function() { |
778 | QUnit.strictEqual(typeof master.playlists[1].excludeUntil, | 838 | QUnit.strictEqual(typeof master.playlists[1].excludeUntil, |
779 | 'undefined', | 839 | 'undefined', |
780 | 'did not blacklist'); | 840 | 'did not blacklist'); |
841 | |||
842 | // verify stats | ||
843 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 1, 'bandwidth set above'); | ||
781 | }); | 844 | }); |
782 | 845 | ||
783 | QUnit.test('does not blacklist compatible AAC codec strings', function() { | 846 | QUnit.test('does not blacklist compatible AAC codec strings', function() { |
... | @@ -808,6 +871,9 @@ QUnit.test('does not blacklist compatible AAC codec strings', function() { | ... | @@ -808,6 +871,9 @@ QUnit.test('does not blacklist compatible AAC codec strings', function() { |
808 | QUnit.strictEqual(typeof master.playlists[1].excludeUntil, | 871 | QUnit.strictEqual(typeof master.playlists[1].excludeUntil, |
809 | 'undefined', | 872 | 'undefined', |
810 | 'did not blacklist'); | 873 | 'did not blacklist'); |
874 | |||
875 | // verify stats | ||
876 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 1, 'bandwidth set above'); | ||
811 | }); | 877 | }); |
812 | 878 | ||
813 | QUnit.test('cancels outstanding XHRs when seeking', function() { | 879 | QUnit.test('cancels outstanding XHRs when seeking', function() { |
... | @@ -883,6 +949,9 @@ QUnit.test('segment 404 should trigger blacklisting of media', function() { | ... | @@ -883,6 +949,9 @@ QUnit.test('segment 404 should trigger blacklisting of media', function() { |
883 | this.requests[2].respond(400); | 949 | this.requests[2].respond(400); |
884 | QUnit.ok(media.excludeUntil > 0, 'original media blacklisted for some time'); | 950 | QUnit.ok(media.excludeUntil > 0, 'original media blacklisted for some time'); |
885 | QUnit.equal(this.env.log.warn.calls, 1, 'warning logged for blacklist'); | 951 | QUnit.equal(this.env.log.warn.calls, 1, 'warning logged for blacklist'); |
952 | |||
953 | // verify stats | ||
954 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 20000, 'bandwidth set above'); | ||
886 | }); | 955 | }); |
887 | 956 | ||
888 | QUnit.test('playlist 404 should blacklist media', function() { | 957 | QUnit.test('playlist 404 should blacklist media', function() { |
... | @@ -917,6 +986,8 @@ QUnit.test('playlist 404 should blacklist media', function() { | ... | @@ -917,6 +986,8 @@ QUnit.test('playlist 404 should blacklist media', function() { |
917 | QUnit.ok(media.excludeUntil > 0, 'original media blacklisted for some time'); | 986 | QUnit.ok(media.excludeUntil > 0, 'original media blacklisted for some time'); |
918 | QUnit.equal(this.env.log.warn.calls, 1, 'warning logged for blacklist'); | 987 | QUnit.equal(this.env.log.warn.calls, 1, 'warning logged for blacklist'); |
919 | 988 | ||
989 | // verify stats | ||
990 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 1e10, 'bandwidth set above'); | ||
920 | }); | 991 | }); |
921 | 992 | ||
922 | QUnit.test('seeking in an empty playlist is a non-erroring noop', function() { | 993 | QUnit.test('seeking in an empty playlist is a non-erroring noop', function() { |
... | @@ -965,6 +1036,9 @@ QUnit.test('fire loadedmetadata once we successfully load a playlist', function( | ... | @@ -965,6 +1036,9 @@ QUnit.test('fire loadedmetadata once we successfully load a playlist', function( |
965 | standardXHRResponse(this.requests.shift()); | 1036 | standardXHRResponse(this.requests.shift()); |
966 | QUnit.equal(count, 1, | 1037 | QUnit.equal(count, 1, |
967 | 'loadedMedia triggered after successful recovery from 404'); | 1038 | 'loadedMedia triggered after successful recovery from 404'); |
1039 | |||
1040 | // verify stats | ||
1041 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 20000, 'bandwidth set above'); | ||
968 | }); | 1042 | }); |
969 | 1043 | ||
970 | QUnit.test('sets seekable and duration for live playlists', function() { | 1044 | QUnit.test('sets seekable and duration for live playlists', function() { |
... | @@ -1221,6 +1295,9 @@ QUnit.test('resets the switching algorithm if a request times out', function() { | ... | @@ -1221,6 +1295,9 @@ QUnit.test('resets the switching algorithm if a request times out', function() { |
1221 | QUnit.strictEqual(this.player.tech_.hls.playlists.media(), | 1295 | QUnit.strictEqual(this.player.tech_.hls.playlists.media(), |
1222 | this.player.tech_.hls.playlists.master.playlists[1], | 1296 | this.player.tech_.hls.playlists.master.playlists[1], |
1223 | 'reset to the lowest bitrate playlist'); | 1297 | 'reset to the lowest bitrate playlist'); |
1298 | |||
1299 | // verify stats | ||
1300 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 1, 'bandwidth is reset too'); | ||
1224 | }); | 1301 | }); |
1225 | 1302 | ||
1226 | QUnit.test('disposes the playlist loader', function() { | 1303 | QUnit.test('disposes the playlist loader', function() { |
... | @@ -1411,6 +1488,10 @@ QUnit.test('calling play() at the end of a video replays', function() { | ... | @@ -1411,6 +1488,10 @@ QUnit.test('calling play() at the end of a video replays', function() { |
1411 | 1488 | ||
1412 | this.player.tech_.trigger('play'); | 1489 | this.player.tech_.trigger('play'); |
1413 | QUnit.equal(seekTime, 0, 'seeked to the beginning'); | 1490 | QUnit.equal(seekTime, 0, 'seeked to the beginning'); |
1491 | |||
1492 | // verify stats | ||
1493 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, 16, '16 bytes'); | ||
1494 | QUnit.equal(this.player.tech_.hls.stats.mediaRequests, 1, '1 request'); | ||
1414 | }); | 1495 | }); |
1415 | 1496 | ||
1416 | QUnit.test('keys are resolved relative to the master playlist', function() { | 1497 | QUnit.test('keys are resolved relative to the master playlist', function() { |
... | @@ -1435,6 +1516,9 @@ QUnit.test('keys are resolved relative to the master playlist', function() { | ... | @@ -1435,6 +1516,9 @@ QUnit.test('keys are resolved relative to the master playlist', function() { |
1435 | QUnit.equal(this.requests[0].url, | 1516 | QUnit.equal(this.requests[0].url, |
1436 | absoluteUrl('video/playlist/keys/key.php'), | 1517 | absoluteUrl('video/playlist/keys/key.php'), |
1437 | 'resolves multiple relative paths'); | 1518 | 'resolves multiple relative paths'); |
1519 | |||
1520 | // verify stats | ||
1521 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default'); | ||
1438 | }); | 1522 | }); |
1439 | 1523 | ||
1440 | QUnit.test('keys are resolved relative to their containing playlist', function() { | 1524 | QUnit.test('keys are resolved relative to their containing playlist', function() { |
... | @@ -1487,6 +1571,10 @@ QUnit.test('seeking should abort an outstanding key request and create a new one | ... | @@ -1487,6 +1571,10 @@ QUnit.test('seeking should abort an outstanding key request and create a new one |
1487 | 'https://example.com/' + | 1571 | 'https://example.com/' + |
1488 | this.player.tech_.hls.playlists.media().segments[1].key.uri, | 1572 | this.player.tech_.hls.playlists.media().segments[1].key.uri, |
1489 | 'urls should match'); | 1573 | 'urls should match'); |
1574 | |||
1575 | // verify stats | ||
1576 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, 16, '16 bytes'); | ||
1577 | QUnit.equal(this.player.tech_.hls.stats.mediaRequests, 1, '1 request'); | ||
1490 | }); | 1578 | }); |
1491 | 1579 | ||
1492 | QUnit.test('switching playlists with an outstanding key request aborts request and ' + | 1580 | QUnit.test('switching playlists with an outstanding key request aborts request and ' + |
... | @@ -1529,6 +1617,9 @@ QUnit.test('switching playlists with an outstanding key request aborts request a | ... | @@ -1529,6 +1617,9 @@ QUnit.test('switching playlists with an outstanding key request aborts request a |
1529 | QUnit.equal(this.requests[1].url, | 1617 | QUnit.equal(this.requests[1].url, |
1530 | 'http://media.example.com/fileSequence52-A.ts', | 1618 | 'http://media.example.com/fileSequence52-A.ts', |
1531 | 'requested the segment'); | 1619 | 'requested the segment'); |
1620 | // verify stats | ||
1621 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, 16, '16 bytes'); | ||
1622 | QUnit.equal(this.player.tech_.hls.stats.mediaRequests, 1, '1 request'); | ||
1532 | }); | 1623 | }); |
1533 | 1624 | ||
1534 | QUnit.test('does not download segments if preload option set to none', function() { | 1625 | QUnit.test('does not download segments if preload option set to none', function() { |
... | @@ -1549,6 +1640,9 @@ QUnit.test('does not download segments if preload option set to none', function( | ... | @@ -1549,6 +1640,9 @@ QUnit.test('does not download segments if preload option set to none', function( |
1549 | return !(/m3u8$/).test(request.uri); | 1640 | return !(/m3u8$/).test(request.uri); |
1550 | }); | 1641 | }); |
1551 | QUnit.equal(this.requests.length, 0, 'did not download any segments'); | 1642 | QUnit.equal(this.requests.length, 0, 'did not download any segments'); |
1643 | |||
1644 | // verify stats | ||
1645 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default'); | ||
1552 | }); | 1646 | }); |
1553 | 1647 | ||
1554 | // workaround https://bugzilla.mozilla.org/show_bug.cgi?id=548397 | 1648 | // workaround https://bugzilla.mozilla.org/show_bug.cgi?id=548397 |
... | @@ -1572,6 +1666,9 @@ QUnit.test('selectPlaylist does not fail if getComputedStyle returns null', func | ... | @@ -1572,6 +1666,9 @@ QUnit.test('selectPlaylist does not fail if getComputedStyle returns null', func |
1572 | this.player.tech_.hls.selectPlaylist(); | 1666 | this.player.tech_.hls.selectPlaylist(); |
1573 | QUnit.ok(true, 'should not throw'); | 1667 | QUnit.ok(true, 'should not throw'); |
1574 | window.getComputedStyle = oldGetComputedStyle; | 1668 | window.getComputedStyle = oldGetComputedStyle; |
1669 | |||
1670 | // verify stats | ||
1671 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default'); | ||
1575 | }); | 1672 | }); |
1576 | 1673 | ||
1577 | QUnit.test('resolves relative key URLs against the playlist', function() { | 1674 | QUnit.test('resolves relative key URLs against the playlist', function() { |
... | @@ -1608,6 +1705,9 @@ QUnit.test('adds 1 default audio track if we have not parsed any, and the playli | ... | @@ -1608,6 +1705,9 @@ QUnit.test('adds 1 default audio track if we have not parsed any, and the playli |
1608 | 1705 | ||
1609 | QUnit.equal(this.player.audioTracks().length, 1, 'one audio track after load'); | 1706 | QUnit.equal(this.player.audioTracks().length, 1, 'one audio track after load'); |
1610 | QUnit.ok(this.player.audioTracks()[0] instanceof HlsAudioTrack, 'audio track is an hls audio track'); | 1707 | QUnit.ok(this.player.audioTracks()[0] instanceof HlsAudioTrack, 'audio track is an hls audio track'); |
1708 | |||
1709 | // verify stats | ||
1710 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default'); | ||
1611 | }); | 1711 | }); |
1612 | 1712 | ||
1613 | QUnit.test('adds 1 default audio track if in flash mode', function() { | 1713 | QUnit.test('adds 1 default audio track if in flash mode', function() { |
... | @@ -1673,6 +1773,9 @@ QUnit.test('adds audio tracks if we have parsed some from a playlist', function( | ... | @@ -1673,6 +1773,9 @@ QUnit.test('adds audio tracks if we have parsed some from a playlist', function( |
1673 | 1773 | ||
1674 | QUnit.equal(vjsAudioTracks[1].enabled, false, 'main track is disabled'); | 1774 | QUnit.equal(vjsAudioTracks[1].enabled, false, 'main track is disabled'); |
1675 | QUnit.equal(hlsAudioTracks[1].enabled, false, 'main track is disabled'); | 1775 | QUnit.equal(hlsAudioTracks[1].enabled, false, 'main track is disabled'); |
1776 | |||
1777 | // verify stats | ||
1778 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default'); | ||
1676 | }); | 1779 | }); |
1677 | 1780 | ||
1678 | QUnit.test('audio info from audioinfo event is stored on hls', function() { | 1781 | QUnit.test('audio info from audioinfo event is stored on hls', function() { |
... | @@ -1754,6 +1857,9 @@ QUnit.test('audioinfo changes with three tracks, enabled track is blacklisted an | ... | @@ -1754,6 +1857,9 @@ QUnit.test('audioinfo changes with three tracks, enabled track is blacklisted an |
1754 | QUnit.equal(blacklistPlaylistCalls, 0, 'blacklist was not called on playlist'); | 1857 | QUnit.equal(blacklistPlaylistCalls, 0, 'blacklist was not called on playlist'); |
1755 | QUnit.equal(this.env.log.warn.calls, 1, 'firefox issue warning logged'); | 1858 | QUnit.equal(this.env.log.warn.calls, 1, 'firefox issue warning logged'); |
1756 | videojs.browser.IS_FIREFOX = oldIsFirefox; | 1859 | videojs.browser.IS_FIREFOX = oldIsFirefox; |
1860 | |||
1861 | // verify stats | ||
1862 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default'); | ||
1757 | }); | 1863 | }); |
1758 | 1864 | ||
1759 | QUnit.test('audioinfo changes with one track, blacklist playlist', function() { | 1865 | QUnit.test('audioinfo changes with one track, blacklist playlist', function() { |
... | @@ -1787,6 +1893,9 @@ QUnit.test('audioinfo changes with one track, blacklist playlist', function() { | ... | @@ -1787,6 +1893,9 @@ QUnit.test('audioinfo changes with one track, blacklist playlist', function() { |
1787 | QUnit.equal(blacklistPlaylistCalls, 1, 'blacklist was called on playlist'); | 1893 | QUnit.equal(blacklistPlaylistCalls, 1, 'blacklist was called on playlist'); |
1788 | QUnit.equal(this.env.log.warn.calls, 1, 'firefox issue warning logged'); | 1894 | QUnit.equal(this.env.log.warn.calls, 1, 'firefox issue warning logged'); |
1789 | videojs.browser.IS_FIREFOX = oldIsFirefox; | 1895 | videojs.browser.IS_FIREFOX = oldIsFirefox; |
1896 | |||
1897 | // verify stats | ||
1898 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default'); | ||
1790 | }); | 1899 | }); |
1791 | 1900 | ||
1792 | QUnit.test('audioinfo changes with three tracks, default is enabled, blacklisted playlist', function() { | 1901 | QUnit.test('audioinfo changes with three tracks, default is enabled, blacklisted playlist', function() { |
... | @@ -1835,6 +1944,9 @@ QUnit.test('audioinfo changes with three tracks, default is enabled, blacklisted | ... | @@ -1835,6 +1944,9 @@ QUnit.test('audioinfo changes with three tracks, default is enabled, blacklisted |
1835 | QUnit.equal(blacklistPlaylistCalls, 1, 'blacklist was called on playlist'); | 1944 | QUnit.equal(blacklistPlaylistCalls, 1, 'blacklist was called on playlist'); |
1836 | QUnit.equal(this.env.log.warn.calls, 1, 'firefox issue warning logged'); | 1945 | QUnit.equal(this.env.log.warn.calls, 1, 'firefox issue warning logged'); |
1837 | videojs.browser.IS_FIREFOX = oldIsFirefox; | 1946 | videojs.browser.IS_FIREFOX = oldIsFirefox; |
1947 | |||
1948 | // verify stats | ||
1949 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default'); | ||
1838 | }); | 1950 | }); |
1839 | 1951 | ||
1840 | QUnit.test('cleans up the buffer when loading live segments', function() { | 1952 | QUnit.test('cleans up the buffer when loading live segments', function() { |
... | @@ -1884,6 +1996,10 @@ QUnit.test('cleans up the buffer when loading live segments', function() { | ... | @@ -1884,6 +1996,10 @@ QUnit.test('cleans up the buffer when loading live segments', function() { |
1884 | QUnit.equal(removes.length, 1, 'remove called'); | 1996 | QUnit.equal(removes.length, 1, 'remove called'); |
1885 | QUnit.deepEqual(removes[0], [0, seekable.start(0)], | 1997 | QUnit.deepEqual(removes[0], [0, seekable.start(0)], |
1886 | 'remove called with the right range'); | 1998 | 'remove called with the right range'); |
1999 | |||
2000 | // verify stats | ||
2001 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, 16, '16 bytes'); | ||
2002 | QUnit.equal(this.player.tech_.hls.stats.mediaRequests, 1, '1 request'); | ||
1887 | }); | 2003 | }); |
1888 | 2004 | ||
1889 | QUnit.test('cleans up the buffer based on currentTime when loading a live segment ' + | 2005 | QUnit.test('cleans up the buffer based on currentTime when loading a live segment ' + |
... | @@ -1934,6 +2050,10 @@ QUnit.test('cleans up the buffer based on currentTime when loading a live segmen | ... | @@ -1934,6 +2050,10 @@ QUnit.test('cleans up the buffer based on currentTime when loading a live segmen |
1934 | QUnit.strictEqual(this.requests[0].url, 'liveStart30sBefore.m3u8', 'master playlist requested'); | 2050 | QUnit.strictEqual(this.requests[0].url, 'liveStart30sBefore.m3u8', 'master playlist requested'); |
1935 | QUnit.equal(removes.length, 1, 'remove called'); | 2051 | QUnit.equal(removes.length, 1, 'remove called'); |
1936 | QUnit.deepEqual(removes[0], [0, 80 - 60], 'remove called with the right range'); | 2052 | QUnit.deepEqual(removes[0], [0, 80 - 60], 'remove called with the right range'); |
2053 | |||
2054 | // verify stats | ||
2055 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, 16, '16 bytes'); | ||
2056 | QUnit.equal(this.player.tech_.hls.stats.mediaRequests, 1, '1 request'); | ||
1937 | }); | 2057 | }); |
1938 | 2058 | ||
1939 | QUnit.test('cleans up the buffer when loading VOD segments', function() { | 2059 | QUnit.test('cleans up the buffer when loading VOD segments', function() { |
... | @@ -1969,6 +2089,10 @@ QUnit.test('cleans up the buffer when loading VOD segments', function() { | ... | @@ -1969,6 +2089,10 @@ QUnit.test('cleans up the buffer when loading VOD segments', function() { |
1969 | 'media playlist requested'); | 2089 | 'media playlist requested'); |
1970 | QUnit.equal(removes.length, 1, 'remove called'); | 2090 | QUnit.equal(removes.length, 1, 'remove called'); |
1971 | QUnit.deepEqual(removes[0], [0, 120 - 60], 'remove called with the right range'); | 2091 | QUnit.deepEqual(removes[0], [0, 120 - 60], 'remove called with the right range'); |
2092 | |||
2093 | // verify stats | ||
2094 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, 16, '16 bytes'); | ||
2095 | QUnit.equal(this.player.tech_.hls.stats.mediaRequests, 1, '1 request'); | ||
1972 | }); | 2096 | }); |
1973 | 2097 | ||
1974 | QUnit.test('when mediaGroup changes enabled track should not change', function() { | 2098 | QUnit.test('when mediaGroup changes enabled track should not change', function() { |
... | @@ -2042,6 +2166,9 @@ QUnit.test('when mediaGroup changes enabled track should not change', function() | ... | @@ -2042,6 +2166,9 @@ QUnit.test('when mediaGroup changes enabled track should not change', function() |
2042 | QUnit.equal(trackOne.enabled, false, 'track 1 - still disabled'); | 2166 | QUnit.equal(trackOne.enabled, false, 'track 1 - still disabled'); |
2043 | QUnit.equal(trackTwo.enabled, true, 'track 2 - still enabled'); | 2167 | QUnit.equal(trackTwo.enabled, true, 'track 2 - still enabled'); |
2044 | QUnit.equal(trackThree.enabled, false, 'track 3 - disabled'); | 2168 | QUnit.equal(trackThree.enabled, false, 'track 3 - disabled'); |
2169 | |||
2170 | // verify stats | ||
2171 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default'); | ||
2045 | }); | 2172 | }); |
2046 | 2173 | ||
2047 | QUnit.test('Allows specifying the beforeRequest function on the player', function() { | 2174 | QUnit.test('Allows specifying the beforeRequest function on the player', function() { |
... | @@ -2062,6 +2189,9 @@ QUnit.test('Allows specifying the beforeRequest function on the player', functio | ... | @@ -2062,6 +2189,9 @@ QUnit.test('Allows specifying the beforeRequest function on the player', functio |
2062 | standardXHRResponse(this.requests.shift()); | 2189 | standardXHRResponse(this.requests.shift()); |
2063 | 2190 | ||
2064 | QUnit.ok(beforeRequestCalled, 'beforeRequest was called'); | 2191 | QUnit.ok(beforeRequestCalled, 'beforeRequest was called'); |
2192 | |||
2193 | // verify stats | ||
2194 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default'); | ||
2065 | }); | 2195 | }); |
2066 | 2196 | ||
2067 | QUnit.test('Allows specifying the beforeRequest function globally', function() { | 2197 | QUnit.test('Allows specifying the beforeRequest function globally', function() { |
... | @@ -2082,6 +2212,9 @@ QUnit.test('Allows specifying the beforeRequest function globally', function() { | ... | @@ -2082,6 +2212,9 @@ QUnit.test('Allows specifying the beforeRequest function globally', function() { |
2082 | QUnit.ok(beforeRequestCalled, 'beforeRequest was called'); | 2212 | QUnit.ok(beforeRequestCalled, 'beforeRequest was called'); |
2083 | 2213 | ||
2084 | delete videojs.Hls.xhr.beforeRequest; | 2214 | delete videojs.Hls.xhr.beforeRequest; |
2215 | |||
2216 | // verify stats | ||
2217 | QUnit.equal(this.player.tech_.hls.stats.bandwidth, 4194304, 'default'); | ||
2085 | }); | 2218 | }); |
2086 | 2219 | ||
2087 | QUnit.test('Allows overriding the global beforeRequest function', function() { | 2220 | QUnit.test('Allows overriding the global beforeRequest function', function() { |
... | @@ -2114,6 +2247,10 @@ QUnit.test('Allows overriding the global beforeRequest function', function() { | ... | @@ -2114,6 +2247,10 @@ QUnit.test('Allows overriding the global beforeRequest function', function() { |
2114 | 'for the master playlist'); | 2247 | 'for the master playlist'); |
2115 | 2248 | ||
2116 | delete videojs.Hls.xhr.beforeRequest; | 2249 | delete videojs.Hls.xhr.beforeRequest; |
2250 | |||
2251 | // verify stats | ||
2252 | QUnit.equal(this.player.tech_.hls.stats.mediaBytesTransferred, 16, 'seen above'); | ||
2253 | QUnit.equal(this.player.tech_.hls.stats.mediaRequests, 1, 'one segment request'); | ||
2117 | }); | 2254 | }); |
2118 | 2255 | ||
2119 | QUnit.module('HLS Integration', { | 2256 | QUnit.module('HLS Integration', { |
... | @@ -2151,6 +2288,26 @@ QUnit.test('aborts all in-flight work when disposed', function() { | ... | @@ -2151,6 +2288,26 @@ QUnit.test('aborts all in-flight work when disposed', function() { |
2151 | }); | 2288 | }); |
2152 | }); | 2289 | }); |
2153 | 2290 | ||
2291 | QUnit.test('stats are reset on dispose', function() { | ||
2292 | let hls = HlsSourceHandler('html5').handleSource({ | ||
2293 | src: 'manifest/master.m3u8', | ||
2294 | type: 'application/vnd.apple.mpegurl' | ||
2295 | }, this.tech); | ||
2296 | |||
2297 | hls.mediaSource.trigger('sourceopen'); | ||
2298 | // master | ||
2299 | standardXHRResponse(this.requests.shift()); | ||
2300 | // media | ||
2301 | standardXHRResponse(this.requests.shift()); | ||
2302 | |||
2303 | // media | ||
2304 | standardXHRResponse(this.requests.shift()); | ||
2305 | |||
2306 | QUnit.equal(hls.stats.mediaBytesTransferred, 16, 'stat is set'); | ||
2307 | hls.dispose(); | ||
2308 | QUnit.equal(hls.stats.mediaBytesTransferred, 0, 'stat is reset'); | ||
2309 | }); | ||
2310 | |||
2154 | QUnit.test('detects fullscreen and triggers a quality change', function() { | 2311 | QUnit.test('detects fullscreen and triggers a quality change', function() { |
2155 | let qualityChanges = 0; | 2312 | let qualityChanges = 0; |
2156 | let hls = HlsSourceHandler('html5').handleSource({ | 2313 | let hls = HlsSourceHandler('html5').handleSource({ |
... | @@ -2215,6 +2372,11 @@ QUnit.test('downloads additional playlists if required', function() { | ... | @@ -2215,6 +2372,11 @@ QUnit.test('downloads additional playlists if required', function() { |
2215 | hls.playlists.media().resolvedUri, | 2372 | hls.playlists.media().resolvedUri, |
2216 | 'a new playlists was selected'); | 2373 | 'a new playlists was selected'); |
2217 | QUnit.ok(hls.playlists.media().segments, 'segments are now available'); | 2374 | QUnit.ok(hls.playlists.media().segments, 'segments are now available'); |
2375 | |||
2376 | // verify stats | ||
2377 | QUnit.equal(hls.stats.bandwidth, 3000000, 'default'); | ||
2378 | QUnit.equal(hls.stats.mediaBytesTransferred, 16, '16 bytes'); | ||
2379 | QUnit.equal(hls.stats.mediaRequests, 1, '1 request'); | ||
2218 | }); | 2380 | }); |
2219 | 2381 | ||
2220 | QUnit.test('waits to download new segments until the media playlist is stable', function() { | 2382 | QUnit.test('waits to download new segments until the media playlist is stable', function() { |
... | @@ -2251,6 +2413,11 @@ QUnit.test('waits to download new segments until the media playlist is stable', | ... | @@ -2251,6 +2413,11 @@ QUnit.test('waits to download new segments until the media playlist is stable', |
2251 | standardXHRResponse(this.requests.shift()); | 2413 | standardXHRResponse(this.requests.shift()); |
2252 | this.clock.tick(10 * 1000); | 2414 | this.clock.tick(10 * 1000); |
2253 | QUnit.equal(this.requests.length, 1, 'resumes segment fetching'); | 2415 | QUnit.equal(this.requests.length, 1, 'resumes segment fetching'); |
2416 | |||
2417 | // verify stats | ||
2418 | QUnit.equal(hls.stats.bandwidth, Infinity, 'default'); | ||
2419 | QUnit.equal(hls.stats.mediaBytesTransferred, 16, '16 bytes'); | ||
2420 | QUnit.equal(hls.stats.mediaRequests, 1, '1 request'); | ||
2254 | }); | 2421 | }); |
2255 | 2422 | ||
2256 | QUnit.test('live playlist starts three target durations before live', function() { | 2423 | QUnit.test('live playlist starts three target durations before live', function() { |
... | @@ -2286,6 +2453,7 @@ QUnit.test('live playlist starts three target durations before live', function() | ... | @@ -2286,6 +2453,7 @@ QUnit.test('live playlist starts three target durations before live', function() |
2286 | 'seeked to the seekable end'); | 2453 | 'seeked to the seekable end'); |
2287 | 2454 | ||
2288 | QUnit.equal(this.requests.length, 1, 'begins buffering'); | 2455 | QUnit.equal(this.requests.length, 1, 'begins buffering'); |
2456 | |||
2289 | }); | 2457 | }); |
2290 | 2458 | ||
2291 | QUnit.module('HLS - Encryption', { | 2459 | QUnit.module('HLS - Encryption', { |
... | @@ -2361,4 +2529,8 @@ QUnit.test('treats invalid keys as a key request failure and blacklists playlist | ... | @@ -2361,4 +2529,8 @@ QUnit.test('treats invalid keys as a key request failure and blacklists playlist |
2361 | QUnit.ok(hls.playlists.media().excludeUntil > 0, | 2529 | QUnit.ok(hls.playlists.media().excludeUntil > 0, |
2362 | 'blacklisted playlist'); | 2530 | 'blacklisted playlist'); |
2363 | QUnit.equal(this.env.log.warn.calls, 1, 'logged warning for blacklist'); | 2531 | QUnit.equal(this.env.log.warn.calls, 1, 'logged warning for blacklist'); |
2532 | |||
2533 | // verify stats | ||
2534 | QUnit.equal(hls.stats.mediaBytesTransferred, 16, '16 bytes'); | ||
2535 | QUnit.equal(hls.stats.mediaRequests, 1, '1 request'); | ||
2364 | }); | 2536 | }); | ... | ... |
-
Please register or sign in to post a comment