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
214 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() { | ... | ... |
This diff is collapsed.
Click to expand it.
-
Please register or sign in to post a comment