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