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, time 6 7 from autotest_lib.client.bin import utils 8 from autotest_lib.client.common_lib import error 9 from autotest_lib.client.cros.graphics import graphics_utils 10 11 12 PLAYBACK_TEST_TIME_S = 10 13 PLAYER_ENDED_STATE = 'Ended' 14 PLAYER_PAUSE_STATE = 'Paused' 15 PLAYER_PLAYING_STATE = 'Playing' 16 WAIT_TIMEOUT_S = 20 17 18 19 class 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 153 running_quality = self.get_playback_quality() 154 index = video_qualities.index(running_quality) 155 supporting_qualities = video_qualities[index :] 156 logging.info("new video quality %s ", supporting_qualities) 157 158 width, height = graphics_utils.get_internal_resolution() 159 logging.info('checking resolution: %d width %d height', width, height) 160 for quality in supporting_qualities: 161 logging.info('Playing video in %s quality.', quality) 162 self.set_playback_quality(quality) 163 self.wait_for_player_state(PLAYER_PLAYING_STATE) 164 self.wait_for_expected_resolution(quality) 165 current_quality = self.get_playback_quality() 166 167 if current_quality != quality : 168 raise error.TestError( 169 'Expected video quality: %s. Current video quality: %s' 170 % (quality, current_quality)) 171 172 time.sleep(1) 173 174 175 def verify_player_states(self): 176 """Verify the player states like play, pause, ended and seek.""" 177 logging.info('Verifying the player states.') 178 self._tab.ExecuteJavaScript('player.pauseVideo()') 179 self.wait_for_player_state(PLAYER_PAUSE_STATE) 180 self._tab.ExecuteJavaScript('player.playVideo()') 181 self.wait_for_player_state(PLAYER_PLAYING_STATE) 182 # We are seeking the player position to (video length - 2 seconds). 183 # Since the player waits for WAIT_TIMEOUT_S for the status change, 184 # the video should be ended before we hit the timeout. 185 video_end_test_duration = (self._video_duration - 186 self.video_current_time() - 2) 187 if video_end_test_duration >= WAIT_TIMEOUT_S: 188 self._tab.ExecuteJavaScript( 189 'player.seekTo(%d, true)' % (self._video_duration - 5)) 190 self.wait_for_player_state(PLAYER_ENDED_STATE) 191 else: 192 raise error.TestError( 193 'Test video is not long enough for the video end test.') 194 # Verifying seek back from the end position. 195 self._tab.ExecuteJavaScript('player.seekTo(%d, true)' 196 % (self._video_duration / 2)) 197 self.wait_for_player_state(PLAYER_PLAYING_STATE) 198 # So the playback doesn't stay at the mid. 199 seek_test = False 200 for _ in range(WAIT_TIMEOUT_S): 201 logging.info('Waiting for seek position to change.') 202 time.sleep(1) 203 seek_position = self.video_current_time() 204 if (seek_position > self._video_duration / 2 205 and seek_position < self._video_duration): 206 seek_test = True 207 break 208 if not seek_test: 209 raise error.TestError( 210 'Seek location is wrong. ' 211 'Video length: %d, seek position: %d.' % 212 (self._video_duration, seek_position)) 213