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.
Showing
2 changed files
with
56 additions
and
35 deletions
... | @@ -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); | ... | ... |
-
Please register or sign in to post a comment