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