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