1598394f by David LaPalomento

Only download one segment at a time

Check if there is a request in flight and don't perform buffer checks until it completes.
1 parent f2be83ef
...@@ -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();
......