1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "APM::AudioPolicyEngine/Stream" 18 19 #include "Stream.h" 20 #include <system/audio.h> 21 22 using std::string; 23 24 namespace android 25 { 26 namespace audio_policy 27 { 28 29 status_t Element<audio_stream_type_t>::setIdentifier(audio_stream_type_t identifier) 30 { 31 if (identifier > AUDIO_STREAM_CNT) { 32 return BAD_VALUE; 33 } 34 mIdentifier = identifier; 35 ALOGD("%s: Stream %s identifier 0x%X", __FUNCTION__, getName().c_str(), identifier); 36 return NO_ERROR; 37 } 38 39 /** 40 * Set the strategy to follow for this stream. 41 * It checks if the strategy is valid. 42 * 43 * @param[in] strategy to be followed. 44 * 45 * @return NO_ERROR if the strategy is set correctly, error code otherwise. 46 */ 47 template <> 48 status_t Element<audio_stream_type_t>::set<routing_strategy>(routing_strategy strategy) 49 { 50 if (strategy >= NUM_STRATEGIES) { 51 return BAD_VALUE; 52 } 53 mApplicableStrategy = strategy; 54 ALOGD("%s: 0x%X for Stream %s", __FUNCTION__, strategy, getName().c_str()); 55 return NO_ERROR; 56 } 57 58 template <> 59 routing_strategy Element<audio_stream_type_t>::get<routing_strategy>() const 60 { 61 ALOGV("%s: 0x%X for Stream %s", __FUNCTION__, mApplicableStrategy, getName().c_str()); 62 return mApplicableStrategy; 63 } 64 65 status_t Element<audio_stream_type_t>::setVolumeProfile(Volume::device_category category, 66 const VolumeCurvePoints &points) 67 { 68 ALOGD("%s: adding volume profile for %s for device category %d, points nb =%d", __FUNCTION__, 69 getName().c_str(), category, points.size()); 70 mVolumeProfiles[category] = points; 71 72 for (size_t i = 0; i < points.size(); i++) { 73 ALOGV("%s: %s cat=%d curve index =%d Index=%d dBAttenuation=%f", 74 __FUNCTION__, getName().c_str(), category, i, points[i].mIndex, 75 points[i].mDBAttenuation); 76 } 77 return NO_ERROR; 78 } 79 80 status_t Element<audio_stream_type_t>::initVolume(int indexMin, int indexMax) 81 { 82 ALOGV("initStreamVolume() stream %s, min %d, max %d", getName().c_str(), indexMin, indexMax); 83 if (indexMin < 0 || indexMin >= indexMax) { 84 ALOGW("initStreamVolume() invalid index limits for stream %s, min %d, max %d", 85 getName().c_str(), indexMin, indexMax); 86 return BAD_VALUE; 87 } 88 mIndexMin = indexMin; 89 mIndexMax = indexMax; 90 91 return NO_ERROR; 92 } 93 94 float Element<audio_stream_type_t>::volIndexToDb(Volume::device_category deviceCategory, 95 int indexInUi) 96 { 97 VolumeProfileConstIterator it = mVolumeProfiles.find(deviceCategory); 98 if (it == mVolumeProfiles.end()) { 99 ALOGE("%s: device category %d not found for stream %s", __FUNCTION__, deviceCategory, 100 getName().c_str()); 101 return 1.0f; 102 } 103 const VolumeCurvePoints curve = mVolumeProfiles[deviceCategory]; 104 if (curve.size() != Volume::VOLCNT) { 105 ALOGE("%s: invalid profile for category %d and for stream %s", __FUNCTION__, deviceCategory, 106 getName().c_str()); 107 return 1.0f; 108 } 109 110 // the volume index in the UI is relative to the min and max volume indices for this stream type 111 int nbSteps = 1 + curve[Volume::VOLMAX].mIndex - 112 curve[Volume::VOLMIN].mIndex; 113 114 if (mIndexMax - mIndexMin == 0) { 115 ALOGE("%s: Invalid volume indexes Min=Max=%d", __FUNCTION__, mIndexMin); 116 return 1.0f; 117 } 118 int volIdx = (nbSteps * (indexInUi - mIndexMin)) / 119 (mIndexMax - mIndexMin); 120 121 // find what part of the curve this index volume belongs to, or if it's out of bounds 122 int segment = 0; 123 if (volIdx < curve[Volume::VOLMIN].mIndex) { // out of bounds 124 return 0.0f; 125 } else if (volIdx < curve[Volume::VOLKNEE1].mIndex) { 126 segment = 0; 127 } else if (volIdx < curve[Volume::VOLKNEE2].mIndex) { 128 segment = 1; 129 } else if (volIdx <= curve[Volume::VOLMAX].mIndex) { 130 segment = 2; 131 } else { // out of bounds 132 return 1.0f; 133 } 134 135 // linear interpolation in the attenuation table in dB 136 float decibels = curve[segment].mDBAttenuation + 137 ((float)(volIdx - curve[segment].mIndex)) * 138 ( (curve[segment+1].mDBAttenuation - 139 curve[segment].mDBAttenuation) / 140 ((float)(curve[segment+1].mIndex - 141 curve[segment].mIndex)) ); 142 143 ALOGV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f]", 144 curve[segment].mIndex, volIdx, 145 curve[segment+1].mIndex, 146 curve[segment].mDBAttenuation, 147 decibels, 148 curve[segment+1].mDBAttenuation); 149 150 return decibels; 151 } 152 153 } // namespace audio_policy 154 } // namespace android 155 156