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         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:
    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
    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     }
    178     virtual void clearCurrentVolumeIndex(audio_stream_type_t stream)
    179     {
    180         editCurvesFor(stream).clearCurrentVolumeIndex();
    181     }
    182     virtual void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, int index)
    183     {
    184         editCurvesFor(stream).addCurrentVolumeIndex(device, index);
    185     }
    186     virtual bool canBeMuted(audio_stream_type_t stream) { return getCurvesFor(stream).canBeMuted(); }
    187 
    188     virtual int getVolumeIndexMin(audio_stream_type_t stream) const
    189     {
    190         return getCurvesFor(stream).getVolumeIndexMin();
    191     }
    192     virtual int getVolumeIndexMax(audio_stream_type_t stream) const
    193     {
    194         return getCurvesFor(stream).getVolumeIndexMax();
    195     }
    196     virtual int getVolumeIndex(audio_stream_type_t stream, audio_devices_t device)
    197     {
    198         return getCurvesFor(stream).getVolumeIndex(device);
    199     }
    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     }
    210     virtual float volIndexToDb(audio_stream_type_t stream, device_category cat, int indexInUi) const
    211     {
    212         return getCurvesFor(stream).volIndexToDb(cat, indexInUi);
    213     }
    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 
    222     ssize_t add(const sp<VolumeCurve> &volumeCurve)
    223     {
    224         audio_stream_type_t streamType = volumeCurve->getStreamType();
    225         return editCurvesFor(streamType).add(volumeCurve);
    226     }
    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     }
    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