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 #pragma once 18 19 #include "IVolumeCurves.h" 20 #include <policy.h> 21 #include <AudioPolicyManagerInterface.h> 22 #include <utils/RefBase.h> 23 #include <HandleGenerator.h> 24 #include <utils/String8.h> 25 #include <utils/SortedVector.h> 26 #include <utils/KeyedVector.h> 27 #include <system/audio.h> 28 #include <cutils/config_utils.h> 29 #include <string> 30 #include <map> 31 #include <utility> 32 33 namespace android { 34 35 struct CurvePoint 36 { 37 CurvePoint() {} 38 CurvePoint(int index, int attenuationInMb) : 39 mIndex(index), mAttenuationInMb(attenuationInMb) {} 40 uint32_t mIndex; 41 int mAttenuationInMb; 42 }; 43 44 inline bool operator< (const CurvePoint &lhs, const CurvePoint &rhs) 45 { 46 return lhs.mIndex < rhs.mIndex; 47 } 48 49 // A volume curve for a given use case and device category 50 // It contains of list of points of this curve expressing the attenuation in Millibels for 51 // a given volume index from 0 to 100 52 class VolumeCurve : public RefBase 53 { 54 public: 55 VolumeCurve(device_category device) : mDeviceCategory(device) {} 56 57 void add(const CurvePoint &point) { mCurvePoints.add(point); } 58 59 float volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const; 60 61 void dump(String8 *dst, int spaces = 0, bool curvePoints = false) const; 62 63 device_category getDeviceCategory() const { return mDeviceCategory; } 64 65 private: 66 const device_category mDeviceCategory; 67 SortedVector<CurvePoint> mCurvePoints; 68 }; 69 70 // Volume Curves for a given use case indexed by device category 71 class VolumeCurves : public KeyedVector<device_category, sp<VolumeCurve> >, 72 public IVolumeCurves 73 { 74 public: 75 VolumeCurves(int indexMin = 0, int indexMax = 100) : 76 mIndexMin(indexMin), mIndexMax(indexMax) 77 { 78 addCurrentVolumeIndex(AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, 0); 79 } 80 status_t initVolume(int indexMin, int indexMax) override 81 { 82 mIndexMin = indexMin; 83 mIndexMax = indexMax; 84 return NO_ERROR; 85 } 86 87 sp<VolumeCurve> getCurvesFor(device_category device) const 88 { 89 if (indexOfKey(device) < 0) { 90 return 0; 91 } 92 return valueFor(device); 93 } 94 95 virtual int getVolumeIndex(audio_devices_t device) const 96 { 97 device = Volume::getDeviceForVolume(device); 98 // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME 99 if (mIndexCur.find(device) == end(mIndexCur)) { 100 device = AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME; 101 } 102 return mIndexCur.at(device); 103 } 104 105 virtual bool canBeMuted() const { return mCanBeMuted; } 106 virtual void clearCurrentVolumeIndex() { mIndexCur.clear(); } 107 void addCurrentVolumeIndex(audio_devices_t device, int index) override 108 { 109 mIndexCur[device] = index; 110 } 111 112 int getVolumeIndexMin() const { return mIndexMin; } 113 114 int getVolumeIndexMax() const { return mIndexMax; } 115 116 bool hasVolumeIndexForDevice(audio_devices_t device) const 117 { 118 device = Volume::getDeviceForVolume(device); 119 return mIndexCur.find(device) != end(mIndexCur); 120 } 121 122 status_t switchCurvesFrom(const VolumeCurves &referenceCurves) 123 { 124 if (size() != referenceCurves.size()) { 125 ALOGE("%s! device category not aligned, cannot switch", __FUNCTION__); 126 return BAD_TYPE; 127 } 128 for (size_t index = 0; index < size(); index++) { 129 device_category cat = keyAt(index); 130 setVolumeCurve(cat, referenceCurves.getOriginVolumeCurve(cat)); 131 } 132 return NO_ERROR; 133 } 134 status_t restoreOriginVolumeCurve() 135 { 136 return switchCurvesFrom(*this); 137 } 138 139 const sp<VolumeCurve> getOriginVolumeCurve(device_category deviceCategory) const 140 { 141 ALOG_ASSERT(mOriginVolumeCurves.indexOfKey(deviceCategory) >= 0, "Invalid device category"); 142 return mOriginVolumeCurves.valueFor(deviceCategory); 143 } 144 void setVolumeCurve(device_category deviceCategory, const sp<VolumeCurve> &volumeCurve) 145 { 146 ALOG_ASSERT(indexOfKey(deviceCategory) >= 0, "Invalid device category for Volume Curve"); 147 replaceValueFor(deviceCategory, volumeCurve); 148 } 149 150 ssize_t add(const sp<VolumeCurve> &volumeCurve) 151 { 152 device_category deviceCategory = volumeCurve->getDeviceCategory(); 153 ssize_t index = indexOfKey(deviceCategory); 154 if (index < 0) { 155 // Keep track of original Volume Curves per device category in order to switch curves. 156 mOriginVolumeCurves.add(deviceCategory, volumeCurve); 157 return KeyedVector::add(deviceCategory, volumeCurve); 158 } 159 return index; 160 } 161 162 virtual float volIndexToDb(device_category deviceCat, int indexInUi) const 163 { 164 sp<VolumeCurve> vc = getCurvesFor(deviceCat); 165 if (vc != 0) { 166 return vc->volIndexToDb(indexInUi, mIndexMin, mIndexMax); 167 } else { 168 ALOGE("Invalid device category %d for Volume Curve", deviceCat); 169 return 0.0f; 170 } 171 } 172 void addAttributes(const audio_attributes_t &attr) 173 { 174 mAttributes.push_back(attr); 175 } 176 AttributesVector getAttributes() const override { return mAttributes; } 177 void addStreamType(audio_stream_type_t stream) 178 { 179 mStreams.push_back(stream); 180 } 181 StreamTypeVector getStreamTypes() const override { return mStreams; } 182 183 void dump(String8 *dst, int spaces = 0, bool curvePoints = false) const override; 184 185 private: 186 KeyedVector<device_category, sp<VolumeCurve> > mOriginVolumeCurves; 187 std::map<audio_devices_t, int> mIndexCur; /**< current volume index per device. */ 188 int mIndexMin; /**< min volume index. */ 189 int mIndexMax; /**< max volume index. */ 190 const bool mCanBeMuted = true; /**< true is the stream can be muted. */ 191 192 AttributesVector mAttributes; 193 StreamTypeVector mStreams; /**< Keep it for legacy. */ 194 }; 195 196 } // namespace android 197