| # Copyright 2015 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import logging |
| import os |
| import re |
| import time |
| |
| from autotest_lib.client.bin import test |
| from autotest_lib.client.bin import utils |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.common_lib.cros import chrome |
| from autotest_lib.client.cros.video import device_capability |
| from autotest_lib.client.cros.video import helper_logger |
| |
| EXTRA_BROWSER_ARGS = ['--use-fake-ui-for-media-stream'] |
| |
| # Variables from the getusermedia.html page. |
| IS_TEST_DONE = 'isTestDone' |
| IS_VIDEO_INPUT_FOUND = 'isVideoInputFound' |
| |
| # Polling timeout. |
| SEVERAL_MINUTES_IN_SECS = 240 |
| |
| |
| class video_WebRtcCamera(test.test): |
| """Local getUserMedia test with webcam at VGA (and 720p, if supported).""" |
| version = 1 |
| |
| def cleanup(self): |
| """Autotest cleanup function |
| |
| It is run by common_lib/test.py. |
| """ |
| if utils.is_virtual_machine(): |
| try: |
| utils.run('sudo modprobe -r vivid') |
| except Exception as e: |
| raise error.TestFail('Failed to unload vivid', e) |
| |
| def start_getusermedia(self, cr): |
| """Opens the test page. |
| |
| @param cr: Autotest Chrome instance. |
| """ |
| cr.browser.platform.SetHTTPServerDirectories(self.bindir) |
| |
| self.tab = cr.browser.tabs[0] |
| self.tab.Navigate(cr.browser.platform.http_server.UrlOf( |
| os.path.join(self.bindir, 'getusermedia.html'))) |
| self.tab.WaitForDocumentReadyStateToBeComplete() |
| |
| if utils.is_virtual_machine(): |
| # Before calling 'getUserMedia()' again, make sure if Chrome has |
| # already recognized vivid as an external camera. |
| self.wait_camera_detected() |
| |
| # Reload the page to run 'getUserMedia()' again |
| self.tab.EvaluateJavaScript('location.reload()') |
| self.tab.WaitForDocumentReadyStateToBeComplete() |
| |
| def wait_camera_detected(self): |
| """Waits until a camera is detected. |
| """ |
| for _ in range(10): |
| self.tab.EvaluateJavaScript('checkVideoInput()') |
| if self.tab.EvaluateJavaScript(IS_VIDEO_INPUT_FOUND): |
| return |
| time.sleep(1) |
| |
| raise error.TestFail('Can not find video input device') |
| |
| def webcam_supports_720p(self): |
| """Checks if 720p capture supported. |
| |
| @returns: True if 720p supported, false if VGA is supported. |
| @raises: TestError if neither 720p nor VGA are supported. |
| """ |
| cmd = 'lsusb -v' |
| # Get usb devices and make output a string with no newline marker. |
| usb_devices = utils.system_output(cmd, ignore_status=True).splitlines() |
| usb_devices = ''.join(usb_devices) |
| |
| # Check if 720p resolution supported. |
| if re.search(r'\s+wWidth\s+1280\s+wHeight\s+720', usb_devices): |
| return True |
| # The device should support at least VGA. |
| # Otherwise the cam must be broken. |
| if re.search(r'\s+wWidth\s+640\s+wHeight\s+480', usb_devices): |
| return False |
| # This should not happen. |
| raise error.TestFail( |
| 'Could not find any cameras reporting ' |
| 'either VGA or 720p in lsusb output: %s' % usb_devices) |
| |
| |
| def wait_test_completed(self, timeout_secs): |
| """Waits until the test is done. |
| |
| @param timeout_secs Max time to wait in seconds. |
| |
| @raises TestError on timeout, or javascript eval fails. |
| """ |
| def _test_done(): |
| return self.tab.EvaluateJavaScript(IS_TEST_DONE) |
| |
| utils.poll_for_condition( |
| _test_done, timeout=timeout_secs, sleep_interval=1, |
| desc=('getusermedia.html:reportTestDone did not run. Test did not ' |
| 'complete successfully.')) |
| |
| @helper_logger.video_log_wrapper |
| def run_once(self, capability): |
| """Runs the test. |
| |
| @param capability: Capability required for executing this test. |
| """ |
| device_capability.DeviceCapability().ensure_capability(capability) |
| |
| self.board = utils.get_current_board() |
| with chrome.Chrome(extra_browser_args=EXTRA_BROWSER_ARGS +\ |
| [helper_logger.chrome_vmodule_flag()], |
| init_network_controller=True) as cr: |
| |
| # TODO(keiichiw): vivid should be loaded in self.setup() after |
| # crbug.com/871185 is fixed |
| if utils.is_virtual_machine(): |
| try: |
| utils.run('sudo modprobe vivid n_devs=1 node_types=0x1') |
| except Exception as e: |
| raise error.TestFail('Failed to load vivid', e) |
| |
| self.start_getusermedia(cr) |
| self.print_perf_results() |
| |
| |
| def print_perf_results(self): |
| """Prints the perf results unless there was an error. |
| |
| @returns the empty string if perf results were printed, otherwise |
| a description of the error that occured. |
| """ |
| self.wait_test_completed(SEVERAL_MINUTES_IN_SECS) |
| try: |
| results = self.tab.EvaluateJavaScript('getResults()') |
| except Exception as e: |
| raise error.TestFail('Failed to get getusermedia.html results', e) |
| logging.info('Results: %s', results) |
| |
| errors = [] |
| for width_height, data in results.iteritems(): |
| resolution = re.sub(',', 'x', width_height) |
| if data['cameraErrors']: |
| if (resolution == '1280x720' and |
| not self.webcam_supports_720p()): |
| logging.info('Accepting 720p failure since device webcam ' |
| 'does not support 720p') |
| continue |
| |
| # Else we had a VGA failure or a legit 720p failure. |
| errors.append('Camera error: %s for resolution ' |
| '%s.' % (data['cameraErrors'], resolution)) |
| continue |
| if not data['frameStats']: |
| errors.append('Frame Stats is empty ' |
| 'for resolution: %s' % resolution) |
| continue |
| |
| total_num_frames = data['frameStats']['numFrames'] |
| num_black_frames = data['frameStats']['numBlackFrames'] |
| num_frozen_frames = data['frameStats']['numFrozenFrames'] |
| |
| def _percent(num, total): |
| if total == 0: |
| return 1.0 |
| return float(num) / float(total) |
| |
| self.output_perf_value( |
| description='black_frames_percentage_%s' % resolution, |
| value=_percent(num_black_frames, total_num_frames), |
| units='percent', higher_is_better=False) |
| self.output_perf_value( |
| description='frozen_frames_percentage_%s' % resolution, |
| value=_percent(num_frozen_frames, total_num_frames), |
| units='percent', higher_is_better=False) |
| |
| if errors: |
| raise error.TestFail('Found errors: %s' % ', '.join(errors)) |