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 "IVolumeCurvesCollection.h" 20 #include <policy.h> 21 #include <utils/RefBase.h> 22 #include <utils/String8.h> 23 #include <utils/SortedVector.h> 24 #include <utils/KeyedVector.h> 25 #include <system/audio.h> 26 #include <cutils/config_utils.h> 27 #include <string> 28 #include <utility> 29 30 namespace android { 31 32 struct CurvePoint 33 { CurvePointCurvePoint34 CurvePoint() {} CurvePointCurvePoint35 CurvePoint(int index, int attenuationInMb) : 36 mIndex(index), mAttenuationInMb(attenuationInMb) {} 37 uint32_t mIndex; 38 int mAttenuationInMb; 39 }; 40 41 inline bool operator< (const CurvePoint &lhs, const CurvePoint &rhs) 42 { 43 return lhs.mIndex < rhs.mIndex; 44 } 45 46 // A volume curve for a given use case and device category 47 // It contains of list of points of this curve expressing the attenuation in Millibels for 48 // a given volume index from 0 to 100 49 class VolumeCurve : public RefBase 50 { 51 public: VolumeCurve(device_category device,audio_stream_type_t stream)52 VolumeCurve(device_category device, audio_stream_type_t stream) : 53 mDeviceCategory(device), mStreamType(stream) {} 54 getDeviceCategory()55 device_category getDeviceCategory() const { return mDeviceCategory; } getStreamType()56 audio_stream_type_t getStreamType() const { return mStreamType; } 57 add(const CurvePoint & point)58 void add(const CurvePoint &point) { mCurvePoints.add(point); } 59 60 float volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const; 61 62 void dump(int fd) const; 63 64 private: 65 SortedVector<CurvePoint> mCurvePoints; 66 device_category mDeviceCategory; 67 audio_stream_type_t mStreamType; 68 }; 69 70 // Volume Curves for a given use case indexed by device category 71 class VolumeCurvesForStream : public KeyedVector<device_category, sp<VolumeCurve> > 72 { 73 public: VolumeCurvesForStream()74 VolumeCurvesForStream() : mIndexMin(0), mIndexMax(1), mCanBeMuted(true) 75 { 76 mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, 0); 77 } 78 getCurvesFor(device_category device)79 sp<VolumeCurve> getCurvesFor(device_category device) const 80 { 81 if (indexOfKey(device) < 0) { 82 return 0; 83 } 84 return valueFor(device); 85 } 86 getVolumeIndex(audio_devices_t device)87 int getVolumeIndex(audio_devices_t device) const 88 { 89 device = Volume::getDeviceForVolume(device); 90 // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME 91 if (mIndexCur.indexOfKey(device) < 0) { 92 device = AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME; 93 } 94 return mIndexCur.valueFor(device); 95 } 96 canBeMuted()97 bool canBeMuted() const { return mCanBeMuted; } clearCurrentVolumeIndex()98 void clearCurrentVolumeIndex() { mIndexCur.clear(); } addCurrentVolumeIndex(audio_devices_t device,int index)99 void addCurrentVolumeIndex(audio_devices_t device, int index) { mIndexCur.add(device, index); } 100 setVolumeIndexMin(int volIndexMin)101 void setVolumeIndexMin(int volIndexMin) { mIndexMin = volIndexMin; } getVolumeIndexMin()102 int getVolumeIndexMin() const { return mIndexMin; } 103 setVolumeIndexMax(int volIndexMax)104 void setVolumeIndexMax(int volIndexMax) { mIndexMax = volIndexMax; } getVolumeIndexMax()105 int getVolumeIndexMax() const { return mIndexMax; } 106 hasVolumeIndexForDevice(audio_devices_t device)107 bool hasVolumeIndexForDevice(audio_devices_t device) const 108 { 109 device = Volume::getDeviceForVolume(device); 110 return mIndexCur.indexOfKey(device) >= 0; 111 } 112 getOriginVolumeCurve(device_category deviceCategory)113 const sp<VolumeCurve> getOriginVolumeCurve(device_category deviceCategory) const 114 { 115 ALOG_ASSERT(mOriginVolumeCurves.indexOfKey(deviceCategory) >= 0, "Invalid device category"); 116 return mOriginVolumeCurves.valueFor(deviceCategory); 117 } setVolumeCurve(device_category deviceCategory,const sp<VolumeCurve> & volumeCurve)118 void setVolumeCurve(device_category deviceCategory, const sp<VolumeCurve> &volumeCurve) 119 { 120 ALOG_ASSERT(indexOfKey(deviceCategory) >= 0, "Invalid device category for Volume Curve"); 121 replaceValueFor(deviceCategory, volumeCurve); 122 } 123 add(const sp<VolumeCurve> & volumeCurve)124 ssize_t add(const sp<VolumeCurve> &volumeCurve) 125 { 126 device_category deviceCategory = volumeCurve->getDeviceCategory(); 127 ssize_t index = indexOfKey(deviceCategory); 128 if (index < 0) { 129 // Keep track of original Volume Curves per device category in order to switch curves. 130 mOriginVolumeCurves.add(deviceCategory, volumeCurve); 131 return KeyedVector::add(deviceCategory, volumeCurve); 132 } 133 return index; 134 } 135 volIndexToDb(device_category deviceCat,int indexInUi)136 float volIndexToDb(device_category deviceCat, int indexInUi) const 137 { 138 sp<VolumeCurve> vc = getCurvesFor(deviceCat); 139 if (vc != 0) { 140 return vc->volIndexToDb(indexInUi, mIndexMin, mIndexMax); 141 } else { 142 ALOGE("Invalid device category %d for Volume Curve", deviceCat); 143 return 0.0f; 144 } 145 } 146 147 void dump(int fd, int spaces, bool curvePoints = false) const; 148 149 private: 150 KeyedVector<device_category, sp<VolumeCurve> > mOriginVolumeCurves; 151 KeyedVector<audio_devices_t, int> mIndexCur; /**< current volume index per device. */ 152 int mIndexMin; /**< min volume index. */ 153 int mIndexMax; /**< max volume index. */ 154 bool mCanBeMuted; /**< true is the stream can be muted. */ 155 }; 156 157 // Collection of Volume Curves indexed by use case 158 class VolumeCurvesCollection : public KeyedVector<audio_stream_type_t, VolumeCurvesForStream>, 159 public IVolumeCurvesCollection 160 { 161 public: VolumeCurvesCollection()162 VolumeCurvesCollection() 163 { 164 // Create an empty collection of curves 165 for (ssize_t i = 0 ; i < AUDIO_STREAM_CNT; i++) { 166 audio_stream_type_t stream = static_cast<audio_stream_type_t>(i); 167 KeyedVector::add(stream, VolumeCurvesForStream()); 168 } 169 } 170 171 // Once XML has been parsed, must be call first to sanity check table and initialize indexes initStreamVolume(audio_stream_type_t stream,int indexMin,int indexMax)172 virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax) 173 { 174 editValueAt(stream).setVolumeIndexMin(indexMin); 175 editValueAt(stream).setVolumeIndexMax(indexMax); 176 return NO_ERROR; 177 } clearCurrentVolumeIndex(audio_stream_type_t stream)178 virtual void clearCurrentVolumeIndex(audio_stream_type_t stream) 179 { 180 editCurvesFor(stream).clearCurrentVolumeIndex(); 181 } addCurrentVolumeIndex(audio_stream_type_t stream,audio_devices_t device,int index)182 virtual void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, int index) 183 { 184 editCurvesFor(stream).addCurrentVolumeIndex(device, index); 185 } canBeMuted(audio_stream_type_t stream)186 virtual bool canBeMuted(audio_stream_type_t stream) { return getCurvesFor(stream).canBeMuted(); } 187 getVolumeIndexMin(audio_stream_type_t stream)188 virtual int getVolumeIndexMin(audio_stream_type_t stream) const 189 { 190 return getCurvesFor(stream).getVolumeIndexMin(); 191 } getVolumeIndexMax(audio_stream_type_t stream)192 virtual int getVolumeIndexMax(audio_stream_type_t stream) const 193 { 194 return getCurvesFor(stream).getVolumeIndexMax(); 195 } getVolumeIndex(audio_stream_type_t stream,audio_devices_t device)196 virtual int getVolumeIndex(audio_stream_type_t stream, audio_devices_t device) 197 { 198 return getCurvesFor(stream).getVolumeIndex(device); 199 } switchVolumeCurve(audio_stream_type_t streamSrc,audio_stream_type_t streamDst)200 virtual void switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst) 201 { 202 const VolumeCurvesForStream &sourceCurves = getCurvesFor(streamSrc); 203 VolumeCurvesForStream &dstCurves = editCurvesFor(streamDst); 204 ALOG_ASSERT(sourceCurves.size() == dstCurves.size(), "device category not aligned"); 205 for (size_t index = 0; index < sourceCurves.size(); index++) { 206 device_category cat = sourceCurves.keyAt(index); 207 dstCurves.setVolumeCurve(cat, sourceCurves.getOriginVolumeCurve(cat)); 208 } 209 } volIndexToDb(audio_stream_type_t stream,device_category cat,int indexInUi)210 virtual float volIndexToDb(audio_stream_type_t stream, device_category cat, int indexInUi) const 211 { 212 return getCurvesFor(stream).volIndexToDb(cat, indexInUi); 213 } hasVolumeIndexForDevice(audio_stream_type_t stream,audio_devices_t device)214 virtual bool hasVolumeIndexForDevice(audio_stream_type_t stream, 215 audio_devices_t device) const 216 { 217 return getCurvesFor(stream).hasVolumeIndexForDevice(device); 218 } 219 220 virtual status_t dump(int fd) const; 221 add(const sp<VolumeCurve> & volumeCurve)222 ssize_t add(const sp<VolumeCurve> &volumeCurve) 223 { 224 audio_stream_type_t streamType = volumeCurve->getStreamType(); 225 return editCurvesFor(streamType).add(volumeCurve); 226 } editCurvesFor(audio_stream_type_t stream)227 VolumeCurvesForStream &editCurvesFor(audio_stream_type_t stream) 228 { 229 ALOG_ASSERT(indexOfKey(stream) >= 0, "Invalid stream type for Volume Curve"); 230 return editValueAt(stream); 231 } getCurvesFor(audio_stream_type_t stream)232 const VolumeCurvesForStream &getCurvesFor(audio_stream_type_t stream) const 233 { 234 ALOG_ASSERT(indexOfKey(stream) >= 0, "Invalid stream type for Volume Curve"); 235 return valueFor(stream); 236 } 237 }; 238 239 } // namespace android 240