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 <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 {
     35     CurvePoint() {}
     36     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:
     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 
     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:
     75     VolumeCurvesForStream() : mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
     76     {
     77         mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, 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_FOR_VOLUME
     92         if (mIndexCur.indexOfKey(device) < 0) {
     93             device = AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME;
     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     bool hasVolumeIndexForDevice(audio_devices_t device) const
    109     {
    110         device = Volume::getDeviceForVolume(device);
    111         return mIndexCur.indexOfKey(device) >= 0;
    112     }
    113 
    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     }
    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 
    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 
    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:
    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
    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     }
    173     virtual void clearCurrentVolumeIndex(audio_stream_type_t stream)
    174     {
    175         editCurvesFor(stream).clearCurrentVolumeIndex();
    176     }
    177     virtual void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, int index)
    178     {
    179         editCurvesFor(stream).addCurrentVolumeIndex(device, index);
    180     }
    181     virtual bool canBeMuted(audio_stream_type_t stream) { return getCurvesFor(stream).canBeMuted(); }
    182 
    183     virtual int getVolumeIndexMin(audio_stream_type_t stream) const
    184     {
    185         return getCurvesFor(stream).getVolumeIndexMin();
    186     }
    187     virtual int getVolumeIndexMax(audio_stream_type_t stream) const
    188     {
    189         return getCurvesFor(stream).getVolumeIndexMax();
    190     }
    191     virtual int getVolumeIndex(audio_stream_type_t stream, audio_devices_t device)
    192     {
    193         return getCurvesFor(stream).getVolumeIndex(device);
    194     }
    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     }
    205     virtual float volIndexToDb(audio_stream_type_t stream, device_category cat, int indexInUi) const
    206     {
    207         return getCurvesFor(stream).volIndexToDb(cat, indexInUi);
    208     }
    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 
    217     ssize_t add(const sp<VolumeCurve> &volumeCurve)
    218     {
    219         audio_stream_type_t streamType = volumeCurve->getStreamType();
    220         return editCurvesFor(streamType).add(volumeCurve);
    221     }
    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     }
    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