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