1# Copyright 2015 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
6import datetime, time
7
8from autotest_lib.client.bin import utils
9from autotest_lib.client.common_lib import error
10from autotest_lib.client.cros.video import method_logger
11
12
13class VideoPlayer(object):
14    """
15    Provides interface to interact with and control video playback via js.
16
17    Specific players such as VimeoPlayer will inherit from this class and
18    customize its behavior.
19
20    """
21
22
23    def __init__(self, tab, full_url, video_id, video_src_path='',
24                 event_timeout=5, polling_wait_time=1):
25        """
26        @param tab: object, tab to interact with the tab in the browser.
27        @param full_url: string, full url pointing to html file to load.
28        @param video_src_path: path, complete path to video used for test.
29        @param video_id: string, name of the video_id element in the html file.
30        @param time_out_for_events_s: integer, how long to wait for an event
31                                      before timing out
32        @param time_btwn_polling_s: integer, how long to wait between one call
33                                    to check a condition and the next.
34
35        """
36        self.tab = tab
37        self.full_url = full_url
38        self.video_id = video_id
39        self.video_src_path = video_src_path
40        self.event_timeout = event_timeout
41        self.polling_wait_time = polling_wait_time
42
43
44    @method_logger.log
45    def load_video(self, wait_for_canplay=True):
46        """
47        Loads video into browser.
48        @param wait_for_canplay: video will be verified before play
49
50        """
51        self.tab.Navigate(self.full_url)
52        self.tab.WaitForDocumentReadyStateToBeComplete()
53        self.inject_source_file()
54        if wait_for_canplay:
55             self.wait_for_video_ready()
56
57
58    def inject_source_file(self):
59        """
60        Injects source file into html file if needed.
61
62        Created for subclasses that need it
63
64        """
65        pass
66
67
68    @method_logger.log
69    def wait_for_video_ready(self):
70        """
71        Waits for video to signal that is ready.
72
73        Each class that inherits from this will define its is_video_ready
74        function.
75
76        """
77        exception_msg = 'Video did not signal ready in time.'
78
79        self._wait_for_event(self.is_video_ready, exception_msg)
80
81
82    @method_logger.log
83    def verify_video_can_play(self):
84        """
85        Plays video and ensures that reported video current time is > 0.
86        @raises: error.TestError if current time is not > 0 after time > 0s
87
88        """
89        exception_msg = 'Expected current > 0 after %ds' %self.event_timeout
90
91        self.play()
92
93        # check that video is playing
94        self._wait_for_event(lambda : self.currentTime() > 0.0, exception_msg)
95
96        self.pause()
97
98        # seek back to the beginning of video
99        self.seek_to(datetime.timedelta(seconds=0))
100
101
102    @method_logger.log
103    def seek_to(self, timestamp):
104        """
105        Uses javascript to set currentTime property of video to desired time.
106
107        @param timestamp: timedelta, instance of time to navigate video to.
108
109        """
110        self.seek_to(timestamp)
111
112
113    @method_logger.log
114    def wait_for_video_to_seek(self):
115        """
116        Waits for video's currentTime to equal the time it was seeked to.
117
118        """
119        exception_msg = 'Video did not complete seeking in time.'
120
121        self._wait_for_event(self.has_video_finished_seeking, exception_msg)
122
123        # it usually takes a little while before new frame renders, so wait
124        time.sleep(1)
125
126
127    @method_logger.log
128    def _wait_for_event(self, predicate_function, exception_msg):
129        """
130         Helper method to wait for a desired condition.
131
132         @param predicate_function: object, function which returns true when
133                                    desired condition is achieved.
134         @param exception_msg: string, an exception message to show when desired
135                               condition is not achieved in allowed time.
136
137        """
138        fullmsg = exception_msg + ' Waited for %ss' % self.event_timeout
139
140        utils.poll_for_condition(predicate_function,
141                                 error.TestError(fullmsg),
142                                 self.event_timeout,
143                                 self.polling_wait_time)
144