Home | History | Annotate | Download | only in chameleon
      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 """This module provides the audio widgets related to ARC used in audio tests."""
      6 
      7 import copy
      8 import tempfile
      9 
     10 from autotest_lib.client.cros.audio import audio_test_data
     11 from autotest_lib.client.cros.chameleon import audio_widget
     12 
     13 class CrosInputWidgetARCHandler(audio_widget.CrosInputWidgetHandler):
     14     """
     15 
     16     This class abstracts a Cros device audio input widget ARC handler.
     17 
     18     """
     19     # AMR-NB uses variable bit rates so we set sample_format to None.
     20     # Other format info are actually useless for sox because sox can read them
     21     # from file header.
     22     _SOURCE_FORMAT = dict(file_type='amr-nb',
     23                           sample_format=None,
     24                           channel=1,
     25                           rate=8000)
     26 
     27     def start_recording(self):
     28         """Starts recording audio through ARC."""
     29         self._audio_facade.start_arc_recording()
     30 
     31 
     32     def stop_recording(self):
     33         """Stops recording audio through ARC.
     34 
     35         @returns:
     36             A tuple (remote_path, format).
     37                 remote_path: The path to the recorded file on Cros device.
     38                 format: A dict containing:
     39                     file_type: 'raw'.
     40                     sample_format: 'S16_LE' for 16-bit signed integer in
     41                                    little-endian.
     42                     channel: channel number.
     43                     rate: sampling rate.
     44 
     45         """
     46         return (self._audio_facade.stop_arc_recording(),
     47                 self._DEFAULT_DATA_FORMAT)
     48 
     49 
     50     def get_recorded_binary(self, remote_path, record_format):
     51         """Gets remote recorded file binary from Cros device..
     52 
     53         Gets and reads recorded file from Cros device.
     54         The argument 'record_format' is what API user want on output.
     55         The real file format of file at 'remote_path' can be another source
     56         format. This method handles the format conversion from source format
     57         into record_format, and returns the converted binary.
     58 
     59         Handle the format conversion from source format into record_format.
     60 
     61         @param remote_path: The path to the recorded file on Cros device.
     62         @param record_format: The data format of returned binary.
     63                      A dict containing
     64                      file_type: 'raw' or 'wav'.
     65                      sample_format: 'S32_LE' for 32-bit signed integer in
     66                                     little-endian. Refer to aplay manpage for
     67                                     other formats.
     68                      channel: channel number.
     69                      rate: sampling rate.
     70 
     71         @returns: The recorded binary.
     72 
     73         @raises: CrosInputWidgetHandlerError if record_format is not correct.
     74 
     75         """
     76         if record_format != self._DEFAULT_DATA_FORMAT:
     77             raise audio_widget.CrosInputWidgetHandlerError(
     78                     'Record format %r is not valid' % record_format)
     79 
     80         ext = '.' + self._SOURCE_FORMAT['file_type']
     81         with tempfile.NamedTemporaryFile(prefix='recorded_', suffix=ext) as f:
     82             self._audio_facade.get_recorded_file(remote_path, f.name)
     83 
     84             # Handles conversion from source format into record_format.
     85             test_data = audio_test_data.AudioTestData(
     86                     self._SOURCE_FORMAT, f.name)
     87             converted_test_data = test_data.convert(record_format, 1.0)
     88             try:
     89                 return converted_test_data.get_binary()
     90             finally:
     91                 converted_test_data.delete()
     92 
     93 
     94 class CrosOutputWidgetARCHandlerError(Exception):
     95     """Error in CrosOutputWidgetARCHandler."""
     96     pass
     97 
     98 
     99 class CrosOutputWidgetARCHandler(audio_widget.CrosOutputWidgetHandler):
    100     """This class abstracts a Cros device audio output widget ARC handler."""
    101     _SUPPORTED_FILE_TYPES = ['wav', 'mp3']
    102     _DEFAULT_FILE_TYPE = 'wav'
    103 
    104     def set_playback_data(self, test_data):
    105         """Sets data to play.
    106 
    107         @param test_data: An AudioTestData object.
    108 
    109         @returns: Path to the file in container on Cros host.
    110 
    111         """
    112         # Handle the format conversion because ARC does not recognize raw file.
    113         if test_data.data_format['file_type'] not in self._SUPPORTED_FILE_TYPES:
    114             new_data_format = copy.deepcopy(test_data.data_format)
    115             new_data_format['file_type'] = self._DEFAULT_FILE_TYPE
    116             test_data = test_data.convert(new_data_format, 1.0)
    117         return self._audio_facade.set_arc_playback_file(test_data.path)
    118 
    119 
    120     def start_playback(self, path, blocking=False):
    121         """Starts playing audio.
    122 
    123         @param path: Path to the file to play in container on Cros host.
    124         @param blocking: Blocks this call until playback finishes.
    125 
    126         @raises: NotImplementedError if blocking is True.
    127 
    128         """
    129         if blocking:
    130             raise NotImplementedError(
    131                     'Blocking playback on ARC is not supported.')
    132         self._audio_facade.start_arc_playback(path)
    133 
    134 
    135     def stop_playback(self):
    136         """Stops playing audio."""
    137         self._audio_facade.stop_arc_playback()
    138