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 7import logging 8import os 9import time 10 11from autotest_lib.client.common_lib import error 12from autotest_lib.client.cros.audio import audio_test_data 13from autotest_lib.client.cros.chameleon import audio_test_utils 14from autotest_lib.client.cros.chameleon import chameleon_audio_helper 15from autotest_lib.client.cros.chameleon import chameleon_audio_ids 16from autotest_lib.client.cros.multimedia import webrtc_utils 17from autotest_lib.server.cros.audio import audio_test 18from autotest_lib.server.cros.multimedia import remote_facade_factory 19 20 21class 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_audio_jack(host): 60 raise error.TestNAError( 61 'No audio jack for the DUT.' 62 'Please check label of the host and control file.' 63 'Please check the host label and test dependency.') 64 65 golden_file = audio_test_data.GenerateAudioTestData( 66 data_format=dict(file_type='wav', 67 sample_format='S16_LE', 68 channel=2, 69 rate=48000), 70 path=os.path.join(self.bindir, 'fix_660_16.wav'), 71 duration_secs=60, 72 frequencies=[660, 660]) 73 74 chameleon_board = host.chameleon 75 76 # Checks if a block size is specified for Chrome. 77 extra_browser_args = None 78 if chrome_block_size: 79 extra_browser_args = ['--audio-buffer-size=%d' % chrome_block_size] 80 81 factory = remote_facade_factory.RemoteFacadeFactory( 82 host, results_dir=self.resultsdir, 83 extra_browser_args=extra_browser_args) 84 85 chameleon_board.setup_and_reset(self.outputdir) 86 87 widget_factory = chameleon_audio_helper.AudioWidgetFactory( 88 factory, host) 89 90 headphone = widget_factory.create_widget( 91 chameleon_audio_ids.CrosIds.HEADPHONE) 92 linein = widget_factory.create_widget( 93 chameleon_audio_ids.ChameleonIds.LINEIN) 94 headphone_linein_binder = widget_factory.create_binder(headphone, linein) 95 96 usb_out = widget_factory.create_widget(chameleon_audio_ids.ChameleonIds.USBOUT) 97 usb_in = widget_factory.create_widget(chameleon_audio_ids.CrosIds.USBIN) 98 usb_binder = widget_factory.create_binder(usb_out, usb_in) 99 100 with chameleon_audio_helper.bind_widgets(headphone_linein_binder): 101 with chameleon_audio_helper.bind_widgets(usb_binder): 102 time.sleep(self.DELAY_AFTER_BINDING_SECONDS) 103 audio_facade = factory.create_audio_facade() 104 105 audio_test_utils.dump_cros_audio_logs( 106 host, audio_facade, self.resultsdir, 'after_binding') 107 108 # Checks whether line-out or headphone is detected. 109 hp_jack_node_type = audio_test_utils.check_hp_or_lineout_plugged( 110 audio_facade) 111 112 # Checks headphone and USB nodes are plugged. 113 # Let Chrome select the proper I/O nodes. 114 # Input is USB, output is headphone. 115 audio_test_utils.check_and_set_chrome_active_node_types( 116 audio_facade=audio_facade, 117 output_type=hp_jack_node_type, 118 input_type='USB') 119 120 logging.info('Setting playback data on Chameleon') 121 usb_out.set_playback_data(golden_file) 122 123 browser_facade = factory.create_browser_facade() 124 apprtc = webrtc_utils.AppRTCController(browser_facade) 125 logging.info('Load AppRTC loopback webpage') 126 apprtc.new_apprtc_loopback_page() 127 128 logging.info('Start recording from Chameleon.') 129 linein.start_recording() 130 131 logging.info('Start playing %s on Cros device', 132 golden_file.path) 133 usb_out.start_playback() 134 135 time.sleep(self.RECORD_SECONDS) 136 137 linein.stop_recording() 138 logging.info('Stopped recording from Chameleon.') 139 140 audio_test_utils.dump_cros_audio_logs( 141 host, audio_facade, self.resultsdir, 'after_recording') 142 143 usb_out.stop_playback() 144 145 linein.read_recorded_binary() 146 logging.info('Read recorded binary from Chameleon.') 147 148 golden_file.delete() 149 150 recorded_file = os.path.join(self.resultsdir, "recorded.raw") 151 logging.info('Saving recorded data to %s', recorded_file) 152 linein.save_file(recorded_file) 153 154 diagnostic_path = os.path.join( 155 self.resultsdir, 156 'audio_diagnostics.txt.after_recording') 157 logging.info('Examine diagnostic file at %s', diagnostic_path) 158 diag_warning_msg = audio_test_utils.examine_audio_diagnostics( 159 diagnostic_path) 160 if diag_warning_msg: 161 logging.warning(diag_warning_msg) 162 163 # Raise error.TestFail if there is issue. 164 audio_test_utils.check_recorded_frequency( 165 golden_file, linein, check_artifacts=check_quality) 166