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