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 audio volume test using the Chameleon board.""" 6 7import logging 8import os 9import time 10 11from autotest_lib.client.cros.chameleon import audio_test_utils 12from autotest_lib.client.cros.chameleon import chameleon_audio_ids 13from autotest_lib.client.cros.chameleon import chameleon_audio_helper 14from autotest_lib.server.cros.audio import audio_test 15from autotest_lib.server.cros.multimedia import remote_facade_factory 16 17 18class audio_AudioArtifacts(audio_test.AudioTest): 19 """Server side audio artifacts test. 20 21 This test talks to a Chameleon board and a Cros device to detect 22 audio artifacts from the Cros device. 23 24 """ 25 version = 1 26 RECORD_SECONDS = 20 27 DELAY_AFTER_BINDING = 0.5 28 KEEP_VOLUME_SECONDS = 0.5 29 START_PLAYBACK_SECONDS = 0.5 30 31 def run_once(self, host, source_id, sink_id, recorder_id, 32 golden_file, switch_hsp=False, 33 mute_duration_in_secs=None, 34 volume_changes=None, 35 record_secs=None): 36 """Running audio volume test. 37 38 mute_duration_in_secs and volume_changes couldn't be both not None. 39 40 @param host: device under test CrosHost 41 @param source_id: An ID defined in chameleon_audio_ids for source. 42 @param sink_id: An ID defined in chameleon_audio_ids for sink if needed. 43 Currently this is only used on bluetooth. 44 @param recorder: An ID defined in chameleon_audio_ids for recording. 45 @param golden_file: A test file defined in audio_test_data. 46 @param switch_hsp: Run a recording process on Cros device. This is 47 to trigger Cros switching from A2DP to HSP. 48 @param mute_duration_in_secs: List of each duration of mute. For example, 49 [0.4, 0.6] will have two delays, each 50 duration will be 0.4 secs and 0.6 secs. 51 And, between delays, there will be 52 KEEP_VOLUME_SECONDS secs sine wave. 53 @param volume_changes: List consisting of -1 and +1, where -1 denoting 54 decreasing volume, +1 denoting increasing volume. 55 Between each changes, the volume will be kept for 56 KEEP_VOLUME_SECONDS secs. 57 @param record_secs: The duration of recording in seconds. If it is not 58 set, duration of the test data will be used. If 59 duration of test data is not set either, default 60 RECORD_SECONDS will be used. 61 62 """ 63 if (source_id == chameleon_audio_ids.CrosIds.SPEAKER and 64 not audio_test_utils.has_internal_speaker(host)): 65 return 66 67 chameleon_board = host.chameleon 68 factory = remote_facade_factory.RemoteFacadeFactory( 69 host, results_dir=self.resultsdir) 70 71 chameleon_board.setup_and_reset(self.outputdir) 72 73 widget_factory = chameleon_audio_helper.AudioWidgetFactory( 74 factory, host) 75 76 source = widget_factory.create_widget(source_id) 77 recorder = widget_factory.create_widget(recorder_id) 78 79 # Chameleon Mic does not need binding. 80 binding = (recorder_id != chameleon_audio_ids.ChameleonIds.MIC) 81 82 binder = None 83 84 if binding: 85 if sink_id: 86 sink = widget_factory.create_widget(sink_id) 87 binder = widget_factory.create_binder(source, sink, recorder) 88 else: 89 binder = widget_factory.create_binder(source, recorder) 90 91 start_volume, low_volume, high_volume = 75, 50, 100 92 93 if not record_secs: 94 if golden_file.duration_secs: 95 record_secs = golden_file.duration_secs 96 else: 97 record_secs = self.RECORD_SECONDS 98 logging.debug('Record duration: %f seconds', record_secs) 99 100 # Checks if the file is local or is served on web. 101 file_url = getattr(golden_file, 'url', None) 102 103 with chameleon_audio_helper.bind_widgets(binder): 104 # Checks the node selected by cras is correct. 105 time.sleep(self.DELAY_AFTER_BINDING) 106 audio_facade = factory.create_audio_facade() 107 108 audio_test_utils.dump_cros_audio_logs( 109 host, audio_facade, self.resultsdir, 'after_binding') 110 111 audio_facade.set_chrome_active_volume(start_volume) 112 113 audio_test_utils.check_output_port(audio_facade, source.port_id) 114 115 if switch_hsp: 116 audio_test_utils.switch_to_hsp(audio_facade) 117 118 if not file_url: 119 logging.info('Setting playback data on Cros device') 120 source.set_playback_data(golden_file) 121 122 logging.info('Start recording from Chameleon.') 123 recorder.start_recording() 124 125 if not file_url: 126 logging.info('Start playing %s on Cros device', 127 golden_file.path) 128 source.start_playback() 129 else: 130 logging.info('Start playing %s on Cros device using browser', 131 file_url) 132 browser_facade = factory.create_browser_facade() 133 tab_descriptor = browser_facade.new_tab(file_url) 134 135 if volume_changes: 136 time.sleep(self.START_PLAYBACK_SECONDS) 137 for x in volume_changes: 138 if x == -1: 139 audio_facade.set_chrome_active_volume(low_volume) 140 if x == +1: 141 audio_facade.set_chrome_active_volume(high_volume) 142 time.sleep(self.KEEP_VOLUME_SECONDS) 143 passed_time_secs = self.START_PLAYBACK_SECONDS 144 passed_time_secs += len(volume_changes) * self.KEEP_VOLUME_SECONDS 145 rest = max(0, record_secs - passed_time_secs) 146 time.sleep(rest) 147 elif mute_duration_in_secs: 148 time.sleep(self.START_PLAYBACK_SECONDS) 149 passed_time_seconds = self.START_PLAYBACK_SECONDS 150 for mute_secs in mute_duration_in_secs: 151 audio_facade.set_chrome_active_volume(0) 152 time.sleep(mute_secs) 153 audio_facade.set_chrome_active_volume(start_volume) 154 time.sleep(self.KEEP_VOLUME_SECONDS) 155 passed_time_seconds += mute_secs + self.KEEP_VOLUME_SECONDS 156 rest = max(0, record_secs - passed_time_seconds) 157 time.sleep(rest) 158 else: 159 time.sleep(record_secs) 160 161 recorder.stop_recording() 162 logging.info('Stopped recording from Chameleon.') 163 164 audio_test_utils.dump_cros_audio_logs( 165 host, audio_facade, self.resultsdir, 166 'after_recording') 167 168 if file_url: 169 browser_facade.close_tab(tab_descriptor) 170 else: 171 source.stop_playback() 172 173 recorder.read_recorded_binary() 174 logging.info('Read recorded binary from Chameleon.') 175 176 recorded_file = os.path.join( 177 self.resultsdir, "recorded.raw" ) 178 logging.info('Saving recorded data to %s', recorded_file) 179 recorder.save_file(recorded_file) 180 181 audio_test_utils.check_recorded_frequency( 182 golden_file, recorder, 183 check_artifacts=True, 184 mute_durations=mute_duration_in_secs, 185 volume_changes=volume_changes) 186 187