• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5import logging
6import os
7import re
8import time
9
10from autotest_lib.client.bin import test
11from autotest_lib.client.bin import utils
12from autotest_lib.client.common_lib import error
13from autotest_lib.client.common_lib.cros import chrome
14from autotest_lib.client.cros.video import device_capability
15from autotest_lib.client.cros.video import helper_logger
16
17EXTRA_BROWSER_ARGS = ['--use-fake-ui-for-media-stream']
18
19# Variables from the getusermedia.html page.
20IS_TEST_DONE = 'isTestDone'
21IS_VIDEO_INPUT_FOUND = 'isVideoInputFound'
22
23# Polling timeout.
24SEVERAL_MINUTES_IN_SECS = 240
25
26
27class video_WebRtcCamera(test.test):
28    """Local getUserMedia test with webcam at VGA (and 720p, if supported)."""
29    version = 1
30
31    def cleanup(self):
32        """Autotest cleanup function
33
34        It is run by common_lib/test.py.
35        """
36        if utils.is_virtual_machine():
37            try:
38                utils.run('sudo modprobe -r vivid')
39            except Exception as e:
40                raise error.TestFail('Failed to unload vivid', e)
41
42    def start_getusermedia(self, cr):
43        """Opens the test page.
44
45        @param cr: Autotest Chrome instance.
46        """
47        cr.browser.platform.SetHTTPServerDirectories(self.bindir)
48
49        self.tab = cr.browser.tabs[0]
50        self.tab.Navigate(cr.browser.platform.http_server.UrlOf(
51                os.path.join(self.bindir, 'getusermedia.html')))
52        self.tab.WaitForDocumentReadyStateToBeComplete()
53
54        if utils.is_virtual_machine():
55            # Before calling 'getUserMedia()' again, make sure if Chrome has
56            # already recognized vivid as an external camera.
57            self.wait_camera_detected()
58
59            # Reload the page to run 'getUserMedia()' again
60            self.tab.EvaluateJavaScript('location.reload()')
61            self.tab.WaitForDocumentReadyStateToBeComplete()
62
63    def wait_camera_detected(self):
64        """Waits until a camera is detected.
65        """
66        for _ in range(10):
67            self.tab.EvaluateJavaScript('checkVideoInput()')
68            if self.tab.EvaluateJavaScript(IS_VIDEO_INPUT_FOUND):
69                return
70            time.sleep(1)
71
72        raise error.TestFail('Can not find video input device')
73
74    def webcam_supports_720p(self):
75        """Checks if 720p capture supported.
76
77        @returns: True if 720p supported, false if VGA is supported.
78        @raises: TestError if neither 720p nor VGA are supported.
79        """
80        cmd = 'lsusb -v'
81        # Get usb devices and make output a string with no newline marker.
82        usb_devices = utils.system_output(cmd, ignore_status=True).splitlines()
83        usb_devices = ''.join(usb_devices)
84
85        # Check if 720p resolution supported.
86        if re.search(r'\s+wWidth\s+1280\s+wHeight\s+720', usb_devices):
87            return True
88        # The device should support at least VGA.
89        # Otherwise the cam must be broken.
90        if re.search(r'\s+wWidth\s+640\s+wHeight\s+480', usb_devices):
91            return False
92        # This should not happen.
93        raise error.TestFail(
94                'Could not find any cameras reporting '
95                'either VGA or 720p in lsusb output: %s' % usb_devices)
96
97
98    def wait_test_completed(self, timeout_secs):
99        """Waits until the test is done.
100
101        @param timeout_secs Max time to wait in seconds.
102
103        @raises TestError on timeout, or javascript eval fails.
104        """
105        def _test_done():
106            return self.tab.EvaluateJavaScript(IS_TEST_DONE)
107
108        utils.poll_for_condition(
109            _test_done, timeout=timeout_secs, sleep_interval=1,
110            desc=('getusermedia.html:reportTestDone did not run. Test did not '
111                  'complete successfully.'))
112
113    @helper_logger.video_log_wrapper
114    def run_once(self, capability):
115        """Runs the test.
116
117        @param capability: Capability required for executing this test.
118        """
119        device_capability.DeviceCapability().ensure_capability(capability)
120
121        self.board = utils.get_current_board()
122        with chrome.Chrome(extra_browser_args=EXTRA_BROWSER_ARGS +\
123                           [helper_logger.chrome_vmodule_flag()],
124                           init_network_controller=True) as cr:
125
126            # TODO(keiichiw): vivid should be loaded in self.setup() after
127            # crbug.com/871185 is fixed
128            if utils.is_virtual_machine():
129                try:
130                    utils.run('sudo modprobe vivid n_devs=1 node_types=0x1')
131                except Exception as e:
132                    raise error.TestFail('Failed to load vivid', e)
133
134            self.start_getusermedia(cr)
135            self.print_perf_results()
136
137
138    def print_perf_results(self):
139        """Prints the perf results unless there was an error.
140
141        @returns the empty string if perf results were printed, otherwise
142                 a description of the error that occured.
143        """
144        self.wait_test_completed(SEVERAL_MINUTES_IN_SECS)
145        try:
146            results = self.tab.EvaluateJavaScript('getResults()')
147        except Exception as e:
148            raise error.TestFail('Failed to get getusermedia.html results', e)
149        logging.info('Results: %s', results)
150
151        errors = []
152        for width_height, data in results.iteritems():
153            resolution = re.sub(',', 'x', width_height)
154            if data['cameraErrors']:
155                if (resolution == '1280x720' and
156                        not self.webcam_supports_720p()):
157                    logging.info('Accepting 720p failure since device webcam '
158                                 'does not support 720p')
159                    continue
160
161                # Else we had a VGA failure or a legit 720p failure.
162                errors.append('Camera error: %s for resolution '
163                            '%s.' % (data['cameraErrors'], resolution))
164                continue
165            if not data['frameStats']:
166                errors.append('Frame Stats is empty '
167                              'for resolution: %s' % resolution)
168                continue
169
170            total_num_frames = data['frameStats']['numFrames']
171            num_black_frames = data['frameStats']['numBlackFrames']
172            num_frozen_frames = data['frameStats']['numFrozenFrames']
173
174            def _percent(num, total):
175                if total == 0:
176                    return 1.0
177                return float(num) / float(total)
178
179            self.output_perf_value(
180                    description='black_frames_percentage_%s' % resolution,
181                    value=_percent(num_black_frames, total_num_frames),
182                    units='percent', higher_is_better=False)
183            self.output_perf_value(
184                    description='frozen_frames_percentage_%s' % resolution,
185                    value=_percent(num_frozen_frames, total_num_frames),
186                    units='percent', higher_is_better=False)
187
188        if errors:
189            raise error.TestFail('Found errors: %s' % ', '.join(errors))
190