audiovideo_Microphone - Refactor: Extract ALSA commands to alsa_utils.

BUG= None

TEST=Run the test on parrot

Change-Id: If92e5b02f9b014b2298e7b890220e7571ea5d055
Reviewed-on: https://chromium-review.googlesource.com/178590
Reviewed-by: Owen Lin <owenlin@chromium.org>
Commit-Queue: Owen Lin <owenlin@chromium.org>
Tested-by: Owen Lin <owenlin@chromium.org>
diff --git a/client/cros/audio/alsa_utils.py b/client/cros/audio/alsa_utils.py
new file mode 100644
index 0000000..1660272
--- /dev/null
+++ b/client/cros/audio/alsa_utils.py
@@ -0,0 +1,111 @@
+# Copyright (c) 2013 The Chromium 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 shlex
+import subprocess
+
+from autotest_lib.client.cros.audio import cmd_utils
+
+ARECORD_PATH='/usr/bin/arecord'
+APLAY_PATH='/usr/bin/aplay'
+
+def _get_format_args(channels, bits, rate):
+    args = ['-c', str(channels)]
+    args += ['-f', 'S%d_LE' % bits]
+    args += ['-r', str(rate)]
+    return args
+
+
+def _get_default_device():
+    return 'plughw:%d' % get_default_soundcard_id()
+
+
+def playback(*args, **kargs):
+    '''A helper funciton to execute playback_cmd.'''
+    cmd_utils.execute(playback_cmd(*args, **kargs))
+
+
+def playback_cmd(
+        input, duration=None, channels=2, bits=16, rate=44100, device=None):
+    '''Plays the given input audio by the ALSA utility: 'aplay'.
+
+    @param input: The input audio to be played.
+    @param duration: The length of the playback (in seconds).
+    @param channels: The number of channels of the input audio.
+    @param bits: The number of bits of each audio sample.
+    @param rate: The sampling rate.
+    @param device: The device to play the audio on.
+    '''
+    args = [APLAY_PATH]
+    if duration is not None:
+        args += ['-d', str(duration)]
+    args += _get_format_args(channels, bits, rate)
+    if device is None:
+        device = _get_default_device()
+    args += ['-D', device]
+    args += [input]
+    return args
+
+
+def record(*args, **kargs):
+    '''A helper function to execute record_cmd.'''
+    cmd_utils.execute(record_cmd(*args, **kargs))
+
+
+def record_cmd(
+        output, duration=None, channels=2, bits=16, rate=44100, device=None):
+    '''Records the audio to the specified output by ALSA utility: 'arecord'.
+
+    @param output: The filename where the recorded audio will be stored to.
+    @param duration: The length of the recording (in seconds).
+    @param channels: The number of channels of the recorded audio.
+    @param bits: The number of bits of each audio sample.
+    @param rate: The sampling rate.
+    @param device: The device used to recorded the audio from.
+    '''
+    args = [ARECORD_PATH]
+    if duration is not None:
+        args += ['-d', str(duration)]
+    args += _get_format_args(channels, bits, rate)
+    if device is None:
+        device = _get_default_device()
+    args += ['-D', device]
+    args += [output]
+    return args
+
+
+_default_soundcard_id = -1
+
+def get_default_soundcard_id():
+    '''Gets the ID of the default soundcard.
+
+    @raise RuntimeError: if it fails to find the default soundcard id.
+    '''
+    global _default_soundcard_id
+    if _default_soundcard_id == -1:
+        _default_soundcard_id = _find_default_soundcard_id()
+
+    if _default_soundcard_id is None:
+        raise RuntimeError('no soundcard found')
+    return _default_soundcard_id
+
+
+def _find_default_soundcard_id():
+    '''Finds the id of the default hardware soundcard.'''
+
+    # If there is only one card, choose it; otherwise,
+    # choose the first card with controls named 'Speaker'
+    cmd = 'amixer -c %d scontrols'
+    id = 0
+    while True:
+        p = cmd_utils.popen(shlex.split(cmd % id), stdout=subprocess.PIPE)
+        output, _ = p.communicate()
+        if p.wait() != 0: # end of the card list
+            break;
+        if 'speaker' in output.lower():
+            return id
+        id = id + 1
+
+    # If there is only one soundcard, return it, else return not found (None)
+    return 0 if id == 1 else None