From fcebc231bdd72a7cd908049b4ef78ba74c0500f0 Mon Sep 17 00:00:00 2001 From: David LaPalomento Date: Thu, 21 Aug 2014 14:40:20 -0400 Subject: [PATCH] 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. --- src/videojs-hls.js | 11 +++++++++-- test/videojs-hls_test.js | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/videojs-hls.js b/src/videojs-hls.js index ed98b652..159a6801 100644 --- a/src/videojs-hls.js +++ b/src/videojs-hls.js @@ -127,9 +127,16 @@ videojs.Hls.prototype.handleSourceOpen = function() { this.fetchKeys(updatedPlaylist, this.mediaIndex); })); - this.playlists.on('mediachange', function() { + this.playlists.on('mediachange', videojs.bind(this, function() { + // abort outstanding key requests and check if new keys need to be retrieved + if (keyXhr) { + keyXhr.abort(); + keyXhr = null; + this.fetchKeys(this.playlists.media(), this.mediaIndex); + } + player.trigger('mediachange'); - }); + })); // if autoplay is enabled, begin playback. This is duplicative of // code in video.js but is required because play() must be invoked diff --git a/test/videojs-hls_test.js b/test/videojs-hls_test.js index a3b7a2b7..87848fcd 100644 --- a/test/videojs-hls_test.js +++ b/test/videojs-hls_test.js @@ -1626,4 +1626,42 @@ test('supplies the media sequence of current segment as the IV by default, if no 'the IV for the segment is the media sequence'); }); +test('switching playlists with an outstanding key request does not stall playback', function() { + var media = '#EXTM3U\n' + + '#EXT-X-MEDIA-SEQUENCE:5\n' + + '#EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=52"\n' + + '#EXTINF:2.833,\n' + + 'http://media.example.com/fileSequence52-A.ts\n' + + '#EXTINF:15.0,\n' + + 'http://media.example.com/fileSequence52-B.ts\n'; + player.src({ + src: 'https://example.com/master.m3u8', + type: 'application/vnd.apple.mpegurl' + }); + openMediaSource(player); + + // master playlist + standardXHRResponse(requests.shift()); + // media playlist + requests.shift().respond(200, null, media); + // mock out media switching from this point on + player.hls.playlists.media = function() { + return player.hls.playlists.master.playlists[0]; + }; + // don't respond to the initial key request + requests.shift(); + // first segment of the original media playlist + standardXHRResponse(requests.shift()); + + // "switch" media + player.hls.playlists.trigger('mediachange'); + + player.trigger('timeupdate'); + + ok(requests.length, 'made a request'); + equal(requests[0].url, + 'https://priv.example.com/key.php?r=52', + 'requested the segment and key'); +}); + })(window, window.videojs);