Home | History | Annotate | Download | only in include
      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 {
     34     CurvePoint() {}
     35     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:
     52     VolumeCurve(device_category device, audio_stream_type_t stream) :
     53         mDeviceCategory(device), mStreamType(stream) {}
     54 
     55     device_category getDeviceCategory() const { return mDeviceCategory; }
     56     audio_stream_type_t getStreamType() const { return mStreamType; }
     57 
     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:
     74     VolumeCurvesForStream() : mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
     75     {
     76         mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, 0);
     77     }
     78 
     79     sp<VolumeCurve> getCurvesFor(device_category device) const
     80     {
     81         if (indexOfKey(device) < 0) {
     82             return 0;
     83         }
     84         return valueFor(device);
     85     }
     86 
     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 
     97     bool canBeMuted() const { return mCanBeMuted; }
     98     void clearCurrentVolumeIndex() { mIndexCur.clear(); }
     99     void addCurrentVolumeIndex(audio_devices_t device, int index) { mIndexCur.add(device, index); }
    100 
    101     void setVolumeIndexMin(int volIndexMin) { mIndexMin = volIndexMin; }
    102     int getVolumeIndexMin() const { return mIndexMin; }
    103 
    104     void setVolumeIndexMax(int volIndexMax) { mIndexMax = volIndexMax; }
    105     int getVolumeIndexMax() const { return mIndexMax; }
    106 
    107     bool hasVolumeIndexForDevice(audio_devices_t device) const
    108     {
    109         device = Volume::getDeviceForVolume(device);
    110         return mIndexCur.indexOfKey(device) >= 0;
    111     }
    112 
    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     }
    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 
    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 
    136     float volIndexToDb(device_category deviceCat, int indexInUi) const
    137     {
    138         return getCurvesFor(deviceCat)->volIndexToDb(indexInUi, mIndexMin, mIndexMax);
    139     }
    140 
    141     void dump(int fd, int spaces, bool curvePoints = false) const;
    142 
    143 private:
    144     KeyedVector<device_category, sp<VolumeCurve> > mOriginVolumeCurves;
    145     KeyedVector<audio_devices_t, int> mIndexCur; /**< current volume index per device. */
    146     int mIndexMin; /**< min volume index. */
    147     int mIndexMax; /**< max volume index. */
    148     bool mCanBeMuted; /**< true is the stream can be muted. */
    149 };
    150 
    151 // Collection of Volume Curves indexed by use case
    152 class VolumeCurvesCollection : public KeyedVector<audio_stream_type_t, VolumeCurvesForStream>,
    153                                public IVolumeCurvesCollection
    154 {
    155 public:
    156     VolumeCurvesCollection()
    157     {
    158         // Create an empty collection of curves
    159         for (ssize_t i = 0 ; i < AUDIO_STREAM_CNT; i++) {
    160             audio_stream_type_t stream = static_cast<audio_stream_type_t>(i);
    161             KeyedVector::add(stream, VolumeCurvesForStream());
    162         }
    163     }
    164 
    165     // Once XML has been parsed, must be call first to sanity check table and initialize indexes
    166     virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax)
    167     {
    168         editValueAt(stream).setVolumeIndexMin(indexMin);
    169         editValueAt(stream).setVolumeIndexMax(indexMax);
    170         return NO_ERROR;
    171     }
    172     virtual void clearCurrentVolumeIndex(audio_stream_type_t stream)
    173     {
    174         editCurvesFor(stream).clearCurrentVolumeIndex();
    175     }
    176     virtual void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, int index)
    177     {
    178         editCurvesFor(stream).addCurrentVolumeIndex(device, index);
    179     }
    180     virtual bool canBeMuted(audio_stream_type_t stream) { return getCurvesFor(stream).canBeMuted(); }
    181 
    182     virtual int getVolumeIndexMin(audio_stream_type_t stream) const
    183     {
    184         return getCurvesFor(stream).getVolumeIndexMin();
    185     }
    186     virtual int getVolumeIndexMax(audio_stream_type_t stream) const
    187     {
    188         return getCurvesFor(stream).getVolumeIndexMax();
    189     }
    190     virtual int getVolumeIndex(audio_stream_type_t stream, audio_devices_t device)
    191     {
    192         return getCurvesFor(stream).getVolumeIndex(device);
    193     }
    194     virtual void switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst)
    195     {
    196         const VolumeCurvesForStream &sourceCurves = getCurvesFor(streamSrc);
    197         VolumeCurvesForStream &dstCurves = editCurvesFor(streamDst);
    198         ALOG_ASSERT(sourceCurves.size() == dstCurves.size(), "device category not aligned");
    199         for (size_t index = 0; index < sourceCurves.size(); index++) {
    200             device_category cat = sourceCurves.keyAt(index);
    201             dstCurves.setVolumeCurve(cat, sourceCurves.getOriginVolumeCurve(cat));
    202         }
    203     }
    204     virtual float volIndexToDb(audio_stream_type_t stream, device_category cat, int indexInUi) const
    205     {
    206         return getCurvesFor(stream).volIndexToDb(cat, indexInUi);
    207     }
    208     virtual bool hasVolumeIndexForDevice(audio_stream_type_t stream,
    209                                          audio_devices_t device) const
    210     {
    211         return getCurvesFor(stream).hasVolumeIndexForDevice(device);
    212     }
    213 
    214     virtual status_t dump(int fd) const;
    215 
    216     ssize_t add(const sp<VolumeCurve> &volumeCurve)
    217     {
    218         audio_stream_type_t streamType = volumeCurve->getStreamType();
    219         return editCurvesFor(streamType).add(volumeCurve);
    220     }
    221     VolumeCurvesForStream &editCurvesFor(audio_stream_type_t stream)
    222     {
    223         ALOG_ASSERT(indexOfKey(stream) >= 0, "Invalid stream type for Volume Curve");
    224         return editValueAt(stream);
    225     }
    226     const VolumeCurvesForStream &getCurvesFor(audio_stream_type_t stream) const
    227     {
    228         ALOG_ASSERT(indexOfKey(stream) >= 0, "Invalid stream type for Volume Curve");
    229         return valueFor(stream);
    230     }
    231 };
    232 
    233 }; // namespace android
    234