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