xref: /aosp_15_r20/external/autotest/client/cros/chameleon/audio_board.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
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