1 # Copyright 2016 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 5 """This is a server side WebRTC audio test using the Chameleon board.""" 6 7 import logging 8 import os 9 import time 10 11 from autotest_lib.client.common_lib import error 12 from autotest_lib.client.cros.audio import audio_test_data 13 from autotest_lib.client.cros.chameleon import audio_test_utils 14 from autotest_lib.client.cros.chameleon import chameleon_audio_helper 15 from autotest_lib.client.cros.chameleon import chameleon_audio_ids 16 from autotest_lib.client.cros.multimedia import webrtc_utils 17 from autotest_lib.server.cros.audio import audio_test 18 from autotest_lib.server.cros.multimedia import remote_facade_factory 19 20 21 class audio_AudioWebRTCLoopback(audio_test.AudioTest): 22 """Server side WebRTC loopback audio test. 23 24 This test talks to a Chameleon board and a Cros device to verify 25 WebRTC audio function of the Cros device. 26 A sine tone is played to Cros device from Chameleon USB. 27 Through AppRTC loopback page, the sine tone is played to Chameleon 28 LineIn from Cros device headphone. 29 Using USB as audio source because it can provide completely correct 30 data to loopback. This enables the test to do quality verification on 31 headphone. 32 33 ----------->->->------------ 34 USB out | | USB in 35 ----------- -------- AppRTC loopback 36 | Chameleon | | Cros | <--------> webpage 37 ----------- -------- 38 Line-In | | Headphone 39 -----------<-<-<------------ 40 41 42 The recorded audio is copied to server side and examined for quality. 43 44 """ 45 version = 1 46 RECORD_SECONDS = 10 47 DELAY_AFTER_BINDING_SECONDS = 0.5 48 49 def run_once(self, host, check_quality=False, chrome_block_size=None): 50 """Running basic headphone audio tests. 51 52 @param host: device under test host 53 @param check_quality: flag to check audio quality. 54 @param chrome_block_size: A number to be passed to Chrome 55 --audio-buffer-size argument to specify 56 block size. 57 58 """ 59 if not audio_test_utils.has_headphone(host): 60 logging.info('Skip the test because there is no headphone') 61 return 62 63 golden_file = audio_test_data.SIMPLE_FREQUENCY_LOUD_WAVE_FILE 64 golden_file.generate_file() 65 66 chameleon_board = host.chameleon 67 68 # Checks if a block size is specified for Chrome. 69 extra_browser_args = None 70 if chrome_block_size: 71 extra_browser_args = ['--audio-buffer-size=%d' % chrome_block_size] 72 73 factory = remote_facade_factory.RemoteFacadeFactory( 74 host, results_dir=self.resultsdir, 75 extra_browser_args=extra_browser_args) 76 77 chameleon_board.setup_and_reset(self.outputdir) 78 79 widget_factory = chameleon_audio_helper.AudioWidgetFactory( 80 factory, host) 81 82 headphone = widget_factory.create_widget( 83 chameleon_audio_ids.CrosIds.HEADPHONE) 84 linein = widget_factory.create_widget( 85 chameleon_audio_ids.ChameleonIds.LINEIN) 86 headphone_linein_binder = widget_factory.create_binder(headphone, linein) 87 88 usb_out = widget_factory.create_widget(chameleon_audio_ids.ChameleonIds.USBOUT) 89 usb_in = widget_factory.create_widget(chameleon_audio_ids.CrosIds.USBIN) 90 usb_binder = widget_factory.create_binder(usb_out, usb_in) 91 92 with chameleon_audio_helper.bind_widgets(headphone_linein_binder): 93 with chameleon_audio_helper.bind_widgets(usb_binder): 94 time.sleep(self.DELAY_AFTER_BINDING_SECONDS) 95 audio_facade = factory.create_audio_facade() 96 97 audio_test_utils.dump_cros_audio_logs( 98 host, audio_facade, self.resultsdir, 'after_binding') 99 100 # Checks headphone and USB nodes are plugged. 101 # Let Chrome select the proper I/O nodes. 102 # Input is USB, output is headphone. 103 audio_test_utils.check_and_set_chrome_active_node_types( 104 audio_facade=audio_facade, 105 output_type='HEADPHONE', 106 input_type='USB') 107 108 logging.info('Setting playback data on Chameleon') 109 usb_out.set_playback_data(golden_file) 110 111 browser_facade = factory.create_browser_facade() 112 apprtc = webrtc_utils.AppRTCController(browser_facade) 113 logging.info('Load AppRTC loopback webpage') 114 apprtc.new_apprtc_loopback_page() 115 116 logging.info('Start recording from Chameleon.') 117 linein.start_recording() 118 119 logging.info('Start playing %s on Cros device', 120 golden_file.path) 121 usb_out.start_playback() 122 123 time.sleep(self.RECORD_SECONDS) 124 125 linein.stop_recording() 126 logging.info('Stopped recording from Chameleon.') 127 128 audio_test_utils.dump_cros_audio_logs( 129 host, audio_facade, self.resultsdir, 'after_recording') 130 131 usb_out.stop_playback() 132 133 linein.read_recorded_binary() 134 logging.info('Read recorded binary from Chameleon.') 135 136 golden_file.delete() 137 138 recorded_file = os.path.join(self.resultsdir, "recorded.raw") 139 logging.info('Saving recorded data to %s', recorded_file) 140 linein.save_file(recorded_file) 141 142 diagnostic_path = os.path.join( 143 self.resultsdir, 144 'audio_diagnostics.txt.after_recording') 145 logging.info('Examine diagnostic file at %s', diagnostic_path) 146 diag_warning_msg = audio_test_utils.examine_audio_diagnostics( 147 diagnostic_path) 148 if diag_warning_msg: 149 logging.warning(diag_warning_msg) 150 151 # Raise error.TestFail if there is issue. 152 audio_test_utils.check_recorded_frequency( 153 golden_file, linein, check_artifacts=check_quality) 154