1# Copyright 2015 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"""This module provides the audio board interface.""" 5 6import logging 7 8from autotest_lib.client.cros.chameleon import chameleon_audio_ids as ids 9 10 11class AudioBoard(object): 12 """AudioBoard is an abstraction of an audio board on a Chameleon board. 13 14 It provides methods to control audio board. 15 16 A ChameleonConnection object is passed to the construction. 17 18 """ 19 20 def __init__(self, chameleon_connection): 21 """Constructs an AudioBoard. 22 23 @param chameleon_connection: A ChameleonConnection object. 24 25 @returns: An AudioBoard object. 26 27 """ 28 self._audio_buses = { 29 1: AudioBus(1, chameleon_connection), 30 2: AudioBus(2, chameleon_connection) 31 } 32 self._chameleon_connection = chameleon_connection 33 self._jack_plugger = None 34 self._bluetooth_controller = BluetoothController(chameleon_connection) 35 36 def get_audio_bus(self, bus_index): 37 """Gets an audio bus on this audio board. 38 39 @param bus_index: The bus index 1 or 2. 40 41 @returns: An AudioBus object. 42 43 """ 44 return self._audio_buses[bus_index] 45 46 def get_jack_plugger(self): 47 """Gets an AudioJackPlugger on this audio board. 48 49 @returns: An AudioJackPlugger object if there is an audio jack plugger. 50 None if there is no audio jack plugger. 51 @raises: 52 AudioJackPluggerException if there is no jack plugger on this audio 53 board. 54 55 """ 56 if self._jack_plugger is None: 57 try: 58 self._jack_plugger = AudioJackPlugger( 59 self._chameleon_connection) 60 except AudioJackPluggerException as e: 61 logging.error( 62 'There is no jack plugger on this audio board. Please ' 63 'check the jack plugger if all labels are correctly ' 64 'configured.') 65 self._jack_plugger = None 66 return self._jack_plugger 67 68 def get_bluetooth_controller(self): 69 """Gets an BluetoothController on this audio board. 70 71 @returns: An BluetoothController object. 72 73 """ 74 return self._bluetooth_controller 75 76 77class AudioBus(object): 78 """AudioBus is an abstraction of an audio bus on an audio board. 79 80 It provides methods to control audio bus. 81 82 A ChameleonConnection object is passed to the construction. 83 84 @properties: 85 bus_index: The bus index 1 or 2. 86 87 """ 88 # Maps port id defined in chameleon_audio_ids to endpoint name used in 89 # chameleond audio bus API. 90 _PORT_ID_AUDIO_BUS_ENDPOINT_MAP = { 91 ids.ChameleonIds.LINEIN: 'Chameleon FPGA line-in', 92 ids.ChameleonIds.LINEOUT: 'Chameleon FPGA line-out', 93 ids.CrosIds.HEADPHONE: 'Cros device headphone', 94 ids.CrosIds.EXTERNAL_MIC: 'Cros device external microphone', 95 ids.PeripheralIds.SPEAKER: 'Peripheral speaker', 96 ids.PeripheralIds.MIC: 'Peripheral microphone', 97 ids.PeripheralIds.BLUETOOTH_DATA_RX: 'Bluetooth module output', 98 ids.PeripheralIds.BLUETOOTH_DATA_TX: 'Bluetooth module input' 99 } 100 101 class AudioBusSnapshot(object): 102 """Abstracts the snapshot of AudioBus for user to restore it later.""" 103 104 def __init__(self, endpoints): 105 """Initializes an AudioBusSnapshot. 106 107 @param endpoints: A set of endpoints to keep a copy. 108 109 """ 110 self._endpoints = endpoints.copy() 111 112 def __init__(self, bus_index, chameleon_connection): 113 """Constructs an AudioBus. 114 115 @param bus_index: The bus index 1 or 2. 116 @param chameleon_connection: A ChameleonConnection object. 117 118 """ 119 self.bus_index = bus_index 120 self._chameleond_proxy = chameleon_connection 121 self._connected_endpoints = set() 122 123 def _get_endpoint_name(self, port_id): 124 """Gets the endpoint name used in audio bus API. 125 126 @param port_id: A string, that is, id in ChameleonIds, CrosIds, or 127 PeripheralIds defined in chameleon_audio_ids. 128 129 @returns: The endpoint name for the port used in audio bus API. 130 131 """ 132 return self._PORT_ID_AUDIO_BUS_ENDPOINT_MAP[port_id] 133 134 def _connect_endpoint(self, endpoint): 135 """Connects an endpoint to audio bus. 136 137 @param endpoint: An endpoint name in _PORT_ID_AUDIO_BUS_ENDPOINT_MAP. 138 139 """ 140 logging.debug('Audio bus %s is connecting endpoint %s', self.bus_index, 141 endpoint) 142 self._chameleond_proxy.AudioBoardConnect(self.bus_index, endpoint) 143 self._connected_endpoints.add(endpoint) 144 145 def _disconnect_endpoint(self, endpoint): 146 """Disconnects an endpoint from audio bus. 147 148 @param endpoint: An endpoint name in _PORT_ID_AUDIO_BUS_ENDPOINT_MAP. 149 150 """ 151 logging.debug('Audio bus %s is disconnecting endpoint %s', 152 self.bus_index, endpoint) 153 self._chameleond_proxy.AudioBoardDisconnect(self.bus_index, endpoint) 154 self._connected_endpoints.remove(endpoint) 155 156 def connect(self, port_id): 157 """Connects an audio port to this audio bus. 158 159 @param port_id: A string, that is, id in ChameleonIds, CrosIds, or 160 PeripheralIds defined in chameleon_audio_ids. 161 162 """ 163 endpoint = self._get_endpoint_name(port_id) 164 self._connect_endpoint(endpoint) 165 166 def disconnect(self, port_id): 167 """Disconnects an audio port from this audio bus. 168 169 @param port_id: A string, that is, id in ChameleonIds, CrosIds, or 170 PeripheralIds defined in chameleon_audio_ids. 171 172 """ 173 endpoint = self._get_endpoint_name(port_id) 174 self._disconnect_endpoint(endpoint) 175 176 def clear(self): 177 """Disconnects all audio port from this audio bus.""" 178 self._disconnect_all_endpoints() 179 180 def _disconnect_all_endpoints(self): 181 """Disconnects all endpoints from this audio bus.""" 182 for endpoint in self._connected_endpoints.copy(): 183 self._disconnect_endpoint(endpoint) 184 185 def get_snapshot(self): 186 """Gets the snapshot of AudioBus so user can restore it later. 187 188 @returns: An AudioBus.AudioBusSnapshot object. 189 190 """ 191 return self.AudioBusSnapshot(self._connected_endpoints) 192 193 def restore_snapshot(self, snapshot): 194 """Restore the snapshot. 195 196 @param: An AudioBus.AudioBusSnapshot object got from get_snapshot. 197 198 """ 199 self._disconnect_all_endpoints() 200 logging.debug('Restoring snapshot with %s', snapshot._endpoints) 201 for endpoint in snapshot._endpoints: 202 self._connect_endpoint(endpoint) 203 204 205class AudioJackPluggerException(Exception): 206 """Errors in AudioJackPlugger.""" 207 pass 208 209 210class AudioJackPlugger(object): 211 """AudioJackPlugger is an abstraction of plugger controlled by audio board. 212 213 There is a motor in the audio box which can plug/unplug 3.5mm 4-ring 214 audio cable to/from audio jack of Cros deivce. 215 This motor is controlled by audio board. 216 217 A ChameleonConnection object is passed to the construction. 218 219 """ 220 221 def __init__(self, chameleon_connection): 222 """Constructs an AudioJackPlugger. 223 224 @param chameleon_connection: A ChameleonConnection object. 225 226 @raises: 227 AudioJackPluggerException if there is no jack plugger on 228 this audio board. 229 230 """ 231 self._chameleond_proxy = chameleon_connection 232 if not self._chameleond_proxy.AudioBoardHasJackPlugger(): 233 raise AudioJackPluggerException( 234 'There is no jack plugger on audio board. ' 235 'Perhaps the audio board is not connected to audio box.') 236 237 def plug(self): 238 """Plugs the audio cable into audio jack of Cros device.""" 239 self._chameleond_proxy.AudioBoardAudioJackPlug() 240 logging.info('Plugged 3.5mm audio cable to Cros device.') 241 242 def unplug(self): 243 """Unplugs the audio cable from audio jack of Cros device.""" 244 self._chameleond_proxy.AudioBoardAudioJackUnplug() 245 logging.info('Unplugged 3.5mm audio cable from Cros device.') 246 247 248class BluetoothController(object): 249 """An abstraction of bluetooth module on audio board. 250 251 There is a bluetooth module on the audio board. It can be controlled through 252 API provided by chameleon proxy. 253 254 """ 255 256 def __init__(self, chameleon_connection): 257 """Constructs an BluetoothController. 258 259 @param chameleon_connection: A ChameleonConnection object. 260 261 """ 262 self._chameleond_proxy = chameleon_connection 263 264 def reset(self): 265 """Resets the bluetooth module.""" 266 self._chameleond_proxy.AudioBoardResetBluetooth() 267 logging.info('Resets bluetooth module on audio board.') 268 269 def disable(self): 270 """Disables the bluetooth module.""" 271 self._chameleond_proxy.AudioBoardDisableBluetooth() 272 logging.info('Disables bluetooth module on audio board.') 273 274 def is_enabled(self): 275 """Checks if the bluetooth module is enabled. 276 277 @returns: True if bluetooth module is enabled. False otherwise. 278 279 """ 280 return self._chameleond_proxy.AudioBoardIsBluetoothEnabled() 281