VolumeCurve.h revision d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4d
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 31namespace android { 32 33struct CurvePoint 34{ 35 CurvePoint() {} 36 CurvePoint(int index, int attenuationInMb) : 37 mIndex(index), mAttenuationInMb(attenuationInMb) {} 38 uint32_t mIndex; 39 int mAttenuationInMb; 40}; 41 42inline 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 cateory 48// It contains of list of points of this cuive expressing the atteunation in Millibels for 49// a given volume index from 0 to 100 50class VolumeCurve : public RefBase 51{ 52public: 53 VolumeCurve(device_category device, audio_stream_type_t stream) : 54 mDeviceCategory(device), mStreamType(stream) {} 55 56 device_category getDeviceCategory() const { return mDeviceCategory; } 57 audio_stream_type_t getStreamType() const { return mStreamType; } 58 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 65private: 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 72class VolumeCurvesForStream : public KeyedVector<device_category, sp<VolumeCurve> > 73{ 74public: 75 VolumeCurvesForStream() : mIndexMin(0), mIndexMax(1), mCanBeMuted(true) 76 { 77 mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0); 78 } 79 80 sp<VolumeCurve> getCurvesFor(device_category device) const 81 { 82 if (indexOfKey(device) < 0) { 83 return 0; 84 } 85 return valueFor(device); 86 } 87 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 92 if (mIndexCur.indexOfKey(device) < 0) { 93 device = AUDIO_DEVICE_OUT_DEFAULT; 94 } 95 return mIndexCur.valueFor(device); 96 } 97 98 bool canBeMuted() const { return mCanBeMuted; } 99 void clearCurrentVolumeIndex() { mIndexCur.clear(); } 100 void addCurrentVolumeIndex(audio_devices_t device, int index) { mIndexCur.add(device, index); } 101 102 void setVolumeIndexMin(int volIndexMin) { mIndexMin = volIndexMin; } 103 int getVolumeIndexMin() const { return mIndexMin; } 104 105 void setVolumeIndexMax(int volIndexMax) { mIndexMax = volIndexMax; } 106 int getVolumeIndexMax() const { return mIndexMax; } 107 108 const sp<VolumeCurve> getOriginVolumeCurve(device_category deviceCategory) const 109 { 110 ALOG_ASSERT(mOriginVolumeCurves.indexOfKey(deviceCategory) >= 0, "Invalid device category"); 111 return mOriginVolumeCurves.valueFor(deviceCategory); 112 } 113 void setVolumeCurve(device_category deviceCategory, const sp<VolumeCurve> &volumeCurve) 114 { 115 ALOG_ASSERT(indexOfKey(deviceCategory) >= 0, "Invalid device category for Volume Curve"); 116 replaceValueFor(deviceCategory, volumeCurve); 117 } 118 119 ssize_t add(const sp<VolumeCurve> &volumeCurve) 120 { 121 device_category deviceCategory = volumeCurve->getDeviceCategory(); 122 ssize_t index = indexOfKey(deviceCategory); 123 if (index < 0) { 124 // Keep track of original Volume Curves per device category in order to switch curves. 125 mOriginVolumeCurves.add(deviceCategory, volumeCurve); 126 return KeyedVector::add(deviceCategory, volumeCurve); 127 } 128 return index; 129 } 130 131 float volIndexToDb(device_category deviceCat, int indexInUi) const 132 { 133 return getCurvesFor(deviceCat)->volIndexToDb(indexInUi, mIndexMin, mIndexMax); 134 } 135 136 void dump(int fd, int spaces, bool curvePoints = false) const; 137 138private: 139 KeyedVector<device_category, sp<VolumeCurve> > mOriginVolumeCurves; 140 KeyedVector<audio_devices_t, int> mIndexCur; /**< current volume index per device. */ 141 int mIndexMin; /**< min volume index. */ 142 int mIndexMax; /**< max volume index. */ 143 bool mCanBeMuted; /**< true is the stream can be muted. */ 144}; 145 146// Collection of Volume Curves indexed by use case 147class VolumeCurvesCollection : public KeyedVector<audio_stream_type_t, VolumeCurvesForStream>, 148 public IVolumeCurvesCollection 149{ 150public: 151 VolumeCurvesCollection() 152 { 153 // Create an empty collection of curves even for CNT stream (used for default curves) 154 for (ssize_t i = 0 ; i <= AUDIO_STREAM_CNT; i++) { 155 audio_stream_type_t stream = static_cast<audio_stream_type_t>(i); 156 KeyedVector::add(stream, VolumeCurvesForStream()); 157 } 158 } 159 160 // Once XML has been parsed, must be call first to sanity check table and initialize indexes 161 virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax) 162 { 163 editValueAt(stream).setVolumeIndexMin(indexMin); 164 editValueAt(stream).setVolumeIndexMax(indexMax); 165 return NO_ERROR; 166 } 167 virtual void clearCurrentVolumeIndex(audio_stream_type_t stream) 168 { 169 editCurvesFor(stream).clearCurrentVolumeIndex(); 170 } 171 virtual void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, int index) 172 { 173 editCurvesFor(stream).addCurrentVolumeIndex(device, index); 174 } 175 virtual bool canBeMuted(audio_stream_type_t stream) { return getCurvesFor(stream).canBeMuted(); } 176 177 virtual int getVolumeIndexMin(audio_stream_type_t stream) const 178 { 179 return getCurvesFor(stream).getVolumeIndexMin(); 180 } 181 virtual int getVolumeIndexMax(audio_stream_type_t stream) const 182 { 183 return getCurvesFor(stream).getVolumeIndexMax(); 184 } 185 virtual int getVolumeIndex(audio_stream_type_t stream, audio_devices_t device) 186 { 187 return getCurvesFor(stream).getVolumeIndex(device); 188 } 189 virtual void switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst) 190 { 191 const VolumeCurvesForStream &sourceCurves = getCurvesFor(streamSrc); 192 VolumeCurvesForStream &dstCurves = editCurvesFor(streamDst); 193 ALOG_ASSERT(sourceCurves.size() == dstCurves.size(), "device category not aligned"); 194 for (size_t index = 0; index < sourceCurves.size(); index++) { 195 device_category cat = sourceCurves.keyAt(index); 196 dstCurves.setVolumeCurve(cat, sourceCurves.getOriginVolumeCurve(cat)); 197 } 198 } 199 virtual float volIndexToDb(audio_stream_type_t stream, device_category cat, int indexInUi) const 200 { 201 return getCurvesFor(stream).volIndexToDb(cat, indexInUi); 202 } 203 204 virtual status_t dump(int fd) const; 205 206 ssize_t add(const sp<VolumeCurve> &volumeCurve) 207 { 208 audio_stream_type_t streamType = volumeCurve->getStreamType(); 209 return editCurvesFor(streamType).add(volumeCurve); 210 } 211 VolumeCurvesForStream &editCurvesFor(audio_stream_type_t stream) 212 { 213 ALOG_ASSERT(indexOfKey(stream) >= 0, "Invalid stream type for Volume Curve"); 214 return editValueAt(stream); 215 } 216 const VolumeCurvesForStream &getCurvesFor(audio_stream_type_t stream) const 217 { 218 ALOG_ASSERT(indexOfKey(stream) >= 0, "Invalid stream type for Volume Curve"); 219 return valueFor(stream); 220 } 221 void setDefaultCurves() 222 { 223 for (size_t i = 0 ; i < AUDIO_STREAM_CNT; i++) { 224 audio_stream_type_t stream = static_cast<audio_stream_type_t>(i); 225 ALOG_ASSERT(indexOfKey(stream) >= 0, "No Default volume table found!"); 226 227 VolumeCurvesForStream &curvesForStream = editValueAt(stream); 228 // Sanity check on All device categories 229 for (int i = 0; i < DEVICE_CATEGORY_CNT; i++) { 230 device_category cat = (device_category)i; 231 if (curvesForStream.getCurvesFor(cat) == 0) { 232 ALOG_ASSERT(valueAt(AUDIO_STREAM_CNT).getCurvesFor(cat) != 0, 233 "No Default volume table found for device category %d", cat); 234 ALOGW("Switching to default table for stream %d category %d", stream, cat); 235 curvesForStream.add(valueAt(AUDIO_STREAM_CNT).getCurvesFor(cat)); 236 } 237 } 238 } 239 } 240}; 241 242}; // namespace android 243