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