Implement blacklisting of playlists in response to some common errors
Showing
1 changed file
with
38 additions
and
21 deletions
... | @@ -7,17 +7,18 @@ | ... | @@ -7,17 +7,18 @@ |
7 | 'use strict'; | 7 | 'use strict'; |
8 | 8 | ||
9 | var | 9 | var |
10 | // a fudge factor to apply to advertised playlist bitrates to account for | 10 | // A fudge factor to apply to advertised playlist bitrates to account for |
11 | // temporary flucations in client bandwidth | 11 | // temporary flucations in client bandwidth |
12 | bandwidthVariance = 1.2, | 12 | bandwidthVariance = 1.2, |
13 | blacklistDuration = 5 * 60 * 1000, // 2 minute blacklist | ||
14 | TIME_FUDGE_FACTOR = 1 / 60, // Fudge factor to account for TimeRanges rounding | ||
13 | Component = videojs.getComponent('Component'), | 15 | Component = videojs.getComponent('Component'), |
14 | 16 | ||
15 | // the amount of time to wait between checking the state of the buffer | 17 | // The amount of time to wait between checking the state of the buffer |
16 | bufferCheckInterval = 500, | 18 | bufferCheckInterval = 500, |
17 | 19 | ||
18 | keyFailed, | 20 | keyFailed, |
19 | resolveUrl, | 21 | resolveUrl; |
20 | TIME_FUDGE_FACTOR = 1 / 60; | ||
21 | 22 | ||
22 | // returns true if a key has failed to download within a certain amount of retries | 23 | // returns true if a key has failed to download within a certain amount of retries |
23 | keyFailed = function(key) { | 24 | keyFailed = function(key) { |
... | @@ -179,15 +180,7 @@ videojs.HlsHandler.prototype.src = function(src) { | ... | @@ -179,15 +180,7 @@ videojs.HlsHandler.prototype.src = function(src) { |
179 | }.bind(this)); | 180 | }.bind(this)); |
180 | 181 | ||
181 | this.playlists.on('error', function() { | 182 | this.playlists.on('error', function() { |
182 | // close the media source with the appropriate error type | 183 | this.blacklistCurrentPlaylist_(this.playlists.error.code); |
183 | if (this.playlists.error.code === 2) { | ||
184 | this.mediaSource.endOfStream('network'); | ||
185 | } else if (this.playlists.error.code === 4) { | ||
186 | this.mediaSource.endOfStream('decode'); | ||
187 | } | ||
188 | |||
189 | // if this error is unrecognized, pass it along to the tech | ||
190 | this.tech_.error(this.playlists.error); | ||
191 | }.bind(this)); | 184 | }.bind(this)); |
192 | 185 | ||
193 | this.playlists.on('loadedplaylist', function() { | 186 | this.playlists.on('loadedplaylist', function() { |
... | @@ -916,6 +909,26 @@ videojs.HlsHandler.prototype.setBandwidth = function(xhr) { | ... | @@ -916,6 +909,26 @@ videojs.HlsHandler.prototype.setBandwidth = function(xhr) { |
916 | this.tech_.trigger('bandwidthupdate'); | 909 | this.tech_.trigger('bandwidthupdate'); |
917 | }; | 910 | }; |
918 | 911 | ||
912 | videojs.HlsHandler.prototype.blacklistCurrentPlaylist_ = function(error) { | ||
913 | var nextPlaylist; | ||
914 | |||
915 | // Blacklist this playlist | ||
916 | this.playlists.media().excludeUntil = Date.now() + blacklistDuration; | ||
917 | |||
918 | // Select a new playlist | ||
919 | nextPlaylist = this.selectPlaylist(); | ||
920 | |||
921 | if (nextPlaylist) { | ||
922 | videojs.log.warn('Problem encountered with the current HLS playlist. Switching to another playlist.'); | ||
923 | return this.playlists.media(nextPlaylist); | ||
924 | } else { | ||
925 | videojs.log.warn('Problem encountered with the current HLS playlist. No suitable alternatives found.'); | ||
926 | // We have no more playlists we can select so we must fail | ||
927 | this.error = error; | ||
928 | return this.mediaSource.endOfStream('network'); | ||
929 | } | ||
930 | }; | ||
931 | |||
919 | videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) { | 932 | videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) { |
920 | var | 933 | var |
921 | self = this, | 934 | self = this, |
... | @@ -930,7 +943,11 @@ videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) { | ... | @@ -930,7 +943,11 @@ videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) { |
930 | this.segmentXhr_ = videojs.Hls.xhr({ | 943 | this.segmentXhr_ = videojs.Hls.xhr({ |
931 | uri: segmentInfo.uri, | 944 | uri: segmentInfo.uri, |
932 | responseType: 'arraybuffer', | 945 | responseType: 'arraybuffer', |
933 | withCredentials: this.source_.withCredentials | 946 | withCredentials: this.source_.withCredentials, |
947 | // Set xhr timeout to 150% of the segment duration to allow us | ||
948 | // some time to switch renditions in the event of a catastrophic | ||
949 | // decrease in network performance or a server issue. | ||
950 | timeout: (segment.duration * 1.5) * 1000 | ||
934 | }, function(error, request) { | 951 | }, function(error, request) { |
935 | // the segment request is no longer outstanding | 952 | // the segment request is no longer outstanding |
936 | self.segmentXhr_ = null; | 953 | self.segmentXhr_ = null; |
... | @@ -943,13 +960,12 @@ videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) { | ... | @@ -943,13 +960,12 @@ videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) { |
943 | 960 | ||
944 | // otherwise, trigger a network error | 961 | // otherwise, trigger a network error |
945 | if (!request.aborted && error) { | 962 | if (!request.aborted && error) { |
946 | self.error = { | 963 | self.pendingSegment_ = null; |
964 | return self.blacklistCurrentPlaylist_({ | ||
947 | status: request.status, | 965 | status: request.status, |
948 | message: 'HLS segment request error at URL: ' + segmentInfo.uri, | 966 | message: 'HLS segment request error at URL: ' + segmentInfo.uri, |
949 | code: (request.status >= 500) ? 4 : 2 | 967 | code: (request.status >= 500) ? 4 : 2 |
950 | }; | 968 | }); |
951 | |||
952 | return self.mediaSource.endOfStream('network'); | ||
953 | } | 969 | } |
954 | 970 | ||
955 | // stop processing if the request was aborted | 971 | // stop processing if the request was aborted |
... | @@ -1021,9 +1037,10 @@ videojs.HlsHandler.prototype.drainBuffer = function(event) { | ... | @@ -1021,9 +1037,10 @@ videojs.HlsHandler.prototype.drainBuffer = function(event) { |
1021 | // if the key download failed, we want to skip this segment | 1037 | // if the key download failed, we want to skip this segment |
1022 | // but if the key hasn't downloaded yet, we want to try again later | 1038 | // but if the key hasn't downloaded yet, we want to try again later |
1023 | if (keyFailed(segment.key)) { | 1039 | if (keyFailed(segment.key)) { |
1024 | videojs.log.warn('Network error retrieving key from "' + | 1040 | return this.blacklistCurrentPlaylist_({ |
1025 | segment.key.uri + '"'); | 1041 | message: 'HLS segment key request error.', |
1026 | return this.mediaSource.endOfStream('network'); | 1042 | code: 4 |
1043 | }); | ||
1027 | } else if (!segment.key.bytes) { | 1044 | } else if (!segment.key.bytes) { |
1028 | 1045 | ||
1029 | // waiting for the key bytes, try again later | 1046 | // waiting for the key bytes, try again later | ... | ... |
-
Please register or sign in to post a comment