1# Copyright 2017 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 7 8from autotest_lib.client.bin import test 9from autotest_lib.client.bin import utils 10from autotest_lib.client.common_lib import error 11from autotest_lib.client.common_lib.cros import chrome 12from autotest_lib.client.cros.video import helper_logger 13from autotest_lib.client.cros.audio import audio_helper 14from autotest_lib.client.cros.audio import cras_utils 15 16# Suppress the media Permission Dialog. 17EXTRA_BROWSER_ARGS = [ 18 '--use-fake-ui-for-media-stream', # Suppress the Permission Dialog 19 '--use-fake-device-for-media-stream' # Use fake audio & video 20] 21 22AUDIO_LOOPBACK_PAGE = 'audio_loopback.html' 23 24# The test's runtime. 25TEST_RUNTIME_SECONDS = 10 26 27# Number of peer connections to use. 28NUM_PEER_CONNECTIONS = 1 29 30# Polling timeout. 31TIMEOUT = TEST_RUNTIME_SECONDS + 10 32 33 34class audio_WebRtcAudioLoopback(test.test): 35 """Tests a WebRTC call with a fake audio.""" 36 version = 1 37 38 def start_test(self, cr, recorded_file): 39 """Opens the WebRTC audio loopback page and records audio output. 40 41 @param cr: Autotest Chrome instance. 42 @param recorded_file: File to recorder the audio output to. 43 """ 44 cr.browser.platform.SetHTTPServerDirectories(self.bindir) 45 46 self.tab = cr.browser.tabs[0] 47 self.tab.Navigate(cr.browser.platform.http_server.UrlOf( 48 os.path.join(self.bindir, AUDIO_LOOPBACK_PAGE))) 49 self.tab.WaitForDocumentReadyStateToBeComplete() 50 self.tab.EvaluateJavaScript( 51 "run(%d, %d)" % (TEST_RUNTIME_SECONDS, NUM_PEER_CONNECTIONS)) 52 self.wait_for_active_stream_count(1) 53 cras_utils.capture(recorded_file, duration=TEST_RUNTIME_SECONDS) 54 55 def wait_test_completed(self, timeout_secs): 56 """Waits until the test is done. 57 58 @param timeout_secs Max time to wait in seconds. 59 60 @raises TestError on timeout, or javascript eval fails. 61 """ 62 def _test_done(): 63 status = self.tab.EvaluateJavaScript('testRunner.getStatus()') 64 logging.info(status) 65 return status == 'ok-done' 66 67 utils.poll_for_condition( 68 _test_done, timeout=timeout_secs, sleep_interval=1, 69 desc='audio.html reports itself as finished') 70 71 @staticmethod 72 def wait_for_active_stream_count(expected_count): 73 """Waits for the expected number of active streams. 74 75 @param expected_count: expected count of active streams. 76 """ 77 utils.poll_for_condition( 78 lambda: cras_utils.get_active_stream_count() == expected_count, 79 exception=error.TestError( 80 'Timeout waiting active stream count to become "%d",' 81 'current value is "%d"' % ( 82 expected_count, cras_utils.get_active_stream_count()))) 83 84 @helper_logger.video_log_wrapper 85 def run_once(self): 86 """Runs the audio_WebRtcAudioLoopback test.""" 87 # Record a sample of "silence" to use as a noise profile. 88 noise_file = os.path.join(self.resultsdir, 'cras_noise.wav') 89 cras_utils.capture(noise_file, duration=1) 90 91 # Create a file for the audio recording. 92 recorded_file = os.path.join(self.resultsdir, 'cras_recorded.wav') 93 94 self.wait_for_active_stream_count(0) 95 with chrome.Chrome(extra_browser_args=EXTRA_BROWSER_ARGS +\ 96 [helper_logger.chrome_vmodule_flag()], 97 init_network_controller=True) as cr: 98 self.start_test(cr, recorded_file) 99 self.wait_test_completed(TIMEOUT) 100 self.print_result(recorded_file, noise_file) 101 102 def print_result(self, recorded_file, noise_file): 103 """Prints results unless status is different from ok-done. 104 105 @raises TestError if the test failed outright. 106 @param recorded_file: File to recorder the audio output to. 107 @param noise_file: Noise recording, used for comparison. 108 """ 109 status = self.tab.EvaluateJavaScript('testRunner.getStatus()') 110 if status != 'ok-done': 111 raise error.TestFail('Failed: %s' % status) 112 113 results = self.tab.EvaluateJavaScript('testRunner.getResults()') 114 logging.info('runTimeSeconds: %.2f', results['runTimeSeconds']) 115 116 rms_value = audio_helper.reduce_noise_and_get_rms( 117 recorded_file, noise_file)[0] 118 logging.info('rms_value: %f', rms_value) 119 self.output_perf_value( 120 description='rms_value', 121 value=rms_value, 122 units='', higher_is_better=True) 123 124