Owen Lin | 21d49eb | 2013-12-03 10:47:58 +0800 | [diff] [blame^] | 1 | # Copyright (c) 2013 The Chromium 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 shlex |
| 6 | import subprocess |
| 7 | |
| 8 | from autotest_lib.client.cros.audio import cmd_utils |
| 9 | |
| 10 | ARECORD_PATH='/usr/bin/arecord' |
| 11 | APLAY_PATH='/usr/bin/aplay' |
| 12 | |
| 13 | def _get_format_args(channels, bits, rate): |
| 14 | args = ['-c', str(channels)] |
| 15 | args += ['-f', 'S%d_LE' % bits] |
| 16 | args += ['-r', str(rate)] |
| 17 | return args |
| 18 | |
| 19 | |
| 20 | def _get_default_device(): |
| 21 | return 'plughw:%d' % get_default_soundcard_id() |
| 22 | |
| 23 | |
| 24 | def playback(*args, **kargs): |
| 25 | '''A helper funciton to execute playback_cmd.''' |
| 26 | cmd_utils.execute(playback_cmd(*args, **kargs)) |
| 27 | |
| 28 | |
| 29 | def playback_cmd( |
| 30 | input, duration=None, channels=2, bits=16, rate=44100, device=None): |
| 31 | '''Plays the given input audio by the ALSA utility: 'aplay'. |
| 32 | |
| 33 | @param input: The input audio to be played. |
| 34 | @param duration: The length of the playback (in seconds). |
| 35 | @param channels: The number of channels of the input audio. |
| 36 | @param bits: The number of bits of each audio sample. |
| 37 | @param rate: The sampling rate. |
| 38 | @param device: The device to play the audio on. |
| 39 | ''' |
| 40 | args = [APLAY_PATH] |
| 41 | if duration is not None: |
| 42 | args += ['-d', str(duration)] |
| 43 | args += _get_format_args(channels, bits, rate) |
| 44 | if device is None: |
| 45 | device = _get_default_device() |
| 46 | args += ['-D', device] |
| 47 | args += [input] |
| 48 | return args |
| 49 | |
| 50 | |
| 51 | def record(*args, **kargs): |
| 52 | '''A helper function to execute record_cmd.''' |
| 53 | cmd_utils.execute(record_cmd(*args, **kargs)) |
| 54 | |
| 55 | |
| 56 | def record_cmd( |
| 57 | output, duration=None, channels=2, bits=16, rate=44100, device=None): |
| 58 | '''Records the audio to the specified output by ALSA utility: 'arecord'. |
| 59 | |
| 60 | @param output: The filename where the recorded audio will be stored to. |
| 61 | @param duration: The length of the recording (in seconds). |
| 62 | @param channels: The number of channels of the recorded audio. |
| 63 | @param bits: The number of bits of each audio sample. |
| 64 | @param rate: The sampling rate. |
| 65 | @param device: The device used to recorded the audio from. |
| 66 | ''' |
| 67 | args = [ARECORD_PATH] |
| 68 | if duration is not None: |
| 69 | args += ['-d', str(duration)] |
| 70 | args += _get_format_args(channels, bits, rate) |
| 71 | if device is None: |
| 72 | device = _get_default_device() |
| 73 | args += ['-D', device] |
| 74 | args += [output] |
| 75 | return args |
| 76 | |
| 77 | |
| 78 | _default_soundcard_id = -1 |
| 79 | |
| 80 | def get_default_soundcard_id(): |
| 81 | '''Gets the ID of the default soundcard. |
| 82 | |
| 83 | @raise RuntimeError: if it fails to find the default soundcard id. |
| 84 | ''' |
| 85 | global _default_soundcard_id |
| 86 | if _default_soundcard_id == -1: |
| 87 | _default_soundcard_id = _find_default_soundcard_id() |
| 88 | |
| 89 | if _default_soundcard_id is None: |
| 90 | raise RuntimeError('no soundcard found') |
| 91 | return _default_soundcard_id |
| 92 | |
| 93 | |
| 94 | def _find_default_soundcard_id(): |
| 95 | '''Finds the id of the default hardware soundcard.''' |
| 96 | |
| 97 | # If there is only one card, choose it; otherwise, |
| 98 | # choose the first card with controls named 'Speaker' |
| 99 | cmd = 'amixer -c %d scontrols' |
| 100 | id = 0 |
| 101 | while True: |
| 102 | p = cmd_utils.popen(shlex.split(cmd % id), stdout=subprocess.PIPE) |
| 103 | output, _ = p.communicate() |
| 104 | if p.wait() != 0: # end of the card list |
| 105 | break; |
| 106 | if 'speaker' in output.lower(): |
| 107 | return id |
| 108 | id = id + 1 |
| 109 | |
| 110 | # If there is only one soundcard, return it, else return not found (None) |
| 111 | return 0 if id == 1 else None |