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.
Showing
2 changed files
with
47 additions
and
2 deletions
... | @@ -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); | ... | ... |
-
Please register or sign in to post a comment