Home | History | Annotate | Download | only in audio_AlsaAPI
      1 # Copyright 2016 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 
      5 import logging
      6 import os
      7 import re
      8 
      9 from autotest_lib.client.bin import test, utils
     10 from autotest_lib.client.common_lib import error
     11 from autotest_lib.client.cros.audio import alsa_utils
     12 
     13 class audio_AlsaAPI(test.test):
     14     """Checks that simple ALSA API functions correctly."""
     15     version = 2
     16     _SND_DEV_DIR = '/dev/snd/'
     17     _PLAYBACK_DEVICE_NAME = '^pcmC(\d+)D(\d+)p$'
     18     # A list of boards that do not correctly implement snd_pcm_drop, see
     19     # crosbug.com/p/51882
     20     _BOARDS_WITHOUT_DROP_SUPPORT  = ['banon', 'elm', 'samus', 'squawks']
     21     # A dict of list of (card name, device) to be skipped on some boards.
     22     _DEVICES_TO_BE_SKIPPED = {
     23         # On the following boards, devices 4,5,6 are HDMI devices.
     24         'asuka': {'sklnau8825max': [4, 5, 6]},
     25         'cave': {'sklnau8825max': [4, 5, 6]},
     26         'snappy': {'bxtda7219max': [4, 5, 6]},
     27         # Chell's HDMI device 4 can not be used without being plugged.
     28         # Also, its HDMI devices 5 and 6 are dummy devices.
     29         'chell': {'sklnau8825adi': [4, 5, 6]},
     30         # Kevin's device 3 is a DisplayPort device.
     31         'kevin': {'rk3399-gru-sound': [3]},
     32     }
     33 
     34     def run_once(self, to_test):
     35         """Run alsa_api_test binary and verify its result.
     36 
     37         Checks the source code of alsa_api_test in audiotest repo for detail.
     38 
     39         @param to_test: support these test items:
     40                         move: Checks snd_pcm_forward API.
     41                         fill: Checks snd_pcm_mmap_begin API.
     42                         drop: Checks snd_pcm_drop API.
     43 
     44         """
     45         # Skip test_drop on boards that do not implement snd_pcm_drop
     46         # correctly, as it cannot pass.
     47         board = utils.get_board().lower()
     48         if to_test == 'drop' and board in self._BOARDS_WITHOUT_DROP_SUPPORT:
     49             logging.info('Skipping test_drop for unsupported board: %s', board)
     50             return
     51 
     52         self._cardnames = alsa_utils.get_soundcard_names()
     53         self._devices = []
     54         self._find_sound_devices()
     55         method_name = '_test_' + to_test
     56         method = getattr(self, method_name)
     57 
     58         # Stop CRAS to make sure the audio device won't be occupied.
     59         utils.stop_service('cras', ignore_status=True)
     60 
     61         try:
     62             for card_index, device_index in self._devices:
     63                 device = 'hw:%s,%s' % (card_index, device_index)
     64                 method(device)
     65         finally:
     66             # Restart CRAS.
     67             utils.start_service('cras', ignore_status=True)
     68 
     69 
     70     def _skip_device(self, card_device):
     71         """Skips devices on some boards.
     72 
     73         @param card_device: A tuple of (card index, device index).
     74 
     75         @returns: True if the device should be skipped. False otherwise.
     76 
     77         """
     78         card_name = self._cardnames[card_device[0]]
     79 
     80         return card_device[1] in self._DEVICES_TO_BE_SKIPPED.get(
     81                 utils.get_board().lower(), {}).get(card_name, [])
     82 
     83 
     84     def _find_sound_devices(self):
     85         """Finds playback devices in sound device directory.
     86 
     87         @raises: error.TestError if there is no playback device.
     88         """
     89         filenames = os.listdir(self._SND_DEV_DIR)
     90         for filename in filenames:
     91             search = re.match(self._PLAYBACK_DEVICE_NAME, filename)
     92             if search:
     93                 card_device = (search.group(1), int(search.group(2)))
     94                 if not self._skip_device(card_device):
     95                     self._devices.append(card_device)
     96         if not self._devices:
     97             raise error.TestError('There is no playback device')
     98 
     99 
    100     def _make_alsa_api_test_command(self, option, device):
    101         """Makes command for alsa_api_test.
    102 
    103         @param option: same as to_test in run_once.
    104         @param device: device in hw:<card index>:<device index> format.
    105 
    106         @returns: The command in a list of args.
    107 
    108         """
    109         return ['alsa_api_test', '--device', device, '--%s' % option]
    110 
    111 
    112     def _test_move(self, device):
    113         """Runs alsa_api_test command and checks the return code.
    114 
    115         Test snd_pcm_forward can move appl_ptr to hw_ptr.
    116 
    117         @param device: device in hw:<card index>:<device index> format.
    118 
    119         @raises error.TestError if command fails.
    120 
    121         """
    122         ret = utils.system(
    123                 command=self._make_alsa_api_test_command('move', device),
    124                 ignore_status=True)
    125         if ret:
    126             raise error.TestError(
    127                     'ALSA API failed to move appl_ptr on device %s' % device)
    128 
    129 
    130     def _test_fill(self, device):
    131         """Runs alsa_api_test command and checks the return code.
    132 
    133         Test snd_pcm_mmap_begin can provide the access to the buffer, and memset
    134         can fill it with zeros without using snd_pcm_mmap_commit.
    135 
    136         @param device: device in hw:<card index>:<device index> format.
    137 
    138         @raises error.TestError if command fails.
    139 
    140         """
    141         ret = utils.system(
    142                 command=self._make_alsa_api_test_command('fill', device),
    143                 ignore_status=True)
    144         if ret:
    145             raise error.TestError(
    146                     'ALSA API failed to fill buffer on device %s' % device)
    147 
    148 
    149     def _test_drop(self, device):
    150         """Runs alsa_api_test command and checks the return code.
    151 
    152         Test snd_pcm_drop can stop playback and reset hw_ptr to 0 in hardware.
    153 
    154         @param device: device in hw:<card index>:<device index> format.
    155 
    156         @raises error.TestError if command fails.
    157 
    158         """
    159         ret = utils.system(
    160                 command=self._make_alsa_api_test_command('drop', device),
    161                 ignore_status=True)
    162         if ret:
    163             raise error.TestError(
    164                     'ALSA API failed to drop playback and reset hw_ptr'
    165                     'on device %s' % device)
    166