Merge pull request #178 from videojs/pre-segment-switch
Pre segment switch
Showing
9 changed files
with
161 additions
and
39 deletions
... | @@ -29,12 +29,13 @@ | ... | @@ -29,12 +29,13 @@ |
29 | "karma-firefox-launcher": "~0.1.3", | 29 | "karma-firefox-launcher": "~0.1.3", |
30 | "karma-ie-launcher": "~0.1.1", | 30 | "karma-ie-launcher": "~0.1.1", |
31 | "karma-opera-launcher": "~0.1.0", | 31 | "karma-opera-launcher": "~0.1.0", |
32 | "karma-phantomjs-launcher": "~0.1.1", | 32 | "karma-phantomjs-launcher": "^0.1.4", |
33 | "karma-qunit": "~0.1.1", | 33 | "karma-qunit": "~0.1.1", |
34 | "karma-safari-launcher": "~0.1.1", | 34 | "karma-safari-launcher": "~0.1.1", |
35 | "karma-sauce-launcher": "~0.1.8", | 35 | "karma-sauce-launcher": "~0.1.8", |
36 | "qunitjs": "^1.15.0", | ||
36 | "sinon": "1.10.2", | 37 | "sinon": "1.10.2", |
37 | "video.js": "^4.7.2" | 38 | "video.js": "^4.9.0" |
38 | }, | 39 | }, |
39 | "dependencies": { | 40 | "dependencies": { |
40 | "pkcs7": "^0.2.2", | 41 | "pkcs7": "^0.2.2", | ... | ... |
... | @@ -58,6 +58,8 @@ | ... | @@ -58,6 +58,8 @@ |
58 | haveMetadata = function(error, xhr, url) { | 58 | haveMetadata = function(error, xhr, url) { |
59 | var parser, refreshDelay, update; | 59 | var parser, refreshDelay, update; |
60 | 60 | ||
61 | loader.setBandwidth(request || xhr); | ||
62 | |||
61 | // any in-flight request is now finished | 63 | // any in-flight request is now finished |
62 | request = null; | 64 | request = null; |
63 | 65 | ||
... | @@ -200,6 +202,10 @@ | ... | @@ -200,6 +202,10 @@ |
200 | }); | 202 | }); |
201 | }; | 203 | }; |
202 | 204 | ||
205 | loader.setBandwidth = function(xhr) { | ||
206 | loader.bandwidth = xhr.bandwidth; | ||
207 | }; | ||
208 | |||
203 | // live playlist staleness timeout | 209 | // live playlist staleness timeout |
204 | loader.on('mediaupdatetimeout', function() { | 210 | loader.on('mediaupdatetimeout', function() { |
205 | if (loader.state !== 'HAVE_METADATA') { | 211 | if (loader.state !== 'HAVE_METADATA') { | ... | ... |
... | @@ -101,19 +101,58 @@ videojs.Hls.prototype.handleSourceOpen = function() { | ... | @@ -101,19 +101,58 @@ videojs.Hls.prototype.handleSourceOpen = function() { |
101 | sourceBuffer.appendBuffer(this.segmentParser_.getFlvHeader()); | 101 | sourceBuffer.appendBuffer(this.segmentParser_.getFlvHeader()); |
102 | 102 | ||
103 | this.mediaIndex = 0; | 103 | this.mediaIndex = 0; |
104 | |||
105 | if (this.playlists) { | ||
106 | this.playlists.dispose(); | ||
107 | } | ||
108 | |||
104 | this.playlists = new videojs.Hls.PlaylistLoader(this.src_, settings.withCredentials); | 109 | this.playlists = new videojs.Hls.PlaylistLoader(this.src_, settings.withCredentials); |
105 | 110 | ||
106 | this.playlists.on('loadedmetadata', videojs.bind(this, function() { | 111 | this.playlists.on('loadedmetadata', videojs.bind(this, function() { |
112 | var selectedPlaylist, loaderHandler, newBitrate, segmentDuration, | ||
113 | segmentDlTime, setupEvents, threshold; | ||
114 | |||
115 | setupEvents = function() { | ||
116 | this.fillBuffer(); | ||
117 | |||
118 | // periodically check if new data needs to be downloaded or | ||
119 | // buffered data should be appended to the source buffer | ||
120 | player.on('timeupdate', videojs.bind(this, this.fillBuffer)); | ||
121 | player.on('timeupdate', videojs.bind(this, this.drainBuffer)); | ||
122 | player.on('waiting', videojs.bind(this, this.drainBuffer)); | ||
123 | |||
124 | player.trigger('loadedmetadata'); | ||
125 | }; | ||
126 | |||
107 | oldMediaPlaylist = this.playlists.media(); | 127 | oldMediaPlaylist = this.playlists.media(); |
128 | this.bandwidth = this.playlists.bandwidth; | ||
129 | selectedPlaylist = this.selectPlaylist(); | ||
130 | newBitrate = selectedPlaylist.attributes && | ||
131 | selectedPlaylist.attributes.BANDWIDTH; | ||
132 | segmentDuration = oldMediaPlaylist.segments && | ||
133 | oldMediaPlaylist.segments[this.mediaIndex].duration || | ||
134 | oldMediaPlaylist.targetDuration; | ||
135 | |||
136 | segmentDlTime = (segmentDuration * newBitrate) / this.bandwidth; | ||
137 | |||
138 | if (!segmentDlTime) { | ||
139 | segmentDlTime = Infinity; | ||
140 | } | ||
108 | 141 | ||
109 | // periodically check if new data needs to be downloaded or | 142 | // this threshold is to account for having a high latency on the manifest |
110 | // buffered data should be appended to the source buffer | 143 | // request which is a somewhat small file. |
111 | this.fillBuffer(); | 144 | threshold = 10; |
112 | player.on('timeupdate', videojs.bind(this, this.fillBuffer)); | ||
113 | player.on('timeupdate', videojs.bind(this, this.drainBuffer)); | ||
114 | player.on('waiting', videojs.bind(this, this.drainBuffer)); | ||
115 | 145 | ||
116 | player.trigger('loadedmetadata'); | 146 | if (segmentDlTime <= threshold) { |
147 | this.playlists.media(selectedPlaylist); | ||
148 | loaderHandler = videojs.bind(this, function() { | ||
149 | setupEvents.call(this); | ||
150 | this.playlists.off('loadedplaylist', loaderHandler); | ||
151 | }); | ||
152 | this.playlists.on('loadedplaylist', loaderHandler); | ||
153 | } else { | ||
154 | setupEvents.call(this); | ||
155 | } | ||
117 | })); | 156 | })); |
118 | 157 | ||
119 | this.playlists.on('error', videojs.bind(this, function() { | 158 | this.playlists.on('error', videojs.bind(this, function() { |
... | @@ -409,12 +448,27 @@ videojs.Hls.prototype.fillBuffer = function(offset) { | ... | @@ -409,12 +448,27 @@ videojs.Hls.prototype.fillBuffer = function(offset) { |
409 | this.loadSegment(segmentUri, offset); | 448 | this.loadSegment(segmentUri, offset); |
410 | }; | 449 | }; |
411 | 450 | ||
451 | /* | ||
452 | * Sets `bandwidth`, `segmentXhrTime`, and appends to the `bytesReceived. | ||
453 | * Expects an object with: | ||
454 | * * `roundTripTime` - the round trip time for the request we're setting the time for | ||
455 | * * `bandwidth` - the bandwidth we want to set | ||
456 | * * `bytesReceived` - amount of bytes downloaded | ||
457 | * `bandwidth` is the only required property. | ||
458 | */ | ||
459 | videojs.Hls.prototype.setBandwidth = function(xhr) { | ||
460 | var tech = this; | ||
461 | // calculate the download bandwidth | ||
462 | tech.segmentXhrTime = xhr.roundTripTime; | ||
463 | tech.bandwidth = xhr.bandwidth; | ||
464 | tech.bytesReceived += xhr.bytesReceived || 0; | ||
465 | }; | ||
466 | |||
412 | videojs.Hls.prototype.loadSegment = function(segmentUri, offset) { | 467 | videojs.Hls.prototype.loadSegment = function(segmentUri, offset) { |
413 | var | 468 | var |
414 | tech = this, | 469 | tech = this, |
415 | player = this.player(), | 470 | player = this.player(), |
416 | settings = player.options().hls || {}, | 471 | settings = player.options().hls || {}; |
417 | startTime = +new Date(); | ||
418 | 472 | ||
419 | // request the next segment | 473 | // request the next segment |
420 | this.segmentXhr_ = videojs.Hls.xhr({ | 474 | this.segmentXhr_ = videojs.Hls.xhr({ |
... | @@ -448,10 +502,7 @@ videojs.Hls.prototype.loadSegment = function(segmentUri, offset) { | ... | @@ -448,10 +502,7 @@ videojs.Hls.prototype.loadSegment = function(segmentUri, offset) { |
448 | return; | 502 | return; |
449 | } | 503 | } |
450 | 504 | ||
451 | // calculate the download bandwidth | 505 | tech.setBandwidth(this); |
452 | tech.segmentXhrTime = (+new Date()) - startTime; | ||
453 | tech.bandwidth = (this.response.byteLength / tech.segmentXhrTime) * 8 * 1000; | ||
454 | tech.bytesReceived += this.response.byteLength; | ||
455 | 506 | ||
456 | // package up all the work to append the segment | 507 | // package up all the work to append the segment |
457 | // if the segment is the start of a timestamp discontinuity, | 508 | // if the segment is the start of a timestamp discontinuity, | ... | ... |
... | @@ -34,6 +34,7 @@ | ... | @@ -34,6 +34,7 @@ |
34 | request = new window.XMLHttpRequest(); | 34 | request = new window.XMLHttpRequest(); |
35 | request.open(options.method, url); | 35 | request.open(options.method, url); |
36 | request.url = url; | 36 | request.url = url; |
37 | request.requestTime = new Date().getTime(); | ||
37 | 38 | ||
38 | if (options.responseType) { | 39 | if (options.responseType) { |
39 | request.responseType = options.responseType; | 40 | request.responseType = options.responseType; |
... | @@ -69,6 +70,13 @@ | ... | @@ -69,6 +70,13 @@ |
69 | return callback.call(this, true, url); | 70 | return callback.call(this, true, url); |
70 | } | 71 | } |
71 | 72 | ||
73 | if (this.response) { | ||
74 | this.responseTime = new Date().getTime(); | ||
75 | this.roundTripTime = this.responseTime - this.requestTime; | ||
76 | this.bytesReceived = this.response.byteLength || this.response.length; | ||
77 | this.bandwidth = Math.floor((this.bytesReceived / this.roundTripTime) * 8 * 1000); | ||
78 | } | ||
79 | |||
72 | return callback.call(this, false, url); | 80 | return callback.call(this, false, url); |
73 | }; | 81 | }; |
74 | request.send(null); | 82 | request.send(null); | ... | ... |
... | @@ -5,21 +5,21 @@ | ... | @@ -5,21 +5,21 @@ |
5 | "segments": [ | 5 | "segments": [ |
6 | { | 6 | { |
7 | "duration": 10, | 7 | "duration": 10, |
8 | "uri": "00001.ts" | 8 | "uri": "media-00001.ts" |
9 | }, | 9 | }, |
10 | { | 10 | { |
11 | "duration": 10, | 11 | "duration": 10, |
12 | "uri": "00002.ts" | 12 | "uri": "media-00002.ts" |
13 | }, | 13 | }, |
14 | { | 14 | { |
15 | "duration": 10, | 15 | "duration": 10, |
16 | "uri": "00003.ts" | 16 | "uri": "media-00003.ts" |
17 | }, | 17 | }, |
18 | { | 18 | { |
19 | "duration": 10, | 19 | "duration": 10, |
20 | "uri": "00004.ts" | 20 | "uri": "media-00004.ts" |
21 | } | 21 | } |
22 | ], | 22 | ], |
23 | "targetDuration": 10, | 23 | "targetDuration": 10, |
24 | "endList": true | 24 | "endList": true |
25 | } | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
25 | } | ... | ... |
... | @@ -2,12 +2,12 @@ | ... | @@ -2,12 +2,12 @@ |
2 | #EXT-X-PLAYLIST-TYPE:VOD | 2 | #EXT-X-PLAYLIST-TYPE:VOD |
3 | #EXT-X-TARGETDURATION:10 | 3 | #EXT-X-TARGETDURATION:10 |
4 | #EXTINF:10, | 4 | #EXTINF:10, |
5 | 00001.ts | 5 | media-00001.ts |
6 | #EXTINF:10, | 6 | #EXTINF:10, |
7 | 00002.ts | 7 | media-00002.ts |
8 | #EXTINF:10, | 8 | #EXTINF:10, |
9 | 00003.ts | 9 | media-00003.ts |
10 | #EXTINF:10, | 10 | #EXTINF:10, |
11 | 00004.ts | 11 | media-00004.ts |
12 | #ZEN-TOTAL-DURATION:57.9911 | 12 | #ZEN-TOTAL-DURATION:57.9911 |
13 | #EXT-X-ENDLIST | 13 | #EXT-X-ENDLIST | ... | ... |
... | @@ -2,12 +2,12 @@ | ... | @@ -2,12 +2,12 @@ |
2 | #EXT-X-PLAYLIST-TYPE:VOD | 2 | #EXT-X-PLAYLIST-TYPE:VOD |
3 | #EXT-X-TARGETDURATION:10 | 3 | #EXT-X-TARGETDURATION:10 |
4 | #EXTINF:10, | 4 | #EXTINF:10, |
5 | 00001.ts | 5 | media1-00001.ts |
6 | #EXTINF:10, | 6 | #EXTINF:10, |
7 | 00002.ts | 7 | media1-00002.ts |
8 | #EXTINF:10, | 8 | #EXTINF:10, |
9 | 00003.ts | 9 | media1-00003.ts |
10 | #EXTINF:10, | 10 | #EXTINF:10, |
11 | 00004.ts | 11 | media1-00004.ts |
12 | #ZEN-TOTAL-DURATION:57.9911 | 12 | #ZEN-TOTAL-DURATION:57.9911 |
13 | #EXT-X-ENDLIST | 13 | #EXT-X-ENDLIST | ... | ... |
... | @@ -2,12 +2,12 @@ | ... | @@ -2,12 +2,12 @@ |
2 | #EXT-X-PLAYLIST-TYPE:VOD | 2 | #EXT-X-PLAYLIST-TYPE:VOD |
3 | #EXT-X-TARGETDURATION:10 | 3 | #EXT-X-TARGETDURATION:10 |
4 | #EXTINF:10, | 4 | #EXTINF:10, |
5 | 00001.ts | 5 | media3-00001.ts |
6 | #EXTINF:10, | 6 | #EXTINF:10, |
7 | 00002.ts | 7 | media3-00002.ts |
8 | #EXTINF:10, | 8 | #EXTINF:10, |
9 | 00003.ts | 9 | media3-00003.ts |
10 | #EXTINF:10, | 10 | #EXTINF:10, |
11 | 00004.ts | 11 | media3-00004.ts |
12 | #ZEN-TOTAL-DURATION:57.9911 | 12 | #ZEN-TOTAL-DURATION:57.9911 |
13 | #EXT-X-ENDLIST | 13 | #EXT-X-ENDLIST | ... | ... |
... | @@ -260,7 +260,7 @@ test('starts downloading a segment on loadedmetadata', function() { | ... | @@ -260,7 +260,7 @@ test('starts downloading a segment on loadedmetadata', function() { |
260 | strictEqual(requests[1].url, | 260 | strictEqual(requests[1].url, |
261 | window.location.origin + | 261 | window.location.origin + |
262 | window.location.pathname.split('/').slice(0, -1).join('/') + | 262 | window.location.pathname.split('/').slice(0, -1).join('/') + |
263 | '/manifest/00001.ts', | 263 | '/manifest/media-00001.ts', |
264 | 'the first segment is requested'); | 264 | 'the first segment is requested'); |
265 | }); | 265 | }); |
266 | 266 | ||
... | @@ -349,8 +349,41 @@ test('downloads media playlists after loading the master', function() { | ... | @@ -349,8 +349,41 @@ test('downloads media playlists after loading the master', function() { |
349 | openMediaSource(player); | 349 | openMediaSource(player); |
350 | 350 | ||
351 | standardXHRResponse(requests[0]); | 351 | standardXHRResponse(requests[0]); |
352 | |||
353 | // set bandwidth to a high number, so, we don't switch; | ||
354 | player.hls.bandwidth = 500000; | ||
355 | standardXHRResponse(requests[1]); | ||
356 | standardXHRResponse(requests[2]); | ||
357 | |||
358 | strictEqual(requests[0].url, 'manifest/master.m3u8', 'master playlist requested'); | ||
359 | strictEqual(requests[1].url, | ||
360 | window.location.origin + | ||
361 | window.location.pathname.split('/').slice(0, -1).join('/') + | ||
362 | '/manifest/media.m3u8', | ||
363 | 'media playlist requested'); | ||
364 | strictEqual(requests[2].url, | ||
365 | window.location.origin + | ||
366 | window.location.pathname.split('/').slice(0, -1).join('/') + | ||
367 | '/manifest/media-00001.ts', | ||
368 | 'first segment requested'); | ||
369 | }); | ||
370 | |||
371 | test('downloads a second media playlist before playback, if bandwidth is high', function() { | ||
372 | player.src({ | ||
373 | src: 'manifest/master.m3u8', | ||
374 | type: 'application/vnd.apple.mpegurl' | ||
375 | }); | ||
376 | openMediaSource(player); | ||
377 | |||
378 | standardXHRResponse(requests[0]); | ||
379 | |||
380 | player.hls.playlists.setBandwidth = function() { | ||
381 | player.hls.playlists.bandwidth = 100000; | ||
382 | }; | ||
383 | |||
352 | standardXHRResponse(requests[1]); | 384 | standardXHRResponse(requests[1]); |
353 | standardXHRResponse(requests[2]); | 385 | standardXHRResponse(requests[2]); |
386 | standardXHRResponse(requests[3]); | ||
354 | 387 | ||
355 | strictEqual(requests[0].url, 'manifest/master.m3u8', 'master playlist requested'); | 388 | strictEqual(requests[0].url, 'manifest/master.m3u8', 'master playlist requested'); |
356 | strictEqual(requests[1].url, | 389 | strictEqual(requests[1].url, |
... | @@ -361,7 +394,12 @@ test('downloads media playlists after loading the master', function() { | ... | @@ -361,7 +394,12 @@ test('downloads media playlists after loading the master', function() { |
361 | strictEqual(requests[2].url, | 394 | strictEqual(requests[2].url, |
362 | window.location.origin + | 395 | window.location.origin + |
363 | window.location.pathname.split('/').slice(0, -1).join('/') + | 396 | window.location.pathname.split('/').slice(0, -1).join('/') + |
364 | '/manifest/00001.ts', | 397 | '/manifest/media1.m3u8', |
398 | 'media playlist requested'); | ||
399 | strictEqual(requests[3].url, | ||
400 | window.location.origin + | ||
401 | window.location.pathname.split('/').slice(0, -1).join('/') + | ||
402 | '/manifest/media1-00001.ts', | ||
365 | 'first segment requested'); | 403 | 'first segment requested'); |
366 | }); | 404 | }); |
367 | 405 | ||
... | @@ -385,6 +423,10 @@ test('calculates the bandwidth after downloading a segment', function() { | ... | @@ -385,6 +423,10 @@ test('calculates the bandwidth after downloading a segment', function() { |
385 | openMediaSource(player); | 423 | openMediaSource(player); |
386 | 424 | ||
387 | standardXHRResponse(requests[0]); | 425 | standardXHRResponse(requests[0]); |
426 | |||
427 | // set the request time to be a bit earlier so our bandwidth calculations are not NaN | ||
428 | requests[1].requestTime = (new Date())-100; | ||
429 | |||
388 | standardXHRResponse(requests[1]); | 430 | standardXHRResponse(requests[1]); |
389 | 431 | ||
390 | ok(player.hls.bandwidth, 'bandwidth is calculated'); | 432 | ok(player.hls.bandwidth, 'bandwidth is calculated'); |
... | @@ -407,10 +449,12 @@ test('selects a playlist after segment downloads', function() { | ... | @@ -407,10 +449,12 @@ test('selects a playlist after segment downloads', function() { |
407 | openMediaSource(player); | 449 | openMediaSource(player); |
408 | 450 | ||
409 | standardXHRResponse(requests[0]); | 451 | standardXHRResponse(requests[0]); |
452 | |||
453 | player.hls.bandwidth = 3000000; | ||
410 | standardXHRResponse(requests[1]); | 454 | standardXHRResponse(requests[1]); |
411 | standardXHRResponse(requests[2]); | 455 | standardXHRResponse(requests[2]); |
412 | 456 | ||
413 | strictEqual(calls, 1, 'selects after the initial segment'); | 457 | strictEqual(calls, 2, 'selects after the initial segment'); |
414 | player.currentTime = function() { | 458 | player.currentTime = function() { |
415 | return 1; | 459 | return 1; |
416 | }; | 460 | }; |
... | @@ -420,7 +464,8 @@ test('selects a playlist after segment downloads', function() { | ... | @@ -420,7 +464,8 @@ test('selects a playlist after segment downloads', function() { |
420 | player.trigger('timeupdate'); | 464 | player.trigger('timeupdate'); |
421 | 465 | ||
422 | standardXHRResponse(requests[3]); | 466 | standardXHRResponse(requests[3]); |
423 | strictEqual(calls, 2, 'selects after additional segments'); | 467 | |
468 | strictEqual(calls, 3, 'selects after additional segments'); | ||
424 | }); | 469 | }); |
425 | 470 | ||
426 | test('moves to the next segment if there is a network error', function() { | 471 | test('moves to the next segment if there is a network error', function() { |
... | @@ -433,6 +478,8 @@ test('moves to the next segment if there is a network error', function() { | ... | @@ -433,6 +478,8 @@ test('moves to the next segment if there is a network error', function() { |
433 | openMediaSource(player); | 478 | openMediaSource(player); |
434 | 479 | ||
435 | standardXHRResponse(requests[0]); | 480 | standardXHRResponse(requests[0]); |
481 | |||
482 | player.hls.bandwidth = 3000000; | ||
436 | standardXHRResponse(requests[1]); | 483 | standardXHRResponse(requests[1]); |
437 | 484 | ||
438 | mediaIndex = player.hls.mediaIndex; | 485 | mediaIndex = player.hls.mediaIndex; |
... | @@ -486,6 +533,8 @@ test('downloads additional playlists if required', function() { | ... | @@ -486,6 +533,8 @@ test('downloads additional playlists if required', function() { |
486 | openMediaSource(player); | 533 | openMediaSource(player); |
487 | 534 | ||
488 | standardXHRResponse(requests[0]); | 535 | standardXHRResponse(requests[0]); |
536 | |||
537 | player.hls.bandwidth = 3000000; | ||
489 | standardXHRResponse(requests[1]); | 538 | standardXHRResponse(requests[1]); |
490 | // before an m3u8 is downloaded, no segments are available | 539 | // before an m3u8 is downloaded, no segments are available |
491 | player.hls.selectPlaylist = function() { | 540 | player.hls.selectPlaylist = function() { |
... | @@ -661,7 +710,7 @@ test('downloads the next segment if the buffer is getting low', function() { | ... | @@ -661,7 +710,7 @@ test('downloads the next segment if the buffer is getting low', function() { |
661 | strictEqual(requests[2].url, | 710 | strictEqual(requests[2].url, |
662 | window.location.origin + | 711 | window.location.origin + |
663 | window.location.pathname.split('/').slice(0, -1).join('/') + | 712 | window.location.pathname.split('/').slice(0, -1).join('/') + |
664 | '/manifest/00002.ts', | 713 | '/manifest/media-00002.ts', |
665 | 'made segment request'); | 714 | 'made segment request'); |
666 | }); | 715 | }); |
667 | 716 | ||
... | @@ -1161,6 +1210,8 @@ test('resets the switching algorithm if a request times out', function() { | ... | @@ -1161,6 +1210,8 @@ test('resets the switching algorithm if a request times out', function() { |
1161 | }); | 1210 | }); |
1162 | openMediaSource(player); | 1211 | openMediaSource(player); |
1163 | standardXHRResponse(requests.shift()); // master | 1212 | standardXHRResponse(requests.shift()); // master |
1213 | |||
1214 | player.hls.bandwidth = 3000000; | ||
1164 | standardXHRResponse(requests.shift()); // media.m3u8 | 1215 | standardXHRResponse(requests.shift()); // media.m3u8 |
1165 | // simulate a segment timeout | 1216 | // simulate a segment timeout |
1166 | requests[0].timedout = true; | 1217 | requests[0].timedout = true; |
... | @@ -1207,7 +1258,10 @@ test('remove event handlers on dispose', function() { | ... | @@ -1207,7 +1258,10 @@ test('remove event handlers on dispose', function() { |
1207 | oldOn.call(player, type, handler); | 1258 | oldOn.call(player, type, handler); |
1208 | }; | 1259 | }; |
1209 | player.off = function(type, handler) { | 1260 | player.off = function(type, handler) { |
1210 | offhandlers++; | 1261 | // ignore the top-level videojs removals that aren't relevant to HLS |
1262 | if (type && type !== 'dispose') { | ||
1263 | offhandlers++; | ||
1264 | } | ||
1211 | oldOff.call(player, type, handler); | 1265 | oldOff.call(player, type, handler); |
1212 | }; | 1266 | }; |
1213 | player.src({ | 1267 | player.src({ |
... | @@ -1215,7 +1269,9 @@ test('remove event handlers on dispose', function() { | ... | @@ -1215,7 +1269,9 @@ test('remove event handlers on dispose', function() { |
1215 | type: 'application/vnd.apple.mpegurl' | 1269 | type: 'application/vnd.apple.mpegurl' |
1216 | }); | 1270 | }); |
1217 | openMediaSource(player); | 1271 | openMediaSource(player); |
1218 | player.hls.playlists.trigger('loadedmetadata'); | 1272 | |
1273 | standardXHRResponse(requests[0]); | ||
1274 | standardXHRResponse(requests[1]); | ||
1219 | 1275 | ||
1220 | player.dispose(); | 1276 | player.dispose(); |
1221 | 1277 | ... | ... |
-
Please register or sign in to post a comment