| # Copyright 2015 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """This module provides the audio board interface.""" |
| |
| import logging |
| |
| from autotest_lib.client.cros.chameleon import chameleon_audio_ids as ids |
| |
| |
| class AudioBoard(object): |
| """AudioBoard is an abstraction of an audio board on a Chameleon board. |
| |
| It provides methods to control audio board. |
| |
| A ChameleonConnection object is passed to the construction. |
| |
| """ |
| def __init__(self, chameleon_connection): |
| """Constructs an AudioBoard. |
| |
| @param chameleon_connection: A ChameleonConnection object. |
| |
| """ |
| self._audio_buses = { |
| 1: AudioBus(1, chameleon_connection), |
| 2: AudioBus(2, chameleon_connection)} |
| |
| self._jack_plugger = None |
| try: |
| self._jack_plugger = AudioJackPlugger(chameleon_connection) |
| except AudioJackPluggerException: |
| logging.warning( |
| 'There is no jack plugger on this audio board.') |
| self._jack_plugger = None |
| |
| self._bluetooth_controller = BluetoothController(chameleon_connection) |
| |
| |
| def get_audio_bus(self, bus_index): |
| """Gets an audio bus on this audio board. |
| |
| @param bus_index: The bus index 1 or 2. |
| |
| @returns: An AudioBus object. |
| |
| """ |
| return self._audio_buses[bus_index] |
| |
| |
| def get_jack_plugger(self): |
| """Gets an AudioJackPlugger on this audio board. |
| |
| @returns: An AudioJackPlugger object if there is an audio jack plugger. |
| None if there is no audio jack plugger. |
| |
| """ |
| return self._jack_plugger |
| |
| |
| def get_bluetooth_controller(self): |
| """Gets an BluetoothController on this audio board. |
| |
| @returns: An BluetoothController object. |
| |
| """ |
| return self._bluetooth_controller |
| |
| |
| class AudioBus(object): |
| """AudioBus is an abstraction of an audio bus on an audio board. |
| |
| It provides methods to control audio bus. |
| |
| A ChameleonConnection object is passed to the construction. |
| |
| @properties: |
| bus_index: The bus index 1 or 2. |
| |
| """ |
| # Maps port id defined in chameleon_audio_ids to endpoint name used in |
| # chameleond audio bus API. |
| _PORT_ID_AUDIO_BUS_ENDPOINT_MAP = { |
| ids.ChameleonIds.LINEIN: 'Chameleon FPGA line-in', |
| ids.ChameleonIds.LINEOUT: 'Chameleon FPGA line-out', |
| ids.CrosIds.HEADPHONE: 'Cros device headphone', |
| ids.CrosIds.EXTERNAL_MIC: 'Cros device external microphone', |
| ids.PeripheralIds.SPEAKER: 'Peripheral speaker', |
| ids.PeripheralIds.MIC: 'Peripheral microphone', |
| ids.PeripheralIds.BLUETOOTH_DATA_RX: |
| 'Bluetooth module output', |
| ids.PeripheralIds.BLUETOOTH_DATA_TX: |
| 'Bluetooth module input'} |
| |
| |
| class AudioBusSnapshot(object): |
| """Abstracts the snapshot of AudioBus for user to restore it later.""" |
| def __init__(self, endpoints): |
| """Initializes an AudioBusSnapshot. |
| |
| @param endpoints: A set of endpoints to keep a copy. |
| |
| """ |
| self._endpoints = endpoints.copy() |
| |
| |
| def __init__(self, bus_index, chameleon_connection): |
| """Constructs an AudioBus. |
| |
| @param bus_index: The bus index 1 or 2. |
| @param chameleon_connection: A ChameleonConnection object. |
| |
| """ |
| self.bus_index = bus_index |
| self._chameleond_proxy = chameleon_connection.chameleond_proxy |
| self._connected_endpoints = set() |
| |
| |
| def _get_endpoint_name(self, port_id): |
| """Gets the endpoint name used in audio bus API. |
| |
| @param port_id: A string, that is, id in ChameleonIds, CrosIds, or |
| PeripheralIds defined in chameleon_audio_ids. |
| |
| @returns: The endpoint name for the port used in audio bus API. |
| |
| """ |
| return self._PORT_ID_AUDIO_BUS_ENDPOINT_MAP[port_id] |
| |
| |
| def _connect_endpoint(self, endpoint): |
| """Connects an endpoint to audio bus. |
| |
| @param endpoint: An endpoint name in _PORT_ID_AUDIO_BUS_ENDPOINT_MAP. |
| |
| """ |
| logging.debug( |
| 'Audio bus %s is connecting endpoint %s', |
| self.bus_index, endpoint) |
| self._chameleond_proxy.AudioBoardConnect(self.bus_index, endpoint) |
| self._connected_endpoints.add(endpoint) |
| |
| |
| def _disconnect_endpoint(self, endpoint): |
| """Disconnects an endpoint from audio bus. |
| |
| @param endpoint: An endpoint name in _PORT_ID_AUDIO_BUS_ENDPOINT_MAP. |
| |
| """ |
| logging.debug( |
| 'Audio bus %s is disconnecting endpoint %s', |
| self.bus_index, endpoint) |
| self._chameleond_proxy.AudioBoardDisconnect(self.bus_index, endpoint) |
| self._connected_endpoints.remove(endpoint) |
| |
| |
| def connect(self, port_id): |
| """Connects an audio port to this audio bus. |
| |
| @param port_id: A string, that is, id in ChameleonIds, CrosIds, or |
| PeripheralIds defined in chameleon_audio_ids. |
| |
| """ |
| endpoint = self._get_endpoint_name(port_id) |
| self._connect_endpoint(endpoint) |
| |
| |
| def disconnect(self, port_id): |
| """Disconnects an audio port from this audio bus. |
| |
| @param port_id: A string, that is, id in ChameleonIds, CrosIds, or |
| PeripheralIds defined in chameleon_audio_ids. |
| |
| """ |
| endpoint = self._get_endpoint_name(port_id) |
| self._disconnect_endpoint(endpoint) |
| |
| |
| def clear(self): |
| """Disconnects all audio port from this audio bus.""" |
| self._disconnect_all_endpoints() |
| |
| |
| def _disconnect_all_endpoints(self): |
| """Disconnects all endpoints from this audio bus.""" |
| for endpoint in self._connected_endpoints.copy(): |
| self._disconnect_endpoint(endpoint) |
| |
| |
| def get_snapshot(self): |
| """Gets the snapshot of AudioBus so user can restore it later. |
| |
| @returns: An AudioBus.AudioBusSnapshot object. |
| |
| """ |
| return self.AudioBusSnapshot(self._connected_endpoints) |
| |
| |
| def restore_snapshot(self, snapshot): |
| """Restore the snapshot. |
| |
| @param: An AudioBus.AudioBusSnapshot object got from get_snapshot. |
| |
| """ |
| self._disconnect_all_endpoints() |
| logging.debug('Restoring snapshot with %s', snapshot._endpoints) |
| for endpoint in snapshot._endpoints: |
| self._connect_endpoint(endpoint) |
| |
| |
| class AudioJackPluggerException(Exception): |
| """Errors in AudioJackPlugger.""" |
| pass |
| |
| |
| class AudioJackPlugger(object): |
| """AudioJackPlugger is an abstraction of plugger controlled by audio board. |
| |
| There is a motor in the audio box which can plug/unplug 3.5mm 4-ring |
| audio cable to/from audio jack of Cros deivce. |
| This motor is controlled by audio board. |
| |
| A ChameleonConnection object is passed to the construction. |
| |
| """ |
| def __init__(self, chameleon_connection): |
| """Constructs an AudioJackPlugger. |
| |
| @param chameleon_connection: A ChameleonConnection object. |
| |
| @raises: |
| AudioJackPluggerException if there is no jack plugger on |
| this audio board. |
| |
| """ |
| self._chameleond_proxy = chameleon_connection.chameleond_proxy |
| if not self._chameleond_proxy.AudioBoardHasJackPlugger(): |
| raise AudioJackPluggerException( |
| 'There is no jack plugger on audio board. ' |
| 'Perhaps the audio board is not connected to audio box.') |
| |
| |
| def plug(self): |
| """Plugs the audio cable into audio jack of Cros device.""" |
| self._chameleond_proxy.AudioBoardAudioJackPlug() |
| logging.info('Plugged 3.5mm audio cable to Cros device') |
| |
| |
| def unplug(self): |
| """Unplugs the audio cable from audio jack of Cros device.""" |
| self._chameleond_proxy.AudioBoardAudioJackUnplug() |
| logging.info('Unplugged 3.5mm audio cable from Cros device') |
| |
| |
| class BluetoothController(object): |
| """An abstraction of bluetooth module on audio board. |
| |
| There is a bluetooth module on the audio board. It can be controlled through |
| API provided by chameleon proxy. |
| |
| """ |
| def __init__(self, chameleon_connection): |
| """Constructs an BluetoothController. |
| |
| @param chameleon_connection: A ChameleonConnection object. |
| |
| """ |
| self._chameleond_proxy = chameleon_connection.chameleond_proxy |
| |
| |
| def reset(self): |
| """Resets the bluetooth module.""" |
| self._chameleond_proxy.AudioBoardResetBluetooth() |
| logging.info('Resets bluetooth module on audio board.') |
| |
| |
| def disable(self): |
| """Disables the bluetooth module.""" |
| self._chameleond_proxy.AudioBoardDisableBluetooth() |
| logging.info('Disables bluetooth module on audio board.') |
| |
| |
| def is_enabled(self): |
| """Checks if the bluetooth module is enabled. |
| |
| @returns: True if bluetooth module is enabled. False otherwise. |
| |
| """ |
| return self._chameleond_proxy.AudioBoardIsBluetoothEnabled() |