1# Copyright (c) 2013 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 5import logging 6import time 7 8from autotest_lib.client.bin import test, utils 9from autotest_lib.client.common_lib import error 10from autotest_lib.client.cros.audio import alsa_utils 11from autotest_lib.client.cros.audio import audio_spec 12from autotest_lib.client.cros.audio import cras_utils 13 14APLAY_FILE = '/dev/zero' # raw data 15 16# Expected results of 'aplay -v' commands. 17APLAY_EXPECTED = set([ 18 ('stream', 'PLAYBACK')]) 19 20 21def _play_audio(device_name, duration=1): 22 """Play a tone and try to ensure it played properly. 23 24 Sample output from aplay -v: 25 26 Playing raw data '/dev/zero' : Signed 16 bit Little Endian, Rate 44100 Hz, 27 Stereo 28 Hardware PCM card 0 'HDA Intel PCH' device 0 subdevice 0 29 Its setup is: 30 stream : PLAYBACK 31 access : RW_INTERLEAVED format : S16_LE 32 subformat : STD 33 channels : 2 34 rate : 44100 35 exact rate : 44100 (44100/1) 36 msbits : 16 37 buffer_size : 16384 38 period_size : 4096 39 period_time : 92879 40 tstamp_mode : NONE 41 period_step : 1 42 avail_min : 4096 43 period_event : 0 44 start_threshold : 16384 45 stop_threshold : 16384 46 silence_threshold: 0 47 silence_size : 0 48 boundary : 4611686018427387904 49 appl_ptr : 0 50 hw_ptr : 0 51 52 @param device_name: The output device for aplay. 53 @param duration: Duration supplied to aplay. 54 @return String output from the command (may be empty). 55 @raises CmdError when cmd returns <> 0. 56 """ 57 cmd = ['aplay', 58 '-v', # show verbose details 59 '-D %s' % device_name, 60 '-d %d' % duration, 61 '-f cd', # format 62 APLAY_FILE, 63 '2>&1'] # verbose details 64 return utils.system_output(' '.join(cmd)).strip() 65 66 67def _check_play(device_name, duration, expected): 68 """Runs aplay command and checks the output against an expected result. 69 70 The expected results are compared as sets of tuples. 71 72 @param device_name: The output device for aplay. 73 @param duration: Duration supplied to aplay. 74 @param expected: The set of expected tuples. 75 @raises error.TestError for invalid output or invalidly matching expected. 76 """ 77 error_msg = 'invalid response from aplay' 78 results = _play_audio(device_name, duration) 79 if not results.startswith("Playing raw data '%s' :" % APLAY_FILE): 80 raise error.TestError('%s: %s' % (error_msg, results)) 81 result_set = utils.set_from_keyval_output(results, '[\s]*:[\s]*') 82 if set(expected) <= result_set: 83 return 84 raise error.TestError('%s: expected=%s.' % 85 (error_msg, sorted(set(expected) - result_set))) 86 87 88class audio_Aplay(test.test): 89 """Checks that simple aplay functions correctly.""" 90 version = 1 91 92 def run_once(self, duration=1, test_headphone=False): 93 """Run aplay and verify its output is as expected. 94 95 @param duration: The duration to run aplay in seconds. 96 @param test_headphone: If the value is true, test a headphone. If false, 97 test an internal speaker. 98 """ 99 100 # Check CRAS server is alive. If not, restart it and wait a second to 101 # get server ready. 102 if utils.get_service_pid('cras') == 0: 103 logging.debug("CRAS server is down. Restart it.") 104 utils.start_service('cras', ignore_status=True) 105 time.sleep(1) 106 107 # Skip test if there is no internal speaker on the board. 108 if not test_headphone: 109 board_type = utils.get_board_type() 110 board_name = utils.get_board() 111 if not audio_spec.has_internal_speaker(board_type, board_name): 112 logging.debug("No internal speaker. Skipping the test.") 113 return 114 115 if test_headphone: 116 output_node = audio_spec.get_headphone_node(utils.get_board()) 117 else: 118 output_node = "INTERNAL_SPEAKER" 119 logging.debug("Test output device %s", output_node) 120 121 cras_utils.set_single_selected_output_node(output_node) 122 123 cras_device_type = cras_utils.get_selected_output_device_type() 124 logging.debug("Selected output device type=%s", cras_device_type) 125 if cras_device_type != output_node: 126 raise error.TestFail("Fail to select output device.") 127 128 cras_device_name = cras_utils.get_selected_output_device_name() 129 logging.debug("Selected output device name=%s", cras_device_name) 130 if cras_device_name is None: 131 raise error.TestFail("Fail to get selected output device.") 132 133 alsa_device_name = alsa_utils.convert_device_name(cras_device_name) 134 135 # Stop CRAS to make sure the audio device won't be occupied. 136 utils.stop_service('cras', ignore_status=True) 137 try: 138 _check_play(alsa_device_name, duration, APLAY_EXPECTED) 139 finally: 140 #Restart CRAS 141 utils.start_service('cras', ignore_status=True) 142