Merge pull request #156 from videojs/abortxhr
null out segmentXhr, remove event handlers on dispose
Showing
2 changed files
with
101 additions
and
1 deletions
... | @@ -188,7 +188,9 @@ videojs.Hls.prototype.setCurrentTime = function(currentTime) { | ... | @@ -188,7 +188,9 @@ videojs.Hls.prototype.setCurrentTime = function(currentTime) { |
188 | 188 | ||
189 | // cancel outstanding requests and buffer appends | 189 | // cancel outstanding requests and buffer appends |
190 | if (this.segmentXhr_) { | 190 | if (this.segmentXhr_) { |
191 | this.segmentXhr_.onreadystatechange = null; | ||
191 | this.segmentXhr_.abort(); | 192 | this.segmentXhr_.abort(); |
193 | this.segmentXhr_ = null; | ||
192 | } | 194 | } |
193 | 195 | ||
194 | // fetch new encryption keys, if necessary | 196 | // fetch new encryption keys, if necessary |
... | @@ -232,9 +234,17 @@ videojs.Hls.prototype.updateDuration = function(playlist) { | ... | @@ -232,9 +234,17 @@ videojs.Hls.prototype.updateDuration = function(playlist) { |
232 | * Abort all outstanding work and cleanup. | 234 | * Abort all outstanding work and cleanup. |
233 | */ | 235 | */ |
234 | videojs.Hls.prototype.dispose = function() { | 236 | videojs.Hls.prototype.dispose = function() { |
237 | var player = this.player(); | ||
238 | |||
239 | // remove event handlers | ||
240 | player.off('timeupdate', this.fillBuffer); | ||
241 | player.off('timeupdate', this.drainBuffer); | ||
242 | player.off('waiting', this.drainBuffer); | ||
243 | |||
235 | if (this.segmentXhr_) { | 244 | if (this.segmentXhr_) { |
236 | this.segmentXhr_.onreadystatechange = null; | 245 | this.segmentXhr_.onreadystatechange = null; |
237 | this.segmentXhr_.abort(); | 246 | this.segmentXhr_.abort(); |
247 | this.segmentXhr_ = null; | ||
238 | } | 248 | } |
239 | if (keyXhr) { | 249 | if (keyXhr) { |
240 | keyXhr.onreadystatechange = null; | 250 | keyXhr.onreadystatechange = null; | ... | ... |
... | @@ -710,6 +710,62 @@ test('cancels outstanding XHRs when seeking', function() { | ... | @@ -710,6 +710,62 @@ test('cancels outstanding XHRs when seeking', function() { |
710 | strictEqual(requests.length, 3, 'opened new XHR'); | 710 | strictEqual(requests.length, 3, 'opened new XHR'); |
711 | }); | 711 | }); |
712 | 712 | ||
713 | test('when outstanding XHRs are cancelled, they get aborted properly', function() { | ||
714 | var readystatechanges = 0; | ||
715 | |||
716 | player.src({ | ||
717 | src: 'manifest/media.m3u8', | ||
718 | type: 'application/vnd.apple.mpegurl' | ||
719 | }); | ||
720 | openMediaSource(player); | ||
721 | standardXHRResponse(requests[0]); | ||
722 | |||
723 | // trigger a segment download request | ||
724 | player.trigger('timeupdate'); | ||
725 | |||
726 | player.hls.segmentXhr_.onreadystatechange = function() { | ||
727 | readystatechanges++; | ||
728 | }; | ||
729 | |||
730 | // attempt to seek while the download is in progress | ||
731 | player.currentTime(12); | ||
732 | |||
733 | ok(requests[1].aborted, 'XHR aborted'); | ||
734 | strictEqual(requests.length, 3, 'opened new XHR'); | ||
735 | notEqual(player.hls.segmentXhr_.url, requests[1].url, 'a new segment is request that is not the aborted one'); | ||
736 | strictEqual(readystatechanges, 0, 'onreadystatechange was not called'); | ||
737 | }); | ||
738 | |||
739 | test('segmentXhr is properly nulled out when dispose is called', function() { | ||
740 | var | ||
741 | readystatechanges = 0, | ||
742 | oldDispose = videojs.Flash.prototype.dispose; | ||
743 | videojs.Flash.prototype.dispose = function() {}; | ||
744 | |||
745 | player.src({ | ||
746 | src: 'manifest/media.m3u8', | ||
747 | type: 'application/vnd.apple.mpegurl' | ||
748 | }); | ||
749 | openMediaSource(player); | ||
750 | standardXHRResponse(requests[0]); | ||
751 | |||
752 | // trigger a segment download request | ||
753 | player.trigger('timeupdate'); | ||
754 | |||
755 | player.hls.segmentXhr_.onreadystatechange = function() { | ||
756 | readystatechanges++; | ||
757 | }; | ||
758 | |||
759 | player.hls.dispose(); | ||
760 | |||
761 | ok(requests[1].aborted, 'XHR aborted'); | ||
762 | strictEqual(requests.length, 2, 'did not open a new XHR'); | ||
763 | equal(player.hls.segmentXhr_, null, 'the segment xhr is nulled out'); | ||
764 | strictEqual(readystatechanges, 0, 'onreadystatechange was not called'); | ||
765 | |||
766 | videojs.Flash.prototype.dispose = oldDispose; | ||
767 | }); | ||
768 | |||
713 | test('flushes the parser after each segment', function() { | 769 | test('flushes the parser after each segment', function() { |
714 | var flushes = 0; | 770 | var flushes = 0; |
715 | // mock out the segment parser | 771 | // mock out the segment parser |
... | @@ -1126,6 +1182,40 @@ test('disposes the playlist loader', function() { | ... | @@ -1126,6 +1182,40 @@ test('disposes the playlist loader', function() { |
1126 | strictEqual(disposes, 1, 'disposed playlist loader'); | 1182 | strictEqual(disposes, 1, 'disposed playlist loader'); |
1127 | }); | 1183 | }); |
1128 | 1184 | ||
1185 | test('remove event handlers on dispose', function() { | ||
1186 | var | ||
1187 | player, | ||
1188 | onhandlers = 0, | ||
1189 | offhandlers = 0, | ||
1190 | oldOn, | ||
1191 | oldOff; | ||
1192 | |||
1193 | player = createPlayer(); | ||
1194 | oldOn = player.on; | ||
1195 | oldOff = player.off; | ||
1196 | player.on = function(type, handler) { | ||
1197 | onhandlers++; | ||
1198 | oldOn.call(player, type, handler); | ||
1199 | }; | ||
1200 | player.off = function(type, handler) { | ||
1201 | offhandlers++; | ||
1202 | oldOff.call(player, type, handler); | ||
1203 | }; | ||
1204 | player.src({ | ||
1205 | src: 'manifest/master.m3u8', | ||
1206 | type: 'application/vnd.apple.mpegurl' | ||
1207 | }); | ||
1208 | openMediaSource(player); | ||
1209 | player.hls.playlists.trigger('loadedmetadata'); | ||
1210 | |||
1211 | player.dispose(); | ||
1212 | |||
1213 | equal(offhandlers, onhandlers, 'the amount of on and off handlers is the same'); | ||
1214 | |||
1215 | player.off = oldOff; | ||
1216 | player.on = oldOn; | ||
1217 | }); | ||
1218 | |||
1129 | test('aborts the source buffer on disposal', function() { | 1219 | test('aborts the source buffer on disposal', function() { |
1130 | var aborts = 0, player; | 1220 | var aborts = 0, player; |
1131 | player = createPlayer(); | 1221 | player = createPlayer(); |
... | @@ -1247,7 +1337,7 @@ test('can be disposed before finishing initialization', function() { | ... | @@ -1247,7 +1337,7 @@ test('can be disposed before finishing initialization', function() { |
1247 | ok(readyHandlers.length > 0, 'registered a ready handler'); | 1337 | ok(readyHandlers.length > 0, 'registered a ready handler'); |
1248 | try { | 1338 | try { |
1249 | while (readyHandlers.length) { | 1339 | while (readyHandlers.length) { |
1250 | readyHandlers.shift()(); | 1340 | readyHandlers.shift().call(player); |
1251 | } | 1341 | } |
1252 | ok(true, 'did not throw an exception'); | 1342 | ok(true, 'did not throw an exception'); |
1253 | } catch (e) { | 1343 | } catch (e) { | ... | ... |
-
Please register or sign in to post a comment