• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
6import time
7
8from autotest_lib.client.bin import utils
9from autotest_lib.client.common_lib import error
10from autotest_lib.client.cros.graphics import graphics_utils
11from autotest_lib.client.cros.power import power_utils, power_rapl, power_status
12
13
14PLAYBACK_TEST_TIME_S = 10
15PLAYER_ENDED_STATE = 'Ended'
16PLAYER_PAUSE_STATE = 'Paused'
17PLAYER_PLAYING_STATE = 'Playing'
18WAIT_TIMEOUT_S = 20
19
20
21class 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