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