| # 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 level control for audio widgets.""" |
| |
| |
| from autotest_lib.client.cros.chameleon import chameleon_audio_ids as ids |
| |
| |
| class _AudioLevel(object): |
| """Audio signal level on audio widgets.""" |
| # Line level signal on consumer equipment is typically -10 dBV, or |
| # 0.316 Volt RMS. |
| LINE_LEVEL = 'Line level' |
| # Mic level signal on microphone is typically -60 dBV, or |
| # 1 mV RMS. |
| MIC_LEVEL = 'Mic level' |
| # Digital signal, e.g., USB, HDMI. is not subjected to bias level or |
| # full swing constraints. The signal is guranteed to be transmitted to the |
| # other end without noise introduced on the path. |
| # Signal level is relative to full swing of data width. |
| # E.g. 2^12 is 1/8 of maximum amplitude, that is, 2^15 - 1, of signed |
| # 16 bit data format. |
| # TODO(cychiang) Check if we need to do level scaling for digital signal. |
| DIGITAL = 'Digital' |
| # The signal level of input of bluetooth module on the audio board is |
| # slightly higher than mic level. |
| BLUETOOTH_SIGNAL_INPUT_LEVEL = 'Bluetooth signal input level' |
| |
| |
| # The relative level of audio levels. This is used to compute scale between |
| # two levels. |
| _RELATIVE_LEVEL = { |
| _AudioLevel.LINE_LEVEL: 1.0, |
| _AudioLevel.MIC_LEVEL: 0.033, |
| _AudioLevel.BLUETOOTH_SIGNAL_INPUT_LEVEL: 0.05, |
| } |
| |
| _SOURCE_LEVEL_TABLE = { |
| ids.ChameleonIds.LINEOUT: _AudioLevel.LINE_LEVEL, |
| ids.ChameleonIds.USBOUT: _AudioLevel.DIGITAL, |
| ids.CrosIds.HDMI: _AudioLevel.DIGITAL, |
| ids.CrosIds.HEADPHONE: _AudioLevel.LINE_LEVEL, |
| ids.CrosIds.SPEAKER: _AudioLevel.LINE_LEVEL, |
| ids.CrosIds.BLUETOOTH_HEADPHONE: _AudioLevel.DIGITAL, |
| ids.CrosIds.USBOUT: _AudioLevel.DIGITAL, |
| ids.PeripheralIds.MIC: _AudioLevel.MIC_LEVEL, |
| ids.PeripheralIds.BLUETOOTH_DATA_RX: _AudioLevel.LINE_LEVEL, |
| ids.PeripheralIds.BLUETOOTH_DATA_TX: _AudioLevel.DIGITAL, |
| } |
| |
| _SINK_LEVEL_TABLE = { |
| ids.ChameleonIds.HDMI: _AudioLevel.DIGITAL, |
| ids.ChameleonIds.LINEIN: _AudioLevel.LINE_LEVEL, |
| ids.ChameleonIds.USBIN: _AudioLevel.DIGITAL, |
| ids.CrosIds.EXTERNAL_MIC: _AudioLevel.MIC_LEVEL, |
| ids.CrosIds.INTERNAL_MIC: _AudioLevel.MIC_LEVEL, |
| ids.CrosIds.BLUETOOTH_MIC: _AudioLevel.DIGITAL, |
| ids.CrosIds.USBIN: _AudioLevel.DIGITAL, |
| ids.PeripheralIds.SPEAKER: _AudioLevel.LINE_LEVEL, |
| ids.PeripheralIds.BLUETOOTH_DATA_RX: _AudioLevel.DIGITAL, |
| ids.PeripheralIds.BLUETOOTH_DATA_TX: |
| _AudioLevel.BLUETOOTH_SIGNAL_INPUT_LEVEL, |
| } |
| |
| |
| class LevelController(object): |
| """The controller which sets scale between widgets of different levels.""" |
| def __init__(self, source, sink): |
| """Initializes a LevelController. |
| |
| @param source: An AudioWidget for source. |
| @param sink: An AudioWidget for sink. |
| |
| """ |
| self._source = source |
| self._sink = sink |
| |
| |
| def _get_needed_scale(self): |
| """Gets the needed scale for _source and _sink to balance the level. |
| |
| @returns: A number for scaling on source widget. |
| |
| """ |
| source_level = _SOURCE_LEVEL_TABLE[self._source.port_id] |
| sink_level = _SINK_LEVEL_TABLE[self._sink.port_id] |
| if source_level == sink_level: |
| return 1 |
| else: |
| return _RELATIVE_LEVEL[sink_level] / _RELATIVE_LEVEL[source_level] |
| |
| |
| def reset(self): |
| """Resets scale of _source.""" |
| self._source.handler.scale = 1 |
| |
| |
| def set_scale(self): |
| """Sets scale of _source to balance the level.""" |
| self._source.handler.scale = self._get_needed_scale() |
| self._sink.handler.scale = 1 |