You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6541 lines
186 KiB

Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Fmp4 support (#829) * Media init segment support Resolve EXT-X-MAP URI information in the playlist loader. Add support for requesting and appending initialization segments to the segment loader. * Basic support for fragmented MP4 playback Re-arrange source updater and track support to fit our design goals more closely. Make adjustments so that the correct source buffer types are created when a fragmented mp4 is encountered. This version will play Apple's fMp4 bipbop stream but you have to seek the player to 10 seconds after starting because the first fragment starts at 10, not 0. * Finish consolidating audio loaders Manage a single pair of audio playlist and segment loaders, instead of one per track. Update track logic to work with the new flow. * Detect and set the correct starting timestamp offset Probe the init and first MP4 segment to correctly set timestamp offset so that the stream begins at time zero. After this change, Apple's fragmented MP4 HLS example stream plays without additional modification. * Guard against media playlists without bandwidth information If a media playlist is loaded directly or bandwidth info is unavailable, make sure the lowest bitrate check doesn't error. Add some unnecessary request shifting to tests to avoid extraneous requests caused by the current behavior of segment loader when abort()-ing THEN pause()-ing. * Add stub prog_index.m3u8 for tests Some of the tests point to master playlists that reference prog_index.m3u8. Sinon caught most of the exceptions related to this but the tests weren't really exercising realistic scenarios. Add a stub prog_index to the test fixtures so that requests for prog_index don't unintentionally error. * Abort init segment XHR alongside other segment XHRs If the segment loader XHRs are aborted, stop the init segment one as well. Make sure to check the right property for the init segment XHR before continuing the loading process. Make sure falsey values do not cause a playlist to be blacklisted in FF for audio info changes. * Fix audio track management after reorganization Delay segment loader initialization steps until all starting configuration is ready. This allowed source updater MIME types to be specified early without triggering the main updater to have its audio disabled on startup. Tweak the mime type identifier function to signal alternate audio earlier. Move `this` references in segment loader's checkBuffer_ out to stateful functions to align with the original design goals. Removed a segment loader test that seemed duplicative after the checkBuffer_ change. * Fix D3 on stats page Update URL for D3. Remove audio switcher since it's included by default now. * Only override codec defaults if an actual value was parsed When converting codec strings into MIME type configurations for source buffers, make sure to use default values if the codec string didn't supply particular fields. Export the codec to MIME helper function so it can be unit-tested. * IE fixes Array.prototype.find() isn't available in IE so use .filter()[0] instead. * Blacklist unsupported codecs If MediaSource.isTypeSupported fails in a generic MP4 container, swapping to a variant with those codecs is unlikely to be successful. For instance, the fragmented bip-bop stream includes AC-3 and EC-3 audio which is not supported on Chrome or Firefox today. Exclude variants with codecs that don't pass the isTypeSupported test.
9 years ago
Fmp4 support (#829) * Media init segment support Resolve EXT-X-MAP URI information in the playlist loader. Add support for requesting and appending initialization segments to the segment loader. * Basic support for fragmented MP4 playback Re-arrange source updater and track support to fit our design goals more closely. Make adjustments so that the correct source buffer types are created when a fragmented mp4 is encountered. This version will play Apple's fMp4 bipbop stream but you have to seek the player to 10 seconds after starting because the first fragment starts at 10, not 0. * Finish consolidating audio loaders Manage a single pair of audio playlist and segment loaders, instead of one per track. Update track logic to work with the new flow. * Detect and set the correct starting timestamp offset Probe the init and first MP4 segment to correctly set timestamp offset so that the stream begins at time zero. After this change, Apple's fragmented MP4 HLS example stream plays without additional modification. * Guard against media playlists without bandwidth information If a media playlist is loaded directly or bandwidth info is unavailable, make sure the lowest bitrate check doesn't error. Add some unnecessary request shifting to tests to avoid extraneous requests caused by the current behavior of segment loader when abort()-ing THEN pause()-ing. * Add stub prog_index.m3u8 for tests Some of the tests point to master playlists that reference prog_index.m3u8. Sinon caught most of the exceptions related to this but the tests weren't really exercising realistic scenarios. Add a stub prog_index to the test fixtures so that requests for prog_index don't unintentionally error. * Abort init segment XHR alongside other segment XHRs If the segment loader XHRs are aborted, stop the init segment one as well. Make sure to check the right property for the init segment XHR before continuing the loading process. Make sure falsey values do not cause a playlist to be blacklisted in FF for audio info changes. * Fix audio track management after reorganization Delay segment loader initialization steps until all starting configuration is ready. This allowed source updater MIME types to be specified early without triggering the main updater to have its audio disabled on startup. Tweak the mime type identifier function to signal alternate audio earlier. Move `this` references in segment loader's checkBuffer_ out to stateful functions to align with the original design goals. Removed a segment loader test that seemed duplicative after the checkBuffer_ change. * Fix D3 on stats page Update URL for D3. Remove audio switcher since it's included by default now. * Only override codec defaults if an actual value was parsed When converting codec strings into MIME type configurations for source buffers, make sure to use default values if the codec string didn't supply particular fields. Export the codec to MIME helper function so it can be unit-tested. * IE fixes Array.prototype.find() isn't available in IE so use .filter()[0] instead. * Blacklist unsupported codecs If MediaSource.isTypeSupported fails in a generic MP4 container, swapping to a variant with those codecs is unlikely to be successful. For instance, the fragmented bip-bop stream includes AC-3 and EC-3 audio which is not supported on Chrome or Firefox today. Exclude variants with codecs that don't pass the isTypeSupported test.
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Fmp4 support (#829) * Media init segment support Resolve EXT-X-MAP URI information in the playlist loader. Add support for requesting and appending initialization segments to the segment loader. * Basic support for fragmented MP4 playback Re-arrange source updater and track support to fit our design goals more closely. Make adjustments so that the correct source buffer types are created when a fragmented mp4 is encountered. This version will play Apple's fMp4 bipbop stream but you have to seek the player to 10 seconds after starting because the first fragment starts at 10, not 0. * Finish consolidating audio loaders Manage a single pair of audio playlist and segment loaders, instead of one per track. Update track logic to work with the new flow. * Detect and set the correct starting timestamp offset Probe the init and first MP4 segment to correctly set timestamp offset so that the stream begins at time zero. After this change, Apple's fragmented MP4 HLS example stream plays without additional modification. * Guard against media playlists without bandwidth information If a media playlist is loaded directly or bandwidth info is unavailable, make sure the lowest bitrate check doesn't error. Add some unnecessary request shifting to tests to avoid extraneous requests caused by the current behavior of segment loader when abort()-ing THEN pause()-ing. * Add stub prog_index.m3u8 for tests Some of the tests point to master playlists that reference prog_index.m3u8. Sinon caught most of the exceptions related to this but the tests weren't really exercising realistic scenarios. Add a stub prog_index to the test fixtures so that requests for prog_index don't unintentionally error. * Abort init segment XHR alongside other segment XHRs If the segment loader XHRs are aborted, stop the init segment one as well. Make sure to check the right property for the init segment XHR before continuing the loading process. Make sure falsey values do not cause a playlist to be blacklisted in FF for audio info changes. * Fix audio track management after reorganization Delay segment loader initialization steps until all starting configuration is ready. This allowed source updater MIME types to be specified early without triggering the main updater to have its audio disabled on startup. Tweak the mime type identifier function to signal alternate audio earlier. Move `this` references in segment loader's checkBuffer_ out to stateful functions to align with the original design goals. Removed a segment loader test that seemed duplicative after the checkBuffer_ change. * Fix D3 on stats page Update URL for D3. Remove audio switcher since it's included by default now. * Only override codec defaults if an actual value was parsed When converting codec strings into MIME type configurations for source buffers, make sure to use default values if the codec string didn't supply particular fields. Export the codec to MIME helper function so it can be unit-tested. * IE fixes Array.prototype.find() isn't available in IE so use .filter()[0] instead. * Blacklist unsupported codecs If MediaSource.isTypeSupported fails in a generic MP4 container, swapping to a variant with those codecs is unlikely to be successful. For instance, the fragmented bip-bop stream includes AC-3 and EC-3 audio which is not supported on Chrome or Firefox today. Exclude variants with codecs that don't pass the isTypeSupported test.
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Update sinon to v8.1.1 and fix abort tracking in mediaRequestsAborted (#724) * Update sinon to v8.1.1 and fix abort tracking in mediaRequestsAborted * Add check to media-segment-request for empty responseText when handling partial data This was not needed in the past, as the responseText property of a sinon response was anually set by VHS' test helpers. However, sinon now clears out the responseText property on a response, the mime type override trick doesn't work like it would in a browser. The additional check to the code should prove harmless, and acts as a guard against browsers which don't implement the mime type override trick in the same way. * Add an abortFn callback to media-segment-request to fix abort tracking in mediaRequestsAborted In the previously used version of sinon (v1.10.3), aborts of requests triggered the XHR callback. In the XHR standard however, this does not happen. Later versions of sinon fixed this issue. VHS' use of the old sinon lead to tests relying on broken behavior to verify abort tracking in mediaRequestsAborted. To properly use mediaRequestsAborted, aborts are tracked on loadend, part of XHR's [request error steps](https://xhr.spec.whatwg.org/#request-error-steps), and called back via the abortFn to increment mediaRequestsAborted * Skip id3 with partial data handling tests until they no longer rely on segments being fully requested A couple of tests checking for id3 frames surfacing from partial data handling were found to rely on the segment finishing its request before the data was surfaced. These tests are skipped until a fix can be made such that they rely only on partial data. * No longer override sinon's abort behavior for tests * No longer work around sinon's response types in standardXHRResponse With a newer sinon version, a few workarounds needed in test-helpers are no longer needed. * Skip partial data caption tests until they no longer rely on full segment responses
6 years ago
Update sinon to v8.1.1 and fix abort tracking in mediaRequestsAborted (#724) * Update sinon to v8.1.1 and fix abort tracking in mediaRequestsAborted * Add check to media-segment-request for empty responseText when handling partial data This was not needed in the past, as the responseText property of a sinon response was anually set by VHS' test helpers. However, sinon now clears out the responseText property on a response, the mime type override trick doesn't work like it would in a browser. The additional check to the code should prove harmless, and acts as a guard against browsers which don't implement the mime type override trick in the same way. * Add an abortFn callback to media-segment-request to fix abort tracking in mediaRequestsAborted In the previously used version of sinon (v1.10.3), aborts of requests triggered the XHR callback. In the XHR standard however, this does not happen. Later versions of sinon fixed this issue. VHS' use of the old sinon lead to tests relying on broken behavior to verify abort tracking in mediaRequestsAborted. To properly use mediaRequestsAborted, aborts are tracked on loadend, part of XHR's [request error steps](https://xhr.spec.whatwg.org/#request-error-steps), and called back via the abortFn to increment mediaRequestsAborted * Skip id3 with partial data handling tests until they no longer rely on segments being fully requested A couple of tests checking for id3 frames surfacing from partial data handling were found to rely on the segment finishing its request before the data was surfaced. These tests are skipped until a fix can be made such that they rely only on partial data. * No longer override sinon's abort behavior for tests * No longer work around sinon's response types in standardXHRResponse With a newer sinon version, a few workarounds needed in test-helpers are no longer needed. * Skip partial data caption tests until they no longer rely on full segment responses
6 years ago
Update sinon to v8.1.1 and fix abort tracking in mediaRequestsAborted (#724) * Update sinon to v8.1.1 and fix abort tracking in mediaRequestsAborted * Add check to media-segment-request for empty responseText when handling partial data This was not needed in the past, as the responseText property of a sinon response was anually set by VHS' test helpers. However, sinon now clears out the responseText property on a response, the mime type override trick doesn't work like it would in a browser. The additional check to the code should prove harmless, and acts as a guard against browsers which don't implement the mime type override trick in the same way. * Add an abortFn callback to media-segment-request to fix abort tracking in mediaRequestsAborted In the previously used version of sinon (v1.10.3), aborts of requests triggered the XHR callback. In the XHR standard however, this does not happen. Later versions of sinon fixed this issue. VHS' use of the old sinon lead to tests relying on broken behavior to verify abort tracking in mediaRequestsAborted. To properly use mediaRequestsAborted, aborts are tracked on loadend, part of XHR's [request error steps](https://xhr.spec.whatwg.org/#request-error-steps), and called back via the abortFn to increment mediaRequestsAborted * Skip id3 with partial data handling tests until they no longer rely on segments being fully requested A couple of tests checking for id3 frames surfacing from partial data handling were found to rely on the segment finishing its request before the data was surfaced. These tests are skipped until a fix can be made such that they rely only on partial data. * No longer override sinon's abort behavior for tests * No longer work around sinon's response types in standardXHRResponse With a newer sinon version, a few workarounds needed in test-helpers are no longer needed. * Skip partial data caption tests until they no longer rely on full segment responses
6 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Fmp4 support (#829) * Media init segment support Resolve EXT-X-MAP URI information in the playlist loader. Add support for requesting and appending initialization segments to the segment loader. * Basic support for fragmented MP4 playback Re-arrange source updater and track support to fit our design goals more closely. Make adjustments so that the correct source buffer types are created when a fragmented mp4 is encountered. This version will play Apple's fMp4 bipbop stream but you have to seek the player to 10 seconds after starting because the first fragment starts at 10, not 0. * Finish consolidating audio loaders Manage a single pair of audio playlist and segment loaders, instead of one per track. Update track logic to work with the new flow. * Detect and set the correct starting timestamp offset Probe the init and first MP4 segment to correctly set timestamp offset so that the stream begins at time zero. After this change, Apple's fragmented MP4 HLS example stream plays without additional modification. * Guard against media playlists without bandwidth information If a media playlist is loaded directly or bandwidth info is unavailable, make sure the lowest bitrate check doesn't error. Add some unnecessary request shifting to tests to avoid extraneous requests caused by the current behavior of segment loader when abort()-ing THEN pause()-ing. * Add stub prog_index.m3u8 for tests Some of the tests point to master playlists that reference prog_index.m3u8. Sinon caught most of the exceptions related to this but the tests weren't really exercising realistic scenarios. Add a stub prog_index to the test fixtures so that requests for prog_index don't unintentionally error. * Abort init segment XHR alongside other segment XHRs If the segment loader XHRs are aborted, stop the init segment one as well. Make sure to check the right property for the init segment XHR before continuing the loading process. Make sure falsey values do not cause a playlist to be blacklisted in FF for audio info changes. * Fix audio track management after reorganization Delay segment loader initialization steps until all starting configuration is ready. This allowed source updater MIME types to be specified early without triggering the main updater to have its audio disabled on startup. Tweak the mime type identifier function to signal alternate audio earlier. Move `this` references in segment loader's checkBuffer_ out to stateful functions to align with the original design goals. Removed a segment loader test that seemed duplicative after the checkBuffer_ change. * Fix D3 on stats page Update URL for D3. Remove audio switcher since it's included by default now. * Only override codec defaults if an actual value was parsed When converting codec strings into MIME type configurations for source buffers, make sure to use default values if the codec string didn't supply particular fields. Export the codec to MIME helper function so it can be unit-tested. * IE fixes Array.prototype.find() isn't available in IE so use .filter()[0] instead. * Blacklist unsupported codecs If MediaSource.isTypeSupported fails in a generic MP4 container, swapping to a variant with those codecs is unlikely to be successful. For instance, the fragmented bip-bop stream includes AC-3 and EC-3 audio which is not supported on Chrome or Firefox today. Exclude variants with codecs that don't pass the isTypeSupported test.
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Fmp4 support (#829) * Media init segment support Resolve EXT-X-MAP URI information in the playlist loader. Add support for requesting and appending initialization segments to the segment loader. * Basic support for fragmented MP4 playback Re-arrange source updater and track support to fit our design goals more closely. Make adjustments so that the correct source buffer types are created when a fragmented mp4 is encountered. This version will play Apple's fMp4 bipbop stream but you have to seek the player to 10 seconds after starting because the first fragment starts at 10, not 0. * Finish consolidating audio loaders Manage a single pair of audio playlist and segment loaders, instead of one per track. Update track logic to work with the new flow. * Detect and set the correct starting timestamp offset Probe the init and first MP4 segment to correctly set timestamp offset so that the stream begins at time zero. After this change, Apple's fragmented MP4 HLS example stream plays without additional modification. * Guard against media playlists without bandwidth information If a media playlist is loaded directly or bandwidth info is unavailable, make sure the lowest bitrate check doesn't error. Add some unnecessary request shifting to tests to avoid extraneous requests caused by the current behavior of segment loader when abort()-ing THEN pause()-ing. * Add stub prog_index.m3u8 for tests Some of the tests point to master playlists that reference prog_index.m3u8. Sinon caught most of the exceptions related to this but the tests weren't really exercising realistic scenarios. Add a stub prog_index to the test fixtures so that requests for prog_index don't unintentionally error. * Abort init segment XHR alongside other segment XHRs If the segment loader XHRs are aborted, stop the init segment one as well. Make sure to check the right property for the init segment XHR before continuing the loading process. Make sure falsey values do not cause a playlist to be blacklisted in FF for audio info changes. * Fix audio track management after reorganization Delay segment loader initialization steps until all starting configuration is ready. This allowed source updater MIME types to be specified early without triggering the main updater to have its audio disabled on startup. Tweak the mime type identifier function to signal alternate audio earlier. Move `this` references in segment loader's checkBuffer_ out to stateful functions to align with the original design goals. Removed a segment loader test that seemed duplicative after the checkBuffer_ change. * Fix D3 on stats page Update URL for D3. Remove audio switcher since it's included by default now. * Only override codec defaults if an actual value was parsed When converting codec strings into MIME type configurations for source buffers, make sure to use default values if the codec string didn't supply particular fields. Export the codec to MIME helper function so it can be unit-tested. * IE fixes Array.prototype.find() isn't available in IE so use .filter()[0] instead. * Blacklist unsupported codecs If MediaSource.isTypeSupported fails in a generic MP4 container, swapping to a variant with those codecs is unlikely to be successful. For instance, the fragmented bip-bop stream includes AC-3 and EC-3 audio which is not supported on Chrome or Firefox today. Exclude variants with codecs that don't pass the isTypeSupported test.
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Fmp4 support (#829) * Media init segment support Resolve EXT-X-MAP URI information in the playlist loader. Add support for requesting and appending initialization segments to the segment loader. * Basic support for fragmented MP4 playback Re-arrange source updater and track support to fit our design goals more closely. Make adjustments so that the correct source buffer types are created when a fragmented mp4 is encountered. This version will play Apple's fMp4 bipbop stream but you have to seek the player to 10 seconds after starting because the first fragment starts at 10, not 0. * Finish consolidating audio loaders Manage a single pair of audio playlist and segment loaders, instead of one per track. Update track logic to work with the new flow. * Detect and set the correct starting timestamp offset Probe the init and first MP4 segment to correctly set timestamp offset so that the stream begins at time zero. After this change, Apple's fragmented MP4 HLS example stream plays without additional modification. * Guard against media playlists without bandwidth information If a media playlist is loaded directly or bandwidth info is unavailable, make sure the lowest bitrate check doesn't error. Add some unnecessary request shifting to tests to avoid extraneous requests caused by the current behavior of segment loader when abort()-ing THEN pause()-ing. * Add stub prog_index.m3u8 for tests Some of the tests point to master playlists that reference prog_index.m3u8. Sinon caught most of the exceptions related to this but the tests weren't really exercising realistic scenarios. Add a stub prog_index to the test fixtures so that requests for prog_index don't unintentionally error. * Abort init segment XHR alongside other segment XHRs If the segment loader XHRs are aborted, stop the init segment one as well. Make sure to check the right property for the init segment XHR before continuing the loading process. Make sure falsey values do not cause a playlist to be blacklisted in FF for audio info changes. * Fix audio track management after reorganization Delay segment loader initialization steps until all starting configuration is ready. This allowed source updater MIME types to be specified early without triggering the main updater to have its audio disabled on startup. Tweak the mime type identifier function to signal alternate audio earlier. Move `this` references in segment loader's checkBuffer_ out to stateful functions to align with the original design goals. Removed a segment loader test that seemed duplicative after the checkBuffer_ change. * Fix D3 on stats page Update URL for D3. Remove audio switcher since it's included by default now. * Only override codec defaults if an actual value was parsed When converting codec strings into MIME type configurations for source buffers, make sure to use default values if the codec string didn't supply particular fields. Export the codec to MIME helper function so it can be unit-tested. * IE fixes Array.prototype.find() isn't available in IE so use .filter()[0] instead. * Blacklist unsupported codecs If MediaSource.isTypeSupported fails in a generic MP4 container, swapping to a variant with those codecs is unlikely to be successful. For instance, the fragmented bip-bop stream includes AC-3 and EC-3 audio which is not supported on Chrome or Firefox today. Exclude variants with codecs that don't pass the isTypeSupported test.
9 years ago
Fmp4 support (#829) * Media init segment support Resolve EXT-X-MAP URI information in the playlist loader. Add support for requesting and appending initialization segments to the segment loader. * Basic support for fragmented MP4 playback Re-arrange source updater and track support to fit our design goals more closely. Make adjustments so that the correct source buffer types are created when a fragmented mp4 is encountered. This version will play Apple's fMp4 bipbop stream but you have to seek the player to 10 seconds after starting because the first fragment starts at 10, not 0. * Finish consolidating audio loaders Manage a single pair of audio playlist and segment loaders, instead of one per track. Update track logic to work with the new flow. * Detect and set the correct starting timestamp offset Probe the init and first MP4 segment to correctly set timestamp offset so that the stream begins at time zero. After this change, Apple's fragmented MP4 HLS example stream plays without additional modification. * Guard against media playlists without bandwidth information If a media playlist is loaded directly or bandwidth info is unavailable, make sure the lowest bitrate check doesn't error. Add some unnecessary request shifting to tests to avoid extraneous requests caused by the current behavior of segment loader when abort()-ing THEN pause()-ing. * Add stub prog_index.m3u8 for tests Some of the tests point to master playlists that reference prog_index.m3u8. Sinon caught most of the exceptions related to this but the tests weren't really exercising realistic scenarios. Add a stub prog_index to the test fixtures so that requests for prog_index don't unintentionally error. * Abort init segment XHR alongside other segment XHRs If the segment loader XHRs are aborted, stop the init segment one as well. Make sure to check the right property for the init segment XHR before continuing the loading process. Make sure falsey values do not cause a playlist to be blacklisted in FF for audio info changes. * Fix audio track management after reorganization Delay segment loader initialization steps until all starting configuration is ready. This allowed source updater MIME types to be specified early without triggering the main updater to have its audio disabled on startup. Tweak the mime type identifier function to signal alternate audio earlier. Move `this` references in segment loader's checkBuffer_ out to stateful functions to align with the original design goals. Removed a segment loader test that seemed duplicative after the checkBuffer_ change. * Fix D3 on stats page Update URL for D3. Remove audio switcher since it's included by default now. * Only override codec defaults if an actual value was parsed When converting codec strings into MIME type configurations for source buffers, make sure to use default values if the codec string didn't supply particular fields. Export the codec to MIME helper function so it can be unit-tested. * IE fixes Array.prototype.find() isn't available in IE so use .filter()[0] instead. * Blacklist unsupported codecs If MediaSource.isTypeSupported fails in a generic MP4 container, swapping to a variant with those codecs is unlikely to be successful. For instance, the fragmented bip-bop stream includes AC-3 and EC-3 audio which is not supported on Chrome or Firefox today. Exclude variants with codecs that don't pass the isTypeSupported test.
9 years ago
Fmp4 support (#829) * Media init segment support Resolve EXT-X-MAP URI information in the playlist loader. Add support for requesting and appending initialization segments to the segment loader. * Basic support for fragmented MP4 playback Re-arrange source updater and track support to fit our design goals more closely. Make adjustments so that the correct source buffer types are created when a fragmented mp4 is encountered. This version will play Apple's fMp4 bipbop stream but you have to seek the player to 10 seconds after starting because the first fragment starts at 10, not 0. * Finish consolidating audio loaders Manage a single pair of audio playlist and segment loaders, instead of one per track. Update track logic to work with the new flow. * Detect and set the correct starting timestamp offset Probe the init and first MP4 segment to correctly set timestamp offset so that the stream begins at time zero. After this change, Apple's fragmented MP4 HLS example stream plays without additional modification. * Guard against media playlists without bandwidth information If a media playlist is loaded directly or bandwidth info is unavailable, make sure the lowest bitrate check doesn't error. Add some unnecessary request shifting to tests to avoid extraneous requests caused by the current behavior of segment loader when abort()-ing THEN pause()-ing. * Add stub prog_index.m3u8 for tests Some of the tests point to master playlists that reference prog_index.m3u8. Sinon caught most of the exceptions related to this but the tests weren't really exercising realistic scenarios. Add a stub prog_index to the test fixtures so that requests for prog_index don't unintentionally error. * Abort init segment XHR alongside other segment XHRs If the segment loader XHRs are aborted, stop the init segment one as well. Make sure to check the right property for the init segment XHR before continuing the loading process. Make sure falsey values do not cause a playlist to be blacklisted in FF for audio info changes. * Fix audio track management after reorganization Delay segment loader initialization steps until all starting configuration is ready. This allowed source updater MIME types to be specified early without triggering the main updater to have its audio disabled on startup. Tweak the mime type identifier function to signal alternate audio earlier. Move `this` references in segment loader's checkBuffer_ out to stateful functions to align with the original design goals. Removed a segment loader test that seemed duplicative after the checkBuffer_ change. * Fix D3 on stats page Update URL for D3. Remove audio switcher since it's included by default now. * Only override codec defaults if an actual value was parsed When converting codec strings into MIME type configurations for source buffers, make sure to use default values if the codec string didn't supply particular fields. Export the codec to MIME helper function so it can be unit-tested. * IE fixes Array.prototype.find() isn't available in IE so use .filter()[0] instead. * Blacklist unsupported codecs If MediaSource.isTypeSupported fails in a generic MP4 container, swapping to a variant with those codecs is unlikely to be successful. For instance, the fragmented bip-bop stream includes AC-3 and EC-3 audio which is not supported on Chrome or Firefox today. Exclude variants with codecs that don't pass the isTypeSupported test.
9 years ago
Fmp4 support (#829) * Media init segment support Resolve EXT-X-MAP URI information in the playlist loader. Add support for requesting and appending initialization segments to the segment loader. * Basic support for fragmented MP4 playback Re-arrange source updater and track support to fit our design goals more closely. Make adjustments so that the correct source buffer types are created when a fragmented mp4 is encountered. This version will play Apple's fMp4 bipbop stream but you have to seek the player to 10 seconds after starting because the first fragment starts at 10, not 0. * Finish consolidating audio loaders Manage a single pair of audio playlist and segment loaders, instead of one per track. Update track logic to work with the new flow. * Detect and set the correct starting timestamp offset Probe the init and first MP4 segment to correctly set timestamp offset so that the stream begins at time zero. After this change, Apple's fragmented MP4 HLS example stream plays without additional modification. * Guard against media playlists without bandwidth information If a media playlist is loaded directly or bandwidth info is unavailable, make sure the lowest bitrate check doesn't error. Add some unnecessary request shifting to tests to avoid extraneous requests caused by the current behavior of segment loader when abort()-ing THEN pause()-ing. * Add stub prog_index.m3u8 for tests Some of the tests point to master playlists that reference prog_index.m3u8. Sinon caught most of the exceptions related to this but the tests weren't really exercising realistic scenarios. Add a stub prog_index to the test fixtures so that requests for prog_index don't unintentionally error. * Abort init segment XHR alongside other segment XHRs If the segment loader XHRs are aborted, stop the init segment one as well. Make sure to check the right property for the init segment XHR before continuing the loading process. Make sure falsey values do not cause a playlist to be blacklisted in FF for audio info changes. * Fix audio track management after reorganization Delay segment loader initialization steps until all starting configuration is ready. This allowed source updater MIME types to be specified early without triggering the main updater to have its audio disabled on startup. Tweak the mime type identifier function to signal alternate audio earlier. Move `this` references in segment loader's checkBuffer_ out to stateful functions to align with the original design goals. Removed a segment loader test that seemed duplicative after the checkBuffer_ change. * Fix D3 on stats page Update URL for D3. Remove audio switcher since it's included by default now. * Only override codec defaults if an actual value was parsed When converting codec strings into MIME type configurations for source buffers, make sure to use default values if the codec string didn't supply particular fields. Export the codec to MIME helper function so it can be unit-tested. * IE fixes Array.prototype.find() isn't available in IE so use .filter()[0] instead. * Blacklist unsupported codecs If MediaSource.isTypeSupported fails in a generic MP4 container, swapping to a variant with those codecs is unlikely to be successful. For instance, the fragmented bip-bop stream includes AC-3 and EC-3 audio which is not supported on Chrome or Firefox today. Exclude variants with codecs that don't pass the isTypeSupported test.
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Fmp4 support (#829) * Media init segment support Resolve EXT-X-MAP URI information in the playlist loader. Add support for requesting and appending initialization segments to the segment loader. * Basic support for fragmented MP4 playback Re-arrange source updater and track support to fit our design goals more closely. Make adjustments so that the correct source buffer types are created when a fragmented mp4 is encountered. This version will play Apple's fMp4 bipbop stream but you have to seek the player to 10 seconds after starting because the first fragment starts at 10, not 0. * Finish consolidating audio loaders Manage a single pair of audio playlist and segment loaders, instead of one per track. Update track logic to work with the new flow. * Detect and set the correct starting timestamp offset Probe the init and first MP4 segment to correctly set timestamp offset so that the stream begins at time zero. After this change, Apple's fragmented MP4 HLS example stream plays without additional modification. * Guard against media playlists without bandwidth information If a media playlist is loaded directly or bandwidth info is unavailable, make sure the lowest bitrate check doesn't error. Add some unnecessary request shifting to tests to avoid extraneous requests caused by the current behavior of segment loader when abort()-ing THEN pause()-ing. * Add stub prog_index.m3u8 for tests Some of the tests point to master playlists that reference prog_index.m3u8. Sinon caught most of the exceptions related to this but the tests weren't really exercising realistic scenarios. Add a stub prog_index to the test fixtures so that requests for prog_index don't unintentionally error. * Abort init segment XHR alongside other segment XHRs If the segment loader XHRs are aborted, stop the init segment one as well. Make sure to check the right property for the init segment XHR before continuing the loading process. Make sure falsey values do not cause a playlist to be blacklisted in FF for audio info changes. * Fix audio track management after reorganization Delay segment loader initialization steps until all starting configuration is ready. This allowed source updater MIME types to be specified early without triggering the main updater to have its audio disabled on startup. Tweak the mime type identifier function to signal alternate audio earlier. Move `this` references in segment loader's checkBuffer_ out to stateful functions to align with the original design goals. Removed a segment loader test that seemed duplicative after the checkBuffer_ change. * Fix D3 on stats page Update URL for D3. Remove audio switcher since it's included by default now. * Only override codec defaults if an actual value was parsed When converting codec strings into MIME type configurations for source buffers, make sure to use default values if the codec string didn't supply particular fields. Export the codec to MIME helper function so it can be unit-tested. * IE fixes Array.prototype.find() isn't available in IE so use .filter()[0] instead. * Blacklist unsupported codecs If MediaSource.isTypeSupported fails in a generic MP4 container, swapping to a variant with those codecs is unlikely to be successful. For instance, the fragmented bip-bop stream includes AC-3 and EC-3 audio which is not supported on Chrome or Firefox today. Exclude variants with codecs that don't pass the isTypeSupported test.
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Fmp4 support (#829) * Media init segment support Resolve EXT-X-MAP URI information in the playlist loader. Add support for requesting and appending initialization segments to the segment loader. * Basic support for fragmented MP4 playback Re-arrange source updater and track support to fit our design goals more closely. Make adjustments so that the correct source buffer types are created when a fragmented mp4 is encountered. This version will play Apple's fMp4 bipbop stream but you have to seek the player to 10 seconds after starting because the first fragment starts at 10, not 0. * Finish consolidating audio loaders Manage a single pair of audio playlist and segment loaders, instead of one per track. Update track logic to work with the new flow. * Detect and set the correct starting timestamp offset Probe the init and first MP4 segment to correctly set timestamp offset so that the stream begins at time zero. After this change, Apple's fragmented MP4 HLS example stream plays without additional modification. * Guard against media playlists without bandwidth information If a media playlist is loaded directly or bandwidth info is unavailable, make sure the lowest bitrate check doesn't error. Add some unnecessary request shifting to tests to avoid extraneous requests caused by the current behavior of segment loader when abort()-ing THEN pause()-ing. * Add stub prog_index.m3u8 for tests Some of the tests point to master playlists that reference prog_index.m3u8. Sinon caught most of the exceptions related to this but the tests weren't really exercising realistic scenarios. Add a stub prog_index to the test fixtures so that requests for prog_index don't unintentionally error. * Abort init segment XHR alongside other segment XHRs If the segment loader XHRs are aborted, stop the init segment one as well. Make sure to check the right property for the init segment XHR before continuing the loading process. Make sure falsey values do not cause a playlist to be blacklisted in FF for audio info changes. * Fix audio track management after reorganization Delay segment loader initialization steps until all starting configuration is ready. This allowed source updater MIME types to be specified early without triggering the main updater to have its audio disabled on startup. Tweak the mime type identifier function to signal alternate audio earlier. Move `this` references in segment loader's checkBuffer_ out to stateful functions to align with the original design goals. Removed a segment loader test that seemed duplicative after the checkBuffer_ change. * Fix D3 on stats page Update URL for D3. Remove audio switcher since it's included by default now. * Only override codec defaults if an actual value was parsed When converting codec strings into MIME type configurations for source buffers, make sure to use default values if the codec string didn't supply particular fields. Export the codec to MIME helper function so it can be unit-tested. * IE fixes Array.prototype.find() isn't available in IE so use .filter()[0] instead. * Blacklist unsupported codecs If MediaSource.isTypeSupported fails in a generic MP4 container, swapping to a variant with those codecs is unlikely to be successful. For instance, the fragmented bip-bop stream includes AC-3 and EC-3 audio which is not supported on Chrome or Firefox today. Exclude variants with codecs that don't pass the isTypeSupported test.
9 years ago
Fmp4 support (#829) * Media init segment support Resolve EXT-X-MAP URI information in the playlist loader. Add support for requesting and appending initialization segments to the segment loader. * Basic support for fragmented MP4 playback Re-arrange source updater and track support to fit our design goals more closely. Make adjustments so that the correct source buffer types are created when a fragmented mp4 is encountered. This version will play Apple's fMp4 bipbop stream but you have to seek the player to 10 seconds after starting because the first fragment starts at 10, not 0. * Finish consolidating audio loaders Manage a single pair of audio playlist and segment loaders, instead of one per track. Update track logic to work with the new flow. * Detect and set the correct starting timestamp offset Probe the init and first MP4 segment to correctly set timestamp offset so that the stream begins at time zero. After this change, Apple's fragmented MP4 HLS example stream plays without additional modification. * Guard against media playlists without bandwidth information If a media playlist is loaded directly or bandwidth info is unavailable, make sure the lowest bitrate check doesn't error. Add some unnecessary request shifting to tests to avoid extraneous requests caused by the current behavior of segment loader when abort()-ing THEN pause()-ing. * Add stub prog_index.m3u8 for tests Some of the tests point to master playlists that reference prog_index.m3u8. Sinon caught most of the exceptions related to this but the tests weren't really exercising realistic scenarios. Add a stub prog_index to the test fixtures so that requests for prog_index don't unintentionally error. * Abort init segment XHR alongside other segment XHRs If the segment loader XHRs are aborted, stop the init segment one as well. Make sure to check the right property for the init segment XHR before continuing the loading process. Make sure falsey values do not cause a playlist to be blacklisted in FF for audio info changes. * Fix audio track management after reorganization Delay segment loader initialization steps until all starting configuration is ready. This allowed source updater MIME types to be specified early without triggering the main updater to have its audio disabled on startup. Tweak the mime type identifier function to signal alternate audio earlier. Move `this` references in segment loader's checkBuffer_ out to stateful functions to align with the original design goals. Removed a segment loader test that seemed duplicative after the checkBuffer_ change. * Fix D3 on stats page Update URL for D3. Remove audio switcher since it's included by default now. * Only override codec defaults if an actual value was parsed When converting codec strings into MIME type configurations for source buffers, make sure to use default values if the codec string didn't supply particular fields. Export the codec to MIME helper function so it can be unit-tested. * IE fixes Array.prototype.find() isn't available in IE so use .filter()[0] instead. * Blacklist unsupported codecs If MediaSource.isTypeSupported fails in a generic MP4 container, swapping to a variant with those codecs is unlikely to be successful. For instance, the fragmented bip-bop stream includes AC-3 and EC-3 audio which is not supported on Chrome or Firefox today. Exclude variants with codecs that don't pass the isTypeSupported test.
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Update sinon to v8.1.1 and fix abort tracking in mediaRequestsAborted (#724) * Update sinon to v8.1.1 and fix abort tracking in mediaRequestsAborted * Add check to media-segment-request for empty responseText when handling partial data This was not needed in the past, as the responseText property of a sinon response was anually set by VHS' test helpers. However, sinon now clears out the responseText property on a response, the mime type override trick doesn't work like it would in a browser. The additional check to the code should prove harmless, and acts as a guard against browsers which don't implement the mime type override trick in the same way. * Add an abortFn callback to media-segment-request to fix abort tracking in mediaRequestsAborted In the previously used version of sinon (v1.10.3), aborts of requests triggered the XHR callback. In the XHR standard however, this does not happen. Later versions of sinon fixed this issue. VHS' use of the old sinon lead to tests relying on broken behavior to verify abort tracking in mediaRequestsAborted. To properly use mediaRequestsAborted, aborts are tracked on loadend, part of XHR's [request error steps](https://xhr.spec.whatwg.org/#request-error-steps), and called back via the abortFn to increment mediaRequestsAborted * Skip id3 with partial data handling tests until they no longer rely on segments being fully requested A couple of tests checking for id3 frames surfacing from partial data handling were found to rely on the segment finishing its request before the data was surfaced. These tests are skipped until a fix can be made such that they rely only on partial data. * No longer override sinon's abort behavior for tests * No longer work around sinon's response types in standardXHRResponse With a newer sinon version, a few workarounds needed in test-helpers are no longer needed. * Skip partial data caption tests until they no longer rely on full segment responses
6 years ago
Update sinon to v8.1.1 and fix abort tracking in mediaRequestsAborted (#724) * Update sinon to v8.1.1 and fix abort tracking in mediaRequestsAborted * Add check to media-segment-request for empty responseText when handling partial data This was not needed in the past, as the responseText property of a sinon response was anually set by VHS' test helpers. However, sinon now clears out the responseText property on a response, the mime type override trick doesn't work like it would in a browser. The additional check to the code should prove harmless, and acts as a guard against browsers which don't implement the mime type override trick in the same way. * Add an abortFn callback to media-segment-request to fix abort tracking in mediaRequestsAborted In the previously used version of sinon (v1.10.3), aborts of requests triggered the XHR callback. In the XHR standard however, this does not happen. Later versions of sinon fixed this issue. VHS' use of the old sinon lead to tests relying on broken behavior to verify abort tracking in mediaRequestsAborted. To properly use mediaRequestsAborted, aborts are tracked on loadend, part of XHR's [request error steps](https://xhr.spec.whatwg.org/#request-error-steps), and called back via the abortFn to increment mediaRequestsAborted * Skip id3 with partial data handling tests until they no longer rely on segments being fully requested A couple of tests checking for id3 frames surfacing from partial data handling were found to rely on the segment finishing its request before the data was surfaced. These tests are skipped until a fix can be made such that they rely only on partial data. * No longer override sinon's abort behavior for tests * No longer work around sinon's response types in standardXHRResponse With a newer sinon version, a few workarounds needed in test-helpers are no longer needed. * Skip partial data caption tests until they no longer rely on full segment responses
6 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
Simplified fetch algorithm as much as possible (#875) Fixed seeking behavior Updated getMediaIndexForTime to be simple and stupid Remove spurious console logs Fixed an issue with forward seeks and a different problem with backwards seeking (thanks Matt!). Fixed fast rendition change behavior. Remove limits on gap-skipper. Skip instantly without waiting. Use the proper native MediaSource duration for buffer removals. Improvements for live stream rendition changes Fixed an undefined variable bug Some more simplification and a very conservative live stream rendition change approach VOD fixes Experimental change to the way we throttle the fetcher Use GOAL_BUFFER_LENGTH again Continued massive changes to segment fetching. Cleanup and comments. Fixed a bug where we were fetching starting at mediaIndex 0 on every seek. Refactor probing code in preparation for pulling into it's own module or class Moved sync-related logic out of segment-loader and into a new sync-controller class Removed expired from the SegmentLoader Update mux.js dependency to 2.5.0 Don't error when the tsprobe returns null Fixed two issues: MAAT switching and Flash seeking Rename duration variable fix flash failing first segment load (#859) dont use tech for has played (#861) Code Coverage and Unit tests for Simple Fetcher (#862) fix has played returning false on vod (#866) Fixed preload="none" behavior and reduced the incidence of repeating initial segment requests (#878) Provide option to set contrib-hls first in the HTML5 tech (#889) This reverts commit 59ddbe1188c0b4a1d55d63fa7a334174001fbd28. Add playback tests (#894) Fixed MSE and environment test helpers, restore properly Removed unused test files remove expired time tracking and use sync points to calculate seekable (#898) Fixing a few tests for QUnit 2.0
9 years ago
  1. import document from 'global/document';
  2. import videojs from 'video.js';
  3. import Events from 'video.js';
  4. import QUnit from 'qunit';
  5. import testDataManifests from 'create-test-data!manifests';
  6. import {
  7. muxed as muxedSegment,
  8. encryptionKey,
  9. encrypted as encryptedSegment,
  10. audio as audioSegment,
  11. video as videoSegment,
  12. mp4VideoInit as mp4VideoInitSegment,
  13. mp4Video as mp4VideoSegment,
  14. mp4AudioInit as mp4AudioInitSegment,
  15. mp4Audio as mp4AudioSegment
  16. } from 'create-test-data!segments';
  17. import {
  18. useFakeEnvironment,
  19. useFakeMediaSource,
  20. createPlayer,
  21. openMediaSource,
  22. standardXHRResponse,
  23. absoluteUrl,
  24. requestAndAppendSegment,
  25. disposePlaybackWatcher
  26. } from './test-helpers.js';
  27. import {
  28. createPlaylistID,
  29. parseManifest
  30. } from '../src/manifest.js';
  31. /* eslint-disable no-unused-vars */
  32. // we need this so that it can register vhs with videojs
  33. import {
  34. VhsSourceHandler,
  35. VhsHandler,
  36. Vhs,
  37. emeKeySystems,
  38. LOCAL_STORAGE_KEY,
  39. expandDataUri,
  40. setupEmeOptions,
  41. getAllPsshKeySystemsOptions,
  42. waitForKeySessionCreation
  43. } from '../src/videojs-http-streaming';
  44. import window from 'global/window';
  45. // we need this so the plugin registers itself
  46. import 'videojs-contrib-quality-levels';
  47. import 'videojs-contrib-eme';
  48. import {version as vhsVersion} from '../package.json';
  49. import {version as muxVersion} from 'mux.js/package.json';
  50. import {version as mpdVersion} from 'mpd-parser/package.json';
  51. import {version as m3u8Version} from 'm3u8-parser/package.json';
  52. import {version as aesVersion} from 'aes-decrypter/package.json';
  53. let testOrSkip = 'test';
  54. // some tests just don't work reliably on ie11 or edge
  55. if (videojs.browser.IS_EDGE || videojs.browser.IE_VERSION) {
  56. testOrSkip = 'skip';
  57. }
  58. const ogVhsHandlerSetupQualityLevels = videojs.VhsHandler.prototype.setupQualityLevels_;
  59. // do a shallow copy of the properties of source onto the target object
  60. const merge = function(target, source) {
  61. let name;
  62. for (name in source) {
  63. target[name] = source[name];
  64. }
  65. };
  66. QUnit.module('VHS', {
  67. beforeEach(assert) {
  68. this.env = useFakeEnvironment(assert);
  69. this.requests = this.env.requests;
  70. this.mse = useFakeMediaSource();
  71. this.clock = this.env.clock;
  72. this.old = {};
  73. if (!videojs.browser.IE_VERSION) {
  74. this.old.devicePixelRatio = window.devicePixelRatio;
  75. window.devicePixelRatio = 1;
  76. }
  77. // store functionality that some tests need to mock
  78. this.old.GlobalOptions = videojs.mergeOptions(videojs.options);
  79. // force the HLS tech to run
  80. this.old.NativeHlsSupport = videojs.Vhs.supportsNativeHls;
  81. videojs.Vhs.supportsNativeHls = false;
  82. this.old.NativeDashSupport = videojs.Vhs.supportsNativeDash;
  83. videojs.Vhs.supportsNativeDash = false;
  84. this.old.Decrypt = videojs.Vhs.Decrypter;
  85. videojs.Vhs.Decrypter = function() {};
  86. // save and restore browser detection for the Firefox-specific tests
  87. this.old.browser = videojs.browser;
  88. videojs.browser = videojs.mergeOptions({}, videojs.browser);
  89. this.standardXHRResponse = (request, data) => {
  90. standardXHRResponse(request, data);
  91. // Because SegmentLoader#fillBuffer_ is now scheduled asynchronously
  92. // we have to use clock.tick to get the expected side effects of
  93. // SegmentLoader#handleAppendsDone_
  94. this.clock.tick(1);
  95. };
  96. // setup a player
  97. this.player = createPlayer();
  98. this.clock.tick(1);
  99. },
  100. afterEach() {
  101. this.env.restore();
  102. this.mse.restore();
  103. if (this.old.hasOwnProperty('devicePixelRatio')) {
  104. window.devicePixelRatio = this.old.devicePixelRatio;
  105. }
  106. merge(videojs.options, this.old.GlobalOptions);
  107. videojs.Vhs.supportsNativeHls = this.old.NativeHlsSupport;
  108. videojs.Vhs.supportsNativeDash = this.old.NativeDashSupport;
  109. videojs.Vhs.Decrypter = this.old.Decrypt;
  110. videojs.browser = this.old.browser;
  111. window.localStorage.clear();
  112. this.player.dispose();
  113. }
  114. });
  115. QUnit.test('mse urls are created and revoked', function(assert) {
  116. const old = {
  117. createObjectURL: window.URL.createObjectURL,
  118. revokeObjectURL: window.URL.revokeObjectURL
  119. };
  120. const ids = [];
  121. window.URL.createObjectURL = (...args) => {
  122. const id = old.createObjectURL.apply(window.URL, args);
  123. ids.push(id);
  124. return id;
  125. };
  126. window.URL.revokeObjectURL = (...args) => {
  127. const index = ids.indexOf(args[0]);
  128. if (index !== -1) {
  129. ids.splice(index, 1);
  130. }
  131. return old.revokeObjectURL.apply(window.URL, args);
  132. };
  133. this.player.src({
  134. src: 'manifest/playlist.m3u8',
  135. type: 'application/vnd.apple.mpegurl'
  136. });
  137. this.clock.tick(1);
  138. assert.ok(ids.length > 0, 'object urls created');
  139. this.player.dispose();
  140. assert.equal(ids.length, 0, 'all object urls removed');
  141. window.URL.createObjectURL = old.createObjectURL;
  142. window.URL.revokeObjectURL = old.revokeObjectURL;
  143. });
  144. QUnit.test('version is exported', function(assert) {
  145. this.player.src({
  146. src: 'manifest/playlist.m3u8',
  147. type: 'application/vnd.apple.mpegurl'
  148. });
  149. this.clock.tick(1);
  150. assert.ok(this.player.tech(true).vhs.version, 'version function');
  151. assert.ok(videojs.VhsHandler.version, 'version function');
  152. assert.deepEqual(this.player.tech(true).vhs.version(), {
  153. '@videojs/http-streaming': vhsVersion,
  154. 'mux.js': muxVersion,
  155. 'mpd-parser': mpdVersion,
  156. 'm3u8-parser': m3u8Version,
  157. 'aes-decrypter': aesVersion
  158. }, 'version is correct');
  159. });
  160. QUnit.test('canChangeType is exported', function(assert) {
  161. this.player.src({
  162. src: 'manifest/playlist.m3u8',
  163. type: 'application/vnd.apple.mpegurl'
  164. });
  165. this.clock.tick(1);
  166. assert.ok(this.player.tech(true).vhs.canChangeType, 'canChangeType function');
  167. const canChangeType = window.SourceBuffer &&
  168. window.SourceBuffer.prototype &&
  169. typeof window.SourceBuffer.prototype.changeType === 'function';
  170. const assertion = canChangeType ? 'ok' : 'notOk';
  171. assert[assertion](this.player.tech(true).vhs.canChangeType(), 'canChangeType is correct');
  172. });
  173. QUnit.test('deprecation warning is show when using player.hls', function(assert) {
  174. const oldWarn = videojs.log.warn;
  175. let warning = '';
  176. let vhsPlayerAccessEvents = 0;
  177. let hlsPlayerAccessEvents = 0;
  178. this.player.src({
  179. src: 'manifest/playlist.m3u8',
  180. type: 'application/vnd.apple.mpegurl'
  181. });
  182. this.clock.tick(1);
  183. this.player.tech_.on('usage', (event) => {
  184. if (event.name === 'vhs-player-access') {
  185. vhsPlayerAccessEvents++;
  186. }
  187. if (event.name === 'hls-player-access') {
  188. hlsPlayerAccessEvents++;
  189. }
  190. });
  191. videojs.log.warn = (text) => {
  192. warning = text;
  193. };
  194. assert.equal(vhsPlayerAccessEvents, 0, 'no vhs-player-access event was fired');
  195. assert.equal(hlsPlayerAccessEvents, 0, 'no hls-player-access event was fired');
  196. const hls = this.player.hls;
  197. assert.equal(vhsPlayerAccessEvents, 0, 'no vhs-player-access event was fired');
  198. assert.equal(hlsPlayerAccessEvents, 1, 'an hls-player-access event was fired');
  199. assert.equal(
  200. warning,
  201. 'player.hls is deprecated. Use player.tech().vhs instead.',
  202. 'warning would have been shown'
  203. );
  204. assert.ok(hls, 'an instance of hls is returned by player.hls');
  205. videojs.log.warn = oldWarn;
  206. });
  207. QUnit.test('deprecation warning is show when using player.vhs', function(assert) {
  208. const oldWarn = videojs.log.warn;
  209. let warning = '';
  210. let vhsPlayerAccessEvents = 0;
  211. let hlsPlayerAccessEvents = 0;
  212. this.player.src({
  213. src: 'manifest/playlist.m3u8',
  214. type: 'application/vnd.apple.mpegurl'
  215. });
  216. this.clock.tick(1);
  217. this.player.tech_.on('usage', (event) => {
  218. if (event.name === 'vhs-player-access') {
  219. vhsPlayerAccessEvents++;
  220. }
  221. if (event.name === 'hls-player-access') {
  222. hlsPlayerAccessEvents++;
  223. }
  224. });
  225. videojs.log.warn = (text) => {
  226. warning = text;
  227. };
  228. assert.equal(vhsPlayerAccessEvents, 0, 'no vhs-player-access event was fired');
  229. assert.equal(hlsPlayerAccessEvents, 0, 'no hls-player-access event was fired');
  230. const vhs = this.player.vhs;
  231. assert.equal(vhsPlayerAccessEvents, 1, 'a vhs-player-access event was fired');
  232. assert.equal(hlsPlayerAccessEvents, 0, 'no hls-player-access event was fired');
  233. assert.equal(
  234. warning,
  235. 'player.vhs is deprecated. Use player.tech().vhs instead.',
  236. 'warning would have been shown'
  237. );
  238. assert.ok(vhs, 'an instance of vhs is returned by player.vhs');
  239. videojs.log.warn = oldWarn;
  240. });
  241. QUnit.test('the VhsHandler instance is referenced by player.vhs', function(assert) {
  242. this.player.src({
  243. src: 'manifest/playlist.m3u8',
  244. type: 'application/vnd.apple.mpegurl'
  245. });
  246. this.clock.tick(1);
  247. const vhs = this.player.vhs;
  248. assert.ok(vhs instanceof VhsHandler, 'player.vhs references an instance of VhsHandler');
  249. assert.equal(this.env.log.warn.calls, 1, 'warning logged');
  250. });
  251. QUnit.test('tech error may pause loading', function(assert) {
  252. this.player.src({
  253. src: 'manifest/playlist.m3u8',
  254. type: 'application/vnd.apple.mpegurl'
  255. });
  256. this.clock.tick(1);
  257. const vhs = this.player.tech_.vhs;
  258. const mpc = vhs.masterPlaylistController_;
  259. let pauseCalled = false;
  260. mpc.pauseLoading = () => {
  261. pauseCalled = true;
  262. };
  263. this.player.tech_.error = () => null;
  264. this.player.tech_.trigger('error');
  265. assert.notOk(pauseCalled, 'no video el error attribute, no pause loading');
  266. this.player.tech_.error = () => 'foo';
  267. this.player.tech_.trigger('error');
  268. assert.ok(pauseCalled, 'video el error and trigger pauses loading');
  269. assert.equal(this.env.log.error.calls, 1, '1 media error logged');
  270. this.env.log.error.reset();
  271. });
  272. QUnit.test('a deprecation notice is shown when using player.dash', function(assert) {
  273. this.player.src({
  274. src: 'manifest/playlist.m3u8',
  275. type: 'application/vnd.apple.mpegurl'
  276. });
  277. this.clock.tick(1);
  278. assert.ok(
  279. this.player.dash instanceof VhsHandler,
  280. 'player.dash references an instance of VhsHandler'
  281. );
  282. assert.equal(this.env.log.warn.calls, 1, 'warning logged');
  283. assert.equal(
  284. this.env.log.warn.args[0][0],
  285. 'player.dash is deprecated. Use player.tech().vhs instead.',
  286. 'logged deprecation'
  287. );
  288. });
  289. QUnit.test('VhsHandler is referenced by player.tech().vhs', function(assert) {
  290. this.player.src({
  291. src: 'manifest/playlist.m3u8',
  292. type: 'application/vnd.apple.mpegurl'
  293. });
  294. this.clock.tick(1);
  295. assert.ok(
  296. this.player.tech().vhs instanceof VhsHandler,
  297. 'player.tech().vhs references an instance of VhsHandler'
  298. );
  299. assert.equal(this.env.log.warn.calls, 1, 'warning logged');
  300. assert.equal(
  301. this.env.log.warn.args[0][0],
  302. 'Using the tech directly can be dangerous. I hope you know what you\'re doing.\n' +
  303. 'See https://github.com/videojs/video.js/issues/2617 for more info.\n',
  304. 'logged warning'
  305. );
  306. });
  307. QUnit.test('logs deprecation notice when using player.tech().hls', function(assert) {
  308. this.player.src({
  309. src: 'manifest/playlist.m3u8',
  310. type: 'application/vnd.apple.mpegurl'
  311. });
  312. this.clock.tick(1);
  313. assert.ok(
  314. this.player.tech().hls instanceof VhsHandler,
  315. 'player.tech().hls references an instance of VhsHandler'
  316. );
  317. assert.equal(this.env.log.warn.calls, 2, 'warning logged');
  318. assert.equal(
  319. this.env.log.warn.args[0][0],
  320. 'Using the tech directly can be dangerous. I hope you know what you\'re doing.\n' +
  321. 'See https://github.com/videojs/video.js/issues/2617 for more info.\n',
  322. 'logged warning'
  323. );
  324. assert.equal(
  325. this.env.log.warn.args[1][0],
  326. 'player.tech().hls is deprecated. Use player.tech().vhs instead.',
  327. 'logged deprecation'
  328. );
  329. });
  330. QUnit.test('logs deprecation notice when using hls for options', function(assert) {
  331. this.player.dispose();
  332. this.player = createPlayer({ html5: { hls: { bandwidth: 0 } } });
  333. this.player.src({
  334. src: 'http://example.com/media.m3u8',
  335. type: 'application/vnd.apple.mpegurl'
  336. });
  337. this.clock.tick(1);
  338. openMediaSource(this.player, this.clock);
  339. assert.equal(this.player.tech_.vhs.bandwidth, 0, 'set bandwidth to 0');
  340. assert.equal(this.env.log.warn.calls, 1, 'warning logged');
  341. assert.equal(
  342. this.env.log.warn.args[0][0],
  343. 'Using hls options is deprecated. Use vhs instead.',
  344. );
  345. });
  346. QUnit.test('logs deprecation notice when using hls for global options', function(assert) {
  347. const origHlsOptions = videojs.options.hls;
  348. this.player.dispose();
  349. videojs.options.hls = {
  350. bandwidth: 0
  351. };
  352. this.player = createPlayer();
  353. this.player.src({
  354. src: 'http://example.com/media.m3u8',
  355. type: 'application/vnd.apple.mpegurl'
  356. });
  357. this.clock.tick(1);
  358. openMediaSource(this.player, this.clock);
  359. assert.equal(this.player.tech_.vhs.bandwidth, 0, 'set bandwidth to 0');
  360. assert.equal(this.env.log.warn.calls, 1, 'warning logged');
  361. assert.equal(
  362. this.env.log.warn.args[0][0],
  363. 'Using hls options is deprecated. Use vhs instead.',
  364. );
  365. videojs.options.hls = origHlsOptions;
  366. });
  367. QUnit.test('logs deprecation notice when using videojs.Hls', function(assert) {
  368. assert.equal(videojs.Hls, Vhs, 'can get Vhs object from videojs.Hls');
  369. assert.equal(this.env.log.warn.calls, 1, 'warning logged');
  370. assert.equal(
  371. this.env.log.warn.args[0][0],
  372. 'videojs.Hls is deprecated. Use videojs.Vhs instead.'
  373. );
  374. });
  375. QUnit.test('logs deprecation notice when using videojs.HlsHandler', function(assert) {
  376. this.player.src({
  377. src: 'http://example.com/media.m3u8',
  378. type: 'application/vnd.apple.mpegurl'
  379. });
  380. this.clock.tick(1);
  381. assert.equal(
  382. videojs.HlsHandler,
  383. VhsHandler,
  384. 'can get VhsHandler from videojs.HlsHandler'
  385. );
  386. assert.equal(this.env.log.warn.calls, 1, 'warning logged');
  387. assert.equal(
  388. this.env.log.warn.args[0][0],
  389. 'videojs.HlsHandler is deprecated. Use videojs.VhsHandler instead.'
  390. );
  391. });
  392. QUnit.test('logs deprecation notice when using videojs.HlsSourceHandler', function(assert) {
  393. this.player.src({
  394. src: 'http://example.com/media.m3u8',
  395. type: 'application/vnd.apple.mpegurl'
  396. });
  397. this.clock.tick(1);
  398. assert.equal(
  399. videojs.HlsSourceHandler,
  400. VhsSourceHandler,
  401. 'can get VhsSourceHandler from videojs.HlsSourceHandler'
  402. );
  403. assert.equal(this.env.log.warn.calls, 1, 'warning logged');
  404. assert.equal(
  405. this.env.log.warn.args[0][0],
  406. 'videojs.HlsSourceHandler is deprecated. Use videojs.VhsSourceHandler instead.'
  407. );
  408. });
  409. QUnit.test('starts playing if autoplay is specified', function(assert) {
  410. this.player.autoplay(true);
  411. this.player.src({
  412. src: 'manifest/playlist.m3u8',
  413. type: 'application/vnd.apple.mpegurl'
  414. });
  415. this.clock.tick(1);
  416. // make sure play() is called *after* the media source opens
  417. openMediaSource(this.player, this.clock);
  418. this.standardXHRResponse(this.requests[0]);
  419. assert.ok(!this.player.paused(), 'not paused');
  420. });
  421. QUnit.test('stats are reset on each new source', function(assert) {
  422. const done = assert.async();
  423. this.player.src({
  424. src: 'manifest/playlist.m3u8',
  425. type: 'application/vnd.apple.mpegurl'
  426. });
  427. this.clock.tick(1);
  428. // make sure play() is called *after* the media source opens
  429. openMediaSource(this.player, this.clock);
  430. const segment = muxedSegment();
  431. // copy the byte length since the segment bytes get cleared out
  432. const segmentByteLength = segment.byteLength;
  433. assert.ok(segmentByteLength, 'the segment has some number of bytes');
  434. // media
  435. this.standardXHRResponse(this.requests.shift());
  436. this.player.tech(true).vhs.masterPlaylistController_.mainSegmentLoader_.one('appending', () => {
  437. assert.equal(
  438. this.player.tech_.vhs.stats.mediaBytesTransferred,
  439. segmentByteLength,
  440. 'stat is set'
  441. );
  442. this.player.src({
  443. src: 'manifest/master.m3u8',
  444. type: 'application/vnd.apple.mpegurl'
  445. });
  446. this.clock.tick(1);
  447. assert.equal(this.player.tech_.vhs.stats.mediaBytesTransferred, 0, 'stat is reset');
  448. done();
  449. });
  450. // segment 0
  451. this.standardXHRResponse(this.requests.shift(), segment);
  452. });
  453. QUnit.test('XHR requests first byte range on play', function(assert) {
  454. this.player.src({
  455. src: 'manifest/playlist.m3u8',
  456. type: 'application/vnd.apple.mpegurl'
  457. });
  458. this.clock.tick(1);
  459. this.player.tech_.triggerReady();
  460. this.clock.tick(1);
  461. this.player.tech_.trigger('play');
  462. openMediaSource(this.player, this.clock);
  463. this.standardXHRResponse(this.requests[0]);
  464. assert.equal(this.requests[1].headers.Range, 'bytes=0-522827');
  465. });
  466. QUnit.test('Seeking requests correct byte range', function(assert) {
  467. this.player.src({
  468. src: 'manifest/playlist.m3u8',
  469. type: 'application/vnd.apple.mpegurl'
  470. });
  471. this.clock.tick(1);
  472. this.player.tech_.trigger('play');
  473. openMediaSource(this.player, this.clock);
  474. this.standardXHRResponse(this.requests[0]);
  475. this.clock.tick(1);
  476. this.player.currentTime(41);
  477. this.clock.tick(2);
  478. assert.equal(this.requests[2].headers.Range, 'bytes=2299992-2835603');
  479. });
  480. QUnit.test('autoplay seeks to the live point after playlist load', function(assert) {
  481. let currentTime = 0;
  482. this.player.autoplay(true);
  483. this.player.tech_.currentTime = (ct) => {
  484. currentTime = ct;
  485. };
  486. this.player.src({
  487. src: 'liveStart30sBefore.m3u8',
  488. type: 'application/vnd.apple.mpegurl'
  489. });
  490. this.clock.tick(1);
  491. openMediaSource(this.player, this.clock);
  492. this.player.tech_.readyState = () => 4;
  493. this.player.tech_.trigger('play');
  494. this.standardXHRResponse(this.requests.shift());
  495. this.clock.tick(1);
  496. assert.notEqual(currentTime, 0, 'seeked on autoplay');
  497. });
  498. QUnit.test('autoplay seeks to the live point after media source open', function(assert) {
  499. let currentTime = 0;
  500. this.player.autoplay(true);
  501. this.player.tech_.setCurrentTime = (ct) => {
  502. currentTime = ct;
  503. };
  504. this.player.src({
  505. src: 'liveStart30sBefore.m3u8',
  506. type: 'application/vnd.apple.mpegurl'
  507. });
  508. this.player.tech_.readyState = () => 4;
  509. this.clock.tick(1);
  510. this.player.tech_.triggerReady();
  511. this.clock.tick(1);
  512. this.standardXHRResponse(this.requests.shift());
  513. openMediaSource(this.player, this.clock);
  514. this.player.tech_.trigger('play');
  515. this.clock.tick(1);
  516. assert.notEqual(currentTime, 0, 'seeked on autoplay');
  517. });
  518. QUnit.test(
  519. 'autoplay seeks to the live point after tech fires loadedmetadata in ie11',
  520. function(assert) {
  521. videojs.browser.IE_VERSION = 11;
  522. let currentTime = 0;
  523. this.player.autoplay(true);
  524. this.player.on('seeking', () => {
  525. currentTime = this.player.currentTime();
  526. });
  527. this.player.src({
  528. src: 'liveStart30sBefore.m3u8',
  529. type: 'application/vnd.apple.mpegurl'
  530. });
  531. this.clock.tick(1);
  532. openMediaSource(this.player, this.clock);
  533. this.player.tech_.trigger('play');
  534. this.standardXHRResponse(this.requests.shift());
  535. this.clock.tick(1);
  536. assert.equal(currentTime, 0, 'have not played yet');
  537. this.player.tech_.trigger('loadedmetadata');
  538. this.clock.tick(1);
  539. assert.notEqual(currentTime, 0, 'seeked after tech is ready');
  540. }
  541. );
  542. QUnit.test(
  543. 'duration is set when the source opens after the playlist is loaded',
  544. function(assert) {
  545. this.player.src({
  546. src: 'media.m3u8',
  547. type: 'application/vnd.apple.mpegurl'
  548. });
  549. this.clock.tick(1);
  550. this.player.tech_.triggerReady();
  551. this.clock.tick(1);
  552. this.standardXHRResponse(this.requests.shift());
  553. openMediaSource(this.player, this.clock);
  554. assert.equal(
  555. this.player.tech_.vhs.mediaSource.duration,
  556. 40,
  557. 'set the duration'
  558. );
  559. }
  560. );
  561. QUnit.test('codecs are passed to the source buffer', function(assert) {
  562. const done = assert.async();
  563. const codecs = [];
  564. this.player.src({
  565. src: 'custom-codecs.m3u8',
  566. type: 'application/vnd.apple.mpegurl'
  567. });
  568. this.clock.tick(1);
  569. openMediaSource(this.player, this.clock);
  570. const addSourceBuffer = this.player.tech_.vhs.mediaSource.addSourceBuffer;
  571. this.player.tech_.vhs.mediaSource.addSourceBuffer = function(codec) {
  572. codecs.push(codec);
  573. return addSourceBuffer.call(this, codec);
  574. };
  575. // master
  576. this.requests.shift().respond(
  577. 200, null,
  578. '#EXTM3U\n' +
  579. '#EXT-X-STREAM-INF:BANDWIDTH=10,CODECS="avc1.dd00dd, mp4a.40.9"\n' +
  580. 'media.m3u8\n'
  581. );
  582. // media
  583. this.standardXHRResponse(this.requests.shift());
  584. // source buffer won't be created until we have our first segment
  585. this.player.tech(true).vhs.masterPlaylistController_.mainSegmentLoader_.one('appending', () => {
  586. // always create separate audio and video source buffers
  587. assert.equal(codecs.length, 2, 'created two source buffers');
  588. assert.notEqual(
  589. codecs.indexOf('audio/mp4;codecs="mp4a.40.9"'),
  590. -1,
  591. 'specified the audio codec'
  592. );
  593. assert.notEqual(
  594. codecs.indexOf('video/mp4;codecs="avc1.dd00dd"'),
  595. -1,
  596. 'specified the video codec'
  597. );
  598. done();
  599. });
  600. // segment 0
  601. this.standardXHRResponse(this.requests.shift(), muxedSegment());
  602. });
  603. QUnit.test('including HLS as a tech does not error', function(assert) {
  604. this.player.dispose();
  605. this.player = createPlayer({
  606. techOrder: ['vhs', 'html5']
  607. });
  608. this.clock.tick(1);
  609. assert.ok(this.player, 'created the player');
  610. assert.equal(this.env.log.warn.calls, 2, 'logged two warnings for deprecations');
  611. });
  612. QUnit.test('creates a PlaylistLoader on init', function(assert) {
  613. this.player.src({
  614. src: 'manifest/playlist.m3u8',
  615. type: 'application/vnd.apple.mpegurl'
  616. });
  617. this.clock.tick(1);
  618. openMediaSource(this.player, this.clock);
  619. this.player.src({
  620. src: 'manifest/playlist.m3u8',
  621. type: 'application/vnd.apple.mpegurl'
  622. });
  623. this.clock.tick(1);
  624. openMediaSource(this.player, this.clock);
  625. assert.equal(this.requests[0].aborted, true, 'aborted previous src');
  626. this.standardXHRResponse(this.requests[1]);
  627. assert.ok(
  628. this.player.tech_.vhs.playlists.master,
  629. 'set the master playlist'
  630. );
  631. assert.ok(
  632. this.player.tech_.vhs.playlists.media(),
  633. 'set the media playlist'
  634. );
  635. assert.ok(
  636. this.player.tech_.vhs.playlists.media().segments,
  637. 'the segment entries are parsed'
  638. );
  639. assert.strictEqual(
  640. this.player.tech_.vhs.playlists.master.playlists[0],
  641. this.player.tech_.vhs.playlists.media(),
  642. 'the playlist is selected'
  643. );
  644. });
  645. QUnit.test('sets the duration if one is available on the playlist', function(assert) {
  646. let events = 0;
  647. this.player.src({
  648. src: 'manifest/media.m3u8',
  649. type: 'application/vnd.apple.mpegurl'
  650. });
  651. this.clock.tick(1);
  652. openMediaSource(this.player, this.clock);
  653. this.player.tech_.on('durationchange', function() {
  654. events++;
  655. });
  656. this.standardXHRResponse(this.requests[0]);
  657. assert.equal(
  658. this.player.tech_.vhs.mediaSource.duration,
  659. 40,
  660. 'set the duration'
  661. );
  662. assert.equal(events, 1, 'durationchange is fired');
  663. });
  664. QUnit.test('estimates individual segment durations if needed', function(assert) {
  665. let changes = 0;
  666. this.player.src({
  667. src: 'http://example.com/manifest/missingExtinf.m3u8',
  668. type: 'application/vnd.apple.mpegurl'
  669. });
  670. this.clock.tick(1);
  671. openMediaSource(this.player, this.clock);
  672. this.player.tech_.vhs.mediaSource.duration = NaN;
  673. this.player.tech_.on('durationchange', function() {
  674. changes++;
  675. });
  676. this.standardXHRResponse(this.requests[0]);
  677. assert.strictEqual(
  678. this.player.tech_.vhs.mediaSource.duration,
  679. this.player.tech_.vhs.playlists.media().segments.length * 10,
  680. 'duration is updated'
  681. );
  682. assert.strictEqual(changes, 1, 'one durationchange fired');
  683. });
  684. QUnit.test(
  685. 'translates seekable by the starting time for live playlists',
  686. function(assert) {
  687. this.player.src({
  688. src: 'media.m3u8',
  689. type: 'application/vnd.apple.mpegurl'
  690. });
  691. this.clock.tick(1);
  692. openMediaSource(this.player, this.clock);
  693. this.requests.shift().respond(
  694. 200, null,
  695. '#EXTM3U\n' +
  696. '#EXT-X-MEDIA-SEQUENCE:15\n' +
  697. '#EXT-X-TARGETDURATION:10\n' +
  698. '#EXTINF:10,\n' +
  699. '0.ts\n' +
  700. '#EXTINF:10,\n' +
  701. '1.ts\n' +
  702. '#EXTINF:10,\n' +
  703. '2.ts\n' +
  704. '#EXTINF:10,\n' +
  705. '3.ts\n'
  706. );
  707. const seekable = this.player.seekable();
  708. assert.equal(seekable.length, 1, 'one seekable range');
  709. assert.equal(seekable.start(0), 0, 'the earliest possible position is at zero');
  710. assert.equal(seekable.end(0), 10, 'end is relative to the start');
  711. }
  712. );
  713. QUnit.test('starts downloading a segment on loadedmetadata', function(assert) {
  714. const done = assert.async();
  715. this.player.src({
  716. src: 'manifest/media.m3u8',
  717. type: 'application/vnd.apple.mpegurl'
  718. });
  719. this.clock.tick(1);
  720. this.player.buffered = function() {
  721. return videojs.createTimeRange(0, 0);
  722. };
  723. openMediaSource(this.player, this.clock);
  724. const segment = muxedSegment();
  725. // copy the byte length since the segment bytes get cleared out
  726. const segmentByteLength = segment.byteLength;
  727. assert.ok(segmentByteLength, 'the segment has some number of bytes');
  728. // media
  729. this.standardXHRResponse(this.requests[0]);
  730. assert.strictEqual(
  731. this.requests[1].url,
  732. absoluteUrl('manifest/media-00001.ts'),
  733. 'the first segment is requested'
  734. );
  735. this.player.tech(true).vhs.masterPlaylistController_.mainSegmentLoader_.one('appending', () => {
  736. // verify stats
  737. assert.equal(
  738. this.player.tech_.vhs.stats.mediaBytesTransferred,
  739. segmentByteLength,
  740. 'transferred the segment byte length'
  741. );
  742. assert.equal(this.player.tech_.vhs.stats.mediaRequests, 1, '1 request');
  743. done();
  744. });
  745. // segment 0
  746. this.standardXHRResponse(this.requests[1], segment);
  747. });
  748. QUnit.test('re-initializes the handler for each source', function(assert) {
  749. let secondPlaylists;
  750. let secondMSE;
  751. this.player.src({
  752. src: 'manifest/master.m3u8',
  753. type: 'application/vnd.apple.mpegurl'
  754. });
  755. this.clock.tick(1);
  756. openMediaSource(this.player, this.clock);
  757. const firstPlaylists = this.player.tech_.vhs.playlists;
  758. const firstMSE = this.player.tech_.vhs.mediaSource;
  759. // master
  760. this.standardXHRResponse(this.requests.shift());
  761. // media
  762. this.standardXHRResponse(this.requests.shift());
  763. const mpc = this.player.tech_.vhs.masterPlaylistController_;
  764. // need a segment request to complete for the source buffers to be created
  765. return requestAndAppendSegment({
  766. request: this.requests.shift(),
  767. mediaSource: mpc.mediaSource,
  768. segmentLoader: mpc.mainSegmentLoader_,
  769. clock: this.clock,
  770. tickClock: false
  771. }).then(() => {
  772. let audioBufferAborts = 0;
  773. let videoBufferAborts = 0;
  774. mpc.mainSegmentLoader_.sourceUpdater_.audioBuffer.abort = () => audioBufferAborts++;
  775. mpc.mainSegmentLoader_.sourceUpdater_.videoBuffer.abort = () => videoBufferAborts++;
  776. // allow timeout for making another request
  777. this.clock.tick(1);
  778. assert.equal(this.requests.length, 1, 'made another request');
  779. this.player.src({
  780. src: 'manifest/master.m3u8',
  781. type: 'application/vnd.apple.mpegurl'
  782. });
  783. this.clock.tick(1);
  784. openMediaSource(this.player, this.clock);
  785. secondPlaylists = this.player.tech_.vhs.playlists;
  786. secondMSE = this.player.tech_.vhs.mediaSource;
  787. assert.equal(audioBufferAborts, 1, 'aborted the old audio source buffer');
  788. assert.equal(videoBufferAborts, 1, 'aborted the old video source buffer');
  789. assert.ok(this.requests[0].aborted, 'aborted the old segment request');
  790. assert.notStrictEqual(
  791. firstPlaylists,
  792. secondPlaylists,
  793. 'the playlist object is not reused'
  794. );
  795. assert.notStrictEqual(firstMSE, secondMSE, 'the media source object is not reused');
  796. });
  797. });
  798. QUnit.test(
  799. 'triggers a media source error when an initial playlist request errors',
  800. function(assert) {
  801. this.player.src({
  802. src: 'manifest/master.m3u8',
  803. type: 'application/vnd.apple.mpegurl'
  804. });
  805. this.clock.tick(1);
  806. openMediaSource(this.player, this.clock);
  807. this.requests.pop().respond(500);
  808. assert.equal(
  809. this.player.tech_.vhs.mediaSource.error_,
  810. 'network',
  811. 'a network error is triggered'
  812. );
  813. }
  814. );
  815. QUnit.test(
  816. 'triggers a player error when an initial playlist request errors and the media source ' +
  817. 'isn\'t open',
  818. function(assert) {
  819. const done = assert.async();
  820. const origError = videojs.log.error;
  821. const errLogs = [];
  822. const endOfStreams = [];
  823. videojs.log.error = (log) => errLogs.push(log);
  824. this.player.src({
  825. src: 'manifest/master.m3u8',
  826. type: 'application/vnd.apple.mpegurl'
  827. });
  828. openMediaSource(this.player, this.clock);
  829. this.player.tech_.vhs.masterPlaylistController_.mediaSource.readyState = 'closed';
  830. this.player.on('error', () => {
  831. const error = this.player.error();
  832. assert.equal(error.code, 2, 'error has correct code');
  833. assert.equal(
  834. error.message,
  835. 'HLS playlist request error at URL: manifest/master.m3u8.',
  836. 'error has correct message'
  837. );
  838. assert.equal(errLogs.length, 1, 'logged an error');
  839. videojs.log.error = origError;
  840. assert.notOk(this.player.tech_.vhs.mediaSource.error_, 'no media source error');
  841. done();
  842. });
  843. this.requests.pop().respond(500);
  844. }
  845. );
  846. QUnit.test('downloads media playlists after loading the master', function(assert) {
  847. const done = assert.async();
  848. this.player.src({
  849. src: 'manifest/master.m3u8',
  850. type: 'application/vnd.apple.mpegurl'
  851. });
  852. this.clock.tick(1);
  853. openMediaSource(this.player, this.clock);
  854. this.player.tech_.vhs.bandwidth = 20e10;
  855. // master
  856. this.standardXHRResponse(this.requests[0]);
  857. // media
  858. this.standardXHRResponse(this.requests[1]);
  859. const segment = muxedSegment();
  860. // copy the byte length since the segment bytes get cleared out
  861. const segmentByteLength = segment.byteLength;
  862. assert.ok(segmentByteLength, 'the segment has some number of bytes');
  863. this.player.tech(true).vhs.masterPlaylistController_.mainSegmentLoader_.one('appending', () => {
  864. // verify stats
  865. assert.equal(
  866. this.player.tech_.vhs.stats.mediaBytesTransferred,
  867. segmentByteLength,
  868. 'transferred the segment byte length'
  869. );
  870. assert.equal(this.player.tech_.vhs.stats.mediaRequests, 1, '1 request');
  871. done();
  872. });
  873. // segment 0
  874. this.standardXHRResponse(this.requests[2], segment);
  875. assert.strictEqual(
  876. this.requests[0].url,
  877. 'manifest/master.m3u8',
  878. 'master playlist requested'
  879. );
  880. assert.strictEqual(
  881. this.requests[1].url,
  882. absoluteUrl('manifest/media2.m3u8'),
  883. 'media playlist requested'
  884. );
  885. assert.strictEqual(
  886. this.requests[2].url,
  887. absoluteUrl('manifest/media2-00001.ts'),
  888. 'first segment requested'
  889. );
  890. });
  891. QUnit.test('setting bandwidth resets throughput', function(assert) {
  892. this.player.src({
  893. src: 'manifest/master.m3u8',
  894. type: 'application/vnd.apple.mpegurl'
  895. });
  896. this.clock.tick(1);
  897. this.player.tech_.vhs.throughput = 1000;
  898. assert.strictEqual(
  899. this.player.tech_.vhs.throughput,
  900. 1000,
  901. 'throughput is set'
  902. );
  903. this.player.tech_.vhs.bandwidth = 20e10;
  904. assert.strictEqual(
  905. this.player.tech_.vhs.throughput,
  906. 0,
  907. 'throughput is reset when bandwidth is specified'
  908. );
  909. });
  910. QUnit.test('a thoughput of zero is ignored in systemBandwidth', function(assert) {
  911. this.player.src({
  912. src: 'manifest/master.m3u8',
  913. type: 'application/vnd.apple.mpegurl'
  914. });
  915. this.clock.tick(1);
  916. this.player.tech_.vhs.bandwidth = 20e10;
  917. assert.strictEqual(
  918. this.player.tech_.vhs.throughput,
  919. 0,
  920. 'throughput is reset when bandwidth is specified'
  921. );
  922. assert.strictEqual(
  923. this.player.tech_.vhs.systemBandwidth,
  924. 20e10,
  925. 'systemBandwidth is the same as bandwidth'
  926. );
  927. });
  928. QUnit.test(
  929. 'systemBandwidth is a combination of thoughput and bandwidth',
  930. function(assert) {
  931. this.player.src({
  932. src: 'manifest/master.m3u8',
  933. type: 'application/vnd.apple.mpegurl'
  934. });
  935. this.clock.tick(1);
  936. this.player.tech_.vhs.bandwidth = 20e10;
  937. this.player.tech_.vhs.throughput = 20e10;
  938. // 1 / ( 1 / 20e10 + 1 / 20e10) = 10e10
  939. assert.strictEqual(
  940. this.player.tech_.vhs.systemBandwidth,
  941. 10e10,
  942. 'systemBandwidth is the combination of bandwidth and throughput'
  943. );
  944. }
  945. );
  946. QUnit.module('NetworkInformationApi', hooks => {
  947. hooks.beforeEach(function(assert) {
  948. this.env = useFakeEnvironment(assert);
  949. this.ogNavigator = window.navigator;
  950. this.clock = this.env.clock;
  951. this.resetNavigatorConnection = (connection = {}) => {
  952. // Need to delete the property before setting since navigator doesn't have a setter
  953. delete window.navigator;
  954. window.navigator = {
  955. connection
  956. };
  957. };
  958. });
  959. hooks.afterEach(function() {
  960. this.env.restore();
  961. window.navigator = this.ogNavigator;
  962. });
  963. QUnit[testOrSkip](
  964. 'bandwidth returns networkInformation.downlink when useNetworkInformationApi option is enabled',
  965. function(assert) {
  966. this.resetNavigatorConnection({
  967. downlink: 10
  968. });
  969. this.player = createPlayer({ html5: { vhs: { useNetworkInformationApi: true } } });
  970. this.player.src({
  971. src: 'manifest/master.m3u8',
  972. type: 'application/vnd.apple.mpegurl'
  973. });
  974. this.clock.tick(1);
  975. // downlink in bits = 10 * 1000000 = 10e6
  976. assert.strictEqual(
  977. this.player.tech_.vhs.bandwidth,
  978. 10e6,
  979. 'bandwidth equals networkInfo.downlink represented as bits per second'
  980. );
  981. }
  982. );
  983. QUnit[testOrSkip](
  984. 'bandwidth uses player-estimated bandwidth when its value is greater than networkInformation.downLink and both values are >= 10 Mbps',
  985. function(assert) {
  986. this.resetNavigatorConnection({
  987. // 10 Mbps or 10e6
  988. downlink: 10
  989. });
  990. this.player = createPlayer({ html5: { vhs: { useNetworkInformationApi: true } } });
  991. this.player.src({
  992. src: 'manifest/master.m3u8',
  993. type: 'application/vnd.apple.mpegurl'
  994. });
  995. this.clock.tick(1);
  996. this.player.tech_.vhs.bandwidth = 20e6;
  997. assert.strictEqual(
  998. this.player.tech_.vhs.bandwidth,
  999. 20e6,
  1000. 'bandwidth getter returned the player-estimated bandwidth value'
  1001. );
  1002. }
  1003. );
  1004. QUnit[testOrSkip](
  1005. 'bandwidth uses network-information-api bandwidth when its value is less than the player bandwidth and 10 Mbps',
  1006. function(assert) {
  1007. this.resetNavigatorConnection({
  1008. // 9 Mbps or 9e6
  1009. downlink: 9
  1010. });
  1011. this.player = createPlayer({ html5: { vhs: { useNetworkInformationApi: true } } });
  1012. this.player.src({
  1013. src: 'manifest/master.m3u8',
  1014. type: 'application/vnd.apple.mpegurl'
  1015. });
  1016. this.clock.tick(1);
  1017. this.player.tech_.vhs.bandwidth = 20e10;
  1018. assert.strictEqual(
  1019. this.player.tech_.vhs.bandwidth,
  1020. 9e6,
  1021. 'bandwidth getter returned the network-information-api bandwidth value since it was less than 10 Mbps'
  1022. );
  1023. }
  1024. );
  1025. QUnit[testOrSkip](
  1026. 'bandwidth uses player-estimated bandwidth when networkInformation is not supported',
  1027. function(assert) {
  1028. // Nullify the `connection` property on Navigator
  1029. this.resetNavigatorConnection(null);
  1030. this.player = createPlayer({ html5: { vhs: { useNetworkInformationApi: true } } });
  1031. this.player.src({
  1032. src: 'manifest/master.m3u8',
  1033. type: 'application/vnd.apple.mpegurl'
  1034. });
  1035. this.clock.tick(1);
  1036. this.player.tech_.vhs.bandwidth = 20e10;
  1037. assert.strictEqual(
  1038. this.player.tech_.vhs.bandwidth,
  1039. 20e10,
  1040. 'bandwidth getter returned the player-estimated bandwidth value'
  1041. );
  1042. }
  1043. );
  1044. });
  1045. QUnit.test('requests a reasonable rendition to start', function(assert) {
  1046. this.player.src({
  1047. src: 'manifest/master.m3u8',
  1048. type: 'application/vnd.apple.mpegurl'
  1049. });
  1050. this.clock.tick(1);
  1051. openMediaSource(this.player, this.clock);
  1052. this.standardXHRResponse(
  1053. this.requests[0],
  1054. '#EXTM3U\n' +
  1055. '#EXT-X-STREAM-INF:BANDWIDTH=50\n' +
  1056. 'mediaLow.m3u8\n' +
  1057. '#EXT-X-STREAM-INF:BANDWIDTH=240000\n' +
  1058. 'mediaNormal.m3u8\n' +
  1059. '#EXT-X-STREAM-INF:BANDWIDTH=19280000000\n' +
  1060. 'mediaHigh.m3u8\n'
  1061. );
  1062. assert.strictEqual(
  1063. this.requests[0].url,
  1064. 'manifest/master.m3u8',
  1065. 'master playlist requested'
  1066. );
  1067. assert.strictEqual(
  1068. this.requests[1].url,
  1069. absoluteUrl('manifest/mediaNormal.m3u8'),
  1070. 'reasonable bandwidth media playlist requested'
  1071. );
  1072. });
  1073. QUnit.test('upshifts if the initial bandwidth hint is high', function(assert) {
  1074. this.player.src({
  1075. src: 'manifest/master.m3u8',
  1076. type: 'application/vnd.apple.mpegurl'
  1077. });
  1078. this.clock.tick(1);
  1079. openMediaSource(this.player, this.clock);
  1080. this.player.tech_.vhs.bandwidth = 10e20;
  1081. this.standardXHRResponse(
  1082. this.requests[0],
  1083. '#EXTM3U\n' +
  1084. '#EXT-X-STREAM-INF:BANDWIDTH=50\n' +
  1085. 'mediaLow.m3u8\n' +
  1086. '#EXT-X-STREAM-INF:BANDWIDTH=240000\n' +
  1087. 'mediaNormal.m3u8\n' +
  1088. '#EXT-X-STREAM-INF:BANDWIDTH=19280000000\n' +
  1089. 'mediaHigh.m3u8\n'
  1090. );
  1091. assert.strictEqual(
  1092. this.requests[0].url,
  1093. 'manifest/master.m3u8',
  1094. 'master playlist requested'
  1095. );
  1096. assert.strictEqual(
  1097. this.requests[1].url,
  1098. absoluteUrl('manifest/mediaHigh.m3u8'),
  1099. 'high bandwidth media playlist requested'
  1100. );
  1101. });
  1102. QUnit.test('downshifts if the initial bandwidth hint is low', function(assert) {
  1103. this.player.src({
  1104. src: 'manifest/master.m3u8',
  1105. type: 'application/vnd.apple.mpegurl'
  1106. });
  1107. this.clock.tick(1);
  1108. openMediaSource(this.player, this.clock);
  1109. this.player.tech_.vhs.bandwidth = 100;
  1110. this.standardXHRResponse(
  1111. this.requests[0],
  1112. '#EXTM3U\n' +
  1113. '#EXT-X-STREAM-INF:BANDWIDTH=50\n' +
  1114. 'mediaLow.m3u8\n' +
  1115. '#EXT-X-STREAM-INF:BANDWIDTH=240000\n' +
  1116. 'mediaNormal.m3u8\n' +
  1117. '#EXT-X-STREAM-INF:BANDWIDTH=19280000000\n' +
  1118. 'mediaHigh.m3u8\n'
  1119. );
  1120. assert.strictEqual(
  1121. this.requests[0].url,
  1122. 'manifest/master.m3u8',
  1123. 'master playlist requested'
  1124. );
  1125. assert.strictEqual(
  1126. this.requests[1].url,
  1127. absoluteUrl('manifest/mediaLow.m3u8'),
  1128. 'low bandwidth media playlist requested'
  1129. );
  1130. });
  1131. QUnit.test('buffer checks are noops until a media playlist is ready', function(assert) {
  1132. this.player.src({
  1133. src: 'manifest/media.m3u8',
  1134. type: 'application/vnd.apple.mpegurl'
  1135. });
  1136. this.clock.tick(1);
  1137. openMediaSource(this.player, this.clock);
  1138. this.clock.tick(10 * 1000);
  1139. assert.strictEqual(1, this.requests.length, 'one request was made');
  1140. assert.strictEqual(
  1141. this.requests[0].url,
  1142. 'manifest/media.m3u8',
  1143. 'media playlist requested'
  1144. );
  1145. });
  1146. QUnit.test('buffer checks are noops when only the master is ready', function(assert) {
  1147. this.player.src({
  1148. src: 'manifest/master.m3u8',
  1149. type: 'application/vnd.apple.mpegurl'
  1150. });
  1151. this.clock.tick(1);
  1152. openMediaSource(this.player, this.clock);
  1153. // master
  1154. this.standardXHRResponse(this.requests.shift());
  1155. // media
  1156. this.standardXHRResponse(this.requests.shift());
  1157. // ignore any outstanding segment requests
  1158. this.requests.length = 0;
  1159. // load in a new playlist which will cause playlists.media() to be
  1160. // undefined while it is being fetched
  1161. this.player.src({
  1162. src: 'manifest/master.m3u8',
  1163. type: 'application/vnd.apple.mpegurl'
  1164. });
  1165. openMediaSource(this.player, this.clock);
  1166. // respond with the master playlist but don't send the media playlist yet
  1167. // force media1 to be requested
  1168. this.player.tech_.vhs.bandwidth = 1;
  1169. // master
  1170. this.standardXHRResponse(this.requests.shift());
  1171. this.clock.tick(10 * 1000);
  1172. assert.strictEqual(this.requests.length, 1, 'one request was made');
  1173. assert.strictEqual(
  1174. this.requests[0].url,
  1175. absoluteUrl('manifest/media1.m3u8'),
  1176. 'media playlist requested'
  1177. );
  1178. // verify stats
  1179. assert.equal(this.player.tech_.vhs.stats.bandwidth, 1, 'bandwidth set above');
  1180. });
  1181. QUnit.test('selects a playlist below the current bandwidth', function(assert) {
  1182. this.player.src({
  1183. src: 'manifest/master.m3u8',
  1184. type: 'application/vnd.apple.mpegurl'
  1185. });
  1186. this.clock.tick(1);
  1187. openMediaSource(this.player, this.clock);
  1188. this.standardXHRResponse(this.requests[0]);
  1189. // the default playlist has a really high bitrate
  1190. this.player.tech_.vhs.playlists.master.playlists[0].attributes.BANDWIDTH = 9e10;
  1191. // playlist 1 has a very low bitrate
  1192. this.player.tech_.vhs.playlists.master.playlists[1].attributes.BANDWIDTH = 1;
  1193. // but the detected client bandwidth is really low
  1194. this.player.tech_.vhs.bandwidth = 10;
  1195. const playlist = this.player.tech_.vhs.selectPlaylist();
  1196. assert.strictEqual(
  1197. playlist,
  1198. this.player.tech_.vhs.playlists.master.playlists[1],
  1199. 'the low bitrate stream is selected'
  1200. );
  1201. // verify stats
  1202. assert.equal(this.player.tech_.vhs.stats.bandwidth, 10, 'bandwidth set above');
  1203. });
  1204. QUnit.test(
  1205. 'selects a primary rendition when there are multiple rendtions share same attributes',
  1206. function(assert) {
  1207. let playlist;
  1208. this.player.src({
  1209. src: 'manifest/master.m3u8',
  1210. type: 'application/vnd.apple.mpegurl'
  1211. });
  1212. openMediaSource(this.player, this.clock);
  1213. standardXHRResponse(this.requests[0]);
  1214. // covers playlists with same bandwidth but different resolution and different bandwidth
  1215. // but same resolution
  1216. this.player.tech_.vhs.playlists.master.playlists[0].attributes.BANDWIDTH = 528;
  1217. this.player.tech_.vhs.playlists.master.playlists[1].attributes.BANDWIDTH = 528;
  1218. this.player.tech_.vhs.playlists.master.playlists[2].attributes.BANDWIDTH = 728;
  1219. this.player.tech_.vhs.playlists.master.playlists[3].attributes.BANDWIDTH = 728;
  1220. this.player.tech_.vhs.bandwidth = 1000;
  1221. playlist = this.player.tech_.vhs.selectPlaylist();
  1222. assert.strictEqual(
  1223. playlist,
  1224. this.player.tech_.vhs.playlists.master.playlists[2],
  1225. 'select the rendition with largest bandwidth and just-larger-than video player'
  1226. );
  1227. // verify stats
  1228. assert.equal(this.player.tech_.vhs.stats.bandwidth, 1000, 'bandwidth set above');
  1229. // covers playlists share same bandwidth and resolutions
  1230. this.player.tech_.vhs.playlists.master.playlists[0].attributes.BANDWIDTH = 728;
  1231. this.player.tech_.vhs.playlists.master.playlists[0].attributes.RESOLUTION.width = 960;
  1232. this.player.tech_.vhs.playlists.master.playlists[0].attributes.RESOLUTION.height = 540;
  1233. this.player.tech_.vhs.playlists.master.playlists[1].attributes.BANDWIDTH = 728;
  1234. this.player.tech_.vhs.playlists.master.playlists[2].attributes.BANDWIDTH = 728;
  1235. this.player.tech_.vhs.playlists.master.playlists[2].attributes.RESOLUTION.width = 960;
  1236. this.player.tech_.vhs.playlists.master.playlists[2].attributes.RESOLUTION.height = 540;
  1237. this.player.tech_.vhs.playlists.master.playlists[3].attributes.BANDWIDTH = 728;
  1238. this.player.tech_.vhs.bandwidth = 1000;
  1239. playlist = this.player.tech_.vhs.selectPlaylist();
  1240. assert.strictEqual(
  1241. playlist,
  1242. this.player.tech_.vhs.playlists.master.playlists[0],
  1243. 'the primary rendition is selected'
  1244. );
  1245. }
  1246. );
  1247. QUnit.test('allows initial bandwidth to be provided', function(assert) {
  1248. this.player.src({
  1249. src: 'manifest/master.m3u8',
  1250. type: 'application/vnd.apple.mpegurl'
  1251. });
  1252. this.clock.tick(1);
  1253. openMediaSource(this.player, this.clock);
  1254. this.player.tech_.vhs.bandwidth = 500;
  1255. this.requests[0].bandwidth = 1;
  1256. this.requests.shift().respond(
  1257. 200, null,
  1258. '#EXTM3U\n' +
  1259. '#EXT-X-PLAYLIST-TYPE:VOD\n' +
  1260. '#EXT-X-TARGETDURATION:10\n'
  1261. );
  1262. assert.equal(
  1263. this.player.tech_.vhs.bandwidth,
  1264. 500,
  1265. 'prefers user-specified initial bandwidth'
  1266. );
  1267. // verify stats
  1268. assert.equal(this.player.tech_.vhs.stats.bandwidth, 500, 'bandwidth set above');
  1269. });
  1270. QUnit.test('raises the minimum bitrate for a stream proportionially', function(assert) {
  1271. this.player.src({
  1272. src: 'manifest/master.m3u8',
  1273. type: 'application/vnd.apple.mpegurl'
  1274. });
  1275. this.clock.tick(1);
  1276. openMediaSource(this.player, this.clock);
  1277. this.standardXHRResponse(this.requests[0]);
  1278. // the default playlist's bandwidth + 10% is assert.equal to the current bandwidth
  1279. this.player.tech_.vhs.playlists.master.playlists[0].attributes.BANDWIDTH = 10;
  1280. this.player.tech_.vhs.bandwidth = 11;
  1281. // 9.9 * 1.1 < 11
  1282. this.player.tech_.vhs.playlists.master.playlists[1].attributes.BANDWIDTH = 9.9;
  1283. const playlist = this.player.tech_.vhs.selectPlaylist();
  1284. assert.strictEqual(
  1285. playlist,
  1286. this.player.tech_.vhs.playlists.master.playlists[1],
  1287. 'a lower bitrate stream is selected'
  1288. );
  1289. // verify stats
  1290. assert.equal(this.player.tech_.vhs.stats.bandwidth, 11, 'bandwidth set above');
  1291. });
  1292. QUnit.test('uses the lowest bitrate if no other is suitable', function(assert) {
  1293. this.player.src({
  1294. src: 'manifest/master.m3u8',
  1295. type: 'application/vnd.apple.mpegurl'
  1296. });
  1297. this.clock.tick(1);
  1298. openMediaSource(this.player, this.clock);
  1299. this.standardXHRResponse(this.requests[0]);
  1300. // the lowest bitrate playlist is much greater than 1b/s
  1301. this.player.tech_.vhs.bandwidth = 1;
  1302. const playlist = this.player.tech_.vhs.selectPlaylist();
  1303. // playlist 1 has the lowest advertised bitrate
  1304. assert.strictEqual(
  1305. playlist,
  1306. this.player.tech_.vhs.playlists.master.playlists[1],
  1307. 'the lowest bitrate stream is selected'
  1308. );
  1309. // verify stats
  1310. assert.equal(this.player.tech_.vhs.stats.bandwidth, 1, 'bandwidth set above');
  1311. });
  1312. QUnit.test('selects the correct rendition by tech dimensions', function(assert) {
  1313. let playlist;
  1314. this.player.src({
  1315. src: 'manifest/master.m3u8',
  1316. type: 'application/vnd.apple.mpegurl'
  1317. });
  1318. this.clock.tick(1);
  1319. openMediaSource(this.player, this.clock);
  1320. this.standardXHRResponse(this.requests[0]);
  1321. const vhs = this.player.tech_.vhs;
  1322. this.player.width(640);
  1323. this.player.height(360);
  1324. vhs.bandwidth = 3000000;
  1325. playlist = vhs.selectPlaylist();
  1326. assert.deepEqual(
  1327. playlist.attributes.RESOLUTION,
  1328. {width: 960, height: 540},
  1329. 'should return the correct resolution by tech dimensions'
  1330. );
  1331. assert.equal(
  1332. playlist.attributes.BANDWIDTH,
  1333. 1928000,
  1334. 'should have the expected bandwidth in case of multiple'
  1335. );
  1336. this.player.width(1920);
  1337. this.player.height(1080);
  1338. vhs.bandwidth = 3000000;
  1339. playlist = vhs.selectPlaylist();
  1340. assert.deepEqual(
  1341. playlist.attributes.RESOLUTION,
  1342. {width: 960, height: 540},
  1343. 'should return the correct resolution by tech dimensions'
  1344. );
  1345. assert.equal(
  1346. playlist.attributes.BANDWIDTH,
  1347. 1928000,
  1348. 'should have the expected bandwidth in case of multiple'
  1349. );
  1350. this.player.width(396);
  1351. this.player.height(224);
  1352. playlist = vhs.selectPlaylist();
  1353. assert.deepEqual(
  1354. playlist.attributes.RESOLUTION,
  1355. {width: 396, height: 224},
  1356. 'should return the correct resolution by ' +
  1357. 'tech dimensions, if exact match'
  1358. );
  1359. assert.equal(
  1360. playlist.attributes.BANDWIDTH,
  1361. 440000,
  1362. 'should have the expected bandwidth in case of multiple, if exact match'
  1363. );
  1364. this.player.width(395);
  1365. this.player.height(222);
  1366. playlist = this.player.tech_.vhs.selectPlaylist();
  1367. assert.deepEqual(
  1368. playlist.attributes.RESOLUTION,
  1369. {width: 396, height: 224},
  1370. 'should return the next larger resolution by tech dimensions, ' +
  1371. 'if no exact match exists'
  1372. );
  1373. assert.equal(
  1374. playlist.attributes.BANDWIDTH,
  1375. 440000,
  1376. 'should have the expected bandwidth in case of multiple, if exact match'
  1377. );
  1378. // verify stats
  1379. assert.equal(this.player.tech_.vhs.stats.bandwidth, 3000000, 'bandwidth set above');
  1380. });
  1381. QUnit.test('selects the highest bitrate playlist when the player dimensions are ' +
  1382. 'larger than any of the variants', function(assert) {
  1383. this.player.src({
  1384. src: 'manifest/master.m3u8',
  1385. type: 'application/vnd.apple.mpegurl'
  1386. });
  1387. this.clock.tick(1);
  1388. openMediaSource(this.player, this.clock);
  1389. // master
  1390. this.requests.shift().respond(
  1391. 200, null,
  1392. '#EXTM3U\n' +
  1393. '#EXT-X-STREAM-INF:BANDWIDTH=1000,RESOLUTION=2x1\n' +
  1394. 'media.m3u8\n' +
  1395. '#EXT-X-STREAM-INF:BANDWIDTH=1,RESOLUTION=1x1\n' +
  1396. 'media1.m3u8\n'
  1397. );
  1398. // media
  1399. this.standardXHRResponse(this.requests.shift());
  1400. this.player.tech_.vhs.bandwidth = 1e10;
  1401. this.player.width(1024);
  1402. this.player.height(768);
  1403. const playlist = this.player.tech_.vhs.selectPlaylist();
  1404. assert.equal(
  1405. playlist.attributes.BANDWIDTH,
  1406. 1000,
  1407. 'selected the highest bandwidth variant'
  1408. );
  1409. // verify stats
  1410. assert.equal(this.player.tech_.vhs.stats.bandwidth, 1e10, 'bandwidth set above');
  1411. });
  1412. QUnit.test('filters playlists that are currently excluded', function(assert) {
  1413. let playlist;
  1414. this.player.src({
  1415. src: 'manifest/master.m3u8',
  1416. type: 'application/vnd.apple.mpegurl'
  1417. });
  1418. this.clock.tick(1);
  1419. openMediaSource(this.player, this.clock);
  1420. this.player.tech_.vhs.bandwidth = 1e10;
  1421. // master
  1422. this.requests.shift().respond(
  1423. 200, null,
  1424. '#EXTM3U\n' +
  1425. '#EXT-X-STREAM-INF:BANDWIDTH=1000\n' +
  1426. 'media.m3u8\n' +
  1427. '#EXT-X-STREAM-INF:BANDWIDTH=1\n' +
  1428. 'media1.m3u8\n'
  1429. );
  1430. // media
  1431. this.standardXHRResponse(this.requests.shift());
  1432. // exclude the current playlist
  1433. this.player.tech_.vhs.playlists.master.playlists[0].excludeUntil = +new Date() + 1000;
  1434. playlist = this.player.tech_.vhs.selectPlaylist();
  1435. assert.equal(
  1436. playlist,
  1437. this.player.tech_.vhs.playlists.master.playlists[1],
  1438. 'respected exclusions'
  1439. );
  1440. // timeout the exclusion
  1441. this.clock.tick(1000);
  1442. playlist = this.player.tech_.vhs.selectPlaylist();
  1443. assert.equal(
  1444. playlist,
  1445. this.player.tech_.vhs.playlists.master.playlists[0],
  1446. 'expired the exclusion'
  1447. );
  1448. // verify stats
  1449. assert.equal(this.player.tech_.vhs.stats.bandwidth, 1e10, 'bandwidth set above');
  1450. });
  1451. QUnit.test('does not blacklist compatible H.264 codec strings', function(assert) {
  1452. this.player.src({
  1453. src: 'manifest/master.m3u8',
  1454. type: 'application/vnd.apple.mpegurl'
  1455. });
  1456. this.clock.tick(1);
  1457. openMediaSource(this.player, this.clock);
  1458. this.player.tech_.vhs.bandwidth = 1;
  1459. // master
  1460. this.requests.shift()
  1461. .respond(
  1462. 200, null,
  1463. '#EXTM3U\n' +
  1464. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d,mp4a.40.5"\n' +
  1465. 'media.m3u8\n' +
  1466. '#EXT-X-STREAM-INF:BANDWIDTH=10,CODECS="avc1.4d400f,mp4a.40.5"\n' +
  1467. 'media1.m3u8\n'
  1468. );
  1469. // media
  1470. this.standardXHRResponse(this.requests.shift());
  1471. const master = this.player.tech_.vhs.playlists.master;
  1472. const loader = this.player.tech_.vhs.masterPlaylistController_.mainSegmentLoader_;
  1473. loader.currentMediaInfo_ = {hasVideo: true, hasAudio: true};
  1474. loader.trigger('trackinfo');
  1475. assert.strictEqual(
  1476. typeof master.playlists[0].excludeUntil,
  1477. 'undefined',
  1478. 'did not blacklist'
  1479. );
  1480. assert.strictEqual(
  1481. typeof master.playlists[1].excludeUntil,
  1482. 'undefined',
  1483. 'did not blacklist'
  1484. );
  1485. // verify stats
  1486. assert.equal(this.player.tech_.vhs.stats.bandwidth, 1, 'bandwidth set above');
  1487. });
  1488. QUnit.test('does not blacklist compatible AAC codec strings', function(assert) {
  1489. this.player.src({
  1490. src: 'manifest/master.m3u8',
  1491. type: 'application/vnd.apple.mpegurl'
  1492. });
  1493. this.clock.tick(1);
  1494. openMediaSource(this.player, this.clock);
  1495. // master
  1496. this.requests.shift()
  1497. .respond(
  1498. 200, null,
  1499. '#EXTM3U\n' +
  1500. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d,mp4a.40.2"\n' +
  1501. 'media.m3u8\n' +
  1502. '#EXT-X-STREAM-INF:BANDWIDTH=10,CODECS="avc1.4d400d,not-an-audio-codec"\n' +
  1503. 'media1.m3u8\n'
  1504. );
  1505. // media
  1506. this.standardXHRResponse(this.requests.shift());
  1507. const loader = this.player.tech_.vhs.masterPlaylistController_.mainSegmentLoader_;
  1508. const master = this.player.tech_.vhs.playlists.master;
  1509. loader.currentMediaInfo_ = {hasVideo: true, hasAudio: true};
  1510. loader.trigger('trackinfo');
  1511. assert.strictEqual(
  1512. typeof master.playlists[0].excludeUntil,
  1513. 'undefined',
  1514. 'did not blacklist mp4a.40.2'
  1515. );
  1516. assert.strictEqual(
  1517. master.playlists[1].excludeUntil,
  1518. Infinity,
  1519. 'blacklisted invalid audio codec'
  1520. );
  1521. });
  1522. QUnit.test('blacklists incompatible playlists by codec, without codec switching', function(assert) {
  1523. this.player.src({
  1524. src: 'manifest/master.m3u8',
  1525. type: 'application/vnd.apple.mpegurl'
  1526. });
  1527. this.clock.tick(1);
  1528. openMediaSource(this.player, this.clock);
  1529. const playlistString =
  1530. '#EXTM3U\n' +
  1531. // selected playlist
  1532. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d,mp4a.40.2"\n' +
  1533. 'media.m3u8\n' +
  1534. // compatible with selected playlist
  1535. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d,mp4a.40.2"\n' +
  1536. 'media1.m3u8\n' +
  1537. // incompatible by audio codec difference
  1538. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d,ac-3"\n' +
  1539. 'media2.m3u8\n' +
  1540. // incompatible by video codec difference
  1541. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="hvc1.4d400d,mp4a.40.2"\n' +
  1542. 'media3.m3u8\n' +
  1543. // incompatible, only audio codec
  1544. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="mp4a.40.2"\n' +
  1545. 'media4.m3u8\n' +
  1546. // incompatible, only video codec
  1547. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d"\n' +
  1548. 'media5.m3u8\n' +
  1549. // compatible with selected playlist
  1550. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1,mp4a"\n' +
  1551. 'media6.m3u8\n';
  1552. // master
  1553. this.requests.shift().respond(200, null, playlistString);
  1554. // media
  1555. this.standardXHRResponse(this.requests.shift());
  1556. const mpc = this.player.tech_.vhs.masterPlaylistController_;
  1557. const loader = mpc.mainSegmentLoader_;
  1558. const master = this.player.tech_.vhs.playlists.master;
  1559. mpc.sourceUpdater_.canChangeType = () => false;
  1560. loader.currentMediaInfo_ = {hasVideo: true, hasAudio: true};
  1561. loader.trigger('trackinfo');
  1562. const playlists = master.playlists;
  1563. assert.strictEqual(playlists.length, 7, 'six playlists total');
  1564. assert.strictEqual(typeof playlists[0].excludeUntil, 'undefined', 'did not blacklist first playlist');
  1565. assert.strictEqual(typeof playlists[1].excludeUntil, 'undefined', 'did not blacklist second playlist');
  1566. assert.strictEqual(playlists[2].excludeUntil, Infinity, 'blacklisted incompatible audio playlist');
  1567. assert.strictEqual(playlists[3].excludeUntil, Infinity, 'blacklisted incompatible video playlist');
  1568. assert.strictEqual(playlists[4].excludeUntil, Infinity, 'blacklisted audio only playlist');
  1569. assert.strictEqual(playlists[5].excludeUntil, Infinity, 'blacklisted video only playlist');
  1570. assert.strictEqual(typeof playlists[6].excludeUntil, 'undefined', 'did not blacklist seventh playlist');
  1571. });
  1572. QUnit.test('does not blacklist incompatible codecs with codec switching', function(assert) {
  1573. const oldIsTypeSupported = window.MediaSource.isTypeSupported;
  1574. window.MediaSource.isTypeSupported = (t) => (/avc1|mp4a/).test(t);
  1575. this.player.src({
  1576. src: 'manifest/master.m3u8',
  1577. type: 'application/vnd.apple.mpegurl'
  1578. });
  1579. this.clock.tick(1);
  1580. openMediaSource(this.player, this.clock);
  1581. const playlistString =
  1582. '#EXTM3U\n' +
  1583. // selected playlist
  1584. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d,mp4a.40.2"\n' +
  1585. 'media.m3u8\n' +
  1586. // compatible with selected playlist
  1587. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d,mp4a.40.2"\n' +
  1588. 'media1.m3u8\n' +
  1589. // incompatible by audio codec difference
  1590. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d,ac-3"\n' +
  1591. 'media2.m3u8\n' +
  1592. // incompatible by video codec difference
  1593. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="hvc1.4d400d,mp4a.40.2"\n' +
  1594. 'media3.m3u8\n' +
  1595. // incompatible, only audio codec
  1596. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="mp4a.40.2"\n' +
  1597. 'media4.m3u8\n' +
  1598. // incompatible, only video codec
  1599. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d"\n' +
  1600. 'media5.m3u8\n' +
  1601. // compatible with selected playlist
  1602. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1,mp4a"\n' +
  1603. 'media6.m3u8\n';
  1604. // master
  1605. this.requests.shift().respond(200, null, playlistString);
  1606. // media
  1607. this.standardXHRResponse(this.requests.shift());
  1608. const mpc = this.player.tech_.vhs.masterPlaylistController_;
  1609. const loader = mpc.mainSegmentLoader_;
  1610. const master = this.player.tech_.vhs.playlists.master;
  1611. mpc.sourceUpdater_.canChangeType = () => true;
  1612. loader.currentMediaInfo_ = {hasVideo: true, hasAudio: true};
  1613. loader.trigger('trackinfo');
  1614. const playlists = master.playlists;
  1615. assert.strictEqual(playlists.length, 7, 'six playlists total');
  1616. assert.strictEqual(typeof playlists[0].excludeUntil, 'undefined', 'did not blacklist first playlist');
  1617. assert.strictEqual(typeof playlists[1].excludeUntil, 'undefined', 'did not blacklist second playlist');
  1618. assert.strictEqual(playlists[2].excludeUntil, Infinity, 'blacklisted incompatible audio playlist');
  1619. assert.strictEqual(playlists[3].excludeUntil, Infinity, 'blacklisted incompatible video playlist');
  1620. assert.strictEqual(playlists[4].excludeUntil, Infinity, 'blacklisted audio only playlist');
  1621. assert.strictEqual(playlists[5].excludeUntil, Infinity, 'blacklisted video only playlist');
  1622. assert.strictEqual(typeof playlists[6].excludeUntil, 'undefined', 'did not blacklist seventh playlist');
  1623. window.MediaSource.isTypeSupported = oldIsTypeSupported;
  1624. });
  1625. QUnit.test('blacklists fmp4 playlists by browser support', function(assert) {
  1626. const oldIsTypeSupported = window.MediaSource.isTypeSupported;
  1627. window.MediaSource.isTypeSupported = (t) => (/avc1|mp4a/).test(t);
  1628. this.player.src({
  1629. src: 'manifest/master.m3u8',
  1630. type: 'application/vnd.apple.mpegurl'
  1631. });
  1632. this.clock.tick(1);
  1633. openMediaSource(this.player, this.clock);
  1634. const playlistString =
  1635. '#EXTM3U\n' +
  1636. // video not supported
  1637. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="hvc1,mp4a.40.2"\n' +
  1638. 'media.m3u8\n' +
  1639. // audio not supported
  1640. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d,ac-3"\n' +
  1641. 'media.m3u8\n' +
  1642. // supported!
  1643. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d,mp4a.40.2"\n' +
  1644. 'media1.m3u8\n';
  1645. const mpc = this.player.tech_.vhs.masterPlaylistController_;
  1646. // do not exclude incompatible so that we can run this test.
  1647. mpc.excludeUnsupportedVariants_ = () => {};
  1648. // master
  1649. this.requests.shift().respond(200, null, playlistString);
  1650. // media
  1651. this.standardXHRResponse(this.requests.shift());
  1652. const playlistLoader = mpc.masterPlaylistLoader_;
  1653. const loader = mpc.mainSegmentLoader_;
  1654. const master = this.player.tech_.vhs.playlists.master;
  1655. let debugLogs = [];
  1656. mpc.logger_ = (...logs) => {
  1657. debugLogs = debugLogs.concat(logs);
  1658. };
  1659. const playlists = master.playlists;
  1660. playlistLoader.media = () => playlists[0];
  1661. loader.mainStartingMedia_ = playlists[0];
  1662. loader.currentMediaInfo_ = {hasVideo: true, hasAudio: true, isFmp4: true};
  1663. loader.trigger('trackinfo');
  1664. playlistLoader.media = () => playlists[1];
  1665. loader.mainStartingMedia_ = playlists[1];
  1666. loader.currentMediaInfo_ = {hasVideo: true, hasAudio: true, isFmp4: true};
  1667. loader.trigger('trackinfo');
  1668. playlistLoader.media = () => playlists[2];
  1669. loader.mainStartingMedia_ = playlists[2];
  1670. loader.currentMediaInfo_ = {hasVideo: true, hasAudio: true, isFmp4: true};
  1671. loader.trigger('trackinfo');
  1672. assert.strictEqual(playlists.length, 3, 'three playlists total');
  1673. assert.strictEqual(playlists[0].excludeUntil, Infinity, 'blacklisted first playlist');
  1674. assert.strictEqual(playlists[1].excludeUntil, Infinity, 'blacklisted second playlist');
  1675. assert.strictEqual(typeof playlists[2].excludeUntil, 'undefined', 'did not blacklist second playlist');
  1676. assert.deepEqual(debugLogs, [
  1677. `Internal problem encountered with playlist ${playlists[0].id}. browser does not support codec(s): "hvc1". Switching to playlist ${playlists[1].id}.`,
  1678. `switch media ${playlists[0].id} -> ${playlists[1].id} from exclude`,
  1679. `Internal problem encountered with playlist ${playlists[1].id}. browser does not support codec(s): "ac-3". Switching to playlist ${playlists[2].id}.`,
  1680. `switch media ${playlists[1].id} -> ${playlists[2].id} from exclude`
  1681. ], 'debug log as expected');
  1682. window.MediaSource.isTypeSupported = oldIsTypeSupported;
  1683. });
  1684. QUnit.test('blacklists ts playlists by muxer support', function(assert) {
  1685. const oldIsTypeSupported = window.MediaSource.isTypeSupported;
  1686. window.MediaSource.isTypeSupported = (t) => true;
  1687. this.player.src({
  1688. src: 'manifest/master.m3u8',
  1689. type: 'application/vnd.apple.mpegurl'
  1690. });
  1691. this.clock.tick(1);
  1692. openMediaSource(this.player, this.clock);
  1693. const playlistString =
  1694. '#EXTM3U\n' +
  1695. // video not supported
  1696. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="hvc1,mp4a.40.2"\n' +
  1697. 'media.m3u8\n' +
  1698. // audio not supported
  1699. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d,ac-3"\n' +
  1700. 'media.m3u8\n' +
  1701. // supported!
  1702. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d,mp4a.40.2"\n' +
  1703. 'media1.m3u8\n';
  1704. // master
  1705. this.requests.shift().respond(200, null, playlistString);
  1706. // media
  1707. this.standardXHRResponse(this.requests.shift());
  1708. const mpc = this.player.tech_.vhs.masterPlaylistController_;
  1709. const playlistLoader = mpc.masterPlaylistLoader_;
  1710. const loader = mpc.mainSegmentLoader_;
  1711. const master = this.player.tech_.vhs.playlists.master;
  1712. let debugLogs = [];
  1713. mpc.logger_ = (...logs) => {
  1714. debugLogs = debugLogs.concat(logs);
  1715. };
  1716. const playlists = master.playlists;
  1717. playlistLoader.media = () => playlists[0];
  1718. loader.mainStartingMedia_ = playlists[0];
  1719. loader.currentMediaInfo_ = {hasVideo: true, hasAudio: true};
  1720. loader.trigger('trackinfo');
  1721. playlistLoader.media = () => playlists[1];
  1722. loader.mainStartingMedia_ = playlists[1];
  1723. loader.currentMediaInfo_ = {hasVideo: true, hasAudio: true};
  1724. loader.trigger('trackinfo');
  1725. playlistLoader.media = () => playlists[2];
  1726. loader.mainStartingMedia_ = playlists[2];
  1727. loader.currentMediaInfo_ = {hasVideo: true, hasAudio: true};
  1728. loader.trigger('trackinfo');
  1729. assert.strictEqual(playlists.length, 3, 'three playlists total');
  1730. assert.strictEqual(playlists[0].excludeUntil, Infinity, 'blacklisted first playlist');
  1731. assert.strictEqual(playlists[1].excludeUntil, Infinity, 'blacklisted second playlist');
  1732. assert.strictEqual(typeof playlists[2].excludeUntil, 'undefined', 'did not blacklist third playlist');
  1733. assert.deepEqual(debugLogs, [
  1734. `Internal problem encountered with playlist ${playlists[0].id}. muxer does not support codec(s): "hvc1". Switching to playlist ${playlists[1].id}.`,
  1735. `switch media ${playlists[0].id} -> ${playlists[1].id} from exclude`,
  1736. `Internal problem encountered with playlist ${playlists[1].id}. muxer does not support codec(s): "ac-3". Switching to playlist ${playlists[2].id}.`,
  1737. `switch media ${playlists[1].id} -> ${playlists[2].id} from exclude`
  1738. ], 'debug log as expected');
  1739. window.MediaSource.isTypeSupported = oldIsTypeSupported;
  1740. });
  1741. QUnit.test('cancels outstanding XHRs when seeking', function(assert) {
  1742. this.player.src({
  1743. src: 'manifest/media.m3u8',
  1744. type: 'application/vnd.apple.mpegurl'
  1745. });
  1746. this.clock.tick(1);
  1747. openMediaSource(this.player, this.clock);
  1748. this.standardXHRResponse(this.requests[0]);
  1749. this.player.tech_.vhs.media = {
  1750. segments: [{
  1751. uri: '0.ts',
  1752. duration: 10
  1753. }, {
  1754. uri: '1.ts',
  1755. duration: 10
  1756. }]
  1757. };
  1758. // attempt to seek while the download is in progress
  1759. this.player.currentTime(7);
  1760. this.clock.tick(2);
  1761. assert.ok(this.requests[1].aborted, 'XHR aborted');
  1762. assert.strictEqual(this.requests.length, 3, 'opened new XHR');
  1763. });
  1764. QUnit.test('does not abort segment loading for in-buffer seeking', function(assert) {
  1765. this.player.src({
  1766. src: 'manifest/media.m3u8',
  1767. type: 'application/vnd.apple.mpegurl'
  1768. });
  1769. this.clock.tick(1);
  1770. openMediaSource(this.player, this.clock);
  1771. this.standardXHRResponse(this.requests.shift());
  1772. this.player.tech_.buffered = function() {
  1773. return videojs.createTimeRange(0, 20);
  1774. };
  1775. this.player.tech_.setCurrentTime(11);
  1776. this.clock.tick(1);
  1777. assert.equal(this.requests.length, 1, 'did not abort the outstanding request');
  1778. });
  1779. QUnit.test('unsupported playlist should not be re-included when excluding last playlist', function(assert) {
  1780. this.player.src({
  1781. src: 'manifest/master.m3u8',
  1782. type: 'application/vnd.apple.mpegurl'
  1783. });
  1784. this.clock.tick(1);
  1785. openMediaSource(this.player, this.clock);
  1786. this.player.tech_.vhs.bandwidth = 1;
  1787. // master
  1788. this.requests.shift()
  1789. .respond(
  1790. 200, null,
  1791. '#EXTM3U\n' +
  1792. '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d,mp4a.40.2"\n' +
  1793. 'media.m3u8\n' +
  1794. '#EXT-X-STREAM-INF:BANDWIDTH=10,CODECS="avc1.4d400d,not-an-audio-codec"\n' +
  1795. 'media1.m3u8\n'
  1796. );
  1797. // media
  1798. this.standardXHRResponse(this.requests.shift());
  1799. const master = this.player.tech_.vhs.playlists.master;
  1800. const media = this.player.tech_.vhs.playlists.media_;
  1801. const mpc = this.player.tech_.vhs.masterPlaylistController_;
  1802. return requestAndAppendSegment({
  1803. request: this.requests.shift(),
  1804. mediaSource: mpc.mediaSource,
  1805. segmentLoader: mpc.mainSegmentLoader_,
  1806. clock: this.clock
  1807. }).then(() => {
  1808. assert.strictEqual(
  1809. master.playlists[1].excludeUntil,
  1810. Infinity,
  1811. 'blacklisted invalid audio codec'
  1812. );
  1813. const requri = this.requests[0].uri;
  1814. this.requests.shift().respond(400);
  1815. assert.ok(master.playlists[0].excludeUntil > 0, 'original media excluded for some time');
  1816. assert.strictEqual(
  1817. master.playlists[1].excludeUntil,
  1818. Infinity,
  1819. 'audio codec still blacklisted'
  1820. );
  1821. assert.equal(this.env.log.warn.calls, 1, 'warning logged for blacklist');
  1822. assert.equal(
  1823. this.env.log.warn.args[0][0],
  1824. `Problem encountered with playlist ${master.playlists[0].id}. HLS request errored at URL: ${requri} Switching to playlist 0-media.m3u8.`,
  1825. 'log generic error message'
  1826. );
  1827. });
  1828. });
  1829. QUnit.test('segment 404 should trigger blacklisting of media', function(assert) {
  1830. this.player.src({
  1831. src: 'manifest/master.m3u8',
  1832. type: 'application/vnd.apple.mpegurl'
  1833. });
  1834. this.clock.tick(1);
  1835. openMediaSource(this.player, this.clock);
  1836. this.player.tech_.vhs.bandwidth = 20000;
  1837. // master
  1838. this.standardXHRResponse(this.requests[0]);
  1839. // media
  1840. this.standardXHRResponse(this.requests[1]);
  1841. const media = this.player.tech_.vhs.playlists.media_;
  1842. // segment
  1843. this.requests[2].respond(400);
  1844. assert.ok(media.excludeUntil > 0, 'original media blacklisted for some time');
  1845. assert.equal(this.env.log.warn.calls, 1, 'warning logged for blacklist');
  1846. // verify stats
  1847. assert.equal(this.player.tech_.vhs.stats.bandwidth, 20000, 'bandwidth set above');
  1848. });
  1849. QUnit.test('playlist 404 should blacklist media', function(assert) {
  1850. let media;
  1851. let url;
  1852. let index;
  1853. let blacklistplaylist = 0;
  1854. let retryplaylist = 0;
  1855. let vhsRenditionBlacklistedEvents = 0;
  1856. let hlsRenditionBlacklistedEvents = 0;
  1857. this.player.src({
  1858. src: 'manifest/master.m3u8',
  1859. type: 'application/vnd.apple.mpegurl'
  1860. });
  1861. this.clock.tick(1);
  1862. openMediaSource(this.player, this.clock);
  1863. this.player.tech_.on('blacklistplaylist', () => blacklistplaylist++);
  1864. this.player.tech_.on('retryplaylist', () => retryplaylist++);
  1865. this.player.tech_.on('usage', (event) => {
  1866. if (event.name === 'vhs-rendition-blacklisted') {
  1867. vhsRenditionBlacklistedEvents++;
  1868. }
  1869. if (event.name === 'hls-rendition-blacklisted') {
  1870. hlsRenditionBlacklistedEvents++;
  1871. }
  1872. });
  1873. this.player.tech_.vhs.bandwidth = 1e10;
  1874. // master
  1875. this.requests[0].respond(
  1876. 200, null,
  1877. '#EXTM3U\n' +
  1878. '#EXT-X-STREAM-INF:BANDWIDTH=1000\n' +
  1879. 'media.m3u8\n' +
  1880. '#EXT-X-STREAM-INF:BANDWIDTH=1\n' +
  1881. 'media1.m3u8\n'
  1882. );
  1883. assert.equal(
  1884. typeof this.player.tech_.vhs.playlists.media_,
  1885. 'undefined',
  1886. 'no media is initially set'
  1887. );
  1888. assert.equal(blacklistplaylist, 0, 'there is no blacklisted playlist');
  1889. assert.equal(
  1890. vhsRenditionBlacklistedEvents,
  1891. 0,
  1892. 'no vhs-rendition-blacklisted event was fired'
  1893. );
  1894. assert.equal(
  1895. hlsRenditionBlacklistedEvents,
  1896. 0,
  1897. 'no hls-rendition-blacklisted event was fired'
  1898. );
  1899. // media
  1900. this.requests[1].respond(404);
  1901. url = this.requests[1].url.slice(this.requests[1].url.lastIndexOf('/') + 1);
  1902. if (url === 'media.m3u8') {
  1903. index = 0;
  1904. } else {
  1905. index = 1;
  1906. }
  1907. media = this.player.tech_.vhs.playlists.master.playlists[createPlaylistID(index, url)];
  1908. assert.ok(media.excludeUntil > 0, 'original media blacklisted for some time');
  1909. assert.equal(this.env.log.warn.calls, 1, 'warning logged for blacklist');
  1910. assert.equal(
  1911. this.env.log.warn.args[0],
  1912. `Problem encountered with playlist ${media.id}. HLS playlist request error at URL: media.m3u8. Switching to playlist 1-media1.m3u8.`,
  1913. 'log generic error message'
  1914. );
  1915. assert.equal(blacklistplaylist, 1, 'there is one blacklisted playlist');
  1916. assert.equal(
  1917. vhsRenditionBlacklistedEvents,
  1918. 1,
  1919. 'a vhs-rendition-blacklisted event was fired'
  1920. );
  1921. assert.equal(
  1922. hlsRenditionBlacklistedEvents,
  1923. 1,
  1924. 'an hls-rendition-blacklisted event was fired'
  1925. );
  1926. assert.equal(retryplaylist, 0, 'haven\'t retried any playlist');
  1927. // request for the final available media
  1928. this.requests[2].respond(404);
  1929. url = this.requests[2].url.slice(this.requests[2].url.lastIndexOf('/') + 1);
  1930. if (url === 'media.m3u8') {
  1931. index = 0;
  1932. } else {
  1933. index = 1;
  1934. }
  1935. media = this.player.tech_.vhs.playlists.master.playlists[createPlaylistID(index, url)];
  1936. assert.ok(media.excludeUntil > 0, 'second media was blacklisted after playlist 404');
  1937. assert.equal(this.env.log.warn.calls, 2, 'warning logged for blacklist');
  1938. assert.equal(
  1939. this.env.log.warn.args[1],
  1940. 'Removing other playlists from the exclusion list because the last rendition is about to be excluded.',
  1941. 'log generic error message'
  1942. );
  1943. assert.equal(
  1944. this.env.log.warn.args[2],
  1945. `Problem encountered with playlist ${media.id}. HLS playlist request error at URL: media1.m3u8. ` +
  1946. 'Switching to playlist 0-media.m3u8.',
  1947. 'log generic error message'
  1948. );
  1949. assert.equal(retryplaylist, 1, 'fired a retryplaylist event');
  1950. assert.equal(blacklistplaylist, 2, 'media1 is blacklisted');
  1951. this.clock.tick(2 * 1000);
  1952. // no new request was made since it hasn't been half the segment duration
  1953. assert.strictEqual(3, this.requests.length, 'no new request was made');
  1954. this.clock.tick(3 * 1000);
  1955. // loading the first playlist since the blacklist duration was cleared
  1956. // when half the segment duaration passed
  1957. assert.strictEqual(4, this.requests.length, 'one more request was made');
  1958. url = this.requests[3].url.slice(this.requests[3].url.lastIndexOf('/') + 1);
  1959. if (url === 'media.m3u8') {
  1960. index = 0;
  1961. } else {
  1962. index = 1;
  1963. }
  1964. media = this.player.tech_.vhs.playlists.master.playlists[createPlaylistID(index, url)];
  1965. // the first media was unblacklisted after a refresh delay
  1966. assert.ok(!media.excludeUntil, 'removed first media from blacklist');
  1967. assert.strictEqual(
  1968. this.requests[3].url,
  1969. absoluteUrl('manifest/media.m3u8'),
  1970. 'media playlist requested'
  1971. );
  1972. // verify stats
  1973. assert.equal(this.player.tech_.vhs.stats.bandwidth, 1e10, 'bandwidth set above');
  1974. });
  1975. QUnit.test('blacklists playlist if it has stopped being updated', function(assert) {
  1976. let playliststuck = 0;
  1977. this.player.src({
  1978. src: 'master.m3u8',
  1979. type: 'application/vnd.apple.mpegurl'
  1980. });
  1981. openMediaSource(this.player, this.clock);
  1982. this.player.tech_.triggerReady();
  1983. this.standardXHRResponse(this.requests.shift());
  1984. this.player.tech_.vhs.masterPlaylistController_.seekable = function() {
  1985. return videojs.createTimeRange(90, 130);
  1986. };
  1987. this.player.tech_.setCurrentTime(170);
  1988. this.player.tech_.buffered = function() {
  1989. return videojs.createTimeRange(0, 170);
  1990. };
  1991. Vhs.Playlist.playlistEnd = function() {
  1992. return 170;
  1993. };
  1994. this.player.tech_.on('playliststuck', () => playliststuck++);
  1995. this.requests.shift().respond(
  1996. 200, null,
  1997. '#EXTM3U\n' +
  1998. '#EXT-X-MEDIA-SEQUENCE:16\n' +
  1999. '#EXTINF:10,\n' +
  2000. '16.ts\n'
  2001. );
  2002. assert.ok(
  2003. !this.player.tech_.vhs.playlists.media().excludeUntil,
  2004. 'playlist was not blacklisted'
  2005. );
  2006. assert.equal(this.env.log.warn.calls, 0, 'no warning logged for blacklist');
  2007. assert.equal(playliststuck, 0, 'there is no stuck playlist');
  2008. this.player.tech_.trigger('play');
  2009. this.player.tech_.trigger('playing');
  2010. // trigger a refresh
  2011. this.clock.tick(10 * 1000);
  2012. this.requests.shift().respond(
  2013. 200, null,
  2014. '#EXTM3U\n' +
  2015. '#EXT-X-MEDIA-SEQUENCE:16\n' +
  2016. '#EXTINF:10,\n' +
  2017. '16.ts\n'
  2018. );
  2019. const media = this.player.tech_.vhs.playlists.media();
  2020. assert.ok(
  2021. media.excludeUntil > 0,
  2022. 'playlist blacklisted for some time'
  2023. );
  2024. assert.equal(this.env.log.warn.calls, 1, 'warning logged for blacklist');
  2025. assert.equal(
  2026. this.env.log.warn.args[0],
  2027. `Problem encountered with playlist ${media.id}. ` +
  2028. 'Playlist no longer updating. Switching to playlist 0-media.m3u8.',
  2029. 'log specific error message for not updated playlist'
  2030. );
  2031. assert.equal(playliststuck, 1, 'there is one stuck playlist');
  2032. });
  2033. QUnit.test('never blacklist the playlist if it is the only playlist', function(assert) {
  2034. this.player.src({
  2035. src: 'manifest/media.m3u8',
  2036. type: 'application/vnd.apple.mpegurl'
  2037. });
  2038. openMediaSource(this.player, this.clock);
  2039. this.requests.shift().respond(
  2040. 200, null,
  2041. '#EXTM3U\n' +
  2042. '#EXTINF:10,\n' +
  2043. '0.ts\n'
  2044. );
  2045. this.clock.tick(10 * 1000);
  2046. this.requests.shift().respond(404);
  2047. const media = this.player.tech_.vhs.playlists.media();
  2048. // media wasn't blacklisted because it's the only rendition
  2049. assert.ok(!media.excludeUntil, 'media was not blacklisted after playlist 404');
  2050. assert.equal(this.env.log.warn.calls, 1, 'warning logged for blacklist');
  2051. assert.equal(
  2052. this.env.log.warn.args[0],
  2053. `Problem encountered with playlist ${media.id}. ` +
  2054. 'Trying again since it is the only playlist.',
  2055. 'log specific error message for the only playlist'
  2056. );
  2057. });
  2058. QUnit.test(
  2059. 'error on the first playlist request does not trigger an error when there is master ' +
  2060. 'playlist with only one media playlist',
  2061. function(assert) {
  2062. this.player.src({
  2063. src: 'manifest/master.m3u8',
  2064. type: 'application/vnd.apple.mpegurl'
  2065. });
  2066. openMediaSource(this.player, this.clock);
  2067. this.requests[0]
  2068. .respond(
  2069. 200, null,
  2070. '#EXTM3U\n' +
  2071. '#EXT-X-STREAM-INF:BANDWIDTH=1000\n' +
  2072. 'media.m3u8\n'
  2073. );
  2074. this.requests[1].respond(404);
  2075. const url = this.requests[1].url.slice(this.requests[1].url.lastIndexOf('/') + 1);
  2076. const media = this.player.tech_.vhs.playlists.master.playlists[createPlaylistID(0, url)];
  2077. // media wasn't blacklisted because it's the only rendition
  2078. assert.ok(!media.excludeUntil, 'media was not blacklisted after playlist 404');
  2079. assert.equal(this.env.log.warn.calls, 1, 'warning logged for blacklist');
  2080. assert.equal(
  2081. this.env.log.warn.args[0],
  2082. `Problem encountered with playlist ${media.id}. ` +
  2083. 'Trying again since it is the only playlist.',
  2084. 'log specific error message for the onlyplaylist'
  2085. );
  2086. }
  2087. );
  2088. QUnit.test('seeking in an empty playlist is a non-erroring noop', function(assert) {
  2089. this.player.src({
  2090. src: 'manifest/empty-live.m3u8',
  2091. type: 'application/vnd.apple.mpegurl'
  2092. });
  2093. this.clock.tick(1);
  2094. openMediaSource(this.player, this.clock);
  2095. this.requests.shift().respond(200, null, '#EXTM3U\n');
  2096. const requestsLength = this.requests.length;
  2097. this.player.tech_.setCurrentTime(183);
  2098. this.clock.tick(1);
  2099. assert.equal(this.requests.length, requestsLength, 'made no additional requests');
  2100. });
  2101. QUnit.test('fire loadedmetadata once we successfully load a playlist', function(assert) {
  2102. let count = 0;
  2103. this.player.src({
  2104. src: 'manifest/master.m3u8',
  2105. type: 'application/vnd.apple.mpegurl'
  2106. });
  2107. this.clock.tick(1);
  2108. openMediaSource(this.player, this.clock);
  2109. const vhs = this.player.tech_.vhs;
  2110. vhs.bandwidth = 20000;
  2111. vhs.masterPlaylistController_.masterPlaylistLoader_.on('loadedmetadata', function() {
  2112. count += 1;
  2113. });
  2114. // masters
  2115. this.standardXHRResponse(this.requests.shift());
  2116. assert.equal(
  2117. count, 0,
  2118. 'loadedMedia not triggered before requesting playlist'
  2119. );
  2120. // media
  2121. this.requests.shift().respond(404);
  2122. assert.equal(
  2123. count, 0,
  2124. 'loadedMedia not triggered after playlist 404'
  2125. );
  2126. assert.equal(this.env.log.warn.calls, 1, 'warning logged for blacklist');
  2127. // media
  2128. this.standardXHRResponse(this.requests.shift());
  2129. assert.equal(
  2130. count, 1,
  2131. 'loadedMedia triggered after successful recovery from 404'
  2132. );
  2133. // verify stats
  2134. assert.equal(this.player.tech_.vhs.stats.bandwidth, 20000, 'bandwidth set above');
  2135. });
  2136. QUnit.test('sets seekable and duration for live playlists', function(assert) {
  2137. this.player.src({
  2138. src: 'http://example.com/manifest/missingEndlist.m3u8',
  2139. type: 'application/vnd.apple.mpegurl'
  2140. });
  2141. this.clock.tick(1);
  2142. openMediaSource(this.player, this.clock);
  2143. // since the safe live end will be 3 target durations back, in order for there to be a
  2144. // positive seekable end, there should be at least 4 segments
  2145. this.requests.shift().respond(200, null, `
  2146. #EXTM3U
  2147. #EXT-X-TARGETDURATION:5
  2148. #EXTINF:5
  2149. 0.ts
  2150. #EXTINF:5
  2151. 1.ts
  2152. #EXTINF:5
  2153. 2.ts
  2154. #EXTINF:5
  2155. 3.ts
  2156. `);
  2157. assert.equal(this.player.tech(true).vhs.seekable().length, 1, 'set one seekable range');
  2158. assert.equal(this.player.tech(true).vhs.seekable().start(0), 0, 'set seekable start');
  2159. assert.equal(this.player.tech(true).vhs.seekable().end(0), 5, 'set seekable end');
  2160. assert.strictEqual(
  2161. this.player.tech(true).vhs.duration(),
  2162. Infinity,
  2163. 'duration reported by VHS is infinite'
  2164. );
  2165. assert.strictEqual(
  2166. this.player.tech(true).vhs.mediaSource.duration,
  2167. this.player.tech(true).vhs.seekable().end(0),
  2168. 'duration on the mediaSource is seekable end'
  2169. );
  2170. });
  2171. QUnit.test('live playlist starts with correct currentTime value', function(assert) {
  2172. this.player.src({
  2173. src: 'http://example.com/manifest/liveStart30sBefore.m3u8',
  2174. type: 'application/vnd.apple.mpegurl'
  2175. });
  2176. this.clock.tick(1);
  2177. openMediaSource(this.player, this.clock);
  2178. this.standardXHRResponse(this.requests[0]);
  2179. let currentTime = 0;
  2180. this.player.tech_.setCurrentTime = (ct) => {
  2181. currentTime = ct;
  2182. };
  2183. this.player.tech_.readyState = () => 4;
  2184. this.player.tech_.vhs.playlists.trigger('loadedmetadata');
  2185. this.player.tech_.paused = function() {
  2186. return false;
  2187. };
  2188. this.player.tech_.trigger('play');
  2189. this.clock.tick(1);
  2190. const media = this.player.tech_.vhs.playlists.media();
  2191. assert.strictEqual(
  2192. currentTime,
  2193. Vhs.Playlist.seekable(media).end(0),
  2194. 'currentTime is updated at playback'
  2195. );
  2196. });
  2197. QUnit.test(
  2198. 'estimates seekable ranges for live streams that have been paused for a long time',
  2199. function(assert) {
  2200. this.player.src({
  2201. src: 'http://example.com/manifest/liveStart30sBefore.m3u8',
  2202. type: 'application/vnd.apple.mpegurl'
  2203. });
  2204. this.clock.tick(1);
  2205. openMediaSource(this.player, this.clock);
  2206. this.standardXHRResponse(this.requests.shift());
  2207. this.player.tech_.vhs.playlists.media().mediaSequence = 172;
  2208. this.player.tech_.vhs.playlists.media().syncInfo = {
  2209. mediaSequence: 130,
  2210. time: 80
  2211. };
  2212. this.player.tech_.vhs.masterPlaylistController_.onSyncInfoUpdate_();
  2213. assert.equal(
  2214. this.player.seekable().start(0),
  2215. 500,
  2216. 'offset the seekable start'
  2217. );
  2218. }
  2219. );
  2220. QUnit.test('resets the time to the live point when resuming a live stream after a ' +
  2221. 'long break', function(assert) {
  2222. let seekTarget;
  2223. this.player.src({
  2224. src: 'live0.m3u8',
  2225. type: 'application/vnd.apple.mpegurl'
  2226. });
  2227. this.clock.tick(1);
  2228. openMediaSource(this.player, this.clock);
  2229. this.requests.shift().respond(
  2230. 200, null,
  2231. '#EXTM3U\n' +
  2232. '#EXT-X-MEDIA-SEQUENCE:16\n' +
  2233. '#EXTINF:10,\n' +
  2234. '16.ts\n'
  2235. );
  2236. // mock out the player to simulate a live stream that has been
  2237. // playing for awhile
  2238. this.player.tech_.vhs.seekable = function() {
  2239. return videojs.createTimeRange(160, 170);
  2240. };
  2241. this.player.tech_.setCurrentTime = function(time) {
  2242. if (typeof time !== 'undefined') {
  2243. seekTarget = time;
  2244. }
  2245. };
  2246. this.player.tech_.played = function() {
  2247. return videojs.createTimeRange(120, 170);
  2248. };
  2249. this.player.tech_.trigger('playing');
  2250. const seekable = this.player.seekable();
  2251. this.player.tech_.trigger('play');
  2252. assert.equal(seekTarget, seekable.end(seekable.length - 1), 'seeked to live point');
  2253. this.player.tech_.trigger('seeked');
  2254. });
  2255. QUnit.test(
  2256. 'reloads out-of-date live playlists when switching variants',
  2257. function(assert) {
  2258. const oldManifest = testDataManifests['variant-update'];
  2259. this.player.src({
  2260. src: 'http://example.com/master.m3u8',
  2261. type: 'application/vnd.apple.mpegurl'
  2262. });
  2263. this.clock.tick(1);
  2264. openMediaSource(this.player, this.clock);
  2265. this.player.tech_.vhs.master = {
  2266. playlists: [{
  2267. mediaSequence: 15,
  2268. segments: [1, 1, 1]
  2269. }, {
  2270. uri: 'http://example.com/variant-update.m3u8',
  2271. mediaSequence: 0,
  2272. segments: [1, 1]
  2273. }]
  2274. };
  2275. // playing segment 15 on playlist zero
  2276. this.player.tech_.vhs.media = this.player.tech_.vhs.master.playlists[0];
  2277. this.player.mediaIndex = 1;
  2278. testDataManifests['variant-update'] = '#EXTM3U\n' +
  2279. '#EXT-X-MEDIA-SEQUENCE:16\n' +
  2280. '#EXTINF:10,\n' +
  2281. '16.ts\n' +
  2282. '#EXTINF:10,\n' +
  2283. '17.ts\n';
  2284. // switch playlists
  2285. this.player.tech_.vhs.selectPlaylist = function() {
  2286. return this.player.tech_.vhs.master.playlists[1];
  2287. };
  2288. // timeupdate downloads segment 16 then switches playlists
  2289. this.player.trigger('timeupdate');
  2290. assert.strictEqual(this.player.mediaIndex, 1, 'mediaIndex points at the next segment');
  2291. testDataManifests['variant-update'] = oldManifest;
  2292. }
  2293. );
  2294. QUnit.test(
  2295. 'if withCredentials global option is used, withCredentials is set on the XHR object',
  2296. function(assert) {
  2297. const vhsOptions = videojs.options.vhs;
  2298. this.player.dispose();
  2299. videojs.options.vhs = {
  2300. withCredentials: true
  2301. };
  2302. this.player.dispose();
  2303. this.player = createPlayer();
  2304. this.player.src({
  2305. src: 'http://example.com/media.m3u8',
  2306. type: 'application/vnd.apple.mpegurl'
  2307. });
  2308. this.clock.tick(1);
  2309. openMediaSource(this.player, this.clock);
  2310. assert.ok(
  2311. this.requests[0].withCredentials,
  2312. 'with credentials should be set to true if that option is passed in'
  2313. );
  2314. videojs.options.vhs = vhsOptions;
  2315. }
  2316. );
  2317. QUnit.test('if handleManifestRedirects global option is used, it should be passed to PlaylistLoader', function(assert) {
  2318. const vhsOptions = videojs.options.vhs;
  2319. this.player.dispose();
  2320. videojs.options.vhs = {
  2321. handleManifestRedirects: true
  2322. };
  2323. this.player = createPlayer();
  2324. this.player.src({
  2325. src: 'http://example.com/media.m3u8',
  2326. type: 'application/vnd.apple.mpegurl'
  2327. });
  2328. this.clock.tick(1);
  2329. assert.ok(
  2330. this.player.tech_.vhs.masterPlaylistController_.masterPlaylistLoader_.handleManifestRedirects,
  2331. 'handleManifestRedirects is set correctly'
  2332. );
  2333. videojs.options.vhs = vhsOptions;
  2334. });
  2335. QUnit.test('the handleManifestRedirects source option overrides the global default', function(assert) {
  2336. const vhsOptions = videojs.options.vhs;
  2337. this.player.dispose();
  2338. videojs.options.vhs = {
  2339. handleManifestRedirects: true
  2340. };
  2341. this.player = createPlayer();
  2342. this.player.src({
  2343. src: 'http://example.com/media.m3u8',
  2344. type: 'application/vnd.apple.mpegurl',
  2345. handleManifestRedirects: false
  2346. });
  2347. this.clock.tick(1);
  2348. assert.notOk(
  2349. this.player.tech_.vhs.masterPlaylistController_.masterPlaylistLoader_.handleManifestRedirects,
  2350. 'handleManifestRedirects is set correctly'
  2351. );
  2352. videojs.options.vhs = vhsOptions;
  2353. });
  2354. QUnit.test('if handleManifestRedirects global option is used, it should be passed to DashPlaylistLoader', function(assert) {
  2355. const vhsOptions = videojs.options.vhs;
  2356. this.player.dispose();
  2357. videojs.options.vhs = {
  2358. handleManifestRedirects: true
  2359. };
  2360. this.player = createPlayer();
  2361. this.player.src({
  2362. src: 'http://example.com/media.mpd',
  2363. type: 'application/dash+xml'
  2364. });
  2365. this.clock.tick(1);
  2366. assert.ok(this.player.tech_.vhs.masterPlaylistController_.masterPlaylistLoader_.handleManifestRedirects);
  2367. videojs.options.vhs = vhsOptions;
  2368. });
  2369. QUnit.test('the handleManifestRedirects in DashPlaylistLoader option overrides the global default', function(assert) {
  2370. const vhsOptions = videojs.options.vhs;
  2371. this.player.dispose();
  2372. videojs.options.vhs = {
  2373. handleManifestRedirects: true
  2374. };
  2375. this.player = createPlayer();
  2376. this.player.src({
  2377. src: 'http://example.com/media.mpd',
  2378. type: 'application/dash+xml',
  2379. handleManifestRedirects: false
  2380. });
  2381. this.clock.tick(1);
  2382. assert.notOk(this.player.tech_.vhs.masterPlaylistController_.masterPlaylistLoader_.handleManifestRedirects);
  2383. videojs.options.vhs = vhsOptions;
  2384. });
  2385. QUnit.test('the withCredentials option overrides the global default', function(assert) {
  2386. const vhsOptions = videojs.options.vhs;
  2387. this.player.dispose();
  2388. videojs.options.vhs = {
  2389. withCredentials: true
  2390. };
  2391. this.player = createPlayer();
  2392. this.player.src({
  2393. src: 'http://example.com/media.m3u8',
  2394. type: 'application/vnd.apple.mpegurl',
  2395. withCredentials: false
  2396. });
  2397. this.clock.tick(1);
  2398. openMediaSource(this.player, this.clock);
  2399. assert.ok(
  2400. !this.requests[0].withCredentials,
  2401. 'with credentials should be set to false if if overrode global option'
  2402. );
  2403. videojs.options.vhs = vhsOptions;
  2404. });
  2405. QUnit.test('playlist blacklisting duration is set through options', function(assert) {
  2406. const vhsOptions = videojs.options.vhs;
  2407. this.player.dispose();
  2408. videojs.options.vhs = {
  2409. blacklistDuration: 3 * 60
  2410. };
  2411. this.player = createPlayer();
  2412. this.player.src({
  2413. src: 'http://example.com/master.m3u8',
  2414. type: 'application/vnd.apple.mpegurl'
  2415. });
  2416. this.player.tech_.triggerReady();
  2417. openMediaSource(this.player, this.clock);
  2418. this.requests[0].respond(
  2419. 200, null,
  2420. '#EXTM3U\n' +
  2421. '#EXT-X-STREAM-INF:BANDWIDTH=1000\n' +
  2422. 'media.m3u8\n' +
  2423. '#EXT-X-STREAM-INF:BANDWIDTH=1\n' +
  2424. 'media1.m3u8\n'
  2425. );
  2426. this.requests[1].respond(404);
  2427. // media
  2428. const url = this.requests[1].url.slice(this.requests[1].url.lastIndexOf('/') + 1);
  2429. let index;
  2430. if (url === 'media.m3u8') {
  2431. index = 0;
  2432. } else {
  2433. index = 1;
  2434. }
  2435. const media = this.player.tech_.vhs.playlists.master.playlists[createPlaylistID(index, url)];
  2436. assert.ok(media.excludeUntil > 0, 'original media blacklisted for some time');
  2437. assert.equal(this.env.log.warn.calls, 1, 'warning logged for blacklist');
  2438. assert.equal(
  2439. this.env.log.warn.args[0],
  2440. `Problem encountered with playlist ${media.id}. ` +
  2441. 'HLS playlist request error at URL: media.m3u8. ' +
  2442. 'Switching to playlist 1-media1.m3u8.',
  2443. 'log generic error message'
  2444. );
  2445. // this takes one millisecond
  2446. this.standardXHRResponse(this.requests[2]);
  2447. this.clock.tick(2 * 60 * 1000 - 1);
  2448. assert.ok(media.excludeUntil - Date.now() > 0, 'original media still be blacklisted');
  2449. this.clock.tick(1 * 60 * 1000);
  2450. assert.equal(
  2451. media.excludeUntil,
  2452. Date.now(),
  2453. 'media\'s exclude time reach to the current time'
  2454. );
  2455. videojs.options.vhs = vhsOptions;
  2456. });
  2457. QUnit.test('respects bandwidth option of 0', function(assert) {
  2458. this.player.dispose();
  2459. this.player = createPlayer({ html5: { vhs: { bandwidth: 0 } } });
  2460. this.player.src({
  2461. src: 'http://example.com/media.m3u8',
  2462. type: 'application/vnd.apple.mpegurl'
  2463. });
  2464. this.clock.tick(1);
  2465. openMediaSource(this.player, this.clock);
  2466. assert.equal(this.player.tech_.vhs.bandwidth, 0, 'set bandwidth to 0');
  2467. });
  2468. QUnit.test(
  2469. 'uses default bandwidth option if non-numerical value provided',
  2470. function(assert) {
  2471. this.player.dispose();
  2472. this.player = createPlayer({ html5: { vhs: { bandwidth: 'garbage' } } });
  2473. this.player.src({
  2474. src: 'http://example.com/media.m3u8',
  2475. type: 'application/vnd.apple.mpegurl'
  2476. });
  2477. this.clock.tick(1);
  2478. openMediaSource(this.player, this.clock);
  2479. assert.equal(this.player.tech_.vhs.bandwidth, 4194304, 'set bandwidth to default');
  2480. }
  2481. );
  2482. QUnit.test('respects initialBandwidth option on the tech', function(assert) {
  2483. this.player.dispose();
  2484. this.player = createPlayer({ html5: { initialBandwidth: 0 } });
  2485. this.player.src({
  2486. src: 'http://example.com/media.m3u8',
  2487. type: 'application/vnd.apple.mpegurl'
  2488. });
  2489. this.clock.tick(1);
  2490. openMediaSource(this.player, this.clock);
  2491. assert.equal(this.player.tech_.vhs.bandwidth, 0, 'set bandwidth to 0');
  2492. });
  2493. QUnit.test('initialBandwidth option on the tech take precedence on over vhs bandwidth option', function(assert) {
  2494. this.player.dispose();
  2495. this.player = createPlayer({ html5: { initialBandwidth: 0, vhs: { bandwidth: 100 } } });
  2496. this.player.src({
  2497. src: 'http://example.com/media.m3u8',
  2498. type: 'application/vnd.apple.mpegurl'
  2499. });
  2500. this.clock.tick(1);
  2501. openMediaSource(this.player, this.clock);
  2502. assert.equal(this.player.tech_.vhs.bandwidth, 0, 'set bandwidth to 0');
  2503. });
  2504. QUnit.test('uses default bandwidth if browser is Android', function(assert) {
  2505. this.player.dispose();
  2506. const origIsAndroid = videojs.browser.IS_ANDROID;
  2507. videojs.browser.IS_ANDROID = false;
  2508. this.player = createPlayer();
  2509. this.player.src({
  2510. src: 'http://example.com/media.m3u8',
  2511. type: 'application/vnd.apple.mpegurl'
  2512. });
  2513. openMediaSource(this.player, this.clock);
  2514. assert.equal(
  2515. this.player.tech_.vhs.bandwidth,
  2516. 4194304,
  2517. 'set bandwidth to desktop default'
  2518. );
  2519. this.player.dispose();
  2520. videojs.browser.IS_ANDROID = true;
  2521. this.player = createPlayer();
  2522. this.player.src({
  2523. src: 'http://example.com/media.m3u8',
  2524. type: 'application/vnd.apple.mpegurl'
  2525. });
  2526. openMediaSource(this.player, this.clock);
  2527. assert.equal(
  2528. this.player.tech_.vhs.bandwidth,
  2529. 4194304,
  2530. 'set bandwidth to mobile default'
  2531. );
  2532. videojs.browser.IS_ANDROID = origIsAndroid;
  2533. });
  2534. QUnit.test('does not break if the playlist has no segments', function(assert) {
  2535. this.player.src({
  2536. src: 'manifest/master.m3u8',
  2537. type: 'application/vnd.apple.mpegurl'
  2538. });
  2539. this.clock.tick(1);
  2540. try {
  2541. openMediaSource(this.player, this.clock);
  2542. this.requests[0].respond(
  2543. 200, null,
  2544. '#EXTM3U\n' +
  2545. '#EXT-X-PLAYLIST-TYPE:VOD\n' +
  2546. '#EXT-X-TARGETDURATION:10\n'
  2547. );
  2548. } catch (e) {
  2549. assert.ok(false, 'an error was thrown');
  2550. throw e;
  2551. }
  2552. assert.ok(true, 'no error was thrown');
  2553. assert.strictEqual(
  2554. this.requests.length,
  2555. 1,
  2556. 'no this.requestsfor non-existent segments were queued'
  2557. );
  2558. });
  2559. QUnit.test('can seek before the source buffer opens', function(assert) {
  2560. this.player.src({
  2561. src: 'media.m3u8',
  2562. type: 'application/vnd.apple.mpegurl'
  2563. });
  2564. this.clock.tick(1);
  2565. this.player.tech_.triggerReady();
  2566. this.clock.tick(1);
  2567. this.standardXHRResponse(this.requests.shift());
  2568. this.player.triggerReady();
  2569. this.player.currentTime(1);
  2570. assert.equal(this.player.currentTime(), 1, 'seeked');
  2571. });
  2572. QUnit.test('resets the switching algorithm if a request times out', function(assert) {
  2573. this.player.src({
  2574. src: 'master.m3u8',
  2575. type: 'application/vnd.apple.mpegurl'
  2576. });
  2577. this.clock.tick(1);
  2578. openMediaSource(this.player, this.clock);
  2579. this.player.tech_.vhs.bandwidth = 1e20;
  2580. // master
  2581. this.standardXHRResponse(this.requests.shift());
  2582. // media.m3u8
  2583. this.standardXHRResponse(this.requests.shift());
  2584. const segmentRequest = this.requests.shift();
  2585. assert.notOk(segmentRequest.timedout, 'request not timed out');
  2586. // simulate a segment timeout
  2587. this.clock.tick(45001);
  2588. assert.ok(segmentRequest.timedout, 'request timed out');
  2589. // new media
  2590. this.standardXHRResponse(this.requests.shift());
  2591. assert.strictEqual(
  2592. this.player.tech_.vhs.playlists.media(),
  2593. this.player.tech_.vhs.playlists.master.playlists[1],
  2594. 'reset to the lowest bitrate playlist'
  2595. );
  2596. // verify stats
  2597. assert.equal(this.player.tech_.vhs.stats.bandwidth, 1, 'bandwidth is reset too');
  2598. });
  2599. QUnit.test('disposes the playlist loader', function(assert) {
  2600. let disposes = 0;
  2601. const player = createPlayer();
  2602. player.src({
  2603. src: 'manifest/master.m3u8',
  2604. type: 'application/vnd.apple.mpegurl'
  2605. });
  2606. this.clock.tick(1);
  2607. openMediaSource(player, this.clock);
  2608. const loaderDispose = player.tech_.vhs.playlists.dispose;
  2609. player.tech_.vhs.playlists.dispose = function() {
  2610. disposes++;
  2611. loaderDispose.call(player.tech_.vhs.playlists);
  2612. };
  2613. player.dispose();
  2614. assert.strictEqual(disposes, 1, 'disposed playlist loader');
  2615. });
  2616. QUnit.test('remove event handlers on dispose', function(assert) {
  2617. let unscoped = 0;
  2618. const player = createPlayer();
  2619. const origPlayerOn = player.on.bind(player);
  2620. const origPlayerOff = player.off.bind(player);
  2621. player.on = function(...args) {
  2622. if (typeof args[0] !== 'object') {
  2623. unscoped++;
  2624. }
  2625. origPlayerOn(...args);
  2626. };
  2627. player.off = function(...args) {
  2628. if (typeof args[0] !== 'object') {
  2629. unscoped--;
  2630. }
  2631. origPlayerOff(...args);
  2632. };
  2633. player.src({
  2634. src: 'manifest/master.m3u8',
  2635. type: 'application/vnd.apple.mpegurl'
  2636. });
  2637. this.clock.tick(1);
  2638. openMediaSource(player, this.clock);
  2639. this.standardXHRResponse(this.requests[0]);
  2640. this.standardXHRResponse(this.requests[1]);
  2641. assert.ok(unscoped > 0, 'has unscoped handlers');
  2642. player.dispose();
  2643. assert.ok(unscoped <= 0, 'no unscoped handlers');
  2644. });
  2645. QUnit.test('the source handler supports HLS mime types', function(assert) {
  2646. assert.ok(VhsSourceHandler.canHandleSource({
  2647. type: 'aPplicatiOn/x-MPegUrl'
  2648. }), 'supports x-mpegurl');
  2649. assert.ok(VhsSourceHandler.canHandleSource({
  2650. type: 'aPplicatiOn/VnD.aPPle.MpEgUrL'
  2651. }), 'supports vnd.apple.mpegurl');
  2652. assert.ok(
  2653. VhsSourceHandler.canPlayType('aPplicatiOn/VnD.aPPle.MpEgUrL'),
  2654. 'supports vnd.apple.mpegurl'
  2655. );
  2656. assert.ok(
  2657. VhsSourceHandler.canPlayType('aPplicatiOn/x-MPegUrl'),
  2658. 'supports x-mpegurl'
  2659. );
  2660. });
  2661. QUnit.test('the source handler supports DASH mime types', function(assert) {
  2662. assert.ok(VhsSourceHandler.canHandleSource({
  2663. type: 'aPplication/dAsh+xMl'
  2664. }), 'supports application/dash+xml');
  2665. assert.ok(
  2666. VhsSourceHandler.canPlayType('aPpLicAtion/DaSh+XmL'),
  2667. 'supports application/dash+xml'
  2668. );
  2669. });
  2670. QUnit.test(
  2671. 'the source handler does not support non HLS/DASH mime types',
  2672. function(assert) {
  2673. assert.ok(!(VhsSourceHandler.canHandleSource({
  2674. type: 'video/mp4'
  2675. }) instanceof VhsHandler), 'does not support mp4');
  2676. assert.ok(!(VhsSourceHandler.canHandleSource({
  2677. type: 'video/x-flv'
  2678. }) instanceof VhsHandler), 'does not support flv');
  2679. assert.ok(
  2680. !(VhsSourceHandler.canPlayType('video/mp4')),
  2681. 'does not support mp4'
  2682. );
  2683. assert.ok(
  2684. !(VhsSourceHandler.canPlayType('video/x-flv')),
  2685. 'does not support flv'
  2686. );
  2687. }
  2688. );
  2689. QUnit.test('has no effect if native HLS is available and browser is Safari', function(assert) {
  2690. const Html5 = videojs.getTech('Html5');
  2691. const oldHtml5CanPlaySource = Html5.canPlaySource;
  2692. const origIsAnySafari = videojs.browser.IS_ANY_SAFARI;
  2693. videojs.browser.IS_ANY_SAFARI = true;
  2694. Html5.canPlaySource = () => true;
  2695. Vhs.supportsNativeHls = true;
  2696. const player = createPlayer();
  2697. player.src({
  2698. src: 'http://example.com/manifest/master.m3u8',
  2699. type: 'application/x-mpegURL'
  2700. });
  2701. this.clock.tick(1);
  2702. assert.ok(!player.tech_.vhs, 'did not load vhs tech');
  2703. player.dispose();
  2704. Html5.canPlaySource = oldHtml5CanPlaySource;
  2705. videojs.browser.IS_ANY_SAFARI = origIsAnySafari;
  2706. });
  2707. QUnit.test('loads if native HLS is available but browser is not Safari', function(assert) {
  2708. const Html5 = videojs.getTech('Html5');
  2709. const oldHtml5CanPlaySource = Html5.canPlaySource;
  2710. const origIsAnySafari = videojs.browser.IS_ANY_SAFARI;
  2711. videojs.browser.IS_ANY_SAFARI = false;
  2712. Html5.canPlaySource = () => true;
  2713. Vhs.supportsNativeHls = true;
  2714. const player = createPlayer();
  2715. player.src({
  2716. src: 'http://example.com/manifest/master.m3u8',
  2717. type: 'application/x-mpegURL'
  2718. });
  2719. this.clock.tick(1);
  2720. assert.ok(player.tech_.vhs, 'loaded VHS tech');
  2721. player.dispose();
  2722. Html5.canPlaySource = oldHtml5CanPlaySource;
  2723. videojs.browser.IS_ANY_SAFARI = origIsAnySafari;
  2724. });
  2725. QUnit.test(
  2726. 'loads if native HLS is available and override is set locally',
  2727. function(assert) {
  2728. let player;
  2729. Vhs.supportsNativeHls = true;
  2730. player = createPlayer({html5: {vhs: {overrideNative: true}}});
  2731. this.clock.tick(1);
  2732. player.tech_.featuresNativeVideoTracks = true;
  2733. player.src({
  2734. src: 'http://example.com/manifest/master.m3u8',
  2735. type: 'application/x-mpegURL'
  2736. });
  2737. this.clock.tick(1);
  2738. assert.ok(player.tech_.vhs, 'did load vhs tech');
  2739. player.dispose();
  2740. player = createPlayer({html5: {vhs: {overrideNative: true}}});
  2741. this.clock.tick(1);
  2742. player.tech_.featuresNativeVideoTracks = false;
  2743. player.tech_.featuresNativeAudioTracks = false;
  2744. player.src({
  2745. src: 'http://example.com/manifest/master.m3u8',
  2746. type: 'application/x-mpegURL'
  2747. });
  2748. this.clock.tick(1);
  2749. assert.ok(player.tech_.vhs, 'did load vhs tech');
  2750. player.dispose();
  2751. }
  2752. );
  2753. QUnit.test(
  2754. 'loads if native HLS is available and override is set globally',
  2755. function(assert) {
  2756. videojs.options.vhs.overrideNative = true;
  2757. let player;
  2758. Vhs.supportsNativeHls = true;
  2759. player = createPlayer();
  2760. player.tech_.featuresNativeVideoTracks = true;
  2761. player.src({
  2762. src: 'http://example.com/manifest/master.m3u8',
  2763. type: 'application/x-mpegURL'
  2764. });
  2765. this.clock.tick(1);
  2766. assert.ok(player.tech_.vhs, 'did load vhs tech');
  2767. player.dispose();
  2768. player = createPlayer();
  2769. player.tech_.featuresNativeVideoTracks = false;
  2770. player.tech_.featuresNativeAudioTracks = false;
  2771. player.src({
  2772. src: 'http://example.com/manifest/master.m3u8',
  2773. type: 'application/x-mpegURL'
  2774. });
  2775. this.clock.tick(1);
  2776. assert.ok(player.tech_.vhs, 'did load vhs tech');
  2777. player.dispose();
  2778. }
  2779. );
  2780. QUnit.test('re-emits mediachange events', function(assert) {
  2781. let mediaChanges = 0;
  2782. this.player.on('mediachange', function() {
  2783. mediaChanges++;
  2784. });
  2785. this.player.src({
  2786. src: 'http://example.com/media.m3u8',
  2787. type: 'application/vnd.apple.mpegurl'
  2788. });
  2789. this.clock.tick(1);
  2790. openMediaSource(this.player, this.clock);
  2791. this.standardXHRResponse(this.requests.shift());
  2792. this.player.tech_.vhs.playlists.trigger('mediachange');
  2793. assert.strictEqual(mediaChanges, 1, 'fired mediachange');
  2794. });
  2795. QUnit.test('can be disposed before finishing initialization', function(assert) {
  2796. const readyHandlers = [];
  2797. this.player.ready = function(callback) {
  2798. readyHandlers.push(callback);
  2799. };
  2800. this.player.src({
  2801. src: 'http://example.com/media.m3u8',
  2802. type: 'application/vnd.apple.mpegurl'
  2803. });
  2804. this.clock.tick(1);
  2805. readyHandlers.shift().call(this.player);
  2806. this.player.src({
  2807. src: 'http://example.com/media.mp4',
  2808. type: 'video/mp4'
  2809. });
  2810. assert.ok(readyHandlers.length > 0, 'registered a ready handler');
  2811. try {
  2812. while (readyHandlers.length) {
  2813. readyHandlers.shift().call(this.player);
  2814. openMediaSource(this.player, this.clock);
  2815. }
  2816. assert.ok(true, 'did not throw an exception');
  2817. } catch (e) {
  2818. assert.ok(false, 'threw an exception');
  2819. }
  2820. });
  2821. QUnit.test('calling play() at the end of a video replays', function(assert) {
  2822. const done = assert.async();
  2823. let seekTime = -1;
  2824. this.player.src({
  2825. src: 'http://example.com/media.m3u8',
  2826. type: 'application/vnd.apple.mpegurl'
  2827. });
  2828. this.clock.tick(1);
  2829. openMediaSource(this.player, this.clock);
  2830. this.player.tech_.setCurrentTime = function(time) {
  2831. if (typeof time !== 'undefined') {
  2832. seekTime = time;
  2833. }
  2834. return 0;
  2835. };
  2836. this.requests.shift().respond(
  2837. 200, null,
  2838. '#EXTM3U\n' +
  2839. '#EXTINF:10,\n' +
  2840. '0.ts\n' +
  2841. '#EXT-X-ENDLIST\n'
  2842. );
  2843. this.clock.tick(1);
  2844. const segment = muxedSegment();
  2845. // copy the byte length since the segment bytes get cleared out
  2846. const segmentByteLength = segment.byteLength;
  2847. this.player.tech(true).vhs.masterPlaylistController_.mainSegmentLoader_.one('appending', () => {
  2848. this.player.tech_.ended = function() {
  2849. return true;
  2850. };
  2851. this.player.tech_.trigger('play');
  2852. this.clock.tick(1);
  2853. assert.equal(seekTime, 0, 'seeked to the beginning');
  2854. // verify stats
  2855. assert.equal(
  2856. this.player.tech_.vhs.stats.mediaBytesTransferred,
  2857. segmentByteLength,
  2858. 'transferred segment bytes'
  2859. );
  2860. assert.equal(this.player.tech_.vhs.stats.mediaRequests, 1, '1 request');
  2861. done();
  2862. });
  2863. assert.ok(segmentByteLength, 'the segment has some number of bytes');
  2864. // segment 0
  2865. this.standardXHRResponse(this.requests.shift(), segment);
  2866. });
  2867. QUnit.test('keys are resolved relative to the master playlist', function(assert) {
  2868. this.player.src({
  2869. src: 'video/master-encrypted.m3u8',
  2870. type: 'application/vnd.apple.mpegurl'
  2871. });
  2872. this.clock.tick(1);
  2873. openMediaSource(this.player, this.clock);
  2874. this.requests.shift().respond(
  2875. 200, null,
  2876. '#EXTM3U\n' +
  2877. '#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=17\n' +
  2878. 'playlist/playlist.m3u8\n' +
  2879. '#EXT-X-ENDLIST\n'
  2880. );
  2881. this.clock.tick(1);
  2882. this.requests.shift().respond(
  2883. 200, null,
  2884. '#EXTM3U\n' +
  2885. '#EXT-X-TARGETDURATION:15\n' +
  2886. '#EXT-X-KEY:METHOD=AES-128,URI="keys/key.php"\n' +
  2887. '#EXTINF:2.833,\n' +
  2888. 'http://media.example.com/fileSequence1.ts\n' +
  2889. '#EXT-X-ENDLIST\n'
  2890. );
  2891. this.clock.tick(1);
  2892. assert.equal(this.requests.length, 2, 'requested the key');
  2893. assert.equal(
  2894. this.requests[0].url,
  2895. absoluteUrl('video/playlist/keys/key.php'),
  2896. 'resolves multiple relative paths'
  2897. );
  2898. // verify stats
  2899. assert.equal(this.player.tech_.vhs.stats.bandwidth, 4194304, 'default');
  2900. });
  2901. QUnit.test('keys are resolved relative to their containing playlist', function(assert) {
  2902. this.player.src({
  2903. src: 'video/media-encrypted.m3u8',
  2904. type: 'application/vnd.apple.mpegurl'
  2905. });
  2906. this.clock.tick(1);
  2907. openMediaSource(this.player, this.clock);
  2908. this.requests.shift().respond(
  2909. 200, null,
  2910. '#EXTM3U\n' +
  2911. '#EXT-X-TARGETDURATION:15\n' +
  2912. '#EXT-X-KEY:METHOD=AES-128,URI="keys/key.php"\n' +
  2913. '#EXTINF:2.833,\n' +
  2914. 'http://media.example.com/fileSequence1.ts\n' +
  2915. '#EXT-X-ENDLIST\n'
  2916. );
  2917. this.clock.tick(1);
  2918. assert.equal(this.requests.length, 2, 'requested a key');
  2919. assert.equal(
  2920. this.requests[0].url,
  2921. absoluteUrl('video/keys/key.php'),
  2922. 'resolves multiple relative paths'
  2923. );
  2924. });
  2925. QUnit.test('keys are not requested when cached key available, cacheEncryptionKeys:true', function(assert) {
  2926. this.player.src({
  2927. src: 'video/media-encrypted.m3u8',
  2928. type: 'application/vnd.apple.mpegurl',
  2929. cacheEncryptionKeys: true
  2930. });
  2931. this.clock.tick(1);
  2932. openMediaSource(this.player, this.clock);
  2933. this.requests.shift().respond(
  2934. 200, null,
  2935. '#EXTM3U\n' +
  2936. '#EXT-X-TARGETDURATION:15\n' +
  2937. '#EXT-X-KEY:METHOD=AES-128,URI="keys/key.php",IV=0x00000000000000000000000000000000\n' +
  2938. '#EXTINF:2.833,\n' +
  2939. 'http://media.example.com/fileSequence1.ts\n' +
  2940. '#EXTINF:2.833,\n' +
  2941. 'http://media.example.com/fileSequence2.ts\n' +
  2942. '#EXT-X-ENDLIST\n'
  2943. );
  2944. this.clock.tick(1);
  2945. assert.equal(this.requests.length, 2, 'requested a key');
  2946. assert.equal(
  2947. this.requests[0].url,
  2948. absoluteUrl('video/keys/key.php'),
  2949. 'requested the key'
  2950. );
  2951. assert.equal(
  2952. this.requests[1].url,
  2953. 'http://media.example.com/fileSequence1.ts',
  2954. 'requested the segment'
  2955. );
  2956. // key response
  2957. this.standardXHRResponse(this.requests.shift(), encryptionKey());
  2958. const mpc = this.player.tech_.vhs.masterPlaylistController_;
  2959. return requestAndAppendSegment({
  2960. request: this.requests.shift(),
  2961. mediaSource: mpc.mediaSource,
  2962. segmentLoader: mpc.mainSegmentLoader_,
  2963. clock: this.clock,
  2964. segment: encryptedSegment(),
  2965. decryptionTicks: true
  2966. }).then(() => {
  2967. assert.equal(this.requests.length, 1, 'requested a segment, not a key');
  2968. assert.equal(
  2969. this.requests[0].url,
  2970. absoluteUrl('http://media.example.com/fileSequence2.ts'),
  2971. 'requested the segment only'
  2972. );
  2973. });
  2974. });
  2975. QUnit.test('keys are requested per segment, cacheEncryptionKeys:false', function(assert) {
  2976. this.player.src({
  2977. src: 'video/media-encrypted.m3u8',
  2978. type: 'application/vnd.apple.mpegurl',
  2979. cacheEncryptionKeys: false
  2980. });
  2981. this.clock.tick(1);
  2982. openMediaSource(this.player, this.clock);
  2983. this.requests.shift().respond(
  2984. 200, null,
  2985. '#EXTM3U\n' +
  2986. '#EXT-X-TARGETDURATION:15\n' +
  2987. '#EXT-X-KEY:METHOD=AES-128,URI="keys/key.php",IV=0x00000000000000000000000000000000\n' +
  2988. '#EXTINF:2.833,\n' +
  2989. 'http://media.example.com/fileSequence1.ts\n' +
  2990. '#EXTINF:2.833,\n' +
  2991. 'http://media.example.com/fileSequence2.ts\n' +
  2992. '#EXT-X-ENDLIST\n'
  2993. );
  2994. this.clock.tick(1);
  2995. assert.equal(this.requests.length, 2, 'requested a key');
  2996. assert.equal(
  2997. this.requests[0].url,
  2998. absoluteUrl('video/keys/key.php'),
  2999. 'requested the key'
  3000. );
  3001. assert.equal(
  3002. this.requests[1].url,
  3003. 'http://media.example.com/fileSequence1.ts',
  3004. 'requested the segment'
  3005. );
  3006. // key response
  3007. this.standardXHRResponse(this.requests.shift(), encryptionKey());
  3008. const mpc = this.player.tech_.vhs.masterPlaylistController_;
  3009. return requestAndAppendSegment({
  3010. request: this.requests.shift(),
  3011. mediaSource: mpc.mediaSource,
  3012. segmentLoader: mpc.mainSegmentLoader_,
  3013. clock: this.clock,
  3014. segment: encryptedSegment(),
  3015. decryptionTicks: true
  3016. }).then(() => {
  3017. assert.equal(this.requests.length, 2, 'requested a segment and a key');
  3018. assert.equal(
  3019. this.requests[0].url,
  3020. absoluteUrl('video/keys/key.php'),
  3021. 'requested the segment only'
  3022. );
  3023. assert.equal(
  3024. this.requests[1].url,
  3025. 'http://media.example.com/fileSequence2.ts',
  3026. 'requested the segment'
  3027. );
  3028. });
  3029. });
  3030. QUnit.test(
  3031. 'seeking should abort an outstanding key request and create a new one',
  3032. function(assert) {
  3033. this.player.src({
  3034. src: 'https://example.com/encrypted.m3u8',
  3035. type: 'application/vnd.apple.mpegurl'
  3036. });
  3037. this.clock.tick(1);
  3038. openMediaSource(this.player, this.clock);
  3039. this.requests.shift().respond(
  3040. 200, null,
  3041. '#EXTM3U\n' +
  3042. '#EXT-X-TARGETDURATION:15\n' +
  3043. '#EXT-X-KEY:METHOD=AES-128,URI="keys/key.php"\n' +
  3044. '#EXTINF:9,\n' +
  3045. 'http://media.example.com/fileSequence1.ts\n' +
  3046. '#EXT-X-KEY:METHOD=AES-128,URI="keys/key2.php"\n' +
  3047. '#EXTINF:9,\n' +
  3048. 'http://media.example.com/fileSequence2.ts\n' +
  3049. '#EXT-X-ENDLIST\n'
  3050. );
  3051. this.clock.tick(1);
  3052. // segment 1
  3053. this.standardXHRResponse(this.requests.pop());
  3054. this.player.currentTime(11);
  3055. this.clock.tick(2);
  3056. assert.ok(this.requests[0].aborted, 'the key XHR should be aborted');
  3057. // aborted key 1
  3058. this.requests.shift();
  3059. assert.equal(this.requests.length, 2, 'requested the new key');
  3060. assert.equal(
  3061. this.requests[0].url,
  3062. 'https://example.com/' +
  3063. this.player.tech_.vhs.playlists.media().segments[1].key.uri,
  3064. 'urls should match'
  3065. );
  3066. }
  3067. );
  3068. QUnit.test('switching playlists with an outstanding key request aborts request and ' +
  3069. 'loads segment', function(assert) {
  3070. const media = '#EXTM3U\n' +
  3071. '#EXT-X-MEDIA-SEQUENCE:5\n' +
  3072. '#EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=52"\n' +
  3073. '#EXTINF:2.833,\n' +
  3074. 'http://media.example.com/fileSequence52-A.ts\n' +
  3075. '#EXTINF:15.0,\n' +
  3076. 'http://media.example.com/fileSequence52-B.ts\n' +
  3077. '#EXT-X-ENDLIST\n';
  3078. this.player.src({
  3079. src: 'https://example.com/master.m3u8',
  3080. type: 'application/vnd.apple.mpegurl'
  3081. });
  3082. this.clock.tick(1);
  3083. openMediaSource(this.player, this.clock);
  3084. this.player.tech_.trigger('play');
  3085. this.clock.tick(1);
  3086. // master playlist
  3087. this.standardXHRResponse(this.requests.shift());
  3088. // media playlist
  3089. this.requests.shift().respond(200, null, media);
  3090. this.clock.tick(1);
  3091. // first segment of the original media playlist
  3092. this.standardXHRResponse(this.requests.pop());
  3093. assert.equal(this.requests.length, 1, 'key request only one outstanding');
  3094. const keyXhr = this.requests.shift();
  3095. assert.ok(!keyXhr.aborted, 'key request outstanding');
  3096. this.player.tech_.vhs.playlists.trigger('mediachanging');
  3097. this.player.tech_.vhs.playlists.trigger('mediachange');
  3098. this.clock.tick(1);
  3099. assert.ok(keyXhr.aborted, 'key request aborted');
  3100. assert.equal(this.requests.length, 2, 'loaded key and segment');
  3101. assert.equal(
  3102. this.requests[0].url,
  3103. 'https://priv.example.com/key.php?r=52',
  3104. 'requested the key'
  3105. );
  3106. assert.equal(
  3107. this.requests[1].url,
  3108. 'http://media.example.com/fileSequence52-A.ts',
  3109. 'requested the segment'
  3110. );
  3111. });
  3112. QUnit.test('does not download anything until play if preload option set to none', function(assert) {
  3113. this.player.preload('none');
  3114. this.player.src({
  3115. src: 'master.m3u8',
  3116. type: 'application/vnd.apple.mpegurl'
  3117. });
  3118. this.clock.tick(1);
  3119. openMediaSource(this.player, this.clock);
  3120. this.clock.tick(10 * 1000);
  3121. assert.equal(this.requests.length, 0, 'did not download any segments');
  3122. // verify stats
  3123. assert.equal(this.player.tech_.vhs.stats.bandwidth, 4194304, 'default');
  3124. this.player.tech_.paused = () => false;
  3125. this.player.tech_.trigger('play');
  3126. // master
  3127. this.standardXHRResponse(this.requests.shift());
  3128. // media
  3129. this.standardXHRResponse(this.requests.shift());
  3130. assert.equal(this.requests.length, 1, 'requested segment');
  3131. });
  3132. // workaround https://bugzilla.mozilla.org/show_bug.cgi?id=548397
  3133. QUnit.test(
  3134. 'selectPlaylist does not fail if getComputedStyle returns null',
  3135. function(assert) {
  3136. const oldGetComputedStyle = window.getComputedStyle;
  3137. window.getComputedStyle = function() {
  3138. return null;
  3139. };
  3140. this.player.src({
  3141. src: 'master.m3u8',
  3142. type: 'application/vnd.apple.mpegurl'
  3143. });
  3144. this.clock.tick(1);
  3145. openMediaSource(this.player, this.clock);
  3146. // master
  3147. this.standardXHRResponse(this.requests.shift());
  3148. // media
  3149. this.standardXHRResponse(this.requests.shift());
  3150. this.player.tech_.vhs.selectPlaylist();
  3151. assert.ok(true, 'should not throw');
  3152. window.getComputedStyle = oldGetComputedStyle;
  3153. // verify stats
  3154. assert.equal(this.player.tech_.vhs.stats.bandwidth, 4194304, 'default');
  3155. }
  3156. );
  3157. QUnit.test('resolves relative key URLs against the playlist', function(assert) {
  3158. this.player.src({
  3159. src: 'https://example.com/media.m3u8',
  3160. type: 'application/vnd.apple.mpegurl'
  3161. });
  3162. this.clock.tick(1);
  3163. openMediaSource(this.player, this.clock);
  3164. this.requests.shift()
  3165. .respond(
  3166. 200, null,
  3167. '#EXTM3U\n' +
  3168. '#EXT-X-MEDIA-SEQUENCE:5\n' +
  3169. '#EXT-X-KEY:METHOD=AES-128,URI="key.php?r=52"\n' +
  3170. '#EXTINF:2.833,\n' +
  3171. 'http://media.example.com/fileSequence52-A.ts\n' +
  3172. '#EXT-X-ENDLIST\n'
  3173. );
  3174. this.clock.tick(1);
  3175. assert.equal(
  3176. this.requests[0].url,
  3177. 'https://example.com/key.php?r=52',
  3178. 'resolves the key URL'
  3179. );
  3180. });
  3181. QUnit.test(
  3182. 'adds 1 default audio track if we have not parsed any and the playlist is loaded',
  3183. function(assert) {
  3184. this.player.src({
  3185. src: 'manifest/master.m3u8',
  3186. type: 'application/vnd.apple.mpegurl'
  3187. });
  3188. this.clock.tick(1);
  3189. assert.equal(this.player.audioTracks().length, 0, 'zero audio tracks at load time');
  3190. openMediaSource(this.player, this.clock);
  3191. // master
  3192. this.standardXHRResponse(this.requests.shift());
  3193. // media
  3194. this.standardXHRResponse(this.requests.shift());
  3195. assert.equal(this.player.audioTracks().length, 1, 'one audio track after load');
  3196. assert.equal(this.player.audioTracks()[0].label, 'default', 'set the label');
  3197. }
  3198. );
  3199. QUnit.test('adds audio tracks if we have parsed some from a playlist', function(assert) {
  3200. this.player.src({
  3201. src: 'manifest/multipleAudioGroups.m3u8',
  3202. type: 'application/vnd.apple.mpegurl'
  3203. });
  3204. this.clock.tick(1);
  3205. assert.equal(this.player.audioTracks().length, 0, 'zero audio tracks at load time');
  3206. openMediaSource(this.player, this.clock);
  3207. // master
  3208. this.standardXHRResponse(this.requests.shift());
  3209. // media
  3210. this.standardXHRResponse(this.requests.shift());
  3211. const vjsAudioTracks = this.player.audioTracks();
  3212. assert.equal(vjsAudioTracks.length, 3, '3 active vjs tracks');
  3213. assert.equal(vjsAudioTracks[0].enabled, true, 'default track is enabled');
  3214. vjsAudioTracks[1].enabled = true;
  3215. assert.equal(vjsAudioTracks[1].enabled, true, 'new track is enabled on vjs');
  3216. assert.equal(vjsAudioTracks[0].enabled, false, 'main track is disabled');
  3217. });
  3218. QUnit.test('cleans up the buffer when loading live segments', function(assert) {
  3219. const seekable = videojs.createTimeRanges([[0, 70]]);
  3220. this.player.src({
  3221. src: 'liveStart30sBefore.m3u8',
  3222. type: 'application/vnd.apple.mpegurl'
  3223. });
  3224. this.clock.tick(1);
  3225. openMediaSource(this.player, this.clock);
  3226. this.player.tech_.vhs.masterPlaylistController_.seekable = function() {
  3227. return seekable;
  3228. };
  3229. this.player.tech_.vhs.bandwidth = 20e10;
  3230. this.player.tech_.readyState = () => 4;
  3231. this.player.tech_.triggerReady();
  3232. // media
  3233. this.standardXHRResponse(this.requests[0]);
  3234. this.player.tech_.vhs.playlists.trigger('loadedmetadata');
  3235. this.player.tech_.trigger('canplay');
  3236. this.player.tech_.paused = function() {
  3237. return false;
  3238. };
  3239. this.player.tech_.trigger('play');
  3240. this.clock.tick(1);
  3241. const mpc = this.player.tech_.vhs.masterPlaylistController_;
  3242. const audioRemoves = [];
  3243. const videoRemoves = [];
  3244. // request first playable segment
  3245. return requestAndAppendSegment({
  3246. request: this.requests[1],
  3247. mediaSource: mpc.mediaSource,
  3248. segmentLoader: mpc.mainSegmentLoader_,
  3249. clock: this.clock
  3250. }).then(() => {
  3251. const audioBuffer = mpc.sourceUpdater_.audioBuffer;
  3252. const videoBuffer = mpc.sourceUpdater_.videoBuffer;
  3253. const origAudioRemove = audioBuffer.remove.bind(audioBuffer);
  3254. const origVideoRemove = videoBuffer.remove.bind(videoBuffer);
  3255. audioBuffer.remove = (start, end) => {
  3256. audioRemoves.push({start, end});
  3257. origAudioRemove();
  3258. };
  3259. videoBuffer.remove = (start, end) => {
  3260. videoRemoves.push({start, end});
  3261. origVideoRemove();
  3262. };
  3263. // since source buffers are mocked, must fake that there's buffered data, or else we
  3264. // don't bother processing removes
  3265. audioBuffer.buffered = videojs.createTimeRanges([[10, 20]]);
  3266. videoBuffer.buffered = videojs.createTimeRanges([[15, 25]]);
  3267. // request second segment, and give enough time for the source buffer to process removes
  3268. return requestAndAppendSegment({
  3269. request: this.requests[2],
  3270. mediaSource: mpc.mediaSource,
  3271. segmentLoader: mpc.mainSegmentLoader_,
  3272. clock: this.clock
  3273. });
  3274. }).then(() => {
  3275. assert.equal(audioRemoves.length, 1, 'one audio remove');
  3276. assert.equal(videoRemoves.length, 1, 'one video remove');
  3277. // segment-loader removes at currentTime - 30
  3278. assert.deepEqual(
  3279. audioRemoves[0],
  3280. { start: 0, end: 40 },
  3281. 'removed from audio buffer with right range'
  3282. );
  3283. assert.deepEqual(
  3284. videoRemoves[0],
  3285. { start: 0, end: 40 },
  3286. 'removed from video buffer with right range'
  3287. );
  3288. });
  3289. });
  3290. QUnit.test('cleans up buffer by removing targetDuration from currentTime when loading a ' +
  3291. 'live segment if seekable start is after currentTime', function(assert) {
  3292. let seekable = videojs.createTimeRanges([[0, 80]]);
  3293. this.player.src({
  3294. src: 'liveStart30sBefore.m3u8',
  3295. type: 'application/vnd.apple.mpegurl'
  3296. });
  3297. openMediaSource(this.player, this.clock);
  3298. this.player.tech_.vhs.masterPlaylistController_.seekable = function() {
  3299. return seekable;
  3300. };
  3301. this.player.tech_.readyState = () => 4;
  3302. this.player.tech_.vhs.bandwidth = 20e10;
  3303. this.player.tech_.triggerReady();
  3304. // media
  3305. this.standardXHRResponse(this.requests.shift());
  3306. this.player.tech_.vhs.playlists.trigger('loadedmetadata');
  3307. this.player.tech_.trigger('canplay');
  3308. this.player.tech_.paused = function() {
  3309. return false;
  3310. };
  3311. this.player.tech_.trigger('play');
  3312. this.clock.tick(1);
  3313. const mpc = this.player.tech_.vhs.masterPlaylistController_;
  3314. const audioRemoves = [];
  3315. const videoRemoves = [];
  3316. // request first playable segment
  3317. return requestAndAppendSegment({
  3318. request: this.requests.shift(),
  3319. mediaSource: mpc.mediaSource,
  3320. segmentLoader: mpc.mainSegmentLoader_,
  3321. clock: this.clock
  3322. }).then(() => {
  3323. // Change seekable so that it starts *after* the currentTime which was set
  3324. // based on the previous seekable range (the end of 80)
  3325. seekable = videojs.createTimeRanges([[110, 120]]);
  3326. this.clock.tick(1);
  3327. const audioBuffer = mpc.sourceUpdater_.audioBuffer;
  3328. const videoBuffer = mpc.sourceUpdater_.videoBuffer;
  3329. const origAudioRemove = audioBuffer.remove.bind(audioBuffer);
  3330. const origVideoRemove = videoBuffer.remove.bind(videoBuffer);
  3331. audioBuffer.remove = (start, end) => {
  3332. audioRemoves.push({start, end});
  3333. origAudioRemove();
  3334. };
  3335. videoBuffer.remove = (start, end) => {
  3336. videoRemoves.push({start, end});
  3337. origVideoRemove();
  3338. };
  3339. // since source buffers are mocked, must fake that there's buffered data, or else we
  3340. // don't bother processing removes
  3341. audioBuffer.buffered = videojs.createTimeRanges([[10, 20]]);
  3342. videoBuffer.buffered = videojs.createTimeRanges([[15, 25]]);
  3343. // prevent trying to correct live time
  3344. disposePlaybackWatcher(this.player);
  3345. // request second segment, and give enough time for the source buffer to process removes
  3346. return requestAndAppendSegment({
  3347. request: this.requests.shift(),
  3348. mediaSource: mpc.mediaSource,
  3349. segmentLoader: mpc.mainSegmentLoader_,
  3350. clock: this.clock
  3351. });
  3352. }).then(() => {
  3353. assert.equal(audioRemoves.length, 1, 'one audio remove');
  3354. assert.equal(videoRemoves.length, 1, 'one video remove');
  3355. // segment-loader removes at currentTime - 30
  3356. assert.deepEqual(
  3357. audioRemoves[0],
  3358. { start: 0, end: 80 - 10 },
  3359. 'removed from audio buffer with right range'
  3360. );
  3361. assert.deepEqual(
  3362. videoRemoves[0],
  3363. { start: 0, end: 80 - 10 },
  3364. 'removed from video buffer with right range'
  3365. );
  3366. });
  3367. });
  3368. QUnit.test('cleans up the buffer when loading VOD segments', function(assert) {
  3369. this.player.src({
  3370. src: 'manifest/master.m3u8',
  3371. type: 'application/vnd.apple.mpegurl'
  3372. });
  3373. this.clock.tick(1);
  3374. openMediaSource(this.player, this.clock);
  3375. this.player.width(640);
  3376. this.player.height(360);
  3377. this.player.tech_.vhs.bandwidth = 20e10;
  3378. // master
  3379. this.standardXHRResponse(this.requests[0]);
  3380. // media
  3381. this.standardXHRResponse(this.requests[1]);
  3382. const mpc = this.player.tech_.vhs.masterPlaylistController_;
  3383. const audioRemoves = [];
  3384. const videoRemoves = [];
  3385. // first segment request will set up all of the source buffers we need
  3386. return requestAndAppendSegment({
  3387. request: this.requests[2],
  3388. mediaSource: mpc.mediaSource,
  3389. segmentLoader: mpc.mainSegmentLoader_,
  3390. clock: this.clock
  3391. }).then(() => {
  3392. const audioBuffer = mpc.sourceUpdater_.audioBuffer;
  3393. const videoBuffer = mpc.sourceUpdater_.videoBuffer;
  3394. const origAudioRemove = audioBuffer.remove.bind(audioBuffer);
  3395. const origVideoRemove = videoBuffer.remove.bind(videoBuffer);
  3396. audioBuffer.remove = (start, end) => {
  3397. audioRemoves.push({start, end});
  3398. window.setTimeout(() => audioBuffer.trigger('updateend'), 1);
  3399. origAudioRemove();
  3400. };
  3401. videoBuffer.remove = (start, end) => {
  3402. videoRemoves.push({start, end});
  3403. window.setTimeout(() => videoBuffer.trigger('updateend'), 1);
  3404. origVideoRemove();
  3405. };
  3406. // the seek will have removed everything to the duration of the video, so we want to
  3407. // only start tracking removes after the seek, once the next segment request is made
  3408. this.player.currentTime(120);
  3409. // since source buffers are mocked, must fake that there's buffered data, or else we
  3410. // don't bother processing removes
  3411. audioBuffer.buffered = videojs.createTimeRanges([[0, 10]]);
  3412. videoBuffer.buffered = videojs.createTimeRanges([[1, 11]]);
  3413. // This requires 2 clock ticks because after updateend monitorBuffer_ is called
  3414. // to setup fillBuffer on the next tick, but the seek also causes monitorBuffer_ to be
  3415. // called, which cancels the previously set timeout and sets a new one for the following
  3416. // tick.
  3417. this.clock.tick(2);
  3418. assert.ok(this.requests[3].aborted, 'request aborted during seek');
  3419. // request second segment, and give enough time for the source buffer to process removes
  3420. return requestAndAppendSegment({
  3421. request: this.requests[4],
  3422. mediaSource: mpc.mediaSource,
  3423. segmentLoader: mpc.mainSegmentLoader_,
  3424. clock: this.clock
  3425. });
  3426. }).then(() => {
  3427. assert.ok(audioRemoves.length, 'audio removes');
  3428. assert.ok(videoRemoves.length, 'video removes');
  3429. // the default manifest is 4 segments that are 10s each.
  3430. assert.deepEqual(audioRemoves, [
  3431. // The first remove comes from the setCurrentTime call,
  3432. // caused by player.currentTime(120)
  3433. { start: 0, end: 40 },
  3434. // The second remove comes from trimBackBuffer_ and is based on currentTime
  3435. { start: 0, end: 120 - 30 },
  3436. // the final remove comes after our final requestAndAppendSegment
  3437. // and happens because our guess to append to a buffered ranged near
  3438. // currentTime is incorrect.
  3439. { start: 0, end: 40 }
  3440. ], 'removed from audio buffer with right range');
  3441. assert.deepEqual(videoRemoves, [
  3442. { start: 0, end: 40 },
  3443. { start: 0, end: 120 - 30 },
  3444. { start: 0, end: 40 }
  3445. ], 'removed from audio buffer with right range');
  3446. });
  3447. });
  3448. QUnit.test('when mediaGroup changes enabled track should not change', function(assert) {
  3449. let vhsAudioChangeEvents = 0;
  3450. let hlsAudioChangeEvents = 0;
  3451. this.player.src({
  3452. src: 'manifest/multipleAudioGroups.m3u8',
  3453. type: 'application/vnd.apple.mpegurl'
  3454. });
  3455. this.clock.tick(1);
  3456. openMediaSource(this.player, this.clock);
  3457. this.player.tech_.on('usage', (event) => {
  3458. if (event.name === 'vhs-audio-change') {
  3459. vhsAudioChangeEvents++;
  3460. }
  3461. if (event.name === 'hls-audio-change') {
  3462. hlsAudioChangeEvents++;
  3463. }
  3464. });
  3465. // master
  3466. this.standardXHRResponse(this.requests.shift());
  3467. // video media
  3468. this.standardXHRResponse(this.requests.shift());
  3469. const vhs = this.player.tech_.vhs;
  3470. const mpc = vhs.masterPlaylistController_;
  3471. let audioTracks = this.player.audioTracks();
  3472. assert.equal(vhsAudioChangeEvents, 0, 'no vhs-audio-change event was fired');
  3473. assert.equal(hlsAudioChangeEvents, 0, 'no hls-audio-change event was fired');
  3474. assert.equal(audioTracks.length, 3, 'three audio tracks after load');
  3475. assert.equal(audioTracks[0].enabled, true, 'track one enabled after load');
  3476. let oldMediaGroup = vhs.playlists.media().attributes.AUDIO;
  3477. // clear out any outstanding requests
  3478. this.requests.length = 0;
  3479. // force mpc to select a playlist from a new media group
  3480. mpc.masterPlaylistLoader_.media(mpc.master().playlists[0]);
  3481. this.clock.tick(1);
  3482. // video media
  3483. this.standardXHRResponse(this.requests.shift());
  3484. assert.notEqual(
  3485. oldMediaGroup,
  3486. vhs.playlists.media().attributes.AUDIO,
  3487. 'selected a new playlist'
  3488. );
  3489. audioTracks = this.player.audioTracks();
  3490. const activeGroup = mpc.mediaTypes_.AUDIO.activeGroup(audioTracks[0]);
  3491. assert.equal(audioTracks.length, 3, 'three audio tracks after changing mediaGroup');
  3492. assert.ok(activeGroup.default, 'track one should be the default');
  3493. assert.ok(audioTracks[0].enabled, 'enabled the default track');
  3494. assert.notOk(audioTracks[1].enabled, 'disabled track two');
  3495. assert.notOk(audioTracks[2].enabled, 'disabled track three');
  3496. audioTracks[1].enabled = true;
  3497. assert.notOk(audioTracks[0].enabled, 'disabled track one');
  3498. assert.ok(audioTracks[1].enabled, 'enabled track two');
  3499. assert.notOk(audioTracks[2].enabled, 'disabled track three');
  3500. oldMediaGroup = vhs.playlists.media().attributes.AUDIO;
  3501. // clear out any outstanding requests
  3502. this.requests.length = 0;
  3503. // swap back to the old media group
  3504. // this playlist is already loaded so no new requests are made
  3505. mpc.masterPlaylistLoader_.media(mpc.master().playlists[3]);
  3506. this.clock.tick(1);
  3507. assert.notEqual(
  3508. oldMediaGroup,
  3509. vhs.playlists.media().attributes.AUDIO,
  3510. 'selected a new playlist'
  3511. );
  3512. audioTracks = this.player.audioTracks();
  3513. assert.equal(vhsAudioChangeEvents, 1, 'a vhs-audio-change event was fired');
  3514. assert.equal(hlsAudioChangeEvents, 1, 'an hls-audio-change event was fired');
  3515. assert.equal(audioTracks.length, 3, 'three audio tracks after reverting mediaGroup');
  3516. assert.notOk(audioTracks[0].enabled, 'the default track is still disabled');
  3517. assert.ok(audioTracks[1].enabled, 'track two is still enabled');
  3518. assert.notOk(audioTracks[2].enabled, 'track three is still disabled');
  3519. });
  3520. QUnit.test(
  3521. 'Allows specifying the beforeRequest function on the player',
  3522. function(assert) {
  3523. let beforeRequestCalled = false;
  3524. this.player.src({
  3525. src: 'master.m3u8',
  3526. type: 'application/vnd.apple.mpegurl'
  3527. });
  3528. this.clock.tick(1);
  3529. openMediaSource(this.player, this.clock);
  3530. this.player.tech_.vhs.xhr.beforeRequest = function() {
  3531. beforeRequestCalled = true;
  3532. };
  3533. // master
  3534. this.standardXHRResponse(this.requests.shift());
  3535. // media
  3536. this.standardXHRResponse(this.requests.shift());
  3537. assert.ok(beforeRequestCalled, 'beforeRequest was called');
  3538. // verify stats
  3539. assert.equal(this.player.tech_.vhs.stats.bandwidth, 4194304, 'default');
  3540. }
  3541. );
  3542. QUnit.test('Allows specifying the beforeRequest function globally', function(assert) {
  3543. let beforeRequestCalled = false;
  3544. videojs.Vhs.xhr.beforeRequest = function() {
  3545. beforeRequestCalled = true;
  3546. };
  3547. this.player.src({
  3548. src: 'master.m3u8',
  3549. type: 'application/vnd.apple.mpegurl'
  3550. });
  3551. this.clock.tick(1);
  3552. openMediaSource(this.player, this.clock);
  3553. // master
  3554. this.standardXHRResponse(this.requests.shift());
  3555. assert.ok(beforeRequestCalled, 'beforeRequest was called');
  3556. delete videojs.Vhs.xhr.beforeRequest;
  3557. // verify stats
  3558. assert.equal(this.player.tech_.vhs.stats.bandwidth, 4194304, 'default');
  3559. });
  3560. QUnit.test('Allows specifying custom xhr() function globally', function(assert) {
  3561. const originalXhr = videojs.Vhs.xhr;
  3562. let customXhr = false;
  3563. videojs.Vhs.xhr = function(opts, callback) {
  3564. customXhr = true;
  3565. return videojs.xhr(opts, function(err, response, body) {
  3566. callback(err, response);
  3567. });
  3568. };
  3569. this.player.src({
  3570. src: 'master.m3u8',
  3571. type: 'application/vnd.apple.mpegurl'
  3572. });
  3573. this.clock.tick(1);
  3574. openMediaSource(this.player, this.clock);
  3575. // master
  3576. this.standardXHRResponse(this.requests.shift());
  3577. assert.ok(customXhr, 'customXhr was called');
  3578. videojs.Vhs.xhr = originalXhr;
  3579. // verify stats
  3580. assert.equal(this.player.tech_.vhs.stats.bandwidth, 4194304, 'default');
  3581. });
  3582. QUnit.test('Allows overriding the global beforeRequest function', function(assert) {
  3583. let beforeGlobalRequestCalled = 0;
  3584. let beforeLocalRequestCalled = 0;
  3585. videojs.Vhs.xhr.beforeRequest = function() {
  3586. beforeGlobalRequestCalled++;
  3587. };
  3588. this.player.src({
  3589. src: 'master.m3u8',
  3590. type: 'application/vnd.apple.mpegurl'
  3591. });
  3592. this.clock.tick(1);
  3593. openMediaSource(this.player, this.clock);
  3594. this.player.tech_.vhs.xhr.beforeRequest = function() {
  3595. beforeLocalRequestCalled++;
  3596. };
  3597. // master
  3598. this.standardXHRResponse(this.requests.shift());
  3599. // media
  3600. this.standardXHRResponse(this.requests.shift());
  3601. // ts
  3602. this.standardXHRResponse(this.requests.shift(), muxedSegment());
  3603. assert.equal(beforeLocalRequestCalled, 2, 'local beforeRequest was called twice ' +
  3604. 'for the media playlist and media');
  3605. assert.equal(beforeGlobalRequestCalled, 1, 'global beforeRequest was called once ' +
  3606. 'for the master playlist');
  3607. delete videojs.Vhs.xhr.beforeRequest;
  3608. });
  3609. QUnit.test(
  3610. 'passes useCueTags vhs option to master playlist controller',
  3611. function(assert) {
  3612. this.player.src({
  3613. src: 'master.m3u8',
  3614. type: 'application/vnd.apple.mpegurl'
  3615. });
  3616. this.clock.tick(1);
  3617. assert.ok(
  3618. !this.player.tech_.vhs.masterPlaylistController_.useCueTags_,
  3619. 'useCueTags is falsy by default'
  3620. );
  3621. const origVhsOptions = videojs.options.vhs;
  3622. videojs.options.vhs = {
  3623. useCueTags: true
  3624. };
  3625. this.player.dispose();
  3626. this.player = createPlayer();
  3627. this.player.src({
  3628. src: 'http://example.com/media.m3u8',
  3629. type: 'application/vnd.apple.mpegurl'
  3630. });
  3631. this.clock.tick(1);
  3632. assert.ok(
  3633. this.player.tech_.vhs.masterPlaylistController_.useCueTags_,
  3634. 'useCueTags passed to master playlist controller'
  3635. );
  3636. videojs.options.vhs = origVhsOptions;
  3637. }
  3638. );
  3639. QUnit.test('populates quality levels list when available', function(assert) {
  3640. this.player.src({
  3641. src: 'manifest/master.m3u8',
  3642. type: 'application/vnd.apple.mpegurl'
  3643. });
  3644. this.clock.tick(1);
  3645. openMediaSource(this.player, this.clock);
  3646. assert.ok(this.player.tech_.vhs.qualityLevels_, 'added quality levels');
  3647. const qualityLevels = this.player.qualityLevels();
  3648. let addCount = 0;
  3649. let changeCount = 0;
  3650. qualityLevels.on('addqualitylevel', () => {
  3651. addCount++;
  3652. });
  3653. qualityLevels.on('change', () => {
  3654. changeCount++;
  3655. });
  3656. // master
  3657. this.standardXHRResponse(this.requests.shift());
  3658. // media
  3659. this.standardXHRResponse(this.requests.shift());
  3660. assert.equal(addCount, 4, 'four levels added from master');
  3661. assert.equal(changeCount, 1, 'selected initial quality level');
  3662. this.player.dispose();
  3663. this.player = createPlayer({}, {
  3664. src: 'http://example.com/media.m3u8',
  3665. type: 'application/vnd.apple.mpegurl'
  3666. }, this.clock);
  3667. openMediaSource(this.player, this.clock);
  3668. assert.ok(
  3669. this.player.tech_.vhs.qualityLevels_,
  3670. 'added quality levels from video with source'
  3671. );
  3672. });
  3673. QUnit.test('configures eme for DASH on source buffer creation', function(assert) {
  3674. this.player.eme = {
  3675. options: {
  3676. previousSetting: 1
  3677. }
  3678. };
  3679. this.player.src({
  3680. src: 'manifest/master.mpd',
  3681. type: 'application/dash+xml',
  3682. keySystems: {
  3683. keySystem1: {
  3684. url: 'url1'
  3685. }
  3686. }
  3687. });
  3688. this.clock.tick(1);
  3689. const media = {
  3690. attributes: {
  3691. CODECS: 'avc1.420015'
  3692. },
  3693. contentProtection: {
  3694. keySystem1: {
  3695. pssh: 'test'
  3696. }
  3697. }
  3698. };
  3699. this.player.tech_.vhs.playlists = {
  3700. master: { playlists: [media] },
  3701. media: () => media
  3702. };
  3703. this.player.tech_.vhs.masterPlaylistController_.mediaTypes_ = {
  3704. SUBTITLES: {},
  3705. AUDIO: {
  3706. activePlaylistLoader: {
  3707. media: () => {
  3708. return {
  3709. attributes: {
  3710. CODECS: 'mp4a.40.2c'
  3711. }
  3712. };
  3713. }
  3714. }
  3715. }
  3716. };
  3717. this.player.tech_.vhs.masterPlaylistController_.sourceUpdater_.trigger('createdsourcebuffers');
  3718. assert.deepEqual(this.player.eme.options, {
  3719. previousSetting: 1
  3720. }, 'did not modify plugin options');
  3721. assert.deepEqual(this.player.currentSource(), {
  3722. src: 'manifest/master.mpd',
  3723. type: 'application/dash+xml',
  3724. keySystems: {
  3725. keySystem1: {
  3726. url: 'url1',
  3727. audioContentType: 'audio/mp4;codecs="mp4a.40.2c"',
  3728. videoContentType: 'video/mp4;codecs="avc1.420015"',
  3729. pssh: 'test'
  3730. }
  3731. }
  3732. }, 'set source eme options');
  3733. });
  3734. QUnit.test('configures eme for HLS on source buffer creation', function(assert) {
  3735. this.player.eme = {
  3736. options: {
  3737. previousSetting: 1
  3738. }
  3739. };
  3740. this.player.src({
  3741. src: 'manifest/master.m3u8',
  3742. type: 'application/x-mpegURL',
  3743. keySystems: {
  3744. keySystem1: {
  3745. url: 'url1'
  3746. }
  3747. }
  3748. });
  3749. this.clock.tick(1);
  3750. const media = {
  3751. attributes: {
  3752. CODECS: 'avc1.420015, mp4a.40.2c'
  3753. },
  3754. contentProtection: {
  3755. keySystem1: {
  3756. pssh: 'test'
  3757. }
  3758. }
  3759. };
  3760. this.player.tech_.vhs.playlists = {
  3761. master: { playlists: [media] },
  3762. media: () => media
  3763. };
  3764. this.player.tech_.vhs.masterPlaylistController_.sourceUpdater_.trigger('createdsourcebuffers');
  3765. assert.deepEqual(this.player.eme.options, {
  3766. previousSetting: 1
  3767. }, 'did not modify plugin options');
  3768. assert.deepEqual(this.player.currentSource(), {
  3769. src: 'manifest/master.m3u8',
  3770. type: 'application/x-mpegURL',
  3771. keySystems: {
  3772. keySystem1: {
  3773. url: 'url1',
  3774. audioContentType: 'audio/mp4;codecs="mp4a.40.2c"',
  3775. videoContentType: 'video/mp4;codecs="avc1.420015"',
  3776. pssh: 'test'
  3777. }
  3778. }
  3779. }, 'set source eme options');
  3780. });
  3781. QUnit.test('eme handles keystatuschange where status is output-restricted', function(assert) {
  3782. this.player.eme = {
  3783. options: {
  3784. previousSetting: 1
  3785. }
  3786. };
  3787. this.player.src({
  3788. src: 'manifest/master.m3u8',
  3789. type: 'application/x-mpegURL',
  3790. keySystems: {
  3791. keySystem1: {
  3792. url: 'url1'
  3793. }
  3794. }
  3795. });
  3796. this.clock.tick(1);
  3797. const media = {
  3798. attributes: {
  3799. CODECS: 'avc1.420015, mp4a.40.2c'
  3800. },
  3801. contentProtection: {
  3802. keySystem1: {
  3803. pssh: 'test'
  3804. }
  3805. }
  3806. };
  3807. this.player.tech_.vhs.playlists = {
  3808. master: { playlists: [media] },
  3809. media: () => media
  3810. };
  3811. const excludes = [];
  3812. this.player.tech_.vhs.masterPlaylistController_.blacklistCurrentPlaylist = (exclude) => {
  3813. excludes.push(exclude);
  3814. };
  3815. this.player.tech_.vhs.masterPlaylistController_.sourceUpdater_.trigger('createdsourcebuffers');
  3816. this.player.tech_.trigger({type: 'keystatuschange', status: 'output-restricted'});
  3817. assert.deepEqual(excludes, [{
  3818. blacklistDuration: Infinity,
  3819. message: 'DRM keystatus changed to output-restricted. Playlist will fail to play. Check for HDCP content.',
  3820. playlist: undefined
  3821. }], 'excluded playlist');
  3822. });
  3823. QUnit.test('eme handles keystatuschange where status is usable', function(assert) {
  3824. this.player.eme = {
  3825. options: {
  3826. previousSetting: 1
  3827. }
  3828. };
  3829. this.player.src({
  3830. src: 'manifest/master.m3u8',
  3831. type: 'application/x-mpegURL',
  3832. keySystems: {
  3833. keySystem1: {
  3834. url: 'url1'
  3835. }
  3836. }
  3837. });
  3838. this.clock.tick(1);
  3839. const media = {
  3840. attributes: {
  3841. CODECS: 'avc1.420015, mp4a.40.2c'
  3842. },
  3843. contentProtection: {
  3844. keySystem1: {
  3845. pssh: 'test'
  3846. }
  3847. }
  3848. };
  3849. this.player.tech_.vhs.playlists = {
  3850. master: { playlists: [media] },
  3851. media: () => media
  3852. };
  3853. const excludes = [];
  3854. this.player.tech_.vhs.masterPlaylistController_.blacklistCurrentPlaylist = (exclude) => {
  3855. excludes.push(exclude);
  3856. };
  3857. this.player.tech_.vhs.masterPlaylistController_.sourceUpdater_.trigger('createdsourcebuffers');
  3858. this.player.tech_.trigger({type: 'keystatuschange', status: 'usable'});
  3859. assert.deepEqual(excludes, [], 'did not exclude anything');
  3860. });
  3861. QUnit.test('integration: configures eme for DASH on source buffer creation', function(assert) {
  3862. assert.timeout(3000);
  3863. const done = assert.async();
  3864. this.player.eme = {
  3865. options: {
  3866. previousSetting: 1
  3867. }
  3868. };
  3869. this.player.src({
  3870. src: 'dash.mpd',
  3871. type: 'application/dash+xml',
  3872. keySystems: {
  3873. keySystem1: {
  3874. url: 'url1'
  3875. }
  3876. }
  3877. });
  3878. openMediaSource(this.player, this.clock);
  3879. this.player.tech_.vhs.masterPlaylistController_.sourceUpdater_.on(
  3880. 'createdsourcebuffers',
  3881. () => {
  3882. assert.deepEqual(this.player.eme.options, {
  3883. previousSetting: 1
  3884. }, 'did not modify plugin options');
  3885. assert.deepEqual(this.player.currentSource(), {
  3886. src: 'dash.mpd',
  3887. type: 'application/dash+xml',
  3888. keySystems: {
  3889. keySystem1: {
  3890. url: 'url1',
  3891. audioContentType: 'audio/mp4;codecs="mp4a.40.2"',
  3892. videoContentType: 'video/mp4;codecs="avc1.420015"'
  3893. }
  3894. }
  3895. }, 'set source eme options');
  3896. done();
  3897. }
  3898. );
  3899. this.standardXHRResponse(this.requests[0]);
  3900. // this allows the audio playlist loader to load
  3901. this.clock.tick(1);
  3902. // respond to segement request to get trackinfo
  3903. this.standardXHRResponse(this.requests[1], mp4VideoInitSegment());
  3904. this.standardXHRResponse(this.requests[2], mp4VideoSegment());
  3905. this.standardXHRResponse(this.requests[3], mp4AudioInitSegment());
  3906. this.standardXHRResponse(this.requests[4], mp4AudioSegment());
  3907. });
  3908. QUnit.test('integration: configures eme for HLS on source buffer creation', function(assert) {
  3909. assert.timeout(3000);
  3910. const done = assert.async();
  3911. this.player.eme = {
  3912. options: {
  3913. previousSetting: 1
  3914. }
  3915. };
  3916. this.player.src({
  3917. src: 'demuxed-two.m3u8',
  3918. type: 'application/x-mpegURL',
  3919. keySystems: {
  3920. keySystem1: {
  3921. url: 'url1'
  3922. }
  3923. }
  3924. });
  3925. openMediaSource(this.player, this.clock);
  3926. this.player.tech_.vhs.masterPlaylistController_.sourceUpdater_.on(
  3927. 'createdsourcebuffers',
  3928. () => {
  3929. assert.deepEqual(this.player.eme.options, {
  3930. previousSetting: 1
  3931. }, 'did not modify plugin options');
  3932. assert.deepEqual(this.player.currentSource(), {
  3933. src: 'demuxed-two.m3u8',
  3934. type: 'application/x-mpegURL',
  3935. keySystems: {
  3936. keySystem1: {
  3937. url: 'url1',
  3938. audioContentType: 'audio/mp4;codecs="mp4a.40.2"',
  3939. videoContentType: 'video/mp4;codecs="avc1.420015"'
  3940. }
  3941. }
  3942. }, 'set source eme options');
  3943. done();
  3944. }
  3945. );
  3946. // master manifest
  3947. this.standardXHRResponse(this.requests.shift());
  3948. // video manifest
  3949. this.standardXHRResponse(this.requests.shift());
  3950. // audio manifest
  3951. this.standardXHRResponse(this.requests.shift());
  3952. // this allows the audio playlist loader to load
  3953. this.clock.tick(1);
  3954. // respond to segement request to get trackinfo
  3955. this.standardXHRResponse(this.requests.shift(), videoSegment());
  3956. this.standardXHRResponse(this.requests.shift(), audioSegment());
  3957. });
  3958. QUnit.test('integration: updates source updater after eme init', function(assert) {
  3959. assert.expect(4);
  3960. assert.timeout(3000);
  3961. const done = assert.async();
  3962. this.player.src({
  3963. src: 'demuxed-two.m3u8',
  3964. type: 'application/x-mpegURL',
  3965. keySystems: {
  3966. keySystem1: {
  3967. url: 'url1'
  3968. }
  3969. }
  3970. });
  3971. openMediaSource(this.player, this.clock);
  3972. const sourceUpdater = this.player.tech_.vhs.masterPlaylistController_.sourceUpdater_;
  3973. sourceUpdater.on('ready', () => {
  3974. assert.ok(sourceUpdater.hasInitializedAnyEme(), 'updated source updater');
  3975. done();
  3976. });
  3977. sourceUpdater.on(
  3978. 'createdsourcebuffers',
  3979. () => {
  3980. let expected = false;
  3981. // IE initializes eme syncronously directly after source buffer
  3982. // creation
  3983. if (videojs.browser.IE_VERSION) {
  3984. expected = true;
  3985. }
  3986. assert.equal(sourceUpdater.hasInitializedAnyEme(), expected, 'correct eme state');
  3987. }
  3988. );
  3989. // master manifest
  3990. this.standardXHRResponse(this.requests.shift());
  3991. // video manifest
  3992. this.standardXHRResponse(this.requests.shift());
  3993. // audio manifest
  3994. this.standardXHRResponse(this.requests.shift());
  3995. // this allows the audio playlist loader to load
  3996. this.clock.tick(1);
  3997. // respond to segement request to get trackinfo
  3998. this.standardXHRResponse(this.requests.shift(), videoSegment());
  3999. this.standardXHRResponse(this.requests.shift(), audioSegment());
  4000. });
  4001. QUnit[testOrSkip]('player error when key session creation rejects promise', function(assert) {
  4002. const done = assert.async();
  4003. this.player.error = (errorObject) => {
  4004. assert.deepEqual(
  4005. errorObject,
  4006. {
  4007. code: 3,
  4008. message: 'Failed to initialize media keys for EME'
  4009. },
  4010. 'called player error with correct error'
  4011. );
  4012. done();
  4013. };
  4014. this.player.eme = {
  4015. initializeMediaKeys: (keySystems, callback) => {
  4016. // calling back with an error should lead to promise rejection
  4017. callback({
  4018. message: 'this is the error message'
  4019. });
  4020. }
  4021. };
  4022. this.player.src({
  4023. src: 'manifest/master.mpd',
  4024. type: 'application/dash+xml',
  4025. keySystems: {
  4026. keySystem1: {
  4027. url: 'url1'
  4028. }
  4029. }
  4030. });
  4031. this.clock.tick(1);
  4032. const media = {
  4033. attributes: {
  4034. CODECS: 'avc1.420015'
  4035. },
  4036. contentProtection: {
  4037. keySystem1: {
  4038. pssh: 'test'
  4039. }
  4040. }
  4041. };
  4042. this.player.tech_.vhs.playlists = {
  4043. master: { playlists: [media] },
  4044. media: () => media
  4045. };
  4046. this.player.tech_.vhs.masterPlaylistController_.mediaTypes_ = {
  4047. SUBTITLES: {},
  4048. AUDIO: {}
  4049. };
  4050. this.player.tech_.vhs.masterPlaylistController_.sourceUpdater_.trigger('createdsourcebuffers');
  4051. });
  4052. QUnit.test(
  4053. 'does not set source keySystems if keySystems not provided by source',
  4054. function(assert) {
  4055. this.player.src({
  4056. src: 'manifest/master.mpd',
  4057. type: 'application/dash+xml'
  4058. });
  4059. this.clock.tick(1);
  4060. this.player.tech_.vhs.playlists = {
  4061. media: () => {
  4062. return {
  4063. attributes: {
  4064. CODECS: 'video-codec'
  4065. },
  4066. contentProtection: {
  4067. keySystem1: {
  4068. pssh: 'test'
  4069. }
  4070. }
  4071. };
  4072. },
  4073. // mocked for renditions mixin
  4074. master: {
  4075. playlists: []
  4076. }
  4077. };
  4078. this.player.tech_.vhs.masterPlaylistController_.mediaTypes_ = {
  4079. SUBTITLES: {},
  4080. AUDIO: {
  4081. activePlaylistLoader: {
  4082. media: () => {
  4083. return {
  4084. attributes: {
  4085. CODECS: 'audio-codec'
  4086. }
  4087. };
  4088. }
  4089. }
  4090. }
  4091. };
  4092. this.player.tech_.vhs.masterPlaylistController_.sourceUpdater_.trigger('ready');
  4093. assert.deepEqual(this.player.currentSource(), {
  4094. src: 'manifest/master.mpd',
  4095. type: 'application/dash+xml'
  4096. }, 'does not set source eme options');
  4097. }
  4098. );
  4099. QUnit[testOrSkip](
  4100. 'stores bandwidth and throughput in localStorage when global option is true',
  4101. function(assert) {
  4102. videojs.options.vhs = {
  4103. useBandwidthFromLocalStorage: true
  4104. };
  4105. this.player.src({
  4106. src: 'manifest/master.m3u8',
  4107. type: 'application/vnd.apple.mpegurl'
  4108. });
  4109. openMediaSource(this.player, this.clock);
  4110. // master
  4111. this.standardXHRResponse(this.requests.shift());
  4112. // media
  4113. this.standardXHRResponse(this.requests.shift());
  4114. assert.notOk(window.localStorage.getItem(LOCAL_STORAGE_KEY), 'nothing in local storage');
  4115. this.player.tech_.vhs.masterPlaylistController_.mainSegmentLoader_.bandwidth = 11;
  4116. this.player.tech_.vhs.masterPlaylistController_.mainSegmentLoader_.throughput.rate = 22;
  4117. this.player.tech_.trigger('bandwidthupdate');
  4118. const storedObject = JSON.parse(window.localStorage.getItem(LOCAL_STORAGE_KEY));
  4119. assert.equal(parseInt(storedObject.bandwidth, 10), 11, 'set bandwidth');
  4120. assert.equal(parseInt(storedObject.throughput, 10), 22, 'set throughput');
  4121. }
  4122. );
  4123. QUnit[testOrSkip](
  4124. 'stores bandwidth and throughput in localStorage when player option is true',
  4125. function(assert) {
  4126. this.player.dispose();
  4127. this.player = createPlayer({
  4128. html5: {
  4129. vhs: {
  4130. useBandwidthFromLocalStorage: true
  4131. }
  4132. }
  4133. });
  4134. this.player.src({
  4135. src: 'manifest/master.m3u8',
  4136. type: 'application/vnd.apple.mpegurl'
  4137. });
  4138. openMediaSource(this.player, this.clock);
  4139. // master
  4140. this.standardXHRResponse(this.requests.shift());
  4141. // media
  4142. this.standardXHRResponse(this.requests.shift());
  4143. assert.notOk(window.localStorage.getItem(LOCAL_STORAGE_KEY), 'nothing in local storage');
  4144. this.player.tech_.vhs.masterPlaylistController_.mainSegmentLoader_.bandwidth = 11;
  4145. this.player.tech_.vhs.masterPlaylistController_.mainSegmentLoader_.throughput.rate = 22;
  4146. this.player.tech_.trigger('bandwidthupdate');
  4147. const storedObject = JSON.parse(window.localStorage.getItem(LOCAL_STORAGE_KEY));
  4148. assert.equal(parseInt(storedObject.bandwidth, 10), 11, 'set bandwidth');
  4149. assert.equal(parseInt(storedObject.throughput, 10), 22, 'set throughput');
  4150. }
  4151. );
  4152. QUnit[testOrSkip](
  4153. 'stores bandwidth and throughput in localStorage when source option is true',
  4154. function(assert) {
  4155. this.player.dispose();
  4156. this.player = createPlayer();
  4157. this.player.src({
  4158. src: 'manifest/master.m3u8',
  4159. type: 'application/vnd.apple.mpegurl',
  4160. useBandwidthFromLocalStorage: true
  4161. });
  4162. openMediaSource(this.player, this.clock);
  4163. // master
  4164. this.standardXHRResponse(this.requests.shift());
  4165. // media
  4166. this.standardXHRResponse(this.requests.shift());
  4167. assert.notOk(window.localStorage.getItem(LOCAL_STORAGE_KEY), 'nothing in local storage');
  4168. this.player.tech_.vhs.masterPlaylistController_.mainSegmentLoader_.bandwidth = 11;
  4169. this.player.tech_.vhs.masterPlaylistController_.mainSegmentLoader_.throughput.rate = 22;
  4170. this.player.tech_.trigger('bandwidthupdate');
  4171. const storedObject = JSON.parse(window.localStorage.getItem(LOCAL_STORAGE_KEY));
  4172. assert.equal(parseInt(storedObject.bandwidth, 10), 11, 'set bandwidth');
  4173. assert.equal(parseInt(storedObject.throughput, 10), 22, 'set throughput');
  4174. }
  4175. );
  4176. QUnit[testOrSkip](
  4177. 'source localStorage option takes priority over player option',
  4178. function(assert) {
  4179. this.player.dispose();
  4180. this.player = createPlayer({
  4181. html5: {
  4182. vhs: {
  4183. useBandwidthFromLocalStorage: false
  4184. }
  4185. }
  4186. });
  4187. this.player.src({
  4188. src: 'manifest/master.m3u8',
  4189. type: 'application/vnd.apple.mpegurl',
  4190. useBandwidthFromLocalStorage: true
  4191. });
  4192. openMediaSource(this.player, this.clock);
  4193. // master
  4194. this.standardXHRResponse(this.requests.shift());
  4195. // media
  4196. this.standardXHRResponse(this.requests.shift());
  4197. assert.notOk(window.localStorage.getItem(LOCAL_STORAGE_KEY), 'nothing in local storage');
  4198. this.player.tech_.vhs.masterPlaylistController_.mainSegmentLoader_.bandwidth = 11;
  4199. this.player.tech_.vhs.masterPlaylistController_.mainSegmentLoader_.throughput.rate = 22;
  4200. this.player.tech_.trigger('bandwidthupdate');
  4201. const storedObject = JSON.parse(window.localStorage.getItem(LOCAL_STORAGE_KEY));
  4202. assert.equal(parseInt(storedObject.bandwidth, 10), 11, 'set bandwidth');
  4203. assert.equal(parseInt(storedObject.throughput, 10), 22, 'set throughput');
  4204. }
  4205. );
  4206. QUnit[testOrSkip](
  4207. 'does not store bandwidth and throughput in localStorage by default',
  4208. function(assert) {
  4209. this.player.dispose();
  4210. this.player = createPlayer();
  4211. this.player.src({
  4212. src: 'manifest/master.m3u8',
  4213. type: 'application/vnd.apple.mpegurl'
  4214. });
  4215. openMediaSource(this.player, this.clock);
  4216. // master
  4217. this.standardXHRResponse(this.requests.shift());
  4218. // media
  4219. this.standardXHRResponse(this.requests.shift());
  4220. assert.notOk(window.localStorage.getItem(LOCAL_STORAGE_KEY), 'nothing in local storage');
  4221. this.player.tech_.vhs.masterPlaylistController_.mainSegmentLoader_.bandwidth = 11;
  4222. this.player.tech_.vhs.masterPlaylistController_.mainSegmentLoader_.throughput.rate = 22;
  4223. this.player.tech_.trigger('bandwidthupdate');
  4224. assert.notOk(window.localStorage.getItem(LOCAL_STORAGE_KEY), 'nothing in local storage');
  4225. }
  4226. );
  4227. QUnit[testOrSkip]('retrieves bandwidth and throughput from localStorage', function(assert) {
  4228. window.localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify({
  4229. bandwidth: 33,
  4230. throughput: 44
  4231. }));
  4232. let vhsBandwidthUsageEvents = 0;
  4233. let vhsThroughputUsageEvents = 0;
  4234. let hlsBandwidthUsageEvents = 0;
  4235. let hlsThroughputUsageEvents = 0;
  4236. const usageListener = (event) => {
  4237. if (event.name === 'vhs-bandwidth-from-local-storage') {
  4238. vhsBandwidthUsageEvents++;
  4239. }
  4240. if (event.name === 'vhs-throughput-from-local-storage') {
  4241. vhsThroughputUsageEvents++;
  4242. }
  4243. if (event.name === 'hls-bandwidth-from-local-storage') {
  4244. hlsBandwidthUsageEvents++;
  4245. }
  4246. if (event.name === 'hls-throughput-from-local-storage') {
  4247. hlsThroughputUsageEvents++;
  4248. }
  4249. };
  4250. // values must be stored before player is created, otherwise defaults are provided
  4251. this.player.dispose();
  4252. this.player = createPlayer();
  4253. this.player.tech_.on('usage', usageListener);
  4254. this.player.src({
  4255. src: 'manifest/master.m3u8',
  4256. type: 'application/vnd.apple.mpegurl'
  4257. });
  4258. openMediaSource(this.player, this.clock);
  4259. assert.equal(
  4260. this.player.tech_.vhs.bandwidth,
  4261. 4194304,
  4262. 'uses default bandwidth when no option to use stored bandwidth'
  4263. );
  4264. assert.notOk(
  4265. this.player.tech_.vhs.throughput,
  4266. 'no throughput when no option to use stored throughput'
  4267. );
  4268. assert.equal(vhsBandwidthUsageEvents, 0, 'no bandwidth usage event');
  4269. assert.equal(vhsThroughputUsageEvents, 0, 'no throughput usage event');
  4270. assert.equal(hlsBandwidthUsageEvents, 0, 'no bandwidth usage event');
  4271. assert.equal(hlsThroughputUsageEvents, 0, 'no throughput usage event');
  4272. const origVhsOptions = videojs.options.vhs;
  4273. videojs.options.vhs = {
  4274. useBandwidthFromLocalStorage: true
  4275. };
  4276. this.player.dispose();
  4277. this.player = createPlayer();
  4278. this.player.tech_.on('usage', usageListener);
  4279. this.player.src({
  4280. src: 'manifest/master.m3u8',
  4281. type: 'application/vnd.apple.mpegurl'
  4282. });
  4283. openMediaSource(this.player, this.clock);
  4284. assert.equal(this.player.tech_.vhs.bandwidth, 33, 'retrieved stored bandwidth');
  4285. assert.equal(this.player.tech_.vhs.throughput, 44, 'retrieved stored throughput');
  4286. assert.equal(vhsBandwidthUsageEvents, 1, 'one bandwidth usage event');
  4287. assert.equal(vhsThroughputUsageEvents, 1, 'one throughput usage event');
  4288. assert.equal(hlsBandwidthUsageEvents, 1, 'one bandwidth usage event');
  4289. assert.equal(hlsThroughputUsageEvents, 1, 'one throughput usage event');
  4290. videojs.options.vhs = origVhsOptions;
  4291. });
  4292. QUnit[testOrSkip](
  4293. 'does not retrieve bandwidth and throughput from localStorage when stored value is not as expected',
  4294. function(assert) {
  4295. // bad value
  4296. window.localStorage.setItem(LOCAL_STORAGE_KEY, 'a');
  4297. let vhsBandwidthUsageEvents = 0;
  4298. let vhsThroughputUsageEvents = 0;
  4299. let hlsBandwidthUsageEvents = 0;
  4300. let hlsThroughputUsageEvents = 0;
  4301. const usageListener = (event) => {
  4302. if (event.name === 'vhs-bandwidth-from-local-storage') {
  4303. vhsBandwidthUsageEvents++;
  4304. }
  4305. if (event.name === 'vhs-throughput-from-local-storage') {
  4306. vhsThroughputUsageEvents++;
  4307. }
  4308. if (event.name === 'hls-bandwidth-from-local-storage') {
  4309. hlsBandwidthUsageEvents++;
  4310. }
  4311. if (event.name === 'hls-throughput-from-local-storage') {
  4312. hlsThroughputUsageEvents++;
  4313. }
  4314. };
  4315. const origVhsOptions = videojs.options.vhs;
  4316. videojs.options.vhs = {
  4317. useBandwidthFromLocalStorage: true
  4318. };
  4319. // values must be stored before player is created, otherwise defaults are provided
  4320. this.player.dispose();
  4321. this.player = createPlayer();
  4322. this.player.tech_.on('usage', usageListener);
  4323. this.player.src({
  4324. src: 'manifest/master.m3u8',
  4325. type: 'application/vnd.apple.mpegurl'
  4326. });
  4327. openMediaSource(this.player, this.clock);
  4328. assert.equal(
  4329. this.player.tech_.vhs.bandwidth,
  4330. 4194304,
  4331. 'uses default bandwidth when bandwidth value retrieved'
  4332. );
  4333. assert.notOk(this.player.tech_.vhs.throughput, 'no throughput value retrieved');
  4334. assert.equal(vhsBandwidthUsageEvents, 0, 'no bandwidth usage event');
  4335. assert.equal(vhsThroughputUsageEvents, 0, 'no throughput usage event');
  4336. assert.equal(hlsBandwidthUsageEvents, 0, 'no bandwidth usage event');
  4337. assert.equal(hlsThroughputUsageEvents, 0, 'no throughput usage event');
  4338. videojs.options.vhs = origVhsOptions;
  4339. }
  4340. );
  4341. QUnit.test(
  4342. 'convertToProgramTime will return error if time is not buffered',
  4343. function(assert) {
  4344. const done = assert.async();
  4345. this.player.src({
  4346. src: 'manifest/playlist.m3u8',
  4347. type: 'application/vnd.apple.mpegurl'
  4348. });
  4349. this.clock.tick(1);
  4350. openMediaSource(this.player, this.clock);
  4351. // media
  4352. this.standardXHRResponse(this.requests.shift());
  4353. this.player.tech(true).vhs.convertToProgramTime(3, (err, programTime) => {
  4354. assert.deepEqual(
  4355. err,
  4356. {
  4357. message:
  4358. 'Accurate programTime could not be determined.' +
  4359. ' Please seek to e.seekTime and try again',
  4360. seekTime: 0
  4361. },
  4362. 'error is returned as time is not buffered'
  4363. );
  4364. done();
  4365. });
  4366. }
  4367. );
  4368. QUnit.test('convertToProgramTime will return stream time if buffered', function(assert) {
  4369. const done = assert.async();
  4370. this.player.src({
  4371. src: 'manifest/master.m3u8',
  4372. type: 'application/vnd.apple.mpegurl'
  4373. });
  4374. this.clock.tick(1);
  4375. openMediaSource(this.player, this.clock);
  4376. this.player.tech_.vhs.bandwidth = 20e10;
  4377. // master
  4378. this.standardXHRResponse(this.requests[0]);
  4379. // media.m3u8
  4380. this.standardXHRResponse(this.requests[1]);
  4381. const mpc = this.player.tech(true).vhs.masterPlaylistController_;
  4382. const mainSegmentLoader_ = mpc.mainSegmentLoader_;
  4383. mainSegmentLoader_.one('appending', () => {
  4384. // since we don't run through the transmuxer, we have to manually trigger the timing
  4385. // info callback
  4386. mainSegmentLoader_.handleSegmentTimingInfo_('video', mainSegmentLoader_.pendingSegment_.requestId, {
  4387. prependedGopDuration: 0,
  4388. start: {
  4389. presentation: 0
  4390. },
  4391. end: {
  4392. presentation: 1
  4393. }
  4394. });
  4395. });
  4396. return requestAndAppendSegment({
  4397. request: this.requests[2],
  4398. mediaSource: mpc.mediaSource,
  4399. segmentLoader: mpc.mainSegmentLoader_,
  4400. clock: this.clock
  4401. }).then(() => {
  4402. // ts
  4403. this.standardXHRResponse(this.requests[3], muxedSegment());
  4404. this.player.tech(true).vhs.convertToProgramTime(0.01, (err, programTime) => {
  4405. assert.notOk(err, 'no errors');
  4406. assert.equal(
  4407. programTime.mediaSeconds,
  4408. 0.01,
  4409. 'returned the stream time of the source'
  4410. );
  4411. done();
  4412. });
  4413. });
  4414. });
  4415. QUnit.test(
  4416. 'seekToProgramTime will error if live stream has not started',
  4417. function(assert) {
  4418. this.player.src({
  4419. src: 'manifest/program-date-time.m3u8',
  4420. type: 'application/x-mpegurl'
  4421. });
  4422. this.clock.tick(1);
  4423. openMediaSource(this.player, this.clock);
  4424. // media
  4425. this.standardXHRResponse(this.requests.shift());
  4426. this.player.tech(true).vhs.seekToProgramTime(
  4427. '2018-10-12T22:33:49.037+00:00',
  4428. (err, newTime) => {
  4429. assert.equal(
  4430. err.message,
  4431. 'player must be playing a live stream to start buffering',
  4432. 'error is returned when live stream has not started'
  4433. );
  4434. }
  4435. );
  4436. // allows ie to start loading segments, from setupFirstPlay
  4437. this.player.tech_.readyState = () => 4;
  4438. this.player.play();
  4439. // trigger playing with non-existent content
  4440. this.player.tech_.trigger('playing');
  4441. // wait for playlist refresh
  4442. this.clock.tick(4 * 1000 + 1);
  4443. // ts
  4444. this.standardXHRResponse(this.requests.shift(), muxedSegment());
  4445. this.player.tech(true).vhs.seekToProgramTime(
  4446. '2018-10-12T22:33:49.037+00:00',
  4447. (err, newTime) => {
  4448. assert.equal(
  4449. err.message,
  4450. '2018-10-12T22:33:49.037+00:00 is not buffered yet. Try again',
  4451. 'error returned if time has not been buffered'
  4452. );
  4453. }
  4454. );
  4455. }
  4456. );
  4457. QUnit.test('seekToProgramTime seek to time if buffered', function(assert) {
  4458. const done = assert.async();
  4459. this.player.src({
  4460. src: 'manifest/program-date-time.m3u8',
  4461. type: 'application/x-mpegurl'
  4462. });
  4463. this.clock.tick(1);
  4464. openMediaSource(this.player, this.clock);
  4465. // media
  4466. this.standardXHRResponse(this.requests.shift());
  4467. // allows ie to start loading segments, from setupFirstPlay
  4468. this.player.tech_.readyState = () => 4;
  4469. this.player.play();
  4470. // trigger playing with non-existent content
  4471. this.player.tech_.trigger('playing');
  4472. // wait for playlist refresh
  4473. this.clock.tick(2 * 1000 + 1);
  4474. const mpc = this.player.tech(true).vhs.masterPlaylistController_;
  4475. mpc.mainSegmentLoader_.one('appending', () => {
  4476. const videoBuffer = mpc.sourceUpdater_.videoBuffer;
  4477. // must fake the call to videoTimingInfo as the segment isn't transmuxed in the test
  4478. videoBuffer.trigger({
  4479. type: 'videoSegmentTimingInfo',
  4480. videoSegmentTimingInfo: {
  4481. start: {
  4482. presentation: 0
  4483. },
  4484. end: {
  4485. presentation: 0.3333
  4486. },
  4487. baseMediaDecodeTime: 0,
  4488. prependedContentDuration: 0
  4489. }
  4490. });
  4491. });
  4492. return requestAndAppendSegment({
  4493. request: this.requests.shift(),
  4494. mediaSource: mpc.mediaSource,
  4495. segmentLoader: mpc.mainSegmentLoader_,
  4496. clock: this.clock
  4497. }).then(() => {
  4498. this.player.tech(true).vhs.seekToProgramTime(
  4499. '2018-10-12T22:33:49.037+00:00',
  4500. (err, newTime) => {
  4501. assert.notOk(
  4502. err,
  4503. 'no error returned'
  4504. );
  4505. assert.equal(
  4506. newTime,
  4507. 0,
  4508. 'newTime is returned as the time the player seeked to'
  4509. );
  4510. done();
  4511. }
  4512. );
  4513. // This allows seek to take affect
  4514. this.clock.tick(2);
  4515. });
  4516. });
  4517. QUnit.test('manifest object used as source if provided as data URI', function(assert) {
  4518. this.player.src({
  4519. src: 'placeholder-source',
  4520. type: 'application/x-mpegurl'
  4521. });
  4522. this.clock.tick(1);
  4523. openMediaSource(this.player, this.clock);
  4524. // asynchronous setup of initial playlist in playlist loader for JSON sources
  4525. this.clock.tick(1);
  4526. // no manifestObject was provided, so a request is made for the source manifest
  4527. assert.equal(this.requests.length, 1, 'one request');
  4528. assert.equal(this.requests[0].url, 'placeholder-source', 'requested src url');
  4529. this.requests.length = 0;
  4530. const manifestString = testDataManifests.playlist;
  4531. const manifestObject = parseManifest({ manifestString });
  4532. this.player.src({
  4533. src: `data:application/vnd.videojs.vhs+json,${JSON.stringify(manifestObject)}`,
  4534. type: 'application/vnd.videojs.vhs+json'
  4535. });
  4536. openMediaSource(this.player, this.clock);
  4537. // asynchronous setup of initial playlist in playlist loader for JSON sources
  4538. this.clock.tick(1);
  4539. // manifestObject was provided, so a request is made for the segment
  4540. assert.equal(this.requests.length, 1, 'one request');
  4541. assert.equal(
  4542. this.requests[0].uri,
  4543. `${window.location.origin}/test/hls_450k_video.ts`,
  4544. 'requested first segment'
  4545. );
  4546. });
  4547. QUnit.module('HLS Integration', {
  4548. beforeEach(assert) {
  4549. this.env = useFakeEnvironment(assert);
  4550. this.requests = this.env.requests;
  4551. this.mse = useFakeMediaSource();
  4552. this.player = createPlayer();
  4553. this.tech = this.player.tech_;
  4554. this.clock = this.env.clock;
  4555. this.standardXHRResponse = (request, data) => {
  4556. standardXHRResponse(request, data);
  4557. // Because SegmentLoader#fillBuffer_ is now scheduled asynchronously
  4558. // we have to use clock.tick to get the expected side effects of
  4559. // SegmentLoader#handleAppendsDone_
  4560. this.clock.tick(1);
  4561. };
  4562. videojs.VhsHandler.prototype.setupQualityLevels_ = () => {};
  4563. },
  4564. afterEach() {
  4565. this.env.restore();
  4566. this.mse.restore();
  4567. window.localStorage.clear();
  4568. this.player.dispose();
  4569. videojs.VhsHandler.prototype.setupQualityLevels_ = ogVhsHandlerSetupQualityLevels;
  4570. }
  4571. });
  4572. QUnit.test('aborts all in-flight work when disposed', function(assert) {
  4573. const vhs = VhsSourceHandler.handleSource({
  4574. src: 'manifest/master.m3u8',
  4575. type: 'application/vnd.apple.mpegurl'
  4576. }, this.tech);
  4577. vhs.mediaSource.trigger('sourceopen');
  4578. // master
  4579. this.standardXHRResponse(this.requests.shift());
  4580. // media
  4581. this.standardXHRResponse(this.requests.shift());
  4582. vhs.dispose();
  4583. assert.ok(this.requests[0].aborted, 'aborted the old segment request');
  4584. vhs.mediaSource.sourceBuffers.forEach(sourceBuffer => {
  4585. const lastUpdate = sourceBuffer.updates_[sourceBuffer.updates_.length - 1];
  4586. assert.ok(lastUpdate.abort, 'aborted the source buffer');
  4587. });
  4588. });
  4589. QUnit.test('stats are reset on dispose', function(assert) {
  4590. const done = assert.async();
  4591. const vhs = VhsSourceHandler.handleSource({
  4592. src: 'manifest/master.m3u8',
  4593. type: 'application/vnd.apple.mpegurl'
  4594. }, this.tech);
  4595. vhs.mediaSource.trigger('sourceopen');
  4596. // master
  4597. this.standardXHRResponse(this.requests.shift());
  4598. // media
  4599. this.standardXHRResponse(this.requests.shift());
  4600. const segment = muxedSegment();
  4601. // copy the byte length since the segment bytes get cleared out
  4602. const segmentByteLength = segment.byteLength;
  4603. assert.ok(segmentByteLength, 'the segment has some number of bytes');
  4604. vhs.masterPlaylistController_.mainSegmentLoader_.on('appending', () => {
  4605. assert.equal(vhs.stats.mediaBytesTransferred, segmentByteLength, 'stat is set');
  4606. vhs.dispose();
  4607. assert.equal(vhs.stats.mediaBytesTransferred, 0, 'stat is reset');
  4608. done();
  4609. });
  4610. // segment 0
  4611. this.standardXHRResponse(this.requests.shift(), segment);
  4612. });
  4613. // mocking the fullscreenElement no longer works, find another way to mock
  4614. // fullscreen behavior(without user gesture)
  4615. QUnit.skip('detects fullscreen and triggers a fast quality change', function(assert) {
  4616. const vhs = VhsSourceHandler.handleSource({
  4617. src: 'manifest/master.m3u8',
  4618. type: 'application/vnd.apple.mpegurl'
  4619. }, this.tech);
  4620. let qualityChanges = 0;
  4621. let fullscreenElementName;
  4622. ['fullscreenElement', 'webkitFullscreenElement',
  4623. 'mozFullScreenElement', 'msFullscreenElement'].forEach((name) => {
  4624. if (!fullscreenElementName && !document.hasOwnProperty(name)) {
  4625. fullscreenElementName = name;
  4626. }
  4627. });
  4628. vhs.masterPlaylistController_.fastQualityChange_ = function() {
  4629. qualityChanges++;
  4630. };
  4631. // take advantage of capability detection to mock fullscreen activation
  4632. document[fullscreenElementName] = this.tech.el();
  4633. Events.trigger(document, 'fullscreenchange');
  4634. assert.equal(qualityChanges, 1, 'made a fast quality change');
  4635. let checkABRCalls = 0;
  4636. vhs.masterPlaylistController_.checkABR_ = () => checkABRCalls++;
  4637. // don't do a fast quality change when returning from fullscreen;
  4638. //
  4639. // do check the current rendition to see if it should be changed for the next
  4640. // segment loaded
  4641. document[fullscreenElementName] = null;
  4642. Events.trigger(document, 'fullscreenchange');
  4643. assert.equal(qualityChanges, 1, 'did not make another quality change');
  4644. assert.equal(checkABRCalls, 1, 'called to check the ABR');
  4645. vhs.dispose();
  4646. });
  4647. QUnit.test('downloads additional playlists if required', function(assert) {
  4648. const vhs = VhsSourceHandler.handleSource({
  4649. src: 'manifest/master.m3u8',
  4650. type: 'application/vnd.apple.mpegurl'
  4651. }, this.tech);
  4652. // Make segment metadata noop since most test segments dont have real data
  4653. vhs.masterPlaylistController_.mainSegmentLoader_.addSegmentMetadataCue_ = () => {};
  4654. vhs.mediaSource.trigger('sourceopen');
  4655. vhs.bandwidth = 1;
  4656. // master
  4657. this.standardXHRResponse(this.requests[0]);
  4658. // media
  4659. this.standardXHRResponse(this.requests[1]);
  4660. const originalPlaylist = vhs.playlists.media();
  4661. const mpc = vhs.masterPlaylistController_;
  4662. mpc.mainSegmentLoader_.mediaIndex = 0;
  4663. return requestAndAppendSegment({
  4664. request: this.requests[2],
  4665. mediaSource: mpc.mediaSource,
  4666. segmentLoader: mpc.mainSegmentLoader_,
  4667. clock: this.clock,
  4668. // the playlist selection is revisited after a new segment is downloaded
  4669. bandwidth: 3000000,
  4670. tickClock: false
  4671. }).then(() => {
  4672. // update the buffer to reflect the appended segment, and have enough buffer to
  4673. // change playlist
  4674. this.tech.buffered = () => videojs.createTimeRanges([[0, 30]]);
  4675. this.clock.tick(1);
  4676. // new media
  4677. this.standardXHRResponse(this.requests[3]);
  4678. assert.ok(
  4679. (/manifest\/media\d+.m3u8$/).test(this.requests[3].url),
  4680. 'made a playlist request'
  4681. );
  4682. assert.notEqual(
  4683. originalPlaylist.resolvedUri,
  4684. vhs.playlists.media().resolvedUri,
  4685. 'a new playlists was selected'
  4686. );
  4687. assert.ok(vhs.playlists.media().segments, 'segments are now available');
  4688. vhs.dispose();
  4689. });
  4690. });
  4691. QUnit.test('waits to download new segments until the media playlist is stable', function(assert) {
  4692. const vhs = VhsSourceHandler.handleSource({
  4693. src: 'manifest/master.m3u8',
  4694. type: 'application/vnd.apple.mpegurl'
  4695. }, this.tech);
  4696. const mpc = vhs.masterPlaylistController_;
  4697. mpc.mainSegmentLoader_.addSegmentMetadataCue_ = () => {};
  4698. vhs.mediaSource.trigger('sourceopen');
  4699. // make sure we stay on the lowest variant
  4700. vhs.bandwidth = 1;
  4701. // master
  4702. this.standardXHRResponse(this.requests.shift());
  4703. // media1
  4704. this.standardXHRResponse(this.requests.shift());
  4705. // put segment loader in walking forward mode
  4706. mpc.mainSegmentLoader_.mediaIndex = 0;
  4707. return requestAndAppendSegment({
  4708. request: this.requests.shift(),
  4709. mediaSource: mpc.mediaSource,
  4710. segmentLoader: mpc.mainSegmentLoader_,
  4711. clock: this.clock,
  4712. // bandwidth is high enough to switch playlists
  4713. bandwidth: Number.MAX_VALUE,
  4714. tickClock: false
  4715. }).then(() => {
  4716. // update the buffer to reflect the appended segment, and have enough buffer to
  4717. // change playlist
  4718. this.tech.buffered = () => videojs.createTimeRanges([[0, 30]]);
  4719. this.clock.tick(1);
  4720. assert.equal(this.requests.length, 1, 'only the playlist request outstanding');
  4721. this.clock.tick(10 * 1000);
  4722. assert.equal(this.requests.length, 1, 'delays segment fetching');
  4723. // another media playlist
  4724. this.standardXHRResponse(this.requests.shift());
  4725. this.clock.tick(10 * 1000);
  4726. assert.equal(this.requests.length, 1, 'resumes segment fetching');
  4727. // verify stats
  4728. assert.equal(vhs.stats.bandwidth, Infinity, 'bandwidth is set to infinity');
  4729. vhs.dispose();
  4730. });
  4731. });
  4732. QUnit.test('live playlist starts three target durations before live', function(assert) {
  4733. const vhs = VhsSourceHandler.handleSource({
  4734. src: 'manifest/master.m3u8',
  4735. type: 'application/vnd.apple.mpegurl'
  4736. }, this.tech);
  4737. vhs.mediaSource.trigger('sourceopen');
  4738. this.requests.shift().respond(
  4739. 200, null,
  4740. '#EXTM3U\n' +
  4741. '#EXT-X-MEDIA-SEQUENCE:101\n' +
  4742. '#EXT-X-TARGETDURATION:10\n' +
  4743. '#EXTINF:10,\n' +
  4744. '0.ts\n' +
  4745. '#EXTINF:10,\n' +
  4746. '1.ts\n' +
  4747. '#EXTINF:10,\n' +
  4748. '2.ts\n' +
  4749. '#EXTINF:10,\n' +
  4750. '3.ts\n' +
  4751. '#EXTINF:10,\n' +
  4752. '4.ts\n'
  4753. );
  4754. assert.equal(this.requests.length, 0, 'no outstanding segment request');
  4755. this.tech.paused = function() {
  4756. return false;
  4757. };
  4758. let techCurrentTime = 0;
  4759. this.tech.setCurrentTime = function(ct) {
  4760. techCurrentTime = ct;
  4761. };
  4762. this.tech.readyState = () => 4;
  4763. this.tech.trigger('play');
  4764. this.clock.tick(1);
  4765. assert.equal(
  4766. vhs.seekable().end(0),
  4767. 20,
  4768. 'seekable end is three target durations from playlist end'
  4769. );
  4770. assert.equal(
  4771. techCurrentTime,
  4772. vhs.seekable().end(0),
  4773. 'seeked to the seekable end'
  4774. );
  4775. assert.equal(this.requests.length, 1, 'begins buffering');
  4776. vhs.dispose();
  4777. });
  4778. QUnit.test(
  4779. 'uses user defined selectPlaylist from VhsHandler if specified',
  4780. function(assert) {
  4781. const origStandardPlaylistSelector = Vhs.STANDARD_PLAYLIST_SELECTOR;
  4782. let defaultSelectPlaylistCount = 0;
  4783. Vhs.STANDARD_PLAYLIST_SELECTOR = () => defaultSelectPlaylistCount++;
  4784. let vhs = VhsSourceHandler.handleSource({
  4785. src: 'manifest/master.m3u8',
  4786. type: 'application/vnd.apple.mpegurl'
  4787. }, this.tech);
  4788. vhs.masterPlaylistController_.selectPlaylist();
  4789. assert.equal(defaultSelectPlaylistCount, 1, 'uses default playlist selector');
  4790. defaultSelectPlaylistCount = 0;
  4791. let newSelectPlaylistCount = 0;
  4792. const newSelectPlaylist = () => newSelectPlaylistCount++;
  4793. VhsHandler.prototype.selectPlaylist = newSelectPlaylist;
  4794. vhs.dispose();
  4795. vhs = VhsSourceHandler.handleSource({
  4796. src: 'manifest/master.m3u8',
  4797. type: 'application/vnd.apple.mpegurl'
  4798. }, this.tech);
  4799. vhs.masterPlaylistController_.selectPlaylist();
  4800. assert.equal(defaultSelectPlaylistCount, 0, 'standard playlist selector not run');
  4801. assert.equal(newSelectPlaylistCount, 1, 'uses overridden playlist selector');
  4802. newSelectPlaylistCount = 0;
  4803. let setSelectPlaylistCount = 0;
  4804. vhs.selectPlaylist = () => setSelectPlaylistCount++;
  4805. vhs.masterPlaylistController_.selectPlaylist();
  4806. assert.equal(defaultSelectPlaylistCount, 0, 'standard playlist selector not run');
  4807. assert.equal(newSelectPlaylistCount, 0, 'overridden playlist selector not run');
  4808. assert.equal(setSelectPlaylistCount, 1, 'uses set playlist selector');
  4809. Vhs.STANDARD_PLAYLIST_SELECTOR = origStandardPlaylistSelector;
  4810. delete VhsHandler.prototype.selectPlaylist;
  4811. vhs.dispose();
  4812. }
  4813. );
  4814. QUnit.module('HLS - Encryption', {
  4815. beforeEach(assert) {
  4816. this.env = useFakeEnvironment(assert);
  4817. this.requests = this.env.requests;
  4818. this.mse = useFakeMediaSource();
  4819. this.tech = new (videojs.getTech('Html5'))({});
  4820. this.clock = this.env.clock;
  4821. this.standardXHRResponse = (request, data) => {
  4822. standardXHRResponse(request, data);
  4823. // Because SegmentLoader#fillBuffer_ is now scheduled asynchronously
  4824. // we have to use clock.tick to get the expected side effects of
  4825. // SegmentLoader#handleAppendsDone_
  4826. this.clock.tick(1);
  4827. };
  4828. videojs.VhsHandler.prototype.setupQualityLevels_ = () => {};
  4829. },
  4830. afterEach() {
  4831. this.env.restore();
  4832. this.mse.restore();
  4833. window.localStorage.clear();
  4834. videojs.VhsHandler.prototype.setupQualityLevels_ = ogVhsHandlerSetupQualityLevels;
  4835. }
  4836. });
  4837. QUnit.test('blacklists playlist if key requests fail', function(assert) {
  4838. const vhs = VhsSourceHandler.handleSource({
  4839. src: 'manifest/encrypted-master.m3u8',
  4840. type: 'application/vnd.apple.mpegurl'
  4841. }, this.tech);
  4842. vhs.mediaSource.trigger('sourceopen');
  4843. this.requests.shift()
  4844. .respond(
  4845. 200, null,
  4846. '#EXTM3U\n' +
  4847. '#EXT-X-STREAM-INF:BANDWIDTH=1000\n' +
  4848. 'media.m3u8\n' +
  4849. '#EXT-X-STREAM-INF:BANDWIDTH=1\n' +
  4850. 'media1.m3u8\n'
  4851. );
  4852. this.requests.shift()
  4853. .respond(
  4854. 200, null,
  4855. '#EXTM3U\n' +
  4856. '#EXT-X-KEY:METHOD=AES-128,URI="htts://priv.example.com/key.php?r=52"\n' +
  4857. '#EXTINF:2.833,\n' +
  4858. 'http://media.example.com/fileSequence52-A.ts\n' +
  4859. '#EXT-X-KEY:METHOD=AES-128,URI="htts://priv.example.com/key.php?r=53"\n' +
  4860. '#EXTINF:15.0,\n' +
  4861. 'http://media.example.com/fileSequence53-A.ts\n' +
  4862. '#EXT-X-ENDLIST\n'
  4863. );
  4864. this.clock.tick(1);
  4865. // segment 1
  4866. if (/key\.php/i.test(this.requests[0].url)) {
  4867. this.standardXHRResponse(this.requests.pop());
  4868. } else {
  4869. this.standardXHRResponse(this.requests.shift());
  4870. }
  4871. // fail key
  4872. this.requests.shift().respond(404);
  4873. assert.ok(
  4874. vhs.playlists.media().excludeUntil > 0,
  4875. 'playlist blacklisted'
  4876. );
  4877. assert.equal(this.env.log.warn.calls, 1, 'logged warning for blacklist');
  4878. vhs.dispose();
  4879. });
  4880. QUnit.test(
  4881. 'treats invalid keys as a key request failure and blacklists playlist',
  4882. function(assert) {
  4883. const vhs = VhsSourceHandler.handleSource({
  4884. src: 'manifest/encrypted-master.m3u8',
  4885. type: 'application/vnd.apple.mpegurl'
  4886. }, this.tech);
  4887. vhs.mediaSource.trigger('sourceopen');
  4888. this.requests.shift()
  4889. .respond(
  4890. 200, null,
  4891. '#EXTM3U\n' +
  4892. '#EXT-X-STREAM-INF:BANDWIDTH=1000\n' +
  4893. 'media.m3u8\n' +
  4894. '#EXT-X-STREAM-INF:BANDWIDTH=1\n' +
  4895. 'media1.m3u8\n'
  4896. );
  4897. this.requests.shift()
  4898. .respond(
  4899. 200, null,
  4900. '#EXTM3U\n' +
  4901. '#EXT-X-MEDIA-SEQUENCE:5\n' +
  4902. '#EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=52"\n' +
  4903. '#EXTINF:2.833,\n' +
  4904. 'http://media.example.com/fileSequence52-A.ts\n' +
  4905. '#EXT-X-KEY:METHOD=NONE\n' +
  4906. '#EXTINF:15.0,\n' +
  4907. 'http://media.example.com/fileSequence52-B.ts\n' +
  4908. '#EXT-X-ENDLIST\n'
  4909. );
  4910. this.clock.tick(1);
  4911. // segment request
  4912. this.standardXHRResponse(this.requests.pop());
  4913. assert.equal(
  4914. this.requests[0].url,
  4915. 'https://priv.example.com/key.php?r=52',
  4916. 'requested the key'
  4917. );
  4918. // keys *should* be 16 bytes long -- this one is too small
  4919. this.requests[0].response = new Uint8Array(1).buffer;
  4920. this.requests.shift().respond(200, null, '');
  4921. this.clock.tick(1);
  4922. // blacklist this playlist
  4923. assert.ok(
  4924. vhs.playlists.media().excludeUntil > 0,
  4925. 'blacklisted playlist'
  4926. );
  4927. assert.equal(this.env.log.warn.calls, 1, 'logged warning for blacklist');
  4928. // verify stats
  4929. assert.equal(vhs.stats.mediaBytesTransferred, 1024, '1024 bytes');
  4930. assert.equal(vhs.stats.mediaRequests, 1, '1 request');
  4931. vhs.dispose();
  4932. }
  4933. );
  4934. QUnit.module('videojs-http-streaming isolated functions');
  4935. QUnit.test('emeKeySystems adds content types for all keySystems', function(assert) {
  4936. // muxed content
  4937. assert.deepEqual(
  4938. emeKeySystems(
  4939. { keySystem1: {}, keySystem2: {} },
  4940. { attributes: { CODECS: 'avc1.420015, mp4a.40.2c' } },
  4941. ),
  4942. {
  4943. keySystem1: {
  4944. audioContentType: 'audio/mp4;codecs="mp4a.40.2c"',
  4945. videoContentType: 'video/mp4;codecs="avc1.420015"'
  4946. },
  4947. keySystem2: {
  4948. audioContentType: 'audio/mp4;codecs="mp4a.40.2c"',
  4949. videoContentType: 'video/mp4;codecs="avc1.420015"'
  4950. }
  4951. },
  4952. 'added content types'
  4953. );
  4954. // unmuxed content
  4955. assert.deepEqual(
  4956. emeKeySystems(
  4957. { keySystem1: {}, keySystem2: {} },
  4958. { attributes: { CODECS: 'avc1.420015' } },
  4959. { attributes: { CODECS: 'mp4a.40.2c' } },
  4960. ),
  4961. {
  4962. keySystem1: {
  4963. audioContentType: 'audio/mp4;codecs="mp4a.40.2c"',
  4964. videoContentType: 'video/mp4;codecs="avc1.420015"'
  4965. },
  4966. keySystem2: {
  4967. audioContentType: 'audio/mp4;codecs="mp4a.40.2c"',
  4968. videoContentType: 'video/mp4;codecs="avc1.420015"'
  4969. }
  4970. },
  4971. 'added content types'
  4972. );
  4973. });
  4974. QUnit.test('emeKeySystems supports audio only', function(assert) {
  4975. assert.deepEqual(
  4976. emeKeySystems(
  4977. { keySystem1: {}, keySystem2: {} },
  4978. { attributes: { CODECS: 'mp4a.40.2c' } },
  4979. ),
  4980. {
  4981. keySystem1: {
  4982. audioContentType: 'audio/mp4;codecs="mp4a.40.2c"'
  4983. },
  4984. keySystem2: {
  4985. audioContentType: 'audio/mp4;codecs="mp4a.40.2c"'
  4986. }
  4987. },
  4988. 'added content type'
  4989. );
  4990. });
  4991. QUnit.test('emeKeySystems supports external audio only', function(assert) {
  4992. assert.deepEqual(
  4993. emeKeySystems(
  4994. { keySystem1: {}, keySystem2: {} },
  4995. { attributes: {} },
  4996. { attributes: { CODECS: 'mp4a.40.2c' } },
  4997. ),
  4998. {
  4999. keySystem1: {
  5000. audioContentType: 'audio/mp4;codecs="mp4a.40.2c"'
  5001. },
  5002. keySystem2: {
  5003. audioContentType: 'audio/mp4;codecs="mp4a.40.2c"'
  5004. }
  5005. },
  5006. 'added content type'
  5007. );
  5008. });
  5009. QUnit.test('emeKeySystems supports video only', function(assert) {
  5010. assert.deepEqual(
  5011. emeKeySystems(
  5012. { keySystem1: {}, keySystem2: {} },
  5013. { attributes: { CODECS: 'avc1.420015' } },
  5014. ),
  5015. {
  5016. keySystem1: {
  5017. videoContentType: 'video/mp4;codecs="avc1.420015"'
  5018. },
  5019. keySystem2: {
  5020. videoContentType: 'video/mp4;codecs="avc1.420015"'
  5021. }
  5022. },
  5023. 'added content type'
  5024. );
  5025. });
  5026. QUnit.test('emeKeySystems retains non content type properties', function(assert) {
  5027. assert.deepEqual(
  5028. emeKeySystems(
  5029. { keySystem1: { url: '1' }, keySystem2: { url: '2'} },
  5030. { attributes: { CODECS: 'avc1.420015, mp4a.40.2c' } },
  5031. ),
  5032. {
  5033. keySystem1: {
  5034. url: '1',
  5035. audioContentType: 'audio/mp4;codecs="mp4a.40.2c"',
  5036. videoContentType: 'video/mp4;codecs="avc1.420015"'
  5037. },
  5038. keySystem2: {
  5039. url: '2',
  5040. audioContentType: 'audio/mp4;codecs="mp4a.40.2c"',
  5041. videoContentType: 'video/mp4;codecs="avc1.420015"'
  5042. }
  5043. },
  5044. 'retained options'
  5045. );
  5046. });
  5047. QUnit.test('emeKeySystems overwrites content types', function(assert) {
  5048. assert.deepEqual(
  5049. emeKeySystems(
  5050. {
  5051. keySystem1: {
  5052. audioContentType: 'a',
  5053. videoContentType: 'b'
  5054. },
  5055. keySystem2: {
  5056. audioContentType: 'c',
  5057. videoContentType: 'd'
  5058. }
  5059. },
  5060. { attributes: { CODECS: 'avc1.420015, mp4a.40.2c' } },
  5061. ),
  5062. {
  5063. keySystem1: {
  5064. audioContentType: 'audio/mp4;codecs="mp4a.40.2c"',
  5065. videoContentType: 'video/mp4;codecs="avc1.420015"'
  5066. },
  5067. keySystem2: {
  5068. audioContentType: 'audio/mp4;codecs="mp4a.40.2c"',
  5069. videoContentType: 'video/mp4;codecs="avc1.420015"'
  5070. }
  5071. },
  5072. 'overwrote content types'
  5073. );
  5074. });
  5075. QUnit.test('expandDataUri parses JSON for VHS media type', function(assert) {
  5076. const manifestObject = {
  5077. test: 'manifest',
  5078. object: ['here']
  5079. };
  5080. const xMpegDataUriString =
  5081. `data:application/x-mpegURL,${JSON.stringify(manifestObject)}`;
  5082. assert.deepEqual(
  5083. expandDataUri(xMpegDataUriString),
  5084. xMpegDataUriString,
  5085. 'does not parse JSON for non VHS media type'
  5086. );
  5087. assert.deepEqual(
  5088. expandDataUri(`data:application/vnd.videojs.vhs+json,${JSON.stringify(manifestObject)}`),
  5089. manifestObject,
  5090. 'parsed JSON from data URI for VHS media type'
  5091. );
  5092. });
  5093. QUnit.test('expandDataUri is case insensitive', function(assert) {
  5094. const manifestObject = {
  5095. test: 'manifest',
  5096. object: ['here']
  5097. };
  5098. assert.deepEqual(
  5099. expandDataUri(`DaTa:ApPlIcAtIoN/VnD.ViDeOjS.VhS+JsOn,${JSON.stringify(manifestObject)}`),
  5100. manifestObject,
  5101. 'parsed JSON from data URI for VHS media type'
  5102. );
  5103. });
  5104. QUnit.test('expandDataUri requires comma to parse', function(assert) {
  5105. assert.deepEqual(
  5106. expandDataUri('data:application/vnd.videojs.vhs+json'),
  5107. 'data:application/vnd.videojs.vhs+json',
  5108. 'did not parse when no comma after data URI'
  5109. );
  5110. });
  5111. QUnit.module('setupEmeOptions');
  5112. QUnit.test('no error if no eme and no key systems', function(assert) {
  5113. const player = {};
  5114. const sourceKeySystems = null;
  5115. const media = {};
  5116. const audioMedia = {};
  5117. assert.notOk(
  5118. setupEmeOptions({ player, sourceKeySystems, media, audioMedia }),
  5119. 'did not configure EME options'
  5120. );
  5121. assert.ok(true, 'no exception');
  5122. });
  5123. QUnit.test('log error if no eme and we have key systems', function(assert) {
  5124. const sourceKeySystems = {};
  5125. const media = {};
  5126. const audioMedia = {};
  5127. const src = {};
  5128. const player = {currentSource: () => src};
  5129. let logWarn;
  5130. const origWarn = videojs.log.warn;
  5131. videojs.log.warn = (line) => {
  5132. logWarn = line;
  5133. };
  5134. assert.notOk(
  5135. setupEmeOptions({ player, sourceKeySystems, media, audioMedia }),
  5136. 'did not configure EME options'
  5137. );
  5138. assert.equal(logWarn, 'DRM encrypted source cannot be decrypted without a DRM plugin', 'logs expected error');
  5139. assert.ok(src.hasOwnProperty('keySystems'), 'source key systems was set');
  5140. videojs.log.warn = origWarn;
  5141. });
  5142. QUnit.test('converts options for muxed playlist', function(assert) {
  5143. const currentSource = {};
  5144. const player = {
  5145. eme: {},
  5146. currentSource: () => currentSource
  5147. };
  5148. const sourceKeySystems = {
  5149. 'com.widevine.alpha': {
  5150. url: 'license-url'
  5151. }
  5152. };
  5153. const media = {
  5154. attributes: { CODECS: 'avc1.4d400d,mp4a.40.2' },
  5155. contentProtection: { 'com.widevine.alpha': { pssh: new Uint8Array() } }
  5156. };
  5157. const audioMedia = null;
  5158. assert.ok(
  5159. setupEmeOptions({ player, sourceKeySystems, media, audioMedia }),
  5160. 'configured EME options'
  5161. );
  5162. assert.deepEqual(
  5163. currentSource.keySystems,
  5164. {
  5165. 'com.widevine.alpha': {
  5166. audioContentType: 'audio/mp4;codecs="mp4a.40.2"',
  5167. videoContentType: 'video/mp4;codecs="avc1.4d400d"',
  5168. pssh: new Uint8Array(),
  5169. url: 'license-url'
  5170. }
  5171. },
  5172. 'eme keySystems options are corect'
  5173. );
  5174. });
  5175. QUnit.test('converts options for demuxed playlists', function(assert) {
  5176. const currentSource = {};
  5177. const player = {
  5178. eme: {},
  5179. currentSource: () => currentSource
  5180. };
  5181. const sourceKeySystems = {
  5182. 'com.widevine.alpha': {
  5183. url: 'license-url'
  5184. }
  5185. };
  5186. const media = {
  5187. attributes: { CODECS: 'avc1.4d400d,mp4a.40.2' },
  5188. contentProtection: { 'com.widevine.alpha': { pssh: new Uint8Array([1, 2, 3]) } }
  5189. };
  5190. const audioMedia = {
  5191. attributes: {},
  5192. contentProtection: { 'com.widevine.alpha': { pssh: new Uint8Array([4, 5, 6]) } }
  5193. };
  5194. assert.ok(
  5195. setupEmeOptions({ player, sourceKeySystems, media, audioMedia }),
  5196. 'configured eme options'
  5197. );
  5198. assert.deepEqual(
  5199. currentSource.keySystems,
  5200. {
  5201. 'com.widevine.alpha': {
  5202. audioContentType: 'audio/mp4;codecs="mp4a.40.2"',
  5203. videoContentType: 'video/mp4;codecs="avc1.4d400d"',
  5204. pssh: new Uint8Array([1, 2, 3]),
  5205. url: 'license-url'
  5206. }
  5207. },
  5208. 'eme keySystems options are correct'
  5209. );
  5210. });
  5211. QUnit.module('getAllPsshKeySystemsOptions');
  5212. QUnit.test('empty array if no content protection in playlists', function(assert) {
  5213. assert.deepEqual(
  5214. getAllPsshKeySystemsOptions(
  5215. [{}, {}],
  5216. ['com.widevine.alpha', 'com.microsoft.playready']
  5217. ),
  5218. [],
  5219. 'returned an empty array'
  5220. );
  5221. });
  5222. QUnit.test('empty array if no matching key systems in playlists', function(assert) {
  5223. assert.deepEqual(
  5224. getAllPsshKeySystemsOptions(
  5225. [{
  5226. contentProtection: { 'com.widevine.alpha': { pssh: new Uint8Array() } }
  5227. }, {
  5228. contentProtection: { 'com.widevine.alpha': { pssh: new Uint8Array() } }
  5229. }],
  5230. ['com.microsoft.playready']
  5231. ),
  5232. [],
  5233. 'returned an empty array'
  5234. );
  5235. });
  5236. QUnit.test('empty array if no pssh in playlist contentProtection', function(assert) {
  5237. assert.deepEqual(
  5238. getAllPsshKeySystemsOptions(
  5239. [{
  5240. contentProtection: {
  5241. 'com.widevine.alpha': {},
  5242. 'com.microsoft.playready': {}
  5243. }
  5244. }, {
  5245. contentProtection: {
  5246. 'com.widevine.alpha': {},
  5247. 'com.microsoft.playready': {}
  5248. }
  5249. }],
  5250. ['com.widevine.alpha', 'com.microsoft.playready']
  5251. ),
  5252. [],
  5253. 'returned an empty array'
  5254. );
  5255. });
  5256. QUnit.test('returns all key systems and pssh values', function(assert) {
  5257. assert.deepEqual(
  5258. getAllPsshKeySystemsOptions(
  5259. [{
  5260. contentProtection: {
  5261. 'com.widevine.alpha': {
  5262. pssh: new Uint8Array([0]),
  5263. otherProperty: true
  5264. },
  5265. 'com.microsoft.playready': {
  5266. pssh: new Uint8Array([1]),
  5267. otherProperty: true
  5268. }
  5269. }
  5270. }, {
  5271. contentProtection: {
  5272. 'com.widevine.alpha': {
  5273. pssh: new Uint8Array([2]),
  5274. otherProperty: true
  5275. },
  5276. 'com.microsoft.playready': {
  5277. pssh: new Uint8Array([3]),
  5278. otherProperty: true
  5279. }
  5280. }
  5281. }],
  5282. ['com.widevine.alpha', 'com.microsoft.playready']
  5283. ),
  5284. [{
  5285. 'com.widevine.alpha': { pssh: new Uint8Array([0]) },
  5286. 'com.microsoft.playready': { pssh: new Uint8Array([1]) }
  5287. }, {
  5288. 'com.widevine.alpha': { pssh: new Uint8Array([2]) },
  5289. 'com.microsoft.playready': { pssh: new Uint8Array([3]) }
  5290. }],
  5291. 'returned key systems and pssh values without other properties'
  5292. );
  5293. });
  5294. QUnit.module('waitForKeySessionCreation', {
  5295. beforeEach(assert) {
  5296. const listeners = [];
  5297. this.player = {
  5298. eme: {
  5299. initializeMediaKeys(options, callback) {
  5300. callback();
  5301. }
  5302. },
  5303. tech_: {
  5304. one(eventName, callback) {
  5305. listeners.push({ eventName, callback });
  5306. },
  5307. listeners
  5308. }
  5309. };
  5310. this.completeOptions = {
  5311. player: this.player,
  5312. sourceKeySystems: {
  5313. 'com.widevine.alpha': {
  5314. url: 'license-url'
  5315. }
  5316. },
  5317. audioMedia: null,
  5318. mainPlaylists: [{
  5319. contentProtection: {
  5320. 'com.widevine.alpha': { pssh: new Uint8Array() }
  5321. }
  5322. }]
  5323. };
  5324. }
  5325. });
  5326. QUnit.test('resolves on initializeMediaKeys', function(assert) {
  5327. const done = assert.async();
  5328. return waitForKeySessionCreation(this.completeOptions).then(() => {
  5329. assert.ok(true, 'resolved promise');
  5330. done();
  5331. });
  5332. });
  5333. QUnit.test('resolves on all initializeMediaKeys', function(assert) {
  5334. const done = assert.async();
  5335. const initializeCalls = [];
  5336. const initializeCallbacks = [];
  5337. this.completeOptions.mainPlaylists = [{
  5338. contentProtection: {
  5339. 'com.widevine.alpha': { pssh: new Uint8Array([0, 0, 0]) }
  5340. }
  5341. }, {
  5342. contentProtection: {
  5343. 'com.widevine.alpha': { pssh: new Uint8Array([1, 2, 3]) }
  5344. }
  5345. }];
  5346. this.player.eme.initializeMediaKeys = (options, callback) => {
  5347. initializeCalls.push(options);
  5348. initializeCallbacks.push(callback);
  5349. };
  5350. waitForKeySessionCreation(this.completeOptions).then(() => {
  5351. assert.deepEqual(
  5352. initializeCalls,
  5353. [
  5354. { keySystems: { 'com.widevine.alpha': { pssh: new Uint8Array([0, 0, 0]) } } },
  5355. { keySystems: { 'com.widevine.alpha': { pssh: new Uint8Array([1, 2, 3]) } } }
  5356. ],
  5357. 'waited for both initialize calls to resolve'
  5358. );
  5359. done();
  5360. });
  5361. assert.equal(initializeCallbacks.length, 2, 'two initialize calls');
  5362. initializeCallbacks[0]();
  5363. setTimeout(() => {
  5364. // call the second callback async to ensure the promise waits for all
  5365. initializeCallbacks[1]();
  5366. }, 1);
  5367. });
  5368. QUnit.test('resolves on all initializeMediaKeys when demuxed', function(assert) {
  5369. const done = assert.async();
  5370. const initializeCalls = [];
  5371. const initializeCallbacks = [];
  5372. this.completeOptions.mainPlaylists = [{
  5373. contentProtection: {
  5374. 'com.widevine.alpha': { pssh: new Uint8Array([0, 0, 0]) }
  5375. }
  5376. }, {
  5377. contentProtection: {
  5378. 'com.widevine.alpha': { pssh: new Uint8Array([1, 2, 3]) }
  5379. }
  5380. }];
  5381. this.completeOptions.audioMedia = {
  5382. contentProtection: {
  5383. 'com.widevine.alpha': { pssh: new Uint8Array([4, 5, 6]) }
  5384. }
  5385. };
  5386. this.player.eme.initializeMediaKeys = (options, callback) => {
  5387. initializeCalls.push(options);
  5388. initializeCallbacks.push(callback);
  5389. };
  5390. waitForKeySessionCreation(this.completeOptions).then(() => {
  5391. assert.deepEqual(
  5392. initializeCalls,
  5393. [
  5394. { keySystems: { 'com.widevine.alpha': { pssh: new Uint8Array([0, 0, 0]) } } },
  5395. { keySystems: { 'com.widevine.alpha': { pssh: new Uint8Array([1, 2, 3]) } } },
  5396. { keySystems: { 'com.widevine.alpha': { pssh: new Uint8Array([4, 5, 6]) } } }
  5397. ],
  5398. 'waited for all video and audio initialize calls to resolve'
  5399. );
  5400. done();
  5401. });
  5402. assert.equal(initializeCallbacks.length, 3, 'three initialize calls');
  5403. initializeCallbacks[0]();
  5404. setTimeout(() => {
  5405. // call the second callback async to ensure the promise waits for all
  5406. initializeCallbacks[1]();
  5407. setTimeout(() => {
  5408. // call the third callback async to ensure the promise waits for all
  5409. initializeCallbacks[2]();
  5410. }, 1);
  5411. }, 1);
  5412. });
  5413. QUnit.test('resolves on keysessioncreated', function(assert) {
  5414. const done = assert.async();
  5415. // never allow initializeMediaKeys to finish
  5416. this.player.eme.initializeMediaKeys = (options, callback) => {};
  5417. waitForKeySessionCreation(this.completeOptions).then(() => {
  5418. done();
  5419. });
  5420. assert.equal(this.player.tech_.listeners.length, 1, 'one listener');
  5421. assert.equal(this.player.tech_.listeners[0].eventName, 'keysessioncreated');
  5422. this.player.tech_.listeners[0].callback();
  5423. });
  5424. QUnit.test('resolves if no initializeMediaKeys', function(assert) {
  5425. const done = assert.async();
  5426. delete this.player.eme.initializeMediaKeys;
  5427. return waitForKeySessionCreation(this.completeOptions).then(() => {
  5428. assert.ok(true, 'resolved promise');
  5429. done();
  5430. });
  5431. });