Bug 1304961 - Retrieve buffered ranges in VideoPuppeteer. r?maja_zf draft
authorBryce Van Dyk <bvandyk@mozilla.com>
Fri, 23 Sep 2016 17:52:57 +1200
changeset 416855 3c440cb9016c3972f984ce1ede3a37582e641d57
parent 416854 f5b67d4bd8918e53e51e3df9915a98b612da977d
child 531966 2d3b667525c46fef0537cf2646d865e88466770f
push id30266
push userbvandyk@mozilla.com
push dateFri, 23 Sep 2016 06:08:16 +0000
reviewersmaja_zf
bugs1304961
milestone52.0a1
Bug 1304961 - Retrieve buffered ranges in VideoPuppeteer. r?maja_zf Update VideoPuppeteer and make small changes in YoutubePuppeteer to support retrieval of buffered ranges for wrapped video element. This will help diagnose test failures, particularly stalls we're having at the moment. Because the namedtuple storing state has all its fields logged the __str__ methods of the puppeteers don't need to be updated, the new field will be logged automatically. MozReview-Commit-ID: LYwXJfB71RE
dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py
dom/media/test/external/external_media_tests/media_utils/youtube_puppeteer.py
--- a/dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py
+++ b/dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py
@@ -56,16 +56,21 @@ class VideoPuppeteer(object):
      cleared. If 0, do not check for stalls.
     :param timeout: The amount of time to wait until the video starts.
     """
 
     _video_var_script = (
         'var video = arguments[0];'
         'var currentTime = video.wrappedJSObject.currentTime;'
         'var duration = video.wrappedJSObject.duration;'
+        'var buffered = video.wrappedJSObject.buffered;'
+        'var bufferedRanges = [];'
+        'for (var i = 0; i < buffered.length; i++) {'
+        'bufferedRanges.push([buffered.start(i), buffered.end(i)]);'
+        '}'
         'var played = video.wrappedJSObject.played;'
         'var playedRanges = [];'
         'for (var i = 0; i < played.length; i++) {'
         'playedRanges.push([played.start(i), played.end(i)]);'
         '}'
         'var totalFrames = '
         'video.getVideoPlaybackQuality()["totalVideoFrames"];'
         'var droppedFrames = '
@@ -243,16 +248,21 @@ class VideoPuppeteer(object):
     def _video_state_named_tuple():
         """
         Create a named tuple class that can be used to store state snapshots
         of the wrapped element. The fields in the tuple should be used as
         follows:
 
         current_time: The current time of the wrapped element.
         duration: the duration of the wrapped element.
+        buffered: the buffered ranges of the wrapped element. In its raw form
+        this is as a list where the first element is the length and the second
+        element is a list of 2 item lists, where each two items are a buffered
+        range. Once assigned to the tuple this data should be wrapped in the
+        TimeRanges class.
         played: the played ranges of the wrapped element. In its raw form this
         is as a list where the first element is the length and the second
         element is a list of 2 item lists, where each two items are a played
         range. Once assigned to the tuple this data should be wrapped in the
         TimeRanges class.
         lag: the difference in real world time and wrapped element time.
         Calculated as real world time passed - element time passed.
         totalFrames: number of total frames for the wrapped element
@@ -262,16 +272,17 @@ class VideoPuppeteer(object):
         video_url: the url attribute of the wrapped element.
 
         :return: A 'video_state_info' named tuple class.
         """
         return namedtuple('video_state_info',
                           ['current_time',
                            'duration',
                            'remaining_time',
+                           'buffered',
                            'played',
                            'lag',
                            'total_frames',
                            'dropped_frames',
                            'corrupted_frames',
                            'video_src',
                            'video_url'])
 
@@ -284,20 +295,25 @@ class VideoPuppeteer(object):
 
         Aside from raw_played_ranges, see `_video_state_named_tuple` for more
         information on the above keys and values. For raw_played_ranges a
         list is expected that can be consumed to make a TimeRanges object.
 
         :return: A named tuple 'video_state_info' derived from arguments and
         state information from the puppeteer.
         """
+        raw_buffered_ranges = video_state_info_kwargs['raw_buffered_ranges']
         raw_played_ranges = video_state_info_kwargs['raw_played_ranges']
-        # Remove raw ranges from dict as it is not used in the final named
+        # Remove raw ranges from dict as they are not used in the final named
         # tuple and will provide an unexpected kwarg if kept.
+        del video_state_info_kwargs['raw_buffered_ranges']
         del video_state_info_kwargs['raw_played_ranges']
+        # Create buffered ranges
+        video_state_info_kwargs['buffered'] = (
+            TimeRanges(raw_buffered_ranges[0], raw_buffered_ranges[1]))
         # Create played ranges
         video_state_info_kwargs['played'] = (
             TimeRanges(raw_played_ranges[0], raw_played_ranges[1]))
         # Calculate elapsed times
         elapsed_current_time = (video_state_info_kwargs['current_time'] -
                                 self._first_seen_time)
         elapsed_wall_time = clock() - self._first_seen_wall_time
         # Calculate lag
@@ -322,33 +338,35 @@ class VideoPuppeteer(object):
     @property
     def _fetch_state_script(self):
         if not self._fetch_state_script_string:
             self._fetch_state_script_string = (
                 self._video_var_script +
                 'return ['
                 'currentTime,'
                 'duration,'
+                '[buffered.length, bufferedRanges],'
                 '[played.length, playedRanges],'
                 'totalFrames,'
                 'droppedFrames,'
                 'corruptedFrames];')
         return self._fetch_state_script_string
 
     def _refresh_state(self):
         """
         Refresh the snapshot of the underlying video state. We do this all
         in one so that the state doesn't change in between queries.
 
         We also store information that can be derived from the snapshotted
         information, such as lag. This is stored in the last seen state to
         stress that it's based on the snapshot.
         """
-        keys = ['current_time', 'duration', 'raw_played_ranges', 'total_frames',
-                'dropped_frames', 'corrupted_frames']
+        keys = ['current_time', 'duration', 'raw_buffered_ranges',
+                'raw_played_ranges', 'total_frames', 'dropped_frames',
+                'corrupted_frames']
         values = self._execute_video_script(self._fetch_state_script)
         self._last_seen_video_state = (
             self._create_video_state_info(**dict(zip(keys, values))))
 
     def _measure_progress(self):
         self._refresh_state()
         initial = self._last_seen_video_state.current_time
         sleep(1)
--- a/dom/media/test/external/external_media_tests/media_utils/youtube_puppeteer.py
+++ b/dom/media/test/external/external_media_tests/media_utils/youtube_puppeteer.py
@@ -341,16 +341,17 @@ class YouTubePuppeteer(VideoPuppeteer):
     def _fetch_state_script(self):
         if not self._fetch_state_script_string:
             self._fetch_state_script_string = (
                 self._video_var_script +
                 self._player_var_script +
                 'return ['
                 'currentTime,'
                 'duration,'
+                '[buffered.length, bufferedRanges],'
                 '[played.length, playedRanges],'
                 'totalFrames,'
                 'droppedFrames,'
                 'corruptedFrames,'
                 'player_duration,'
                 'player_current_time,'
                 'player_playback_quality,'
                 'player_movie_id,'
@@ -366,18 +367,19 @@ class YouTubePuppeteer(VideoPuppeteer):
         Refresh the snapshot of the underlying video and player state. We do
         this allin one so that the state doesn't change in between queries.
 
         We also store information that can be derived from the snapshotted
         information, such as lag. This is stored in the last seen state to
         stress that it's based on the snapshot.
         """
         values = self._execute_yt_script(self._fetch_state_script)
-        video_keys = ['current_time', 'duration', 'raw_played_ranges',
-                      'total_frames', 'dropped_frames', 'corrupted_frames']
+        video_keys = ['current_time', 'duration', 'raw_buffered_ranges',
+                      'raw_played_ranges', 'total_frames', 'dropped_frames',
+                      'corrupted_frames']
         player_keys = ['player_duration', 'player_current_time',
                        'player_playback_quality', 'player_movie_id',
                        'player_movie_title', 'player_url', 'player_state',
                        'player_ad_state', 'player_breaks_count']
         # Get video state
         self._last_seen_video_state = (
             self._create_video_state_info(**dict(
                 zip(video_keys, values[:len(video_keys)]))))