ac2b2759 by David LaPalomento

Update to an official videojs 5 RC

Start using a real video.js build now that mergeOptions() is working correctly in master. Begin fixing tests-- there are still a number of tests that are broken.
1 parent 03e43447
...@@ -44,11 +44,11 @@ ...@@ -44,11 +44,11 @@
44 "karma-sauce-launcher": "~0.1.8", 44 "karma-sauce-launcher": "~0.1.8",
45 "qunitjs": "^1.18.0", 45 "qunitjs": "^1.18.0",
46 "sinon": "1.10.2", 46 "sinon": "1.10.2",
47 "video.js": "^5.0.0-rc.4" 47 "video.js": "^5.0.0-rc.51"
48 }, 48 },
49 "dependencies": { 49 "dependencies": {
50 "pkcs7": "^0.2.2", 50 "pkcs7": "^0.2.2",
51 "videojs-contrib-media-sources": "^1.0.0", 51 "videojs-contrib-media-sources": "git+ssh://git@github.com: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,8 +131,8 @@ videojs.Hls.prototype.src = function(src) { ...@@ -131,8 +131,8 @@ videojs.Hls.prototype.src = function(src) {
131 this.options_ = {}; 131 this.options_ = {};
132 if (this.source_.withCredentials !== undefined) { 132 if (this.source_.withCredentials !== undefined) {
133 this.options_.withCredentials = this.source_.withCredentials; 133 this.options_.withCredentials = this.source_.withCredentials;
134 } else if (videojs.getGlobalOptions().hls) { 134 } else if (videojs.options.hls) {
135 this.options_.withCredentials = videojs.getGlobalOptions().hls.withCredentials; 135 this.options_.withCredentials = videojs.options.hls.withCredentials;
136 } 136 }
137 this.playlists = new videojs.Hls.PlaylistLoader(this.source_.src, this.options_.withCredentials); 137 this.playlists = new videojs.Hls.PlaylistLoader(this.source_.src, this.options_.withCredentials);
138 138
...@@ -846,7 +846,6 @@ videojs.Hls.prototype.loadSegment = function(segmentUri, offset) { ...@@ -846,7 +846,6 @@ videojs.Hls.prototype.loadSegment = function(segmentUri, offset) {
846 846
847 videojs.Hls.prototype.drainBuffer = function(event) { 847 videojs.Hls.prototype.drainBuffer = function(event) {
848 var 848 var
849 i = 0,
850 segmentInfo, 849 segmentInfo,
851 mediaIndex, 850 mediaIndex,
852 playlist, 851 playlist,
...@@ -855,8 +854,8 @@ videojs.Hls.prototype.drainBuffer = function(event) { ...@@ -855,8 +854,8 @@ videojs.Hls.prototype.drainBuffer = function(event) {
855 segment, 854 segment,
856 decrypter, 855 decrypter,
857 segIv, 856 segIv,
858 ptsTime, 857 // ptsTime,
859 segmentOffset = 0, 858 // segmentOffset = 0,
860 segmentBuffer = this.segmentBuffer_; 859 segmentBuffer = this.segmentBuffer_;
861 860
862 // if the buffer is empty or the source buffer hasn't been created 861 // if the buffer is empty or the source buffer hasn't been created
......
...@@ -26,10 +26,9 @@ var ...@@ -26,10 +26,9 @@ var
26 oldFlash, 26 oldFlash,
27 player, 27 player,
28 clock, 28 clock,
29 oldMediaSourceOpen, 29 oldMediaSource,
30 oldCreateUrl,
30 oldSegmentParser, 31 oldSegmentParser,
31 oldSetTimeout,
32 oldClearTimeout,
33 oldSourceBuffer, 32 oldSourceBuffer,
34 oldFlashSupported, 33 oldFlashSupported,
35 oldNativeHlsSupport, 34 oldNativeHlsSupport,
...@@ -40,6 +39,39 @@ var ...@@ -40,6 +39,39 @@ var
40 39
41 nextId = 0, 40 nextId = 0,
42 41
42 // patch over some methods of the provided tech so it can be tested
43 // synchronously with sinon's fake timers
44 mockTech = function(tech) {
45 tech.currentTime = function() {
46 return tech.currentTime_ === undefined ? tech.currentTime : tech.currentTime_;
47 };
48
49 tech.setSrc = function(src) {
50 tech.src_ = src;
51 };
52 tech.src = function(src) {
53 if (src !== undefined) {
54 return tech.setSrc(src);
55 }
56 return tech.src_ === undefined ? tech.src : tech.src_;
57 };
58 tech.currentSrc_ = tech.currentSrc;
59 tech.currentSrc = function() {
60 return tech.src_ === undefined ? tech.currentSrc_() : tech.src_;
61 };
62
63 tech.setCurrentTime = function(time) {
64 tech.currentTime_ = time;
65
66 setTimeout(function() {
67 tech.trigger('seeking');
68 setTimeout(function() {
69 tech.trigger('seeked');
70 }, 1);
71 }, 1);
72 };
73 },
74
43 createPlayer = function() { 75 createPlayer = function() {
44 var video, player; 76 var video, player;
45 video = document.createElement('video'); 77 video = document.createElement('video');
...@@ -54,6 +86,7 @@ var ...@@ -54,6 +86,7 @@ var
54 player.buffered = function() { 86 player.buffered = function() {
55 return videojs.createTimeRange(0, 0); 87 return videojs.createTimeRange(0, 0);
56 }; 88 };
89 mockTech(player.tech);
57 90
58 return player; 91 return player;
59 }, 92 },
...@@ -62,8 +95,9 @@ var ...@@ -62,8 +95,9 @@ var
62 player.tech.triggerReady(); 95 player.tech.triggerReady();
63 clock.tick(1); 96 clock.tick(1);
64 97
65 // simulate the Flash callback 98 // simulate the sourceopen event
66 player.tech.hls.mediaSource.trigger({ 99 player.tech.hls.mediaSource.readyState = 'open';
100 player.tech.hls.mediaSource.dispatchEvent({
67 type: 'sourceopen', 101 type: 'sourceopen',
68 swfId: player.tech.el().id 102 swfId: player.tech.el().id
69 }); 103 });
...@@ -152,6 +186,26 @@ var ...@@ -152,6 +186,26 @@ var
152 return MockSegmentParser; 186 return MockSegmentParser;
153 }, 187 },
154 188
189 // a no-op MediaSource implementation to allow synchronous testing
190 MockMediaSource = videojs.extends(videojs.EventTarget, {
191 constructor: function() {},
192 addSourceBuffer: function() {
193 return {
194 abort: function() {},
195 buffered: videojs.createTimeRange(),
196 appendBuffer: function() {}
197 };
198 },
199 }),
200
201 // do a shallow copy of the properties of source onto the target object
202 merge = function(target, source) {
203 var name;
204 for (name in source) {
205 target[name] = source[name];
206 }
207 },
208
155 // return an absolute version of a page-relative URL 209 // return an absolute version of a page-relative URL
156 absoluteUrl = function(relativeUrl) { 210 absoluteUrl = function(relativeUrl) {
157 return window.location.origin + 211 return window.location.origin +
...@@ -162,10 +216,16 @@ var ...@@ -162,10 +216,16 @@ var
162 .join('/')); 216 .join('/'));
163 }; 217 };
164 218
219 MockMediaSource.open = function() {};
220
165 module('HLS', { 221 module('HLS', {
166 beforeEach: function() { 222 beforeEach: function() {
167 oldMediaSourceOpen = videojs.MediaSource.open; 223 oldMediaSource = videojs.MediaSource;
168 videojs.MediaSource.open = function() {}; 224 videojs.MediaSource = MockMediaSource;
225 oldCreateUrl = videojs.URL.createObjectURL;
226 videojs.URL.createObjectURL = function() {
227 return 'blob:mock-vjs-object-url';
228 };
169 229
170 // mock out Flash features for phantomjs 230 // mock out Flash features for phantomjs
171 oldFlash = videojs.mergeOptions({}, Flash); 231 oldFlash = videojs.mergeOptions({}, Flash);
...@@ -208,9 +268,7 @@ module('HLS', { ...@@ -208,9 +268,7 @@ module('HLS', {
208 268
209 // store functionality that some tests need to mock 269 // store functionality that some tests need to mock
210 oldSegmentParser = videojs.Hls.SegmentParser; 270 oldSegmentParser = videojs.Hls.SegmentParser;
211 oldSetTimeout = window.setTimeout; 271 oldGlobalOptions = videojs.mergeOptions(videojs.options);
212 oldClearTimeout = window.clearTimeout;
213 oldGlobalOptions = window.videojs.getGlobalOptions();
214 272
215 // force the HLS tech to run 273 // force the HLS tech to run
216 oldNativeHlsSupport = videojs.Hls.supportsNativeHls; 274 oldNativeHlsSupport = videojs.Hls.supportsNativeHls;
...@@ -234,16 +292,18 @@ module('HLS', { ...@@ -234,16 +292,18 @@ module('HLS', {
234 }, 292 },
235 293
236 afterEach: function() { 294 afterEach: function() {
295 videojs.MediaSource = oldMediaSource;
296 videojs.URL.createObjectURL = oldCreateUrl;
297
298 merge(videojs.options, oldGlobalOptions);
237 Flash.isSupported = oldFlashSupported; 299 Flash.isSupported = oldFlashSupported;
238 videojs.mergeOptions(Flash, oldFlash); 300 merge(Flash, oldFlash);
239 videojs.MediaSource.open = oldMediaSourceOpen; 301
240 videojs.Hls.SegmentParser = oldSegmentParser; 302 videojs.Hls.SegmentParser = oldSegmentParser;
241 videojs.Hls.supportsNativeHls = oldNativeHlsSupport; 303 videojs.Hls.supportsNativeHls = oldNativeHlsSupport;
242 videojs.Hls.Decrypter = oldDecrypt; 304 videojs.Hls.Decrypter = oldDecrypt;
243 videojs.SourceBuffer = oldSourceBuffer; 305 videojs.SourceBuffer = oldSourceBuffer;
244 window.setTimeout = oldSetTimeout; 306
245 window.clearTimeout = oldClearTimeout;
246 videojs.setGlobalOptions(oldGlobalOptions);
247 player.dispose(); 307 player.dispose();
248 xhr.restore(); 308 xhr.restore();
249 clock.restore(); 309 clock.restore();
...@@ -282,6 +342,7 @@ test('autoplay seeks to the live point after playlist load', function() { ...@@ -282,6 +342,7 @@ test('autoplay seeks to the live point after playlist load', function() {
282 }); 342 });
283 openMediaSource(player); 343 openMediaSource(player);
284 standardXHRResponse(requests.shift()); 344 standardXHRResponse(requests.shift());
345 clock.tick(1);
285 346
286 notEqual(currentTime, 0, 'seeked on autoplay'); 347 notEqual(currentTime, 0, 'seeked on autoplay');
287 }); 348 });
...@@ -300,6 +361,7 @@ test('autoplay seeks to the live point after media source open', function() { ...@@ -300,6 +361,7 @@ test('autoplay seeks to the live point after media source open', function() {
300 clock.tick(1); 361 clock.tick(1);
301 standardXHRResponse(requests.shift()); 362 standardXHRResponse(requests.shift());
302 openMediaSource(player); 363 openMediaSource(player);
364 clock.tick(1);
303 365
304 notEqual(currentTime, 0, 'seeked on autoplay'); 366 notEqual(currentTime, 0, 'seeked on autoplay');
305 }); 367 });
...@@ -314,7 +376,7 @@ test('duration is set when the source opens after the playlist is loaded', funct ...@@ -314,7 +376,7 @@ test('duration is set when the source opens after the playlist is loaded', funct
314 standardXHRResponse(requests.shift()); 376 standardXHRResponse(requests.shift());
315 openMediaSource(player); 377 openMediaSource(player);
316 378
317 equal(player.duration() , 40, 'set the duration'); 379 equal(player.tech.hls.mediaSource.duration , 40, 'set the duration');
318 }); 380 });
319 381
320 test('creates a PlaylistLoader on init', function() { 382 test('creates a PlaylistLoader on init', function() {
...@@ -323,7 +385,6 @@ test('creates a PlaylistLoader on init', function() { ...@@ -323,7 +385,6 @@ test('creates a PlaylistLoader on init', function() {
323 type: 'application/vnd.apple.mpegurl' 385 type: 'application/vnd.apple.mpegurl'
324 }); 386 });
325 387
326 ok(!player.tech.hls, 'waits for set src to create the source handler');
327 player.src({ 388 player.src({
328 src:'manifest/playlist.m3u8', 389 src:'manifest/playlist.m3u8',
329 type: 'application/vnd.apple.mpegurl' 390 type: 'application/vnd.apple.mpegurl'
...@@ -385,41 +446,28 @@ test('sets the duration if one is available on the playlist', function() { ...@@ -385,41 +446,28 @@ test('sets the duration if one is available on the playlist', function() {
385 type: 'application/vnd.apple.mpegurl' 446 type: 'application/vnd.apple.mpegurl'
386 }); 447 });
387 openMediaSource(player); 448 openMediaSource(player);
388 player.tech.hls.mediaSource.duration = function(value) {
389 if (value !== undefined) {
390 duration = value;
391 calls++;
392 }
393 return duration;
394 };
395 449
396 standardXHRResponse(requests[0]); 450 standardXHRResponse(requests[0]);
397 strictEqual(calls, 1, 'duration is set'); 451 equal(player.tech.hls.mediaSource.duration, 40, 'set the duration');
398 equal(events, 1, 'durationchange is fired'); 452 equal(events, 1, 'durationchange is fired');
399 }); 453 });
400 454
401 test('calculates the duration if needed', function() { 455 test('calculates the duration if needed', function() {
402 var durations = [], changes = 0; 456 var changes = 0;
403 player.src({ 457 player.src({
404 src: 'http://example.com/manifest/missingExtinf.m3u8', 458 src: 'http://example.com/manifest/missingExtinf.m3u8',
405 type: 'application/vnd.apple.mpegurl' 459 type: 'application/vnd.apple.mpegurl'
406 }); 460 });
407 openMediaSource(player); 461 openMediaSource(player);
408 player.tech.hls.mediaSource.duration = function(duration) { 462 player.tech.hls.mediaSource.duration = NaN;
409 if (duration === undefined) {
410 return 0;
411 }
412 durations.push(duration);
413 };
414 player.on('durationchange', function() { 463 player.on('durationchange', function() {
415 changes++; 464 changes++;
416 }); 465 });
417 466
418 standardXHRResponse(requests[0]); 467 standardXHRResponse(requests[0]);
419 strictEqual(durations.length, 1, 'duration is set'); 468 strictEqual(player.tech.hls.mediaSource.duration,
420 strictEqual(durations[0],
421 player.tech.hls.playlists.media().segments.length * 10, 469 player.tech.hls.playlists.media().segments.length * 10,
422 'duration is calculated'); 470 'duration is updated');
423 strictEqual(changes, 1, 'one durationchange fired'); 471 strictEqual(changes, 1, 'one durationchange fired');
424 }); 472 });
425 473
...@@ -780,25 +828,18 @@ test('moves to the next segment if there is a network error', function() { ...@@ -780,25 +828,18 @@ test('moves to the next segment if there is a network error', function() {
780 }); 828 });
781 829
782 test('updates the duration after switching playlists', function() { 830 test('updates the duration after switching playlists', function() {
783 var 831 var selectedPlaylist = false;
784 calls = 0,
785 selectedPlaylist = false;
786 player.src({ 832 player.src({
787 src: 'manifest/master.m3u8', 833 src: 'manifest/master.m3u8',
788 type: 'application/vnd.apple.mpegurl' 834 type: 'application/vnd.apple.mpegurl'
789 }); 835 });
790 openMediaSource(player); 836 openMediaSource(player);
791 player.tech.hls.mediaSource.duration = function(duration) {
792 if (duration === undefined) {
793 return 0;
794 }
795 // only track calls that occur after the playlist has been switched
796 if (player.tech.hls.playlists.media() === player.tech.hls.playlists.master.playlists[1]) {
797 calls++;
798 }
799 };
800 player.tech.hls.selectPlaylist = function() { 837 player.tech.hls.selectPlaylist = function() {
801 selectedPlaylist = true; 838 selectedPlaylist = true;
839
840 // this duraiton should be overwritten by the playlist change
841 player.tech.hls.mediaSource.duration = -Infinity;
842
802 return player.tech.hls.playlists.master.playlists[1]; 843 return player.tech.hls.playlists.master.playlists[1];
803 }; 844 };
804 845
...@@ -807,7 +848,7 @@ test('updates the duration after switching playlists', function() { ...@@ -807,7 +848,7 @@ test('updates the duration after switching playlists', function() {
807 standardXHRResponse(requests[2]); 848 standardXHRResponse(requests[2]);
808 standardXHRResponse(requests[3]); 849 standardXHRResponse(requests[3]);
809 ok(selectedPlaylist, 'selected playlist'); 850 ok(selectedPlaylist, 'selected playlist');
810 strictEqual(calls, 1, 'updates the duration'); 851 ok(player.tech.hls.mediaSource.duration !== -Infinity, 'updates the duration');
811 }); 852 });
812 853
813 test('downloads additional playlists if required', function() { 854 test('downloads additional playlists if required', function() {
...@@ -1246,10 +1287,9 @@ test('cancels outstanding XHRs when seeking', function() { ...@@ -1246,10 +1287,9 @@ test('cancels outstanding XHRs when seeking', function() {
1246 }] 1287 }]
1247 }; 1288 };
1248 1289
1249 // trigger a segment download request
1250 player.trigger('timeupdate');
1251 // attempt to seek while the download is in progress 1290 // attempt to seek while the download is in progress
1252 player.currentTime(7); 1291 player.currentTime(7);
1292 clock.tick(1);
1253 1293
1254 ok(requests[1].aborted, 'XHR aborted'); 1294 ok(requests[1].aborted, 'XHR aborted');
1255 strictEqual(requests.length, 3, 'opened new XHR'); 1295 strictEqual(requests.length, 3, 'opened new XHR');
...@@ -1274,6 +1314,7 @@ test('when outstanding XHRs are cancelled, they get aborted properly', function( ...@@ -1274,6 +1314,7 @@ test('when outstanding XHRs are cancelled, they get aborted properly', function(
1274 1314
1275 // attempt to seek while the download is in progress 1315 // attempt to seek while the download is in progress
1276 player.currentTime(12); 1316 player.currentTime(12);
1317 clock.tick(1);
1277 1318
1278 ok(requests[1].aborted, 'XHR aborted'); 1319 ok(requests[1].aborted, 'XHR aborted');
1279 strictEqual(requests.length, 3, 'opened new XHR'); 1320 strictEqual(requests.length, 3, 'opened new XHR');
...@@ -1311,34 +1352,6 @@ test('segmentXhr is properly nulled out when dispose is called', function() { ...@@ -1311,34 +1352,6 @@ test('segmentXhr is properly nulled out when dispose is called', function() {
1311 Flash.prototype.dispose = oldDispose; 1352 Flash.prototype.dispose = oldDispose;
1312 }); 1353 });
1313 1354
1314 test('flushes the parser after each segment', function() {
1315 var flushes = 0;
1316 // mock out the segment parser
1317 videojs.Hls.SegmentParser = function() {
1318 this.getFlvHeader = function() {
1319 return [];
1320 };
1321 this.parseSegmentBinaryData = function() {};
1322 this.flushTags = function() {
1323 flushes++;
1324 };
1325 this.tagsAvailable = function() {};
1326 this.metadataStream = {
1327 on: Function.prototype
1328 };
1329 };
1330
1331 player.src({
1332 src: 'manifest/media.m3u8',
1333 type: 'application/vnd.apple.mpegurl'
1334 });
1335 openMediaSource(player);
1336
1337 standardXHRResponse(requests[0]);
1338 standardXHRResponse(requests[1]);
1339 strictEqual(flushes, 1, 'tags are flushed at the end of a segment');
1340 });
1341
1342 QUnit.skip('exposes in-band metadata events as cues', function() { 1355 QUnit.skip('exposes in-band metadata events as cues', function() {
1343 var track; 1356 var track;
1344 videojs.Hls.SegmentParser = mockSegmentParser(); 1357 videojs.Hls.SegmentParser = mockSegmentParser();
...@@ -1792,8 +1805,9 @@ test('duration is Infinity for live playlists', function() { ...@@ -1792,8 +1805,9 @@ test('duration is Infinity for live playlists', function() {
1792 1805
1793 standardXHRResponse(requests[0]); 1806 standardXHRResponse(requests[0]);
1794 1807
1795 strictEqual(player.duration(), Infinity, 'duration is infinity'); 1808 strictEqual(player.tech.hls.mediaSource.duration,
1796 ok((' ' + player.el().className + ' ').indexOf(' vjs-live ') >= 0, 'added vjs-live class'); 1809 Infinity,
1810 'duration is infinity');
1797 }); 1811 });
1798 1812
1799 test('updates the media index when a playlist reloads', function() { 1813 test('updates the media index when a playlist reloads', function() {
...@@ -2027,7 +2041,7 @@ test('reloads out-of-date live playlists when switching variants', function() { ...@@ -2027,7 +2041,7 @@ test('reloads out-of-date live playlists when switching variants', function() {
2027 2041
2028 test('if withCredentials global option is used, withCredentials is set on the XHR object', function() { 2042 test('if withCredentials global option is used, withCredentials is set on the XHR object', function() {
2029 player.dispose(); 2043 player.dispose();
2030 videojs.getGlobalOptions().hls = { 2044 videojs.options.hls = {
2031 withCredentials: true 2045 withCredentials: true
2032 }; 2046 };
2033 player = createPlayer(); 2047 player = createPlayer();
......