Only download one segment at a time
Check if there is a request in flight and don't perform buffer checks until it completes.
Showing
2 changed files
with
40 additions
and
12 deletions
... | @@ -25,6 +25,7 @@ var | ... | @@ -25,6 +25,7 @@ var |
25 | player = this, | 25 | player = this, |
26 | url, | 26 | url, |
27 | 27 | ||
28 | segmentXhr, | ||
28 | fillBuffer, | 29 | fillBuffer, |
29 | selectPlaylist; | 30 | selectPlaylist; |
30 | 31 | ||
... | @@ -64,11 +65,15 @@ var | ... | @@ -64,11 +65,15 @@ var |
64 | var | 65 | var |
65 | buffered = player.buffered(), | 66 | buffered = player.buffered(), |
66 | bufferedTime = 0, | 67 | bufferedTime = 0, |
67 | xhr = new window.XMLHttpRequest(), | ||
68 | segment = player.hls.currentPlaylist.segments[player.hls.currentMediaIndex], | 68 | segment = player.hls.currentPlaylist.segments[player.hls.currentMediaIndex], |
69 | segmentUri, | 69 | segmentUri, |
70 | startTime; | 70 | startTime; |
71 | 71 | ||
72 | // if there is a request already in flight, do nothing | ||
73 | if (segmentXhr) { | ||
74 | return; | ||
75 | } | ||
76 | |||
72 | // if the video has finished downloading, stop trying to buffer | 77 | // if the video has finished downloading, stop trying to buffer |
73 | if (!segment) { | 78 | if (!segment) { |
74 | return; | 79 | return; |
... | @@ -77,10 +82,10 @@ var | ... | @@ -77,10 +82,10 @@ var |
77 | if (buffered) { | 82 | if (buffered) { |
78 | // assuming a single, contiguous buffer region | 83 | // assuming a single, contiguous buffer region |
79 | bufferedTime = player.buffered().end(0) - player.currentTime(); | 84 | bufferedTime = player.buffered().end(0) - player.currentTime(); |
85 | console.log('buffered time:', bufferedTime); | ||
80 | } | 86 | } |
81 | 87 | ||
82 | // if there is plenty of content in the buffer, relax for awhile | 88 | // if there is plenty of content in the buffer, relax for awhile |
83 | console.log('bufferedTime:', bufferedTime); | ||
84 | if (bufferedTime >= goalBufferLength) { | 89 | if (bufferedTime >= goalBufferLength) { |
85 | return; | 90 | return; |
86 | } | 91 | } |
... | @@ -92,26 +97,29 @@ var | ... | @@ -92,26 +97,29 @@ var |
92 | } | 97 | } |
93 | 98 | ||
94 | // request the next segment | 99 | // request the next segment |
95 | xhr.open('GET', segmentUri); | 100 | segmentXhr = new window.XMLHttpRequest(); |
96 | xhr.responseType = 'arraybuffer'; | 101 | segmentXhr.open('GET', segmentUri); |
97 | xhr.onreadystatechange = function() { | 102 | segmentXhr.responseType = 'arraybuffer'; |
98 | if (xhr.readyState === 4) { | 103 | segmentXhr.onreadystatechange = function() { |
104 | if (segmentXhr.readyState === 4) { | ||
99 | // calculate the download bandwidth | 105 | // calculate the download bandwidth |
100 | player.hls.segmentRequestTime = (+new Date()) - startTime; | 106 | player.hls.segmentXhrTime = (+new Date()) - startTime; |
101 | player.hls.bandwidth = xhr.response.byteLength / player.hls.segmentRequestTime; | 107 | player.hls.bandwidth = segmentXhr.response.byteLength / player.hls.segmentXhrTime; |
102 | 108 | ||
103 | // transmux the segment data from M2TS to FLV | 109 | // transmux the segment data from M2TS to FLV |
104 | segmentParser.parseSegmentBinaryData(new Uint8Array(xhr.response)); | 110 | segmentParser.parseSegmentBinaryData(new Uint8Array(segmentXhr.response)); |
105 | while (segmentParser.tagsAvailable()) { | 111 | while (segmentParser.tagsAvailable()) { |
106 | player.hls.sourceBuffer.appendBuffer(segmentParser.getNextTag().bytes, | 112 | player.hls.sourceBuffer.appendBuffer(segmentParser.getNextTag().bytes, |
107 | player); | 113 | player); |
108 | } | 114 | } |
109 | 115 | ||
116 | console.log('finished downloading segment ' + player.hls.currentMediaIndex); | ||
117 | segmentXhr = null; | ||
110 | player.hls.currentMediaIndex++; | 118 | player.hls.currentMediaIndex++; |
111 | } | 119 | } |
112 | }; | 120 | }; |
113 | startTime = +new Date(); | 121 | startTime = +new Date(); |
114 | xhr.send(null); | 122 | segmentXhr.send(null); |
115 | }; | 123 | }; |
116 | player.on('loadedmetadata', fillBuffer); | 124 | player.on('loadedmetadata', fillBuffer); |
117 | player.on('timeupdate', fillBuffer); | 125 | player.on('timeupdate', fillBuffer); | ... | ... |
... | @@ -145,8 +145,8 @@ test('calculates the bandwidth after downloading a segment', function() { | ... | @@ -145,8 +145,8 @@ test('calculates the bandwidth after downloading a segment', function() { |
145 | ok(player.hls.bandwidth, 'bandwidth is calculated'); | 145 | ok(player.hls.bandwidth, 'bandwidth is calculated'); |
146 | ok(player.hls.bandwidth > 0, | 146 | ok(player.hls.bandwidth > 0, |
147 | 'bandwidth is positive: ' + player.hls.bandwidth); | 147 | 'bandwidth is positive: ' + player.hls.bandwidth); |
148 | ok(player.hls.segmentRequestTime >= 0, | 148 | ok(player.hls.segmentXhrTime >= 0, |
149 | 'saves segment request time: ' + player.hls.segmentRequestTime + 's'); | 149 | 'saves segment request time: ' + player.hls.segmentXhrTime + 's'); |
150 | }); | 150 | }); |
151 | 151 | ||
152 | test('does not download the next segment if the buffer is full', function() { | 152 | test('does not download the next segment if the buffer is full', function() { |
... | @@ -196,6 +196,26 @@ test('stops downloading segments at the end of the playlist', function() { | ... | @@ -196,6 +196,26 @@ test('stops downloading segments at the end of the playlist', function() { |
196 | strictEqual(xhrParams, null, 'no request is made'); | 196 | strictEqual(xhrParams, null, 'no request is made'); |
197 | }); | 197 | }); |
198 | 198 | ||
199 | test('only makes one segment request at a time', function() { | ||
200 | var openedXhrs = 0; | ||
201 | player.hls('manifest/media.m3u8'); | ||
202 | videojs.mediaSources[player.currentSrc()].trigger({ | ||
203 | type: 'sourceopen' | ||
204 | }); | ||
205 | // mock out a long-running XHR | ||
206 | window.XMLHttpRequest = function() { | ||
207 | this.send = function() {}; | ||
208 | this.open = function() { | ||
209 | openedXhrs++; | ||
210 | }; | ||
211 | }; | ||
212 | player.trigger('timeupdate'); | ||
213 | |||
214 | strictEqual(1, openedXhrs, 'one XHR is made'); | ||
215 | player.trigger('timeupdate'); | ||
216 | strictEqual(1, openedXhrs, 'only one XHR is made'); | ||
217 | }); | ||
218 | |||
199 | module('segment controller', { | 219 | module('segment controller', { |
200 | setup: function() { | 220 | setup: function() { |
201 | segmentController = new window.videojs.hls.SegmentController(); | 221 | segmentController = new window.videojs.hls.SegmentController(); | ... | ... |
-
Please register or sign in to post a comment