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