133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang/* 233707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * Copyright (C) 2018 The Android Open Source Project 333707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * 433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * Licensed under the Apache License, Version 2.0 (the "License"); 533707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * you may not use this file except in compliance with the License. 633707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * You may obtain a copy of the License at 733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * 833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * http://www.apache.org/licenses/LICENSE-2.0 933707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * 1033707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * Unless required by applicable law or agreed to in writing, software 1133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * distributed under the License is distributed on an "AS IS" BASIS, 1233707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1333707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * See the License for the specific language governing permissions and 1433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * limitations under the License. 1533707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang */ 1633707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wangpackage com.android.car; 1733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 1833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wangimport android.media.AudioDeviceInfo; 1933707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wangimport android.media.AudioDevicePort; 201e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wangimport android.media.AudioFormat; 2133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wangimport android.media.AudioGain; 2233707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wangimport android.media.AudioGainConfig; 2333707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wangimport android.media.AudioManager; 2433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wangimport android.media.AudioPort; 2533707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wangimport android.util.Log; 2633707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 2733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wangimport com.android.internal.util.Preconditions; 2833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 293302a6b200fdacd5a23dae114b38581937af231fHongwei Wangimport java.io.PrintWriter; 303302a6b200fdacd5a23dae114b38581937af231fHongwei Wang 3133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang/** 32dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph * A helper class wraps {@link AudioDeviceInfo}, and helps get/set the gain on a specific port 33dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph * in terms of millibels. 341e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang * Note to the reader. For whatever reason, it seems that AudioGain contains only configuration 351e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang * information (min/max/step, etc) while the AudioGainConfig class contains the 36dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph * actual currently active gain value(s). 3733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang */ 3833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang/* package */ class CarAudioDeviceInfo { 3933707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 4033707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang private final AudioDeviceInfo mAudioDeviceInfo; 4133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang private final int mBusNumber; 4233707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang private final int mSampleRate; 431e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang private final int mEncodingFormat; 4433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang private final int mChannelCount; 45dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph private final int mDefaultGain; 46dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph private final int mMaxGain; 47dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph private final int mMinGain; 4833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 491e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang /** 501e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang * We need to store the current gain because it is not accessible from the current 511e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang * audio engine implementation. It would be nice if AudioPort#activeConfig() would return it, 521e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang * but in the current implementation, that function actually works only for mixer ports. 531e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang */ 541e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang private int mCurrentGain; 551e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang 56bd51582556b558a8d371f054743c10cd1fd370cfHongwei Wang CarAudioDeviceInfo(AudioDeviceInfo audioDeviceInfo) { 5733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang mAudioDeviceInfo = audioDeviceInfo; 58dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph mBusNumber = parseDeviceAddress(audioDeviceInfo.getAddress()); 5933707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang mSampleRate = getMaxSampleRate(audioDeviceInfo); 601e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang mEncodingFormat = getEncodingFormat(audioDeviceInfo); 6133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang mChannelCount = getMaxChannels(audioDeviceInfo); 6233707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang final AudioGain audioGain = Preconditions.checkNotNull( 6333707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang getAudioGain(), "No audio gain on device port " + audioDeviceInfo); 64dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph mDefaultGain = audioGain.defaultValue(); 65dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph mMaxGain = audioGain.maxValue(); 66dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph mMinGain = audioGain.minValue(); 671e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang 681e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang mCurrentGain = -1; // Not initialized till explicitly set 6933707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 7033707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 7133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang AudioDeviceInfo getAudioDeviceInfo() { 7233707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang return mAudioDeviceInfo; 7333707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 7433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 7533707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang AudioDevicePort getAudioDevicePort() { 7633707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang return mAudioDeviceInfo.getPort(); 7733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 7833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 7933707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang int getBusNumber() { 8033707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang return mBusNumber; 8133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 8233707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 83dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph int getDefaultGain() { 84dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph return mDefaultGain; 85dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph } 86dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph 87dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph int getMaxGain() { 88dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph return mMaxGain; 8933707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 9033707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 91dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph int getMinGain() { 92dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph return mMinGain; 9333707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 9433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 9533707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang int getSampleRate() { 9633707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang return mSampleRate; 9733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 9833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 991e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang int getEncodingFormat() { 1001e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang return mEncodingFormat; 1011e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang } 1021e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang 10333707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang int getChannelCount() { 10433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang return mChannelCount; 10533707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 10633707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 107dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph // Input is in millibels 108dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph void setCurrentGain(int gainInMillibels) { 109dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph // Clamp the incoming value to our valid range. Out of range values ARE legal input 110dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph if (gainInMillibels < mMinGain) { 111dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph gainInMillibels = mMinGain; 112dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph } else if (gainInMillibels > mMaxGain) { 113dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph gainInMillibels = mMaxGain; 114dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph } 11533707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 116dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph // Push the new gain value down to our underlying port which will cause it to show up 117dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph // at the HAL. 11833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang AudioGain audioGain = getAudioGain(); 119dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph if (audioGain == null) { 120dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph Log.e(CarLog.TAG_AUDIO, "getAudioGain() returned null."); 1211e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang return; 1221e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang } 1231e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang 1241e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang // size of gain values is 1 in MODE_JOINT 1251e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang AudioGainConfig audioGainConfig = audioGain.buildConfig( 1261e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang AudioGain.MODE_JOINT, 1271e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang audioGain.channelMask(), 1281e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang new int[] { gainInMillibels }, 1291e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang 0); 1301e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang if (audioGainConfig == null) { 1311e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang Log.e(CarLog.TAG_AUDIO, "Failed to construct AudioGainConfig"); 1321e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang return; 1331e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang } 1341e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang 1351e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang int r = AudioManager.setAudioPortGain(getAudioDevicePort(), audioGainConfig); 1361e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang if (r == AudioManager.SUCCESS) { 1371e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang // Since we can't query for the gain on a device port later, 1381e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang // we have to remember what we asked for 1391e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang mCurrentGain = gainInMillibels; 140dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph } else { 1411e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang Log.e(CarLog.TAG_AUDIO, "Failed to setAudioPortGain: " + r); 14233707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 14333707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 14433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 14533707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang /** 14633707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * Parse device address. Expected format is BUS%d_%s, address, usage hint 14733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * @return valid address (from 0 to positive) or -1 for invalid address. 14833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang */ 14933707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang private int parseDeviceAddress(String address) { 15033707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang String[] words = address.split("_"); 15133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang int addressParsed = -1; 15233707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang if (words[0].toLowerCase().startsWith("bus")) { 15333707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang try { 15433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang addressParsed = Integer.parseInt(words[0].substring(3)); 15533707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } catch (NumberFormatException e) { 15633707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang //ignore 15733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 15833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 15933707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang if (addressParsed < 0) { 16033707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang return -1; 16133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 16233707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang return addressParsed; 16333707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 16433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 16533707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang private int getMaxSampleRate(AudioDeviceInfo info) { 16633707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang int[] sampleRates = info.getSampleRates(); 16733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang if (sampleRates == null || sampleRates.length == 0) { 16833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang return 48000; 16933707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 17033707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang int sampleRate = sampleRates[0]; 17133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang for (int i = 1; i < sampleRates.length; i++) { 17233707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang if (sampleRates[i] > sampleRate) { 17333707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang sampleRate = sampleRates[i]; 17433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 17533707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 17633707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang return sampleRate; 17733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 17833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 1791e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang /** Always returns {@link AudioFormat#ENCODING_PCM_16BIT} as for now */ 1801e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang private int getEncodingFormat(AudioDeviceInfo info) { 1811e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang return AudioFormat.ENCODING_PCM_16BIT; 1821e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang } 1831e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang 184ff9b36b176de502db4c8ccc5b90423f0a095e3cbHongwei Wang /** 185ff9b36b176de502db4c8ccc5b90423f0a095e3cbHongwei Wang * Gets the maximum channel count for a given {@link AudioDeviceInfo} 186ff9b36b176de502db4c8ccc5b90423f0a095e3cbHongwei Wang * 187ff9b36b176de502db4c8ccc5b90423f0a095e3cbHongwei Wang * @param info {@link AudioDeviceInfo} instance to get maximum channel count for 188ff9b36b176de502db4c8ccc5b90423f0a095e3cbHongwei Wang * @return Maximum channel count for a given {@link AudioDeviceInfo}, 189ff9b36b176de502db4c8ccc5b90423f0a095e3cbHongwei Wang * 1 (mono) if there is no channel masks configured 190ff9b36b176de502db4c8ccc5b90423f0a095e3cbHongwei Wang */ 19133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang private int getMaxChannels(AudioDeviceInfo info) { 192ff9b36b176de502db4c8ccc5b90423f0a095e3cbHongwei Wang int numChannels = 1; 19333707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang int[] channelMasks = info.getChannelMasks(); 19433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang if (channelMasks == null) { 195ff9b36b176de502db4c8ccc5b90423f0a095e3cbHongwei Wang return numChannels; 19633707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 19733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang for (int channelMask : channelMasks) { 19833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang int currentNumChannels = Integer.bitCount(channelMask); 19933707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang if (currentNumChannels > numChannels) { 20033707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang numChannels = currentNumChannels; 20133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 20233707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 203ff9b36b176de502db4c8ccc5b90423f0a095e3cbHongwei Wang return numChannels; 20433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 20533707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 20633707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang /** 207dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph * @return {@link AudioGain} with {@link AudioGain#MODE_JOINT} on a given {@link AudioPort}. 208dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph * This is useful for inspecting the configuration data associated with this gain controller 209dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph * (min/max/step/default). 21033707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang */ 21133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang AudioGain getAudioGain() { 21233707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang final AudioDevicePort audioPort = getAudioDevicePort(); 21333707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang if (audioPort != null && audioPort.gains().length > 0) { 21433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang for (AudioGain audioGain : audioPort.gains()) { 21533707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang if ((audioGain.mode() & AudioGain.MODE_JOINT) != 0) { 21633707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang return checkAudioGainConfiguration(audioGain); 21733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 21833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 21933707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 22033707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang return null; 22133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 22233707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 22333707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang /** 22433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang * Constraints applied to gain configuration, see also audio_policy_configuration.xml 22533707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang */ 22633707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang private AudioGain checkAudioGainConfiguration(AudioGain audioGain) { 22733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang Preconditions.checkArgument(audioGain.maxValue() >= audioGain.minValue()); 22833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang Preconditions.checkArgument((audioGain.defaultValue() >= audioGain.minValue()) 22933707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang && (audioGain.defaultValue() <= audioGain.maxValue())); 23033707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang Preconditions.checkArgument( 23133707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang ((audioGain.maxValue() - audioGain.minValue()) % audioGain.stepValue()) == 0); 23233707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang Preconditions.checkArgument( 23333707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang ((audioGain.defaultValue() - audioGain.minValue()) % audioGain.stepValue()) == 0); 23433707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang return audioGain; 23533707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 23633707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang 23733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang @Override 23833707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang public String toString() { 2391e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang return "bus number: " + mBusNumber 2401e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang + " address: " + mAudioDeviceInfo.getAddress() 2413302a6b200fdacd5a23dae114b38581937af231fHongwei Wang + " sampleRate: " + getSampleRate() 2421e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang + " encodingFormat: " + getEncodingFormat() 2433302a6b200fdacd5a23dae114b38581937af231fHongwei Wang + " channelCount: " + getChannelCount() 2441e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang + " currentGain: " + mCurrentGain 245dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph + " maxGain: " + mMaxGain 246dec25bcbd97a57879e9dd6fbda9d53a122dd1023Scott Randolph + " minGain: " + mMinGain; 24733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang } 2483302a6b200fdacd5a23dae114b38581937af231fHongwei Wang 2493302a6b200fdacd5a23dae114b38581937af231fHongwei Wang void dump(PrintWriter writer) { 2501e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang writer.printf("Bus Number (%d) / address (%s)\n ", 2511e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang mBusNumber, mAudioDeviceInfo.getAddress()); 2521e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang writer.printf("\tsample rate / encoding format / channel count: %d %d %d\n", 2531e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang getSampleRate(), getEncodingFormat(), getChannelCount()); 2543302a6b200fdacd5a23dae114b38581937af231fHongwei Wang writer.printf("\tGain in millibel (min / max / default/ current): %d %d %d %d\n", 2551e7f55cff6d393e66965e17b59804d23ff9ab23bHongwei Wang mMinGain, mMaxGain, mDefaultGain, mCurrentGain); 2563302a6b200fdacd5a23dae114b38581937af231fHongwei Wang } 25733707a9d6e5beb03c5ae010e661035f820cc4bb8Hongwei Wang} 258