| # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import logging |
| import time |
| |
| from autotest_lib.client.bin import test, utils |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.cros.audio import alsa_utils |
| from autotest_lib.client.cros.audio import audio_spec |
| from autotest_lib.client.cros.audio import cras_utils |
| |
| APLAY_FILE = '/dev/zero' # raw data |
| |
| # Expected results of 'aplay -v' commands. |
| APLAY_EXPECTED = set([ |
| ('stream', 'PLAYBACK')]) |
| |
| |
| def _play_audio(device_name, duration=1): |
| """Play a tone and try to ensure it played properly. |
| |
| Sample output from aplay -v: |
| |
| Playing raw data '/dev/zero' : Signed 16 bit Little Endian, Rate 44100 Hz, |
| Stereo |
| Hardware PCM card 0 'HDA Intel PCH' device 0 subdevice 0 |
| Its setup is: |
| stream : PLAYBACK |
| access : RW_INTERLEAVED format : S16_LE |
| subformat : STD |
| channels : 2 |
| rate : 44100 |
| exact rate : 44100 (44100/1) |
| msbits : 16 |
| buffer_size : 16384 |
| period_size : 4096 |
| period_time : 92879 |
| tstamp_mode : NONE |
| period_step : 1 |
| avail_min : 4096 |
| period_event : 0 |
| start_threshold : 16384 |
| stop_threshold : 16384 |
| silence_threshold: 0 |
| silence_size : 0 |
| boundary : 4611686018427387904 |
| appl_ptr : 0 |
| hw_ptr : 0 |
| |
| @param device_name: The output device for aplay. |
| @param duration: Duration supplied to aplay. |
| @return String output from the command (may be empty). |
| @raises CmdError when cmd returns <> 0. |
| """ |
| cmd = ['aplay', |
| '-v', # show verbose details |
| '-D %s' % device_name, |
| '-d %d' % duration, |
| '-f cd', # format |
| APLAY_FILE, |
| '2>&1'] # verbose details |
| return utils.system_output(' '.join(cmd)).strip() |
| |
| |
| def _check_play(device_name, duration, expected): |
| """Runs aplay command and checks the output against an expected result. |
| |
| The expected results are compared as sets of tuples. |
| |
| @param device_name: The output device for aplay. |
| @param duration: Duration supplied to aplay. |
| @param expected: The set of expected tuples. |
| @raises error.TestError for invalid output or invalidly matching expected. |
| """ |
| error_msg = 'invalid response from aplay' |
| results = _play_audio(device_name, duration) |
| if not results.startswith("Playing raw data '%s' :" % APLAY_FILE): |
| raise error.TestError('%s: %s' % (error_msg, results)) |
| result_set = utils.set_from_keyval_output(results, '[\s]*:[\s]*') |
| if set(expected) <= result_set: |
| return |
| raise error.TestError('%s: expected=%s.' % |
| (error_msg, sorted(set(expected) - result_set))) |
| |
| |
| class audio_Aplay(test.test): |
| """Checks that simple aplay functions correctly.""" |
| version = 1 |
| |
| def run_once(self, duration=1, output_node="INTERNAL_SPEAKER"): |
| """Run aplay and verify its output is as expected. |
| |
| @param duration: The duration to run aplay in seconds. |
| @param output_node: The type of output device to test. It should be |
| INTERNAL_SPEAKER or HEADPHONE. |
| """ |
| |
| # Check CRAS server is alive. If not, restart it and wait a second to |
| # get server ready. |
| if utils.get_service_pid('cras') == 0: |
| logging.debug("CRAS server is down. Restart it.") |
| utils.start_service('cras', ignore_status=True) |
| time.sleep(1) |
| |
| # Skip test if there is no internal speaker on the board. |
| if output_node == "INTERNAL_SPEAKER": |
| board_type = utils.get_board_type() |
| board_name = utils.get_board() |
| if not audio_spec.has_internal_speaker(board_type, board_name): |
| logging.debug("No internal speaker. Skipping the test.") |
| return |
| |
| cras_utils.set_single_selected_output_node(output_node) |
| |
| cras_device_type = cras_utils.get_selected_output_device_type() |
| logging.debug("Selected output device type=%s", cras_device_type) |
| if cras_device_type != output_node: |
| raise error.TestFail("Fail to select output device.") |
| |
| cras_device_name = cras_utils.get_selected_output_device_name() |
| logging.debug("Selected output device name=%s", cras_device_name) |
| if cras_device_name is None: |
| raise error.TestFail("Fail to get selected output device.") |
| |
| alsa_device_name = alsa_utils.convert_device_name(cras_device_name) |
| |
| # Stop CRAS to make sure the audio device won't be occupied. |
| utils.stop_service('cras', ignore_status=True) |
| try: |
| _check_play(alsa_device_name, duration, APLAY_EXPECTED) |
| finally: |
| #Restart CRAS |
| utils.start_service('cras', ignore_status=True) |