c30a0cfa by David LaPalomento

Fix variant switching media index test

The original test was invoking the playlist reload callback which tested whether the media index was updating correctly after a refresh. Now, the test correctly triggers the a variant switch after downloading a segment. Consolidated media index update code and ensured state is properly updated after a switch.
1 parent 736b7c35
...@@ -123,6 +123,42 @@ var ...@@ -123,6 +123,42 @@ var
123 }, 123 },
124 124
125 /** 125 /**
126 * Determine the media index in one playlist that corresponds to a
127 * specified media index in another. This function can be used to
128 * calculate a new segment position when a playlist is reloaded or a
129 * variant playlist is becoming active.
130 * @param mediaIndex {number} the index into the original playlist
131 * to translate
132 * @param original {object} the playlist to translate the media
133 * index from
134 * @param update {object} the playlist to translate the media index
135 * to
136 * @param {number} the corresponding media index in the updated
137 * playlist
138 */
139 findCorrespondingMediaIndex = function(mediaIndex, original, update) {
140 var
141 i = update.segments.length,
142 originalSegment;
143
144 // no segments have been loaded from the original playlist
145 if (mediaIndex === 0) {
146 return 0;
147 }
148
149 // try to sync based on URI
150 originalSegment = original.segments[mediaIndex - 1];
151 while (i--) {
152 if (originalSegment.uri === update.segments[i].uri) {
153 return i + 1;
154 }
155 }
156
157 // sync on media sequence
158 return (original.mediaSequence + mediaIndex) - update.mediaSequence;
159 },
160
161 /**
126 * Calculate the total duration for a playlist based on segment metadata. 162 * Calculate the total duration for a playlist based on segment metadata.
127 * @param playlist {object} a media playlist object 163 * @param playlist {object} a media playlist object
128 * @return {number} the currently known duration, in seconds 164 * @return {number} the currently known duration, in seconds
...@@ -316,6 +352,10 @@ var ...@@ -316,6 +352,10 @@ var
316 mediaSequence > (playlist.mediaSequence || 0) + playlist.segments.length) { 352 mediaSequence > (playlist.mediaSequence || 0) + playlist.segments.length) {
317 downloadPlaylist(resolveUrl(srcUrl, playlist.uri)); 353 downloadPlaylist(resolveUrl(srcUrl, playlist.uri));
318 } else { 354 } else {
355 player.hls.mediaIndex =
356 findCorrespondingMediaIndex(player.hls.mediaIndex,
357 player.hls.media,
358 playlist);
319 player.hls.media = playlist; 359 player.hls.media = playlist;
320 360
321 // update the duration 361 // update the duration
...@@ -411,27 +451,7 @@ var ...@@ -411,27 +451,7 @@ var
411 var xhr = new window.XMLHttpRequest(); 451 var xhr = new window.XMLHttpRequest();
412 xhr.open('GET', url); 452 xhr.open('GET', url);
413 xhr.onreadystatechange = function() { 453 xhr.onreadystatechange = function() {
414 var i, parser, playlist, playlistUri, refreshDelay, 454 var i, parser, playlist, playlistUri, refreshDelay;
415 updateMediaIndex = function(original, update) {
416 var
417 i = update.segments.length,
418 updatedIndex = 0,
419 originalSegment;
420
421 // no segments have been loaded from the original playlist
422 if (player.hls.mediaIndex === 0) {
423 return;
424 }
425
426 originalSegment = original.segments[player.hls.mediaIndex - 1];
427 while (i--) {
428 if (originalSegment.uri === update.segments[i].uri) {
429 updatedIndex = i + 1;
430 break;
431 }
432 }
433 player.hls.mediaIndex = updatedIndex;
434 };
435 455
436 // wait until the request completes 456 // wait until the request completes
437 if (xhr.readyState !== 4) { 457 if (xhr.readyState !== 4) {
...@@ -487,7 +507,11 @@ var ...@@ -487,7 +507,11 @@ var
487 507
488 // determine the new mediaIndex if we're updating the 508 // determine the new mediaIndex if we're updating the
489 // current media playlist 509 // current media playlist
490 updateMediaIndex(playlist, parser.manifest); 510 player.hls.mediaIndex =
511 findCorrespondingMediaIndex(player.hls.mediaIndex,
512 playlist,
513 parser.manifest);
514 player.hls.media = parser.manifest;
491 } 515 }
492 } 516 }
493 } else { 517 } else {
......
...@@ -991,7 +991,7 @@ test('updates the media index when a playlist reloads', function() { ...@@ -991,7 +991,7 @@ test('updates the media index when a playlist reloads', function() {
991 '3.ts\n'; 991 '3.ts\n';
992 callback(); 992 callback();
993 993
994 strictEqual(2, player.hls.mediaIndex, 'mediaIndex is updated after the reload'); 994 strictEqual(player.hls.mediaIndex, 2, 'mediaIndex is updated after the reload');
995 }); 995 });
996 996
997 test('mediaIndex is zero before the first segment loads', function() { 997 test('mediaIndex is zero before the first segment loads', function() {
...@@ -1012,42 +1012,39 @@ test('mediaIndex is zero before the first segment loads', function() { ...@@ -1012,42 +1012,39 @@ test('mediaIndex is zero before the first segment loads', function() {
1012 }); 1012 });
1013 1013
1014 test('reloads out-of-date live playlists when switching variants', function() { 1014 test('reloads out-of-date live playlists when switching variants', function() {
1015 var callback;
1016 // capture timeouts
1017 window.setTimeout = function(cb) {
1018 callback = cb;
1019 };
1020
1021 player.hls('http://example.com/master.m3u8'); 1015 player.hls('http://example.com/master.m3u8');
1022 videojs.mediaSources[player.currentSrc()].trigger({ 1016 videojs.mediaSources[player.currentSrc()].trigger({
1023 type: 'sourceopen' 1017 type: 'sourceopen'
1024 }); 1018 });
1025 1019
1026 // playing segment 15 on playlist 0
1027 player.hls.master = { 1020 player.hls.master = {
1028 playlists: [{ 1021 playlists: [{
1029 mediaSequence: 15, 1022 mediaSequence: 15,
1030 segments: [{}, {}] 1023 segments: [1, 1, 1]
1031 }, { 1024 }, {
1032 uri: 'http://example.com/variant-update.m3u8', 1025 uri: 'http://example.com/variant-update.m3u8',
1033 mediaSequence: 0, 1026 mediaSequence: 0,
1034 segments: [{}, {}] 1027 segments: [1, 1]
1035 }] 1028 }]
1036 }; 1029 };
1030 // playing segment 15 on playlist zero
1037 player.hls.media = player.hls.master.playlists[0]; 1031 player.hls.media = player.hls.master.playlists[0];
1038 player.mediaIndex = 0; 1032 player.mediaIndex = 1;
1039 window.manifests['variant-update'] = '#EXTM3U\n' + 1033 window.manifests['variant-update'] = '#EXTM3U\n' +
1040 '#EXT-X-MEDIA-SEQUENCE:16\n' + 1034 '#EXT-X-MEDIA-SEQUENCE:16\n' +
1041 '#EXTINF:10,\n' + 1035 '#EXTINF:10,\n' +
1042 '16.ts\n'; 1036 '16.ts\n' +
1037 '#EXTINF:10,\n' +
1038 '17.ts\n';
1043 1039
1044 // switch playlists 1040 // switch playlists
1045 player.hls.selectPlaylist = function() { 1041 player.hls.selectPlaylist = function() {
1046 return player.hls.master.playlists[1]; 1042 return player.hls.master.playlists[1];
1047 }; 1043 };
1044 // timeupdate downloads segment 16 then switches playlists
1048 player.trigger('timeupdate'); 1045 player.trigger('timeupdate');
1049 1046
1050 ok(callback, 'reload is scheduled'); 1047 strictEqual(player.mediaIndex, 1, 'mediaIndex points at the next segment');
1051 }); 1048 });
1052 1049
1053 })(window, window.videojs); 1050 })(window, window.videojs);
......