# 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
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
EXTRA_BROWSER_ARGS = ['--use-fake-ui-for-media-stream']
# Statistics from the loopback.html page.
TEST_PROGRESS = 'testProgress'
# Polling timeout
TIMEOUT = 90
RES_720P = [1280, 720]
RES_VGA = [640, 480]
# max number of allowed blackframes or frozen frames
BLACK_FRAMES_THRESHOLD = 10
FROZEN_FRAMES_THRESHOLD = 10
class video_WebRtcPeerConnectionWithCamera(test.test):
"""Local Peer connection test with webcam at 720p."""
version = 1
def start_loopback(self, cr):
"""Opens WebRTC loopback 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, 'loopback.html')))
self.tab.WaitForDocumentReadyStateToBeComplete()
self.tab.EvaluateJavaScript("testCamera(%s)" %
self.chosen_resolution)
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 is_test_completed(self):
"""Checks if WebRTC peerconnection test is done.
@returns True if test complete, False otherwise.
"""
def test_done():
"""Check the testProgress variable in HTML page."""
# Wait for test completion on web page.
test_progress = self.tab.EvaluateJavaScript(TEST_PROGRESS)
return test_progress == 1
try:
utils.poll_for_condition(
test_done, timeout=TIMEOUT,
exception=error.TestError('Cannot find testProgress value.'),
sleep_interval=1)
except error.TestError:
partial_results = self.tab.EvaluateJavaScript('getResults()')
logging.info('Here are the partial results so far: %s',
partial_results)
return False
else:
return True
def run_once(self):
"""Runs the video_WebRtcPeerConnectionWithCamera test."""
# Check webcamera resolution capabilities.
# Some laptops have low resolution capture.
if self.webcam_supports_720p():
self.chosen_resolution = RES_720P
else:
self.chosen_resolution = RES_VGA
with chrome.Chrome(extra_browser_args=EXTRA_BROWSER_ARGS) as cr:
# Open WebRTC loopback page and start the loopback.
self.start_loopback(cr)
if not self.check_loopback_result():
raise error.TestFail('Failed %s local peer connection test' %
self.chosen_resolution)
def check_loopback_result(self):
"""Get the WebRTC Peerconnection loopback results."""
if not self.is_test_completed():
logging.error('loopback.html did not complete')
return False
try:
results = self.tab.EvaluateJavaScript('getResults()')
except:
logging.error('Cannot retrieve results from loopback.html page')
return False
logging.info('Camera Type: %s', results['cameraType'])
logging.info('Camera Errors: %s', results['cameraErrors'])
logging.info('PeerConnectionstats: %s',
results['peerConnectionStats'])
logging.info('FrameStats: %s', results['frameStats'])
if results['cameraErrors']:
logging.error('Camera error: %s', results['cameraErrors'])
return False
if not results['peerConnectionStats']:
logging.info('Peer Connection Stats is empty')
return False
if results['peerConnectionStats'][1] == 0:
logging.error('Max Input FPS is zero')
return False
if results['peerConnectionStats'][4] == 0:
logging.error('Max Sent FPS is zero')
return False
if not results['frameStats']:
logging.error('Frame Stats is empty')
return False
if results['frameStats']['numBlackFrames'] > BLACK_FRAMES_THRESHOLD:
logging.error('BlackFrames threshold overreach: '
'got %s > %s allowed',
results['frameStats']['numBlackFrames'],
BLACK_FRAMES_THRESHOLD)
return False
if results['frameStats']['numFrozenFrames'] > FROZEN_FRAMES_THRESHOLD:
logging.error('Frozen Frames threshold overreach: '
'got %s > %s allowed',
results['frameStats']['numFrozenFrames'],
FROZEN_FRAMES_THRESHOLD)
return False
if results['frameStats']['numFrames'] == 0:
logging.error('%s Frames were found',
results['frameStats']['numFrames'])
return False
return True