fcebc231 by David LaPalomento

Abort key XHRs on media change

If a key request was outstanding when the media playlist changed, the call to fetchKeys() for the new playlist would be ignored. This caused segments to get stuck in drainBuffer() waiting for their keys. Now, we abort key requests as soon as we change media and immediately try to fetch the keys for the new playlist.
1 parent 4dc56848
...@@ -127,9 +127,16 @@ videojs.Hls.prototype.handleSourceOpen = function() { ...@@ -127,9 +127,16 @@ videojs.Hls.prototype.handleSourceOpen = function() {
127 this.fetchKeys(updatedPlaylist, this.mediaIndex); 127 this.fetchKeys(updatedPlaylist, this.mediaIndex);
128 })); 128 }));
129 129
130 this.playlists.on('mediachange', function() { 130 this.playlists.on('mediachange', videojs.bind(this, function() {
131 // abort outstanding key requests and check if new keys need to be retrieved
132 if (keyXhr) {
133 keyXhr.abort();
134 keyXhr = null;
135 this.fetchKeys(this.playlists.media(), this.mediaIndex);
136 }
137
131 player.trigger('mediachange'); 138 player.trigger('mediachange');
132 }); 139 }));
133 140
134 // if autoplay is enabled, begin playback. This is duplicative of 141 // if autoplay is enabled, begin playback. This is duplicative of
135 // code in video.js but is required because play() must be invoked 142 // code in video.js but is required because play() must be invoked
......
...@@ -1626,4 +1626,42 @@ test('supplies the media sequence of current segment as the IV by default, if no ...@@ -1626,4 +1626,42 @@ test('supplies the media sequence of current segment as the IV by default, if no
1626 'the IV for the segment is the media sequence'); 1626 'the IV for the segment is the media sequence');
1627 }); 1627 });
1628 1628
1629 test('switching playlists with an outstanding key request does not stall playback', function() {
1630 var media = '#EXTM3U\n' +
1631 '#EXT-X-MEDIA-SEQUENCE:5\n' +
1632 '#EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=52"\n' +
1633 '#EXTINF:2.833,\n' +
1634 'http://media.example.com/fileSequence52-A.ts\n' +
1635 '#EXTINF:15.0,\n' +
1636 'http://media.example.com/fileSequence52-B.ts\n';
1637 player.src({
1638 src: 'https://example.com/master.m3u8',
1639 type: 'application/vnd.apple.mpegurl'
1640 });
1641 openMediaSource(player);
1642
1643 // master playlist
1644 standardXHRResponse(requests.shift());
1645 // media playlist
1646 requests.shift().respond(200, null, media);
1647 // mock out media switching from this point on
1648 player.hls.playlists.media = function() {
1649 return player.hls.playlists.master.playlists[0];
1650 };
1651 // don't respond to the initial key request
1652 requests.shift();
1653 // first segment of the original media playlist
1654 standardXHRResponse(requests.shift());
1655
1656 // "switch" media
1657 player.hls.playlists.trigger('mediachange');
1658
1659 player.trigger('timeupdate');
1660
1661 ok(requests.length, 'made a request');
1662 equal(requests[0].url,
1663 'https://priv.example.com/key.php?r=52',
1664 'requested the segment and key');
1665 });
1666
1629 })(window, window.videojs); 1667 })(window, window.videojs);
......