1# Lint as: python2, python3 2# Copyright 2015 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 test using the Chameleon board.""" 7 8from __future__ import print_function 9 10import logging 11import os 12import tempfile 13import time 14 15from autotest_lib.client.common_lib import error, file_utils 16from autotest_lib.client.cros.chameleon import audio_test_utils 17from autotest_lib.client.cros.chameleon import chameleon_audio_helper 18from autotest_lib.client.cros.chameleon import chameleon_audio_ids 19from autotest_lib.server.cros.audio import audio_test 20from autotest_lib.server.cros.multimedia import remote_facade_factory 21 22 23class audio_AudioQualityAfterSuspend(audio_test.AudioTest): 24 """Server side audio test. 25 26 This test talks to a Chameleon board and a Cros device to verify 27 audio function of the Cros device after suspend/resume. 28 29 """ 30 version = 1 31 RECORD_SECONDS = 10 32 SHORT_WAIT = 4 33 34 35 def check_correct_audio_node_selected(self): 36 """Checks the node selected by Cras is correct.""" 37 audio_test_utils.check_audio_nodes(self.audio_facade, self.audio_nodes) 38 39 40 def play_and_record(self, recorder_widget): 41 """Plays and records audio 42 43 @param recorder_widget: widget to do the recording 44 45 """ 46 audio_test_utils.dump_cros_audio_logs( 47 self.host, self.audio_facade, self.resultsdir, 48 'before_playback') 49 50 self.check_correct_audio_node_selected() 51 52 browser_facade = self.factory.create_browser_facade() 53 54 host_file = os.path.join('/tmp', 55 os.path.basename(self.test_playback_file)) 56 with tempfile.NamedTemporaryFile() as tmpfile: 57 file_utils.download_file(self.test_playback_file, tmpfile.name) 58 os.chmod(tmpfile.name, 0o0444) 59 self.host.send_file(tmpfile.name, host_file) 60 logging.debug('Copied the file on the DUT at %s', host_file) 61 62 # Play, wait for some time, and then start recording. 63 # This is to avoid artifact caused by codec initialization. 64 browser_facade.new_tab('file://' + host_file) 65 logging.info('Start playing %s on Cros device', host_file) 66 67 time.sleep(self.SHORT_WAIT) 68 audio_test_utils.suspend_resume_and_verify(self.host, self.factory) 69 time.sleep(self.SHORT_WAIT) 70 logging.debug('Start recording.') 71 recorder_widget.start_recording() 72 73 time.sleep(self.RECORD_SECONDS) 74 75 recorder_widget.stop_recording() 76 logging.debug('Stopped recording.') 77 78 audio_test_utils.dump_cros_audio_logs( 79 self.host, self.audio_facade, self.resultsdir, 80 'after_recording') 81 82 recorder_widget.read_recorded_binary() 83 84 85 def save_and_check_data(self, recorder_widget): 86 """Saves and checks the data from the recorder 87 88 @param recorder_widget: recorder widget to save data from 89 90 """ 91 recorded_file = os.path.join(self.resultsdir, 'recorded.raw') 92 logging.debug('Saving recorded data to %s', recorded_file) 93 recorder_widget.save_file(recorded_file) 94 95 # Removes the beginning of recorded data. This is to avoid artifact 96 # caused by codec initialization in the beginning of 97 # recording. 98 recorder_widget.remove_head(2.0) 99 100 # Removes noise by a lowpass filter. 101 recorder_widget.lowpass_filter(self.lowpass_freq) 102 recorded_file = os.path.join(self.resultsdir, 'recorded_filtered.raw') 103 logging.debug('Saving filtered data to %s', recorded_file) 104 recorder_widget.save_file(recorded_file) 105 106 # Compares data by frequency and returns the result. 107 audio_test_utils.check_recorded_frequency( 108 self.audio_test_data, recorder_widget, 109 second_peak_ratio=self.second_peak_ratio, 110 ignore_frequencies=self.ignore_frequencies, 111 check_anomaly=True) 112 113 114 def run_once(self, host, audio_nodes, audio_test_data, test_playback_file, 115 lowpass_freq=None, 116 bind_from=None, bind_to=None, 117 source=None, recorder=None, 118 tag=None): 119 """Runs the test main workflow 120 121 @param host: A host object representing the DUT. 122 @param audio_nodes: audio nodes supposed to be selected. 123 @param audio_test_data: audio test frequency defined in audio_test_data 124 @param test_playback_file: audio media file(wav, mp3,...) to be used 125 for testing 126 @param lowpass_freq: frequency noise filter. 127 @param bind_from: audio originating entity to be binded 128 should be defined in chameleon_audio_ids 129 @param bind_to: audio directed_to entity to be binded 130 should be defined in chameleon_audio_ids 131 @param source: source widget entity 132 should be defined in chameleon_audio_ids 133 @param recorder: recorder widget entity 134 should be defined in chameleon_audio_ids 135 136 """ 137 self.host = host 138 self.audio_nodes = audio_nodes 139 140 if (not audio_test_utils.has_internal_speaker(host) and 141 tag == "internal_speaker"): 142 return 143 144 self.second_peak_ratio = audio_test_utils.get_second_peak_ratio( 145 source_id=source, 146 recorder_id=recorder) 147 148 self.ignore_frequencies = None 149 if source == chameleon_audio_ids.CrosIds.SPEAKER: 150 self.ignore_frequencies = [50, 60] 151 152 self.audio_test_data = audio_test_data 153 self.lowpass_freq = lowpass_freq 154 self.test_playback_file = test_playback_file 155 chameleon_board = self.host.chameleon 156 self.factory = remote_facade_factory.RemoteFacadeFactory( 157 self.host, results_dir=self.resultsdir) 158 self.audio_facade = self.factory.create_audio_facade() 159 chameleon_board.setup_and_reset(self.outputdir) 160 widget_factory = chameleon_audio_helper.AudioWidgetFactory( 161 self.factory, host) 162 163 # Two widgets are binded in the factory if necessary. 164 binder_widget = None 165 source_widget = None 166 recorder_widget = None 167 if bind_from != None and bind_to != None: 168 source_widget = widget_factory.create_widget(bind_from) 169 recorder_widget = widget_factory.create_widget(bind_to) 170 binder_widget = widget_factory.create_binder(source_widget, 171 recorder_widget) 172 elif source != None and recorder != None: 173 source_widget = widget_factory.create_widget(source) 174 recorder_widget = widget_factory.create_widget(recorder) 175 else: 176 raise error.TestError('Test configuration or setup problem.') 177 178 self.audio_board = chameleon_board.get_audio_board() 179 180 if binder_widget: 181 # Headphone test which requires Chameleon LINEIN and DUT headphones 182 # binding. 183 with chameleon_audio_helper.bind_widgets(binder_widget): 184 self.play_and_record(recorder_widget) 185 else: 186 # Internal speakers test. 187 self.play_and_record(recorder_widget) 188 189 self.save_and_check_data(recorder_widget) 190