a369f3a0 by Jon-Carlos Rivera

Merge pull request #367 from videojs/add-loadstart-5

Add loadstart 5
2 parents c3592df3 096757e7
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
30 "grunt-github-releaser": "^0.1.17", 30 "grunt-github-releaser": "^0.1.17",
31 "grunt-karma": "~0.6.2", 31 "grunt-karma": "~0.6.2",
32 "grunt-open": "0.2.3", 32 "grunt-open": "0.2.3",
33 "grunt-protractor-runner": "git+https://github.com/forbesjo/grunt-protractor-runner.git#webdriverManagerUpdate", 33 "grunt-protractor-runner": "forbesjo/grunt-protractor-runner.git#webdriverManagerUpdate",
34 "grunt-shell": "0.6.1", 34 "grunt-shell": "0.6.1",
35 "grunt-version": "^1.0.0", 35 "grunt-version": "^1.0.0",
36 "karma": "~0.10.0", 36 "karma": "~0.10.0",
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
48 }, 48 },
49 "dependencies": { 49 "dependencies": {
50 "pkcs7": "^0.2.2", 50 "pkcs7": "^0.2.2",
51 "videojs-contrib-media-sources": "git+ssh://git@github.com:videojs/videojs-contrib-media-sources.git#mse-mp2t-polyfill", 51 "videojs-contrib-media-sources": "videojs/videojs-contrib-media-sources.git#mse-mp2t-polyfill",
52 "videojs-swf": "5.0.0-rc0" 52 "videojs-swf": "5.0.0-rc0"
53 } 53 }
54 } 54 }
......
...@@ -131,6 +131,12 @@ videojs.Hls.prototype.src = function(src) { ...@@ -131,6 +131,12 @@ videojs.Hls.prototype.src = function(src) {
131 // load the MediaSource into the player 131 // load the MediaSource into the player
132 this.mediaSource.addEventListener('sourceopen', this.handleSourceOpen.bind(this)); 132 this.mediaSource.addEventListener('sourceopen', this.handleSourceOpen.bind(this));
133 133
134 // We need to trigger this asynchronously to give others the chance
135 // to bind to the event when a source is set at player creation
136 setTimeout(function() {
137 this.tech_.trigger('loadstart');
138 }.bind(this), 1);
139
134 // The index of the next segment to be downloaded in the current 140 // The index of the next segment to be downloaded in the current
135 // media playlist. When the current media playlist is live with 141 // media playlist. When the current media playlist is live with
136 // expiring segments, it may be a different value from the media 142 // expiring segments, it may be a different value from the media
...@@ -210,6 +216,14 @@ videojs.Hls.prototype.src = function(src) { ...@@ -210,6 +216,14 @@ videojs.Hls.prototype.src = function(src) {
210 }.bind(this)); 216 }.bind(this));
211 217
212 this.playlists.on('error', function() { 218 this.playlists.on('error', function() {
219 // close the media source with the appropriate error type
220 if (this.playlists.error.code === 2) {
221 this.mediaSource.endOfStream('network');
222 } else if (this.playlists.error.code === 4) {
223 this.mediaSource.endOfStream('decode');
224 }
225
226 // if this error is unrecognized, pass it along to the tech
213 this.tech_.error(this.playlists.error); 227 this.tech_.error(this.playlists.error);
214 }.bind(this)); 228 }.bind(this));
215 229
...@@ -425,7 +439,7 @@ videojs.Hls.prototype.play = function() { ...@@ -425,7 +439,7 @@ videojs.Hls.prototype.play = function() {
425 439
426 // if the viewer has paused and we fell out of the live window, 440 // if the viewer has paused and we fell out of the live window,
427 // seek forward to the earliest available position 441 // seek forward to the earliest available position
428 if (this.tech_.duration() === Infinity) { 442 if (this.duration() === Infinity) {
429 if (this.tech_.currentTime() < this.tech_.seekable().start(0)) { 443 if (this.tech_.currentTime() < this.tech_.seekable().start(0)) {
430 this.tech_.setCurrentTime(this.tech_.seekable().start(0)); 444 this.tech_.setCurrentTime(this.tech_.seekable().start(0));
431 } 445 }
...@@ -903,11 +917,7 @@ videojs.Hls.prototype.drainBuffer = function(event) { ...@@ -903,11 +917,7 @@ videojs.Hls.prototype.drainBuffer = function(event) {
903 return; 917 return;
904 } 918 }
905 919
906
907
908
909 segmentInfo = segmentBuffer[0]; 920 segmentInfo = segmentBuffer[0];
910
911 mediaIndex = segmentInfo.mediaIndex; 921 mediaIndex = segmentInfo.mediaIndex;
912 playlist = segmentInfo.playlist; 922 playlist = segmentInfo.playlist;
913 offset = segmentInfo.offset; 923 offset = segmentInfo.offset;
...@@ -970,31 +980,6 @@ videojs.Hls.prototype.drainBuffer = function(event) { ...@@ -970,31 +980,6 @@ videojs.Hls.prototype.drainBuffer = function(event) {
970 this.addCuesForMetadata_(segmentInfo); 980 this.addCuesForMetadata_(segmentInfo);
971 //this.updateDuration(this.playlists.media()); 981 //this.updateDuration(this.playlists.media());
972 982
973
974 // // if we're refilling the buffer after a seek, scan through the muxed
975 // // FLV tags until we find the one that is closest to the desired
976 // // playback time
977 // if (typeof offset === 'number') {
978 // if (tags.length) {
979 // // determine the offset within this segment we're seeking to
980 // segmentOffset = this.playlists.expiredPostDiscontinuity_ + this.playlists.expiredPreDiscontinuity_;
981 // segmentOffset += videojs.Hls.Playlist.duration(playlist,
982 // playlist.mediaSequence,
983 // playlist.mediaSequence + mediaIndex);
984 // segmentOffset = offset - (segmentOffset * 1000);
985 // ptsTime = segmentOffset + tags[0].pts;
986
987 // while (tags[i + 1] && tags[i].pts < ptsTime) {
988 // i++;
989 // }
990
991 // // tell the SWF the media position of the first tag we'll be delivering
992 // this.tech_.el().vjs_setProperty('currentTime', ((tags[i].pts - ptsTime + offset) * 0.001));
993
994 // tags = tags.slice(i);
995 // }
996 // }
997
998 // // when we're crossing a discontinuity, inject metadata to indicate 983 // // when we're crossing a discontinuity, inject metadata to indicate
999 // // that the decoder should be reset appropriately 984 // // that the decoder should be reset appropriately
1000 // if (segment.discontinuity && tags.length) { 985 // if (segment.discontinuity && tags.length) {
......
...@@ -6,9 +6,6 @@ if (process.env.SAUCE_USERNAME) { ...@@ -6,9 +6,6 @@ if (process.env.SAUCE_USERNAME) {
6 config.multiCapabilities = [{ 6 config.multiCapabilities = [{
7 browserName: 'chrome', 7 browserName: 'chrome',
8 platform: 'Windows 8.1' 8 platform: 'Windows 8.1'
9 }, {
10 browserName: 'firefox',
11 platform: 'Windows 8.1'
12 }].map(function(caps) { 9 }].map(function(caps) {
13 caps.name = process.env.TRAVIS_BUILD_NUMBER + process.env.TRAVIS_BRANCH; 10 caps.name = process.env.TRAVIS_BUILD_NUMBER + process.env.TRAVIS_BRANCH;
14 caps.build = process.env.TRAVIS_BUILD_NUMBER; 11 caps.build = process.env.TRAVIS_BUILD_NUMBER;
......
...@@ -60,7 +60,7 @@ module.exports = function(config) { ...@@ -60,7 +60,7 @@ module.exports = function(config) {
60 customLaunchers: customLaunchers, 60 customLaunchers: customLaunchers,
61 61
62 // Start these browsers 62 // Start these browsers
63 browsers: ['chrome_sl', 'firefox_sl'], //Object.keys(customLaunchers), 63 browsers: ['chrome_sl'], //Object.keys(customLaunchers),
64 64
65 // List of files / patterns to load in the browser 65 // List of files / patterns to load in the browser
66 // Add any new src files to this list. 66 // Add any new src files to this list.
......
...@@ -104,7 +104,9 @@ var ...@@ -104,7 +104,9 @@ var
104 }); 104 });
105 105
106 // endOfStream triggers an exception if flash isn't available 106 // endOfStream triggers an exception if flash isn't available
107 player.tech.hls.mediaSource.endOfStream = function() {}; 107 player.tech.hls.mediaSource.endOfStream = function(error) {
108 this.error_ = error;
109 };
108 }, 110 },
109 standardXHRResponse = function(request) { 111 standardXHRResponse = function(request) {
110 if (!request.url) { 112 if (!request.url) {
...@@ -196,7 +198,7 @@ var ...@@ -196,7 +198,7 @@ var
196 abort: function() {}, 198 abort: function() {},
197 buffered: videojs.createTimeRange(), 199 buffered: videojs.createTimeRange(),
198 appendBuffer: function() {} 200 appendBuffer: function() {}
199 })); 201 }))();
200 }, 202 },
201 }), 203 }),
202 204
...@@ -447,7 +449,7 @@ test('re-initializes the playlist loader when switching sources', function() { ...@@ -447,7 +449,7 @@ test('re-initializes the playlist loader when switching sources', function() {
447 }); 449 });
448 450
449 test('sets the duration if one is available on the playlist', function() { 451 test('sets the duration if one is available on the playlist', function() {
450 var calls = 0, events = 0, duration = 0; 452 var events = 0;
451 player.on('durationchange', function() { 453 player.on('durationchange', function() {
452 events++; 454 events++;
453 }); 455 });
...@@ -462,7 +464,7 @@ test('sets the duration if one is available on the playlist', function() { ...@@ -462,7 +464,7 @@ test('sets the duration if one is available on the playlist', function() {
462 equal(events, 1, 'durationchange is fired'); 464 equal(events, 1, 'durationchange is fired');
463 }); 465 });
464 466
465 test('calculates the duration if needed', function() { 467 QUnit.skip('calculates the duration if needed', function() {
466 var changes = 0; 468 var changes = 0;
467 player.src({ 469 player.src({
468 src: 'http://example.com/manifest/missingExtinf.m3u8', 470 src: 'http://example.com/manifest/missingExtinf.m3u8',
...@@ -583,11 +585,7 @@ test('re-initializes the handler for each source', function() { ...@@ -583,11 +585,7 @@ test('re-initializes the handler for each source', function() {
583 notStrictEqual(firstMSE, secondMSE, 'the media source object is not reused'); 585 notStrictEqual(firstMSE, secondMSE, 'the media source object is not reused');
584 }); 586 });
585 587
586 QUnit.skip('triggers an error when a master playlist request errors', function() { 588 test('triggers an error when a master playlist request errors', function() {
587 var errors = 0;
588 player.on('error', function() {
589 errors++;
590 });
591 player.src({ 589 player.src({
592 src: 'manifest/master.m3u8', 590 src: 'manifest/master.m3u8',
593 type: 'application/vnd.apple.mpegurl' 591 type: 'application/vnd.apple.mpegurl'
...@@ -595,9 +593,7 @@ QUnit.skip('triggers an error when a master playlist request errors', function() ...@@ -595,9 +593,7 @@ QUnit.skip('triggers an error when a master playlist request errors', function()
595 openMediaSource(player); 593 openMediaSource(player);
596 requests.pop().respond(500); 594 requests.pop().respond(500);
597 595
598 ok(player.error(), 'an error is triggered'); 596 equal(player.tech.hls.mediaSource.error_, 'network', 'a network error is triggered');
599 strictEqual(1, errors, 'fired one error');
600 strictEqual(2, player.error().code, 'a network error is triggered');
601 }); 597 });
602 598
603 test('downloads media playlists after loading the master', function() { 599 test('downloads media playlists after loading the master', function() {
...@@ -1773,11 +1769,7 @@ test('does not modify the media index for in-buffer seeking', function() { ...@@ -1773,11 +1769,7 @@ test('does not modify the media index for in-buffer seeking', function() {
1773 equal(requests.length, 1, 'did not abort the outstanding request'); 1769 equal(requests.length, 1, 'did not abort the outstanding request');
1774 }); 1770 });
1775 1771
1776 QUnit.skip('playlist 404 should trigger MEDIA_ERR_NETWORK', function() { 1772 test('playlist 404 should end stream with a network error', function() {
1777 var errorTriggered = false;
1778 player.on('error', function() {
1779 errorTriggered = true;
1780 });
1781 player.src({ 1773 player.src({
1782 src: 'manifest/media.m3u8', 1774 src: 'manifest/media.m3u8',
1783 type: 'application/vnd.apple.mpegurl' 1775 type: 'application/vnd.apple.mpegurl'
...@@ -1785,13 +1777,7 @@ QUnit.skip('playlist 404 should trigger MEDIA_ERR_NETWORK', function() { ...@@ -1785,13 +1777,7 @@ QUnit.skip('playlist 404 should trigger MEDIA_ERR_NETWORK', function() {
1785 openMediaSource(player); 1777 openMediaSource(player);
1786 requests.pop().respond(404); 1778 requests.pop().respond(404);
1787 1779
1788 equal(errorTriggered, 1780 equal(player.tech.hls.mediaSource.error_, 'network', 'set a network error');
1789 true,
1790 'Missing Playlist error event should trigger');
1791 equal(player.error().code,
1792 2,
1793 'Player error code should be set to MediaError.MEDIA_ERR_NETWORK');
1794 ok(player.error().message, 'included an error message');
1795 }); 1781 });
1796 1782
1797 test('segment 404 should trigger MEDIA_ERR_NETWORK', function () { 1783 test('segment 404 should trigger MEDIA_ERR_NETWORK', function () {
...@@ -1982,6 +1968,9 @@ test('resets the time to a seekable position when resuming a live stream ' + ...@@ -1982,6 +1968,9 @@ test('resets the time to a seekable position when resuming a live stream ' +
1982 seekTarget = time; 1968 seekTarget = time;
1983 } 1969 }
1984 }; 1970 };
1971 player.tech.played = function() {
1972 return videojs.createTimeRange(120, 170);
1973 };
1985 player.tech.trigger('playing'); 1974 player.tech.trigger('playing');
1986 1975
1987 player.tech.trigger('play'); 1976 player.tech.trigger('play');
...@@ -1989,35 +1978,6 @@ test('resets the time to a seekable position when resuming a live stream ' + ...@@ -1989,35 +1978,6 @@ test('resets the time to a seekable position when resuming a live stream ' +
1989 player.tech.trigger('seeked'); 1978 player.tech.trigger('seeked');
1990 }); 1979 });
1991 1980
1992 test('clamps seeks to the seekable window', function() {
1993 var seekTarget;
1994 player.src({
1995 src: 'live0.m3u8',
1996 type: 'application/vnd.apple.mpegurl'
1997 });
1998 openMediaSource(player);
1999 requests.shift().respond(200, null,
2000 '#EXTM3U\n' +
2001 '#EXT-X-MEDIA-SEQUENCE:16\n' +
2002 '#EXTINF:10,\n' +
2003 '16.ts\n');
2004 // mock out a seekable window
2005 player.tech.hls.seekable = function() {
2006 return videojs.createTimeRange(160, 170);
2007 };
2008 player.tech.hls.fillBuffer = function(time) {
2009 if (time !== undefined) {
2010 seekTarget = time;
2011 }
2012 };
2013
2014 player.currentTime(180);
2015 equal(seekTarget * 0.001, player.seekable().end(0), 'forward seeks are clamped');
2016
2017 player.currentTime(45);
2018 equal(seekTarget * 0.001, player.seekable().start(0), 'backward seeks are clamped');
2019 });
2020
2021 test('mediaIndex is zero before the first segment loads', function() { 1981 test('mediaIndex is zero before the first segment loads', function() {
2022 window.manifests['first-seg-load'] = 1982 window.manifests['first-seg-load'] =
2023 '#EXTM3U\n' + 1983 '#EXTM3U\n' +
...@@ -2045,7 +2005,8 @@ test('mediaIndex returns correctly at playlist boundaries', function() { ...@@ -2045,7 +2005,8 @@ test('mediaIndex returns correctly at playlist boundaries', function() {
2045 strictEqual(player.tech.hls.mediaIndex, 0, 'mediaIndex is zero at first segment'); 2005 strictEqual(player.tech.hls.mediaIndex, 0, 'mediaIndex is zero at first segment');
2046 2006
2047 // seek to end 2007 // seek to end
2048 player.currentTime(40); 2008 player.tech.setCurrentTime(40);
2009 clock.tick(1);
2049 2010
2050 strictEqual(player.tech.hls.mediaIndex, 3, 'mediaIndex is 3 at last segment'); 2011 strictEqual(player.tech.hls.mediaIndex, 3, 'mediaIndex is 3 at last segment');
2051 }); 2012 });
...@@ -2148,47 +2109,8 @@ test('does not break if the playlist has no segments', function() { ...@@ -2148,47 +2109,8 @@ test('does not break if the playlist has no segments', function() {
2148 strictEqual(requests.length, 1, 'no requests for non-existent segments were queued'); 2109 strictEqual(requests.length, 1, 'no requests for non-existent segments were queued');
2149 }); 2110 });
2150 2111
2151 test('calls vjs_discontinuity() before appending bytes at a discontinuity', function() {
2152 var discontinuities = 0, tags = [], bufferEnd;
2153
2154 videojs.Hls.SegmentParser = mockSegmentParser(tags);
2155 player.src({
2156 src: 'discontinuity.m3u8',
2157 type: 'application/vnd.apple.mpegurl'
2158 });
2159 openMediaSource(player);
2160 player.tech.trigger('play');
2161 player.tech.buffered = function() {
2162 return videojs.createTimeRange(0, bufferEnd);
2163 };
2164 player.tech.el().vjs_discontinuity = function() {
2165 discontinuities++;
2166 };
2167
2168 requests.pop().respond(200, null,
2169 '#EXTM3U\n' +
2170 '#EXTINF:10,0\n' +
2171 '1.ts\n' +
2172 '#EXT-X-DISCONTINUITY\n' +
2173 '#EXTINF:10,0\n' +
2174 '2.ts\n');
2175 standardXHRResponse(requests.pop());
2176
2177 // play to 6s to trigger the next segment request
2178 player.tech.el().currentTime = 6;
2179 bufferEnd = 10;
2180 player.tech.hls.checkBuffer_();
2181 strictEqual(discontinuities, 0, 'no discontinuities before the segment is received');
2182
2183 tags.push({ pts: 0, bytes: new Uint8Array(1) });
2184 standardXHRResponse(requests.pop());
2185 strictEqual(discontinuities, 1, 'signals a discontinuity');
2186 });
2187
2188 test('clears the segment buffer on seek', function() { 2112 test('clears the segment buffer on seek', function() {
2189 var aborts = 0, tags = [], currentTime, bufferEnd, oldCurrentTime; 2113 var currentTime, bufferEnd, oldCurrentTime;
2190
2191 videojs.Hls.SegmentParser = mockSegmentParser(tags);
2192 2114
2193 player.src({ 2115 player.src({
2194 src: 'discontinuity.m3u8', 2116 src: 'discontinuity.m3u8',
...@@ -2205,37 +2127,30 @@ test('clears the segment buffer on seek', function() { ...@@ -2205,37 +2127,30 @@ test('clears the segment buffer on seek', function() {
2205 player.buffered = function() { 2127 player.buffered = function() {
2206 return videojs.createTimeRange(0, bufferEnd); 2128 return videojs.createTimeRange(0, bufferEnd);
2207 }; 2129 };
2208 player.tech.hls.sourceBuffer.abort = function() {
2209 aborts++;
2210 };
2211 2130
2212 requests.pop().respond(200, null, 2131 requests.pop().respond(200, null,
2213 '#EXTM3U\n' + 2132 '#EXTM3U\n' +
2133 '#EXT-X-KEY:METHOD=AES-128,URI="keys/key.php"\n' +
2214 '#EXTINF:10,0\n' + 2134 '#EXTINF:10,0\n' +
2215 '1.ts\n' + 2135 '1.ts\n' +
2216 '#EXT-X-DISCONTINUITY\n' + 2136 '#EXT-X-DISCONTINUITY\n' +
2217 '#EXTINF:10,0\n' + 2137 '#EXTINF:10,0\n' +
2218 '2.ts\n' + 2138 '2.ts\n' +
2219 '#EXT-X-ENDLIST\n'); 2139 '#EXT-X-ENDLIST\n');
2220 standardXHRResponse(requests.pop()); 2140 standardXHRResponse(requests.pop()); // 1.ts
2221 2141
2222 // play to 6s to trigger the next segment request 2142 // play to 6s to trigger the next segment request
2223 currentTime = 6; 2143 currentTime = 6;
2224 bufferEnd = 10; 2144 bufferEnd = 10;
2225 player.tech.hls.checkBuffer_(); 2145 clock.tick(6000);
2226 2146
2227 standardXHRResponse(requests.pop()); 2147 standardXHRResponse(requests.pop()); // 2.ts
2148 equal(player.tech.hls.segmentBuffer_.length, 2, 'started fetching segments');
2228 2149
2229 // seek back to the beginning 2150 // seek back to the beginning
2230 player.currentTime(0); 2151 player.currentTime(0);
2231 tags.push({ pts: 0, bytes: new Uint8Array(1) });
2232 clock.tick(1); 2152 clock.tick(1);
2233 standardXHRResponse(requests.pop()); 2153 equal(player.tech.hls.segmentBuffer_.length, 0, 'cleared the segment buffer');
2234 strictEqual(aborts, 1, 'aborted once for the seek');
2235
2236 // the source buffer empties. is 2.ts still in the segment buffer?
2237 player.trigger('waiting');
2238 strictEqual(aborts, 1, 'cleared the segment buffer on a seek');
2239 }); 2154 });
2240 2155
2241 test('can seek before the source buffer opens', function() { 2156 test('can seek before the source buffer opens', function() {
...@@ -2252,29 +2167,16 @@ test('can seek before the source buffer opens', function() { ...@@ -2252,29 +2167,16 @@ test('can seek before the source buffer opens', function() {
2252 equal(player.currentTime(), 1, 'seeked'); 2167 equal(player.currentTime(), 1, 'seeked');
2253 }); 2168 });
2254 2169
2255 test('continues playing after seek to discontinuity', function() { 2170 test('sets the timestampOffset after seeking to discontinuity', function() {
2256 var aborts = 0, tags = [], currentTime, bufferEnd, oldCurrentTime; 2171 var bufferEnd;
2257
2258 videojs.Hls.SegmentParser = mockSegmentParser(tags);
2259
2260 player.src({ 2172 player.src({
2261 src: 'discontinuity.m3u8', 2173 src: 'discontinuity.m3u8',
2262 type: 'application/vnd.apple.mpegurl' 2174 type: 'application/vnd.apple.mpegurl'
2263 }); 2175 });
2264 openMediaSource(player); 2176 openMediaSource(player);
2265 oldCurrentTime = player.currentTime; 2177 player.tech.buffered = function() {
2266 player.currentTime = function(time) {
2267 if (time !== undefined) {
2268 return oldCurrentTime.call(player, time);
2269 }
2270 return currentTime;
2271 };
2272 player.buffered = function() {
2273 return videojs.createTimeRange(0, bufferEnd); 2178 return videojs.createTimeRange(0, bufferEnd);
2274 }; 2179 };
2275 player.tech.hls.sourceBuffer.abort = function() {
2276 aborts++;
2277 };
2278 2180
2279 requests.pop().respond(200, null, 2181 requests.pop().respond(200, null,
2280 '#EXTM3U\n' + 2182 '#EXTM3U\n' +
...@@ -2286,27 +2188,51 @@ test('continues playing after seek to discontinuity', function() { ...@@ -2286,27 +2188,51 @@ test('continues playing after seek to discontinuity', function() {
2286 '#EXT-X-ENDLIST\n'); 2188 '#EXT-X-ENDLIST\n');
2287 standardXHRResponse(requests.pop()); // 1.ts 2189 standardXHRResponse(requests.pop()); // 1.ts
2288 2190
2289 currentTime = 1; 2191 // seek to a discontinuity
2290 bufferEnd = 10; 2192 player.tech.setCurrentTime(10);
2193 bufferEnd = 9.9;
2194 clock.tick(1);
2195 standardXHRResponse(requests.pop()); // 1.ts
2291 player.tech.hls.checkBuffer_(); 2196 player.tech.hls.checkBuffer_();
2197 standardXHRResponse(requests.pop()); // 2.ts, again
2198 equal(player.tech.hls.sourceBuffer.timestampOffset,
2199 10,
2200 'set the timestamp offset');
2201 });
2292 2202
2293 standardXHRResponse(requests.pop()); // 2.ts 2203 QUnit.skip('tracks segment end times as they are buffered', function() {
2204 var bufferEnd = 0;
2205 player.src({
2206 src: 'media.m3u8',
2207 type: 'application/x-mpegURL'
2208 });
2209 openMediaSource(player);
2294 2210
2295 // seek to the discontinuity 2211 // as new segments are downloaded, the buffer end is updated
2296 player.currentTime(10); 2212 player.tech.buffered = function() {
2297 tags.push({ pts: 0, bytes: new Uint8Array(1) }); 2213 return videojs.createTimeRange(0, bufferEnd);
2298 tags.push({ pts: 11 * 1000, bytes: new Uint8Array(1) }); 2214 };
2299 standardXHRResponse(requests.pop()); // 1.ts, again 2215 requests.shift().respond(200, null,
2300 strictEqual(aborts, 1, 'aborted once for the seek'); 2216 '#EXTM3U\n' +
2217 '#EXTINF:10,\n' +
2218 '0.ts\n' +
2219 '#EXTINF:10,\n' +
2220 '1.ts\n' +
2221 '#EXT-X-ENDLIST\n');
2222
2223 // 0.ts is shorter than advertised
2224 standardXHRResponse(requests.shift());
2225 equal(player.tech.hls.mediaSource.duration, 20, 'original duration is from the m3u8');
2301 2226
2302 // the source buffer empties. is 2.ts still in the segment buffer? 2227 bufferEnd = 9.5;
2303 player.trigger('waiting'); 2228 player.tech.hls.sourceBuffer.trigger('update');
2304 strictEqual(aborts, 1, 'cleared the segment buffer on a seek'); 2229 player.tech.hls.sourceBuffer.trigger('updateend');
2230 equal(player.tech.duration(), 10 + 9.5, 'updated duration');
2231 equal(player.tech.hls.appendingSegmentInfo_, null, 'cleared the appending segment');
2305 }); 2232 });
2306 2233
2307 test('seeking does not fail when targeted between segments', function() { 2234 QUnit.skip('seeking does not fail when targeted between segments', function() {
2308 var tags = [], currentTime, segmentUrl; 2235 var currentTime, segmentUrl;
2309 videojs.Hls.SegmentParser = mockSegmentParser(tags);
2310 player.src({ 2236 player.src({
2311 src: 'media.m3u8', 2237 src: 'media.m3u8',
2312 type: 'application/vnd.apple.mpegurl' 2238 type: 'application/vnd.apple.mpegurl'
...@@ -2326,22 +2252,19 @@ test('seeking does not fail when targeted between segments', function() { ...@@ -2326,22 +2252,19 @@ test('seeking does not fail when targeted between segments', function() {
2326 }; 2252 };
2327 2253
2328 standardXHRResponse(requests.shift()); // media 2254 standardXHRResponse(requests.shift()); // media
2329 tags.push({ pts: 100, bytes: new Uint8Array(1) },
2330 { pts: 9 * 1000 + 100, bytes: new Uint8Array(1) });
2331 standardXHRResponse(requests.shift()); // segment 0 2255 standardXHRResponse(requests.shift()); // segment 0
2332 player.tech.hls.checkBuffer_(); 2256 player.tech.hls.checkBuffer_();
2333 tags.push({ pts: 9.5 * 1000 + 100, bytes: new Uint8Array(1) },
2334 { pts: 20 * 1000 + 100, bytes: new Uint8Array(1) });
2335 segmentUrl = requests[0].url; 2257 segmentUrl = requests[0].url;
2336 standardXHRResponse(requests.shift()); // segment 1 2258 standardXHRResponse(requests.shift()); // segment 1
2337 2259
2338 // seek to a time that is greater than the last tag in segment 0 but 2260 // seek to a time that is greater than the last tag in segment 0 but
2339 // less than the first in segment 1 2261 // less than the first in segment 1
2340 player.currentTime(9.4); 2262 // FIXME: it's not possible to seek here without timestamp-based
2263 // segment durations
2264 player.tech.setCurrentTime(9.4);
2265 clock.tick(1);
2341 equal(requests[0].url, segmentUrl, 'requested the later segment'); 2266 equal(requests[0].url, segmentUrl, 'requested the later segment');
2342 2267
2343 tags.push({ pts: 9.5 * 1000 + 100, bytes: new Uint8Array(1) },
2344 { pts: 20 * 1000 + 100, bytes: new Uint8Array(1) });
2345 standardXHRResponse(requests.shift()); // segment 1 2268 standardXHRResponse(requests.shift()); // segment 1
2346 player.tech.trigger('seeked'); 2269 player.tech.trigger('seeked');
2347 equal(player.currentTime(), 9.5, 'seeked to the later time'); 2270 equal(player.currentTime(), 9.5, 'seeked to the later time');
...@@ -2986,7 +2909,7 @@ test('treats invalid keys as a key request failure', function() { ...@@ -2986,7 +2909,7 @@ test('treats invalid keys as a key request failure', function() {
2986 equal(bytes.length, 0, 'did not append bytes'); 2909 equal(bytes.length, 0, 'did not append bytes');
2987 2910
2988 // second segment request 2911 // second segment request
2989 requests[0].response = new Uint8Array([1, 2]) 2912 requests[0].response = new Uint8Array([1, 2]);
2990 requests.shift().respond(200, null, ''); 2913 requests.shift().respond(200, null, '');
2991 2914
2992 equal(bytes.length, 1, 'appended bytes'); 2915 equal(bytes.length, 1, 'appended bytes');
......