Home | History | Annotate | Download | only in video
      1 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import logging
      6 import time
      7 
      8 from autotest_lib.client.bin import utils
      9 from autotest_lib.client.common_lib import error
     10 from autotest_lib.client.cros.graphics import graphics_utils
     11 from autotest_lib.client.cros.power import power_utils, power_rapl, power_status
     12 
     13 
     14 PLAYBACK_TEST_TIME_S = 10
     15 PLAYER_ENDED_STATE = 'Ended'
     16 PLAYER_PAUSE_STATE = 'Paused'
     17 PLAYER_PLAYING_STATE = 'Playing'
     18 WAIT_TIMEOUT_S = 20
     19 
     20 
     21 class YouTubeHelper(object):
     22     """A helper class contains YouTube related utility functions.
     23 
     24        To use this class, please call wait_for_player_state(playing) as below
     25        before calling set_video_duration. Please note that set_video_duration
     26        must be called in order to access few functions which uses the video
     27        length member variable.
     28 
     29        yh = youtube_helper.YouTubeHelper(tab)
     30        yh.wait_for_player_state(PLAYER_PLAYING_STATE)
     31        yh.set_video_duration()
     32 
     33     """
     34 
     35     def __init__(self, youtube_tab, power_logging=False):
     36         self._tab = youtube_tab
     37         self._video_duration = 0
     38         self.power_logger = None
     39 
     40         if power_logging and power_utils.has_rapl_support():
     41             self.power_logger = power_status.PowerLogger(
     42                 power_rapl.create_rapl())
     43             self.power_logger.start()
     44 
     45     def set_video_duration(self):
     46         """Sets the video duration."""
     47         self._video_duration = (int(self._tab.EvaluateJavaScript(
     48             'player.getDuration()')))
     49 
     50     def get_power_measurement(self):
     51         """Return power measurement.
     52 
     53         @return: power readings. None if power_logging is not enabled.
     54         """
     55         if self.power_logger:
     56             return self.power_logger.calc()
     57         return None
     58 
     59     def video_current_time(self):
     60         """Returns video's current playback time.
     61 
     62         Returns:
     63             returns the current playback location in seconds (int).
     64 
     65         """
     66         return int(self._tab.EvaluateJavaScript('player.getCurrentTime()'))
     67 
     68     def get_player_status(self):
     69         """Returns the player status."""
     70         return self._tab.EvaluateJavaScript(
     71             '(typeof playerStatus !== \'undefined\') && '
     72             'playerStatus.innerHTML')
     73 
     74     def set_playback_quality(self, quality):
     75         """Set the video quality to the quality passed in the arg.
     76 
     77         @param quality: video quality to set.
     78 
     79         """
     80         self._tab.ExecuteJavaScript(
     81             'player.setPlaybackQuality("%s")' % quality)
     82 
     83     def get_playback_quality(self):
     84         """Returns the playback quality."""
     85         return self._tab.EvaluateJavaScript('player.getPlaybackQuality()')
     86 
     87     def wait_for_player_state(self, expected_status):
     88         """Wait till the player status changes to expected_status.
     89 
     90         If the status doesn't change for long, the test will time out after
     91         WAIT_TIMEOUT_S and fails.
     92 
     93         @param expected_status: status which is expected for the test
     94                                 to continue.
     95 
     96         """
     97         utils.poll_for_condition(
     98             lambda: self.get_player_status() == expected_status,
     99             exception=error.TestError(
    100                 'Video failed to load. Player expected status: %s'
    101                 ' and current status: %s.'
    102                 % (expected_status, self.get_player_status())),
    103             timeout=WAIT_TIMEOUT_S,
    104             sleep_interval=1)
    105 
    106     def verify_video_playback(self):
    107         """Verify the video playback."""
    108         logging.info('Verifying the YouTube video playback.')
    109         playback = 0  # seconds
    110         prev_playback = 0
    111         count = 0
    112         while (self.video_current_time() < self._video_duration
    113                and playback < PLAYBACK_TEST_TIME_S):
    114             time.sleep(1)
    115             if self.video_current_time() <= prev_playback:
    116                 if count < 2:
    117                     logging.info('Retrying to video playback test.')
    118                     self._tab.ExecuteJavaScript(
    119                         'player.seekTo(%d, true)'
    120                         % (self.video_current_time() + 2))
    121                     time.sleep(1)
    122                     count = count + 1
    123                 else:
    124                     player_status = self.get_player_status()
    125                     raise error.TestError(
    126                         'Video is not playing. Player status: %s.' %
    127                         player_status)
    128             prev_playback = self.video_current_time()
    129             playback = playback + 1
    130 
    131     def wait_for_expected_resolution(self, expected_quality):
    132         """Wait for some time for getting expected resolution.
    133 
    134         @param expected_quality: quality to be set.
    135 
    136         """
    137         for _ in range(WAIT_TIMEOUT_S):
    138             dummy_quality = self.get_playback_quality()
    139             if dummy_quality == expected_quality:
    140                 logging.info('Expected resolution is set.')
    141                 break
    142             else:
    143                 logging.info('Waiting for expected resolution.')
    144                 time.sleep(0.1)
    145 
    146     def verify_video_resolutions(self, power_measurement=False):
    147         """Verify available video resolutions.
    148 
    149         Video resolution should be 360p, 480p, 720p and 1080p.
    150 
    151         """
    152         logging.info('Verifying the video resolutions.')
    153         video_qualities = self._tab.EvaluateJavaScript(
    154             'player.getAvailableQualityLevels()')
    155         logging.info('Available video resolutions: %s', video_qualities)
    156         if not video_qualities:
    157             raise error.TestError(
    158                 'Player failed to return available video qualities.')
    159         video_qualities.reverse()
    160 
    161         running_quality = self.get_playback_quality()
    162         index = video_qualities.index(running_quality)
    163         supporting_qualities = video_qualities[index:]
    164         logging.info("new video quality %s ", supporting_qualities)
    165 
    166         width, height = graphics_utils.get_internal_resolution()
    167         logging.info('checking resolution: %d width  %d height', width, height)
    168         for quality in supporting_qualities:
    169             logging.info('Playing video in %s quality.', quality)
    170 
    171             if quality == "hd1080":
    172                 self._tab.ExecuteJavaScript('player.setSize(1920, 1080)')
    173             if quality == "hd720":
    174                 self._tab.ExecuteJavaScript('player.setSize(1280, 720)')
    175             if quality == "large":
    176                 self._tab.ExecuteJavaScript('player.setSize(853, 480)')
    177             if quality == "medium":
    178                 self._tab.ExecuteJavaScript('player.setSize(640, 360)')
    179             if quality == "small":
    180                 self._tab.ExecuteJavaScript('player.setSize(320, 240)')
    181 
    182             self.set_playback_quality(quality)
    183             self.wait_for_player_state(PLAYER_PLAYING_STATE)
    184             self.wait_for_expected_resolution(quality)
    185             current_quality = self.get_playback_quality()
    186 
    187             if current_quality != quality:
    188                 raise error.TestError(
    189                     'Expected video quality: %s. Current video quality: %s'
    190                     % (quality, current_quality))
    191 
    192             if power_measurement and self.power_logger:
    193                 # Seeking to the beginning and ensure the player is playing.
    194                 self._tab.ExecuteJavaScript('player.seekTo(0, true)')
    195                 self._tab.ExecuteJavaScript('player.playVideo()')
    196                 self.wait_for_player_state(PLAYER_PLAYING_STATE)
    197                 with self.power_logger.checkblock('youtube-' + quality):
    198                     time.sleep(10)
    199             else:
    200                 time.sleep(1)
    201 
    202     def verify_player_states(self):
    203         """Verify the player states like play, pause, ended and seek."""
    204         logging.info('Verifying the player states.')
    205         self._tab.ExecuteJavaScript('player.pauseVideo()')
    206         self.wait_for_player_state(PLAYER_PAUSE_STATE)
    207         self._tab.ExecuteJavaScript('player.playVideo()')
    208         self.wait_for_player_state(PLAYER_PLAYING_STATE)
    209         # We are seeking the player position to (video length - 2 seconds).
    210         # Since the player waits for WAIT_TIMEOUT_S for the status change,
    211         # the video should be ended before we hit the timeout.
    212         video_end_test_duration = (self._video_duration -
    213                                    self.video_current_time() - 2)
    214         if video_end_test_duration >= WAIT_TIMEOUT_S:
    215             self._tab.ExecuteJavaScript(
    216                 'player.seekTo(%d, true)' % (self._video_duration - 5))
    217             self.wait_for_player_state(PLAYER_ENDED_STATE)
    218         else:
    219             raise error.TestError(
    220                 'Test video is not long enough for the video end test.')
    221         # Verifying seek back from the end position.
    222         self._tab.ExecuteJavaScript('player.seekTo(%d, true)'
    223                                     % (self._video_duration / 2))
    224         self.wait_for_player_state(PLAYER_PLAYING_STATE)
    225         # So the playback doesn't stay at the mid.
    226         seek_test = False
    227         for _ in range(WAIT_TIMEOUT_S):
    228             logging.info('Waiting for seek position to change.')
    229             time.sleep(1)
    230             seek_position = self.video_current_time()
    231             if (seek_position > self._video_duration / 2
    232                     and seek_position < self._video_duration):
    233                 seek_test = True
    234                 break
    235         if not seek_test:
    236             raise error.TestError(
    237                 'Seek location is wrong. '
    238                 'Video length: %d, seek position: %d.' %
    239                 (self._video_duration, seek_position))
    240