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