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 8 9from autotest_lib.client.bin import test 10from autotest_lib.client.bin import utils 11from autotest_lib.client.common_lib import error 12from autotest_lib.client.common_lib.cros import chrome 13 14EXTRA_BROWSER_ARGS = ['--use-fake-ui-for-media-stream'] 15 16# Statistics from the loopback.html page. 17TEST_PROGRESS = 'testProgress' 18 19# Polling timeout 20TIMEOUT = 240 21 22# max number of allowed blackframes or frozen frames 23BLACK_FRAMES_THRESHOLD = 10 24FROZEN_FRAMES_THRESHOLD = 10 25 26class video_WebRtcCamera(test.test): 27 """Local Peer connection test with webcam at 720p.""" 28 version = 1 29 30 def start_loopback(self, cr): 31 """Opens WebRTC loopback page. 32 33 @param cr: Autotest Chrome instance. 34 """ 35 cr.browser.platform.SetHTTPServerDirectories(self.bindir) 36 37 self.tab = cr.browser.tabs[0] 38 self.tab.Navigate(cr.browser.platform.http_server.UrlOf( 39 os.path.join(self.bindir, 'loopback.html'))) 40 self.tab.WaitForDocumentReadyStateToBeComplete() 41 42 43 def webcam_supports_720p(self): 44 """Checks if 720p capture supported. 45 46 @returns: True if 720p supported, false if VGA is supported. 47 @raises: TestError if neither 720p nor VGA are supported. 48 """ 49 cmd = 'lsusb -v' 50 # Get usb devices and make output a string with no newline marker. 51 usb_devices = utils.system_output(cmd, ignore_status=True).splitlines() 52 usb_devices = ''.join(usb_devices) 53 54 # Check if 720p resolution supported. 55 if re.search(r'\s+wWidth\s+1280\s+wHeight\s+720', usb_devices): 56 return True 57 # The device should support at least VGA. 58 # Otherwise the cam must be broken. 59 if re.search(r'\s+wWidth\s+640\s+wHeight\s+480', usb_devices): 60 return False 61 # This should not happen. 62 raise error.TestFail( 63 'Could not find any cameras reporting ' 64 'either VGA or 720p in lsusb output: %s' % usb_devices) 65 66 67 def is_test_completed(self): 68 """Checks if WebRTC peerconnection test is done. 69 70 @returns True if test complete, False otherwise. 71 72 """ 73 def test_done(): 74 """Check the testProgress variable in HTML page.""" 75 76 # Wait for test completion on web page. 77 test_progress = self.tab.EvaluateJavaScript(TEST_PROGRESS) 78 return test_progress == 1 79 80 try: 81 utils.poll_for_condition( 82 test_done, timeout=TIMEOUT, 83 exception=error.TestError( 84 'Cannot find testProgress value.'), 85 sleep_interval=1) 86 except error.TestError: 87 partial_results = self.tab.EvaluateJavaScript('getResults()') 88 logging.info('Here are the partial results so far: %s', 89 partial_results) 90 return False 91 else: 92 return True 93 94 95 def run_once(self): 96 """Runs the video_WebRtcPeerConnectionWithCamera test.""" 97 self.board = utils.get_current_board() 98 with chrome.Chrome(extra_browser_args=EXTRA_BROWSER_ARGS) as cr: 99 # Open WebRTC loopback page and start the loopback. 100 self.start_loopback(cr) 101 if not self.check_loopback_result(): 102 raise error.TestFail('Failed webrtc camera test') 103 104 105 def check_loopback_result(self): 106 """Get the WebRTC Camera results.""" 107 if not self.is_test_completed(): 108 logging.error('loopback.html did not complete') 109 return False 110 try: 111 results = self.tab.EvaluateJavaScript('getResults()') 112 except: 113 logging.error('Cannot retrieve results from loopback.html page') 114 return False 115 logging.info('Results: %s', results) 116 for resolution in results: 117 item = results[resolution] 118 if (item['cameraErrors'] and resolution == '1280,720' 119 and self.webcam_supports_720p()): 120 logging.error('Camera error: %s', item['cameraErrors']) 121 return False 122 if not item['frameStats']: 123 output_resolution = re.sub(',', 'x', resolution) 124 logging.error('Frame Stats is empty for resolution: %s', 125 output_resolution) 126 return False 127 128 if item['frameStats']['numBlackFrames'] > BLACK_FRAMES_THRESHOLD: 129 logging.error('BlackFrames threshold overreach: ' 130 'got %s > %s allowed', 131 item['frameStats']['numBlackFrames'], 132 BLACK_FRAMES_THRESHOLD) 133 return False 134 if item['frameStats']['numFrozenFrames'] > FROZEN_FRAMES_THRESHOLD: 135 logging.error('FrozenFrames threshold overreach: ' 136 'got %s > %s allowed', 137 item['frameStats']['numFrozenFrames'], 138 FROZEN_FRAMES_THRESHOLD) 139 return False 140 if item['frameStats']['numFrames'] == 0: 141 logging.error('%s Frames were found', 142 item['frameStats']['numFrames']) 143 return False 144 145 return True 146