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): 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 94class CrosOutputWidgetARCHandlerError(Exception): 95 """Error in CrosOutputWidgetARCHandler.""" 96 pass 97 98 99class 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