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