• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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