Home | History | Annotate | Download | only in chameleon
      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 
      6 """This module provides the level control for audio widgets."""
      7 
      8 
      9 from autotest_lib.client.cros.chameleon import chameleon_audio_ids as ids
     10 
     11 
     12 class _AudioLevel(object):
     13     """Audio signal level on audio widgets."""
     14     # Line level signal on consumer equipment is typically -10 dBV, or
     15     # 0.316 Volt RMS.
     16     LINE_LEVEL = 'Line level'
     17     # Mic level signal on microphone is typically -60 dBV, or
     18     # 1 mV RMS.
     19     MIC_LEVEL = 'Mic level'
     20     # Digital signal, e.g., USB, HDMI. is not subjected to bias level or
     21     # full swing constraints. The signal is guranteed to be transmitted to the
     22     # other end without noise introduced on the path.
     23     # Signal level is relative to full swing of data width.
     24     # E.g. 2^12 is 1/8 of maximum amplitude, that is, 2^15 - 1, of signed
     25     # 16 bit data format.
     26     # TODO(cychiang) Check if we need to do level scaling for digital signal.
     27     DIGITAL = 'Digital'
     28     # The signal level of input of bluetooth module on the audio board is
     29     # slightly higher than mic level.
     30     BLUETOOTH_SIGNAL_INPUT_LEVEL = 'Bluetooth signal input level'
     31 
     32 
     33 # The relative level of audio levels. This is used to compute scale between
     34 # two levels.
     35 _RELATIVE_LEVEL = {
     36     _AudioLevel.LINE_LEVEL: 1.0,
     37     _AudioLevel.MIC_LEVEL: 0.033,
     38     _AudioLevel.BLUETOOTH_SIGNAL_INPUT_LEVEL: 0.05,
     39 }
     40 
     41 _SOURCE_LEVEL_TABLE = {
     42         ids.ChameleonIds.LINEOUT: _AudioLevel.LINE_LEVEL,
     43         ids.ChameleonIds.USBOUT: _AudioLevel.DIGITAL,
     44         ids.CrosIds.HDMI: _AudioLevel.DIGITAL,
     45         ids.CrosIds.HEADPHONE: _AudioLevel.LINE_LEVEL,
     46         ids.CrosIds.SPEAKER: _AudioLevel.LINE_LEVEL,
     47         ids.CrosIds.BLUETOOTH_HEADPHONE: _AudioLevel.DIGITAL,
     48         ids.CrosIds.USBOUT: _AudioLevel.DIGITAL,
     49         ids.PeripheralIds.MIC: _AudioLevel.MIC_LEVEL,
     50         ids.PeripheralIds.BLUETOOTH_DATA_RX: _AudioLevel.LINE_LEVEL,
     51         ids.PeripheralIds.BLUETOOTH_DATA_TX: _AudioLevel.DIGITAL,
     52 }
     53 
     54 _SINK_LEVEL_TABLE = {
     55         ids.ChameleonIds.HDMI: _AudioLevel.DIGITAL,
     56         ids.ChameleonIds.LINEIN: _AudioLevel.LINE_LEVEL,
     57         ids.ChameleonIds.USBIN: _AudioLevel.DIGITAL,
     58         ids.CrosIds.EXTERNAL_MIC: _AudioLevel.MIC_LEVEL,
     59         ids.CrosIds.INTERNAL_MIC: _AudioLevel.MIC_LEVEL,
     60         ids.CrosIds.BLUETOOTH_MIC: _AudioLevel.DIGITAL,
     61         ids.CrosIds.USBIN: _AudioLevel.DIGITAL,
     62         ids.PeripheralIds.SPEAKER: _AudioLevel.LINE_LEVEL,
     63         ids.PeripheralIds.BLUETOOTH_DATA_RX: _AudioLevel.DIGITAL,
     64         ids.PeripheralIds.BLUETOOTH_DATA_TX:
     65                 _AudioLevel.BLUETOOTH_SIGNAL_INPUT_LEVEL,
     66 }
     67 
     68 
     69 class LevelController(object):
     70     """The controller which sets scale between widgets of different levels."""
     71     def __init__(self, source, sink):
     72         """Initializes a LevelController.
     73 
     74         @param source: An AudioWidget for source.
     75         @param sink: An AudioWidget for sink.
     76 
     77         """
     78         self._source = source
     79         self._sink = sink
     80 
     81 
     82     def _get_needed_scale(self):
     83         """Gets the needed scale for _source and _sink to balance the level.
     84 
     85         @returns: A number for scaling on source widget.
     86 
     87         """
     88         source_level = _SOURCE_LEVEL_TABLE[self._source.port_id]
     89         sink_level = _SINK_LEVEL_TABLE[self._sink.port_id]
     90         if source_level == sink_level:
     91             return 1
     92         else:
     93             return _RELATIVE_LEVEL[sink_level] / _RELATIVE_LEVEL[source_level]
     94 
     95 
     96     def reset(self):
     97         """Resets scale of _source."""
     98         self._source.handler.scale = 1
     99 
    100 
    101     def set_scale(self):
    102         """Sets scale of _source to balance the level."""
    103         self._source.handler.scale = self._get_needed_scale()
    104         self._sink.handler.scale = 1
    105