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 ARC audio playback test using the Chameleon board.""" 6 7import logging 8import os 9import time 10 11from autotest_lib.client.bin import utils 12from autotest_lib.client.cros.chameleon import audio_test_utils 13from autotest_lib.client.cros.chameleon import chameleon_audio_helper 14from autotest_lib.client.cros.chameleon import chameleon_audio_ids 15from autotest_lib.client.cros.multimedia import arc_resource_common 16from autotest_lib.server import autotest 17from autotest_lib.server.cros.audio import audio_test 18from autotest_lib.server.cros.multimedia import remote_facade_factory 19 20 21class audio_AudioARCPlayback(audio_test.AudioTest): 22 """Server side ARC audio playback test. 23 24 This test talks to a Chameleon board and a Cros device to verify 25 audio playback function of the Cros device with ARC. 26 27 """ 28 version = 1 29 DELAY_AFTER_BINDING = 0.5 30 WAIT_CLIENT_READY_TIMEOUT_SECS = 150 31 WAIT_PLAYBACK_SECS = 10 32 33 def run_once(self, host, source_id, sink_id, recorder_id, 34 golden_file, switch_hsp=False): 35 """Runs record test through ARC on Cros device. 36 37 @param host: device under test, a CrosHost. 38 @param source_id: An ID defined in chameleon_audio_ids for source. 39 @param sink_id: An ID defined in chameleon_audio_ids for sink if needed. 40 Currently this is only used on bluetooth. 41 @param recorder_id: An ID defined in chameleon_audio_ids for recording. 42 @param golden_file: A test file defined in audio_test_data. 43 @param switch_hsp: Run a recording process on Cros device. This is 44 to trigger Cros switching from A2DP to HSP. 45 46 """ 47 self.host = host 48 49 if (source_id == chameleon_audio_ids.CrosIds.SPEAKER and 50 not audio_test_utils.has_internal_speaker(host)): 51 return 52 53 self.client_at = None 54 55 # Runs a client side test to start Chrome and install Play Music app. 56 self.setup_playmusic_app() 57 58 # Do not start Chrome because client side test had started it. 59 # Do not install autotest because client side test had installed it. 60 factory = remote_facade_factory.RemoteFacadeFactory( 61 host, no_chrome=True, install_autotest=False, 62 results_dir=self.resultsdir) 63 64 # Setup Chameleon and create widgets. 65 host.chameleon.setup_and_reset(self.outputdir) 66 67 widget_factory = chameleon_audio_helper.AudioWidgetFactory( 68 factory, host) 69 70 source = widget_factory.create_widget(source_id, use_arc=True) 71 recorder = widget_factory.create_widget(recorder_id) 72 73 # Chameleon Mic does not need binding. 74 binding = (recorder_id != chameleon_audio_ids.ChameleonIds.MIC) 75 76 binder = None 77 78 if binding: 79 if sink_id: 80 sink = widget_factory.create_widget(sink_id) 81 binder = widget_factory.create_binder(source, sink, recorder) 82 else: 83 binder = widget_factory.create_binder(source, recorder) 84 85 # Second peak ratio is determined by quality of audio path. 86 second_peak_ratio = audio_test_utils.get_second_peak_ratio( 87 source_id=source_id, 88 recorder_id=recorder_id, 89 is_hsp=switch_hsp) 90 91 with chameleon_audio_helper.bind_widgets(binder): 92 time.sleep(self.DELAY_AFTER_BINDING) 93 94 audio_facade = factory.create_audio_facade() 95 96 audio_test_utils.dump_cros_audio_logs( 97 host, audio_facade, self.resultsdir, 'after_binding') 98 99 # Checks the node selected by CRAS is correct. 100 audio_test_utils.check_output_port(audio_facade, source.port_id) 101 102 if switch_hsp: 103 audio_test_utils.switch_to_hsp(audio_facade) 104 105 logging.info('Setting playback file on Cros device') 106 source.set_playback_data(golden_file) 107 108 logging.info('Start recording from Chameleon') 109 recorder.start_recording() 110 111 logging.info('Start playing %s on Cros device', 112 golden_file.path) 113 source.start_playback() 114 115 time.sleep(self.WAIT_PLAYBACK_SECS) 116 117 recorder.stop_recording() 118 logging.info('Stopped recording from Chameleon.') 119 120 audio_test_utils.dump_cros_audio_logs( 121 host, audio_facade, self.resultsdir, 122 'after_recording') 123 124 recorder.read_recorded_binary() 125 logging.info('Read recorded binary from Chameleon.') 126 127 recorded_file = os.path.join(self.resultsdir, "recorded.raw") 128 logging.info('Saving recorded data to %s', recorded_file) 129 recorder.save_file(recorded_file) 130 131 audio_test_utils.check_recorded_frequency( 132 golden_file, recorder, 133 second_peak_ratio=second_peak_ratio) 134 135 136 def run_client_side_test(self): 137 """Runs a client side test on Cros device in background.""" 138 self.client_at = autotest.Autotest(self.host) 139 logging.info('Start running client side test %s', 140 arc_resource_common.PlayMusicProps.TEST_NAME) 141 self.client_at.run_test( 142 arc_resource_common.PlayMusicProps.TEST_NAME, 143 background=True) 144 145 146 def setup_playmusic_app(self): 147 """Setups Play Music app on Cros device. 148 149 Runs a client side test on Cros device to start Chrome and ARC and 150 install Play Music app. 151 Wait for it to be ready. 152 153 """ 154 # Removes ready tag that server side test should wait for later. 155 self.remove_ready_tag() 156 157 # Runs the client side test. 158 self.run_client_side_test() 159 160 logging.info('Waiting for client side Play Music app to be ready') 161 162 # Waits for ready tag to be posted by client side test. 163 utils.poll_for_condition(condition=self.ready_tag_exists, 164 timeout=self.WAIT_CLIENT_READY_TIMEOUT_SECS, 165 desc='Wait for client side test being ready', 166 sleep_interval=1) 167 168 logging.info('Client side Play Music app is ready') 169 170 171 def cleanup(self): 172 """Cleanup of the test.""" 173 self.touch_exit_tag() 174 super(audio_AudioARCPlayback, self).cleanup() 175 176 177 def remove_ready_tag(self): 178 """Removes ready tag on Cros device.""" 179 if self.ready_tag_exists(): 180 self.host.run(command='rm %s' % ( 181 arc_resource_common.PlayMusicProps.READY_TAG_FILE)) 182 183 184 def touch_exit_tag(self): 185 """Touches exit tag on Cros device to stop client side test.""" 186 self.host.run(command='touch %s' % ( 187 arc_resource_common.PlayMusicProps.EXIT_TAG_FILE)) 188 189 190 def ready_tag_exists(self): 191 """Checks if ready tag exists. 192 193 @returns: True if the tag file exists. False otherwise. 194 195 """ 196 return self.host.path_exists( 197 arc_resource_common.PlayMusicProps.READY_TAG_FILE) 198