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
--- 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)]))))