73b4ab8f by David LaPalomento

Merge pull request #156 from videojs/abortxhr

null out segmentXhr, remove event handlers on dispose
2 parents c9bfe153 d78cee51
...@@ -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) {
......