| # Copyright (c) 2012 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. |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.bin import test, utils |
| import logging |
| import os |
| import re |
| |
| class sound_infrastructure(test.test): |
| """ |
| Tests that the expected sound infrastructure is present. |
| |
| If a file is found to be missing, that would imply that the driver |
| has changed, and this will have an impact on the entire sound |
| system. |
| |
| Before submitting the fixes, test & verify: |
| |
| o Sound controls still work on each affected target device |
| |
| Volume Up, Volume Down, Mute |
| Any UI for controlling AV output |
| |
| o I/O devices continue to work |
| |
| Headphone, |
| Internal Speakers |
| HDMI |
| Internal Mic |
| |
| o To create 'files' data file: |
| |
| Execute the following on the DUT: |
| |
| tar --absolute-names -c /dev/snd /proc/asound 2>/dev/null| \ |
| tar -t 2>/dev/null|sed -e 's./$..g' >{codec-name}.files |
| |
| {codec-name} should be replaced with the name of the codec. |
| Replace spaces in the codec name with '_'. |
| See get_codec() to help determine the name of the codec. |
| """ |
| version = 1 |
| |
| codec_info = { |
| 'ALL': { # Things common to all sound codecs |
| 'files': [ |
| '/etc/init/cras.conf', # Upstart script, from ADHD package |
| '/etc/asound.state', # Factory defaults. From ADHD. |
| '/usr/bin/alsamixer', |
| '/usr/bin/amixer', |
| '/usr/sbin/alsactl', |
| '/usr/share/alsa/init/00main', |
| '/usr/share/alsa/init/default', |
| '/usr/share/alsa/init/hda', |
| '/usr/share/alsa/init/help', |
| '/usr/share/alsa/init/info', |
| '/usr/share/alsa/init/test', |
| ] |
| }, |
| |
| 'WM8903': { |
| 'files' : [ ], |
| }, |
| |
| 'ALC271X': { |
| 'files' : [ ], |
| }, |
| |
| 'Cirrus Analog': { |
| 'files' : [ ], |
| }, |
| |
| 'ALC269VB': { |
| 'files' : [ ], |
| }, |
| |
| 'ALC272': { |
| 'files' : [ ], |
| } |
| } |
| |
| # These are the card index patterns that may appear in the |
| # filenames. We will replace the card index with the actual value |
| # before matching the filename. For example, if the actual card |
| # index is 1, we will change "/dev/snd/controlC0" into |
| # "/dev/snd/controlC1" before matching. |
| card_patterns = [ |
| "^/dev/snd/controlC(\d+)", |
| "^/dev/snd/hwC(\d+)", |
| "^/dev/snd/pcmC(\d+)", |
| "^/proc/asound/card(\d+)", |
| ] |
| |
| def replace_card_index(self, input): |
| for p in self.card_patterns: |
| m = re.match(p, input) |
| if m is None: continue |
| start, end = m.span(1) |
| return input[:start] + str(self.card_index) + input[end:] |
| return input |
| |
| # Finds a card with the given codec name. Returns (found, card_index) |
| def find_card(self, codec): |
| r = utils.run("aplay -l|grep -e '%s'" % (codec), ignore_status = True, |
| stdout_tee = utils.TEE_TO_LOGS, |
| stderr_tee = utils.TEE_TO_LOGS) |
| if r.exit_status != 0: |
| return False, 0 |
| m = re.match("card (\d+):", r.stdout) |
| if m is None: |
| return False, 0 |
| return True, int(m.group(1)) |
| |
| def exec_cmd(self, cmd): |
| return utils.system(cmd, ignore_status = True) |
| |
| def pathname_must_exist(self, pathname): |
| pathname = self.replace_card_index(pathname) |
| if not os.path.exists(pathname): |
| logging.error("File missing: '%s'", pathname) |
| return False |
| return True |
| |
| # Returns (codec, card_index) |
| def get_codec(self): |
| # When the codec cannot be determined, the whole test cannot |
| # proceed. The unknown codec name must be added to 'codecs' |
| # below, and the associated attributes must be put into |
| # 'codec_info' above. |
| codecs = [ 'ALC272', # Mario, Alex |
| 'WM8903', # Seaboard, Aebl, Kaen, Asymptote |
| 'ALC269VB', # ZGB |
| 'Cirrus Analog' # Stumpy |
| ] |
| for codec in codecs: |
| found, index = self.find_card(codec) |
| if found: |
| return codec, index |
| raise error.TestError('Unable to determine sound codec.') |
| |
| def get_codec_basename(self, codec): |
| return codec.replace(' ', '_') |
| |
| def get_data_pathname(self, filename): |
| return os.path.join(self.bindir, filename) |
| |
| def validate_files(self, files_list): |
| errors = 0 |
| for f in files_list: |
| if not self.pathname_must_exist(f): |
| errors += 1 |
| return errors |
| |
| def validate_codec(self, codec): |
| err_str = '' |
| errors = self.validate_files(codec['files']) |
| if errors: |
| err_str += " files: %d" % errors |
| |
| if err_str != '': |
| err_str = "(%s)%s" % (self._codec_basename, err_str) |
| return err_str |
| |
| def read_codec_data(self, codec): |
| self._codec_basename = self.get_codec_basename(codec) |
| |
| # Read files which must be present. |
| pathname = self.get_data_pathname(self._codec_basename + ".files") |
| self.codec_info[codec]['files'] = [line.strip() for line in |
| open(pathname)] |
| |
| def run_once(self): |
| codec, self.card_index = self.get_codec() |
| self.read_codec_data(codec) |
| err_str = '' |
| if codec in self.codec_info: |
| err_str += self.validate_codec(self.codec_info['ALL']) |
| err_str += self.validate_codec(self.codec_info[codec]) |
| if err_str != '': |
| raise error.TestError("codec validation failed. %s" % |
| (err_str)) |
| else: |
| raise error.TestError("No test info for codec '%s'." % (codec)) |