xref: /aosp_15_r20/external/autotest/client/cros/video/youtube_helper.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
3*9c5db199SXin Li# found in the LICENSE file.
4*9c5db199SXin Li
5*9c5db199SXin Liimport logging
6*9c5db199SXin Liimport time
7*9c5db199SXin Li
8*9c5db199SXin Lifrom autotest_lib.client.bin import utils
9*9c5db199SXin Lifrom autotest_lib.client.common_lib import error
10*9c5db199SXin Lifrom autotest_lib.client.cros.graphics import graphics_utils
11*9c5db199SXin Li
12*9c5db199SXin Li
13*9c5db199SXin LiPLAYBACK_TEST_TIME_S = 10
14*9c5db199SXin LiPLAYER_ENDED_STATE = 'Ended'
15*9c5db199SXin LiPLAYER_PAUSE_STATE = 'Paused'
16*9c5db199SXin LiPLAYER_PLAYING_STATE = 'Playing'
17*9c5db199SXin LiWAIT_TIMEOUT_S = 20
18*9c5db199SXin Li
19*9c5db199SXin Li
20*9c5db199SXin Liclass YouTubeHelper(object):
21*9c5db199SXin Li    """A helper class contains YouTube related utility functions.
22*9c5db199SXin Li
23*9c5db199SXin Li       To use this class, please call wait_for_player_state(playing) as below
24*9c5db199SXin Li       before calling set_video_duration. Please note that set_video_duration
25*9c5db199SXin Li       must be called in order to access few functions which uses the video
26*9c5db199SXin Li       length member variable.
27*9c5db199SXin Li
28*9c5db199SXin Li       yh = youtube_helper.YouTubeHelper(tab)
29*9c5db199SXin Li       yh.wait_for_player_state(PLAYER_PLAYING_STATE)
30*9c5db199SXin Li       yh.set_video_duration()
31*9c5db199SXin Li
32*9c5db199SXin Li    """
33*9c5db199SXin Li
34*9c5db199SXin Li    def __init__(self, youtube_tab):
35*9c5db199SXin Li        self._tab = youtube_tab
36*9c5db199SXin Li        self._video_duration = 0
37*9c5db199SXin Li
38*9c5db199SXin Li
39*9c5db199SXin Li    def set_video_duration(self):
40*9c5db199SXin Li        """Sets the video duration."""
41*9c5db199SXin Li        self._video_duration = (int(self._tab.EvaluateJavaScript(
42*9c5db199SXin Li            'player.getDuration()')))
43*9c5db199SXin Li
44*9c5db199SXin Li    def video_current_time(self):
45*9c5db199SXin Li        """Returns video's current playback time.
46*9c5db199SXin Li
47*9c5db199SXin Li        Returns:
48*9c5db199SXin Li            returns the current playback location in seconds (int).
49*9c5db199SXin Li
50*9c5db199SXin Li        """
51*9c5db199SXin Li        return int(self._tab.EvaluateJavaScript('player.getCurrentTime()'))
52*9c5db199SXin Li
53*9c5db199SXin Li    def get_player_status(self):
54*9c5db199SXin Li        """Returns the player status."""
55*9c5db199SXin Li        return self._tab.EvaluateJavaScript(
56*9c5db199SXin Li            '(typeof playerStatus !== \'undefined\') && '
57*9c5db199SXin Li            'playerStatus.innerHTML')
58*9c5db199SXin Li
59*9c5db199SXin Li    def get_playback_quality(self):
60*9c5db199SXin Li        """Returns the playback quality."""
61*9c5db199SXin Li        return self._tab.EvaluateJavaScript('player.getPlaybackQuality()')
62*9c5db199SXin Li
63*9c5db199SXin Li    def wait_for_player_state(self, expected_status):
64*9c5db199SXin Li        """Wait till the player status changes to expected_status.
65*9c5db199SXin Li
66*9c5db199SXin Li        If the status doesn't change for long, the test will time out after
67*9c5db199SXin Li        WAIT_TIMEOUT_S and fails.
68*9c5db199SXin Li
69*9c5db199SXin Li        @param expected_status: status which is expected for the test
70*9c5db199SXin Li                                to continue.
71*9c5db199SXin Li
72*9c5db199SXin Li        """
73*9c5db199SXin Li        utils.poll_for_condition(
74*9c5db199SXin Li            lambda: self.get_player_status() == expected_status,
75*9c5db199SXin Li            exception=error.TestError(
76*9c5db199SXin Li                'Video failed to load. Player expected status: %s'
77*9c5db199SXin Li                ' and current status: %s.'
78*9c5db199SXin Li                % (expected_status, self.get_player_status())),
79*9c5db199SXin Li            timeout=WAIT_TIMEOUT_S,
80*9c5db199SXin Li            sleep_interval=1)
81*9c5db199SXin Li
82*9c5db199SXin Li    def verify_video_playback(self):
83*9c5db199SXin Li        """Verify the video playback."""
84*9c5db199SXin Li        logging.info('Verifying the YouTube video playback.')
85*9c5db199SXin Li        playback = 0  # seconds
86*9c5db199SXin Li        prev_playback = 0
87*9c5db199SXin Li        count = 0
88*9c5db199SXin Li        while (self.video_current_time() < self._video_duration
89*9c5db199SXin Li               and playback < PLAYBACK_TEST_TIME_S):
90*9c5db199SXin Li            time.sleep(1)
91*9c5db199SXin Li            if self.video_current_time() <= prev_playback:
92*9c5db199SXin Li                if count < 2:
93*9c5db199SXin Li                    logging.info('Retrying to video playback test.')
94*9c5db199SXin Li                    self._tab.ExecuteJavaScript(
95*9c5db199SXin Li                        'player.seekTo(%d, true)'
96*9c5db199SXin Li                        % (self.video_current_time() + 2))
97*9c5db199SXin Li                    time.sleep(1)
98*9c5db199SXin Li                    count = count + 1
99*9c5db199SXin Li                else:
100*9c5db199SXin Li                    player_status = self.get_player_status()
101*9c5db199SXin Li                    raise error.TestError(
102*9c5db199SXin Li                        'Video is not playing. Player status: %s.' %
103*9c5db199SXin Li                        player_status)
104*9c5db199SXin Li            prev_playback = self.video_current_time()
105*9c5db199SXin Li            playback = playback + 1
106*9c5db199SXin Li
107*9c5db199SXin Li    def verify_player_states(self):
108*9c5db199SXin Li        """Verify the player states like play, pause, ended and seek."""
109*9c5db199SXin Li        logging.info('Verifying the player states.')
110*9c5db199SXin Li        self._tab.ExecuteJavaScript('player.pauseVideo()')
111*9c5db199SXin Li        self.wait_for_player_state(PLAYER_PAUSE_STATE)
112*9c5db199SXin Li        self._tab.ExecuteJavaScript('player.playVideo()')
113*9c5db199SXin Li        self.wait_for_player_state(PLAYER_PLAYING_STATE)
114*9c5db199SXin Li        # We are seeking the player position to (video length - 2 seconds).
115*9c5db199SXin Li        # Since the player waits for WAIT_TIMEOUT_S for the status change,
116*9c5db199SXin Li        # the video should be ended before we hit the timeout.
117*9c5db199SXin Li        video_end_test_duration = (self._video_duration -
118*9c5db199SXin Li                                   self.video_current_time() - 2)
119*9c5db199SXin Li        if video_end_test_duration >= WAIT_TIMEOUT_S:
120*9c5db199SXin Li            self._tab.ExecuteJavaScript(
121*9c5db199SXin Li                'player.seekTo(%d, true)' % (self._video_duration - 5))
122*9c5db199SXin Li            self.wait_for_player_state(PLAYER_ENDED_STATE)
123*9c5db199SXin Li        else:
124*9c5db199SXin Li            raise error.TestError(
125*9c5db199SXin Li                'Test video is not long enough for the video end test.')
126*9c5db199SXin Li        # Verifying seek back from the end position.
127*9c5db199SXin Li        self._tab.ExecuteJavaScript('player.seekTo(%d, true)'
128*9c5db199SXin Li                                    % (self._video_duration / 2))
129*9c5db199SXin Li        self.wait_for_player_state(PLAYER_PLAYING_STATE)
130*9c5db199SXin Li        # So the playback doesn't stay at the mid.
131*9c5db199SXin Li        seek_test = False
132*9c5db199SXin Li        for _ in range(WAIT_TIMEOUT_S):
133*9c5db199SXin Li            logging.info('Waiting for seek position to change.')
134*9c5db199SXin Li            time.sleep(1)
135*9c5db199SXin Li            seek_position = self.video_current_time()
136*9c5db199SXin Li            if (seek_position > self._video_duration / 2
137*9c5db199SXin Li                    and seek_position < self._video_duration):
138*9c5db199SXin Li                seek_test = True
139*9c5db199SXin Li                break
140*9c5db199SXin Li        if not seek_test:
141*9c5db199SXin Li            raise error.TestError(
142*9c5db199SXin Li                'Seek location is wrong. '
143*9c5db199SXin Li                'Video length: %d, seek position: %d.' %
144*9c5db199SXin Li                (self._video_duration, seek_position))
145