1f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie/*
2f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie * Copyright (C) 2015 The Android Open Source Project
3f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie *
4f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie * Licensed under the Apache License, Version 2.0 (the "License");
5f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie * you may not use this file except in compliance with the License.
6f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie * You may obtain a copy of the License at
7f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie *
8f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie *      http://www.apache.org/licenses/LICENSE-2.0
9f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie *
10f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie * Unless required by applicable law or agreed to in writing, software
11f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie * distributed under the License is distributed on an "AS IS" BASIS,
12f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie * See the License for the specific language governing permissions and
14f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie * limitations under the License.
15f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie */
16f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie
17f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie#pragma once
18f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie
19d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie#include "IVolumeCurvesCollection.h"
20d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie#include <policy.h>
21f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie#include <hardware/audio.h>
22f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie#include <utils/RefBase.h>
23f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie#include <utils/String8.h>
24d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie#include <utils/SortedVector.h>
25d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie#include <utils/KeyedVector.h>
26f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie#include <system/audio.h>
27f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie#include <cutils/config_utils.h>
28f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie#include <string>
29f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie#include <utility>
30f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie
31f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffienamespace android {
32f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie
33d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffiestruct CurvePoint
34d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie{
35d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    CurvePoint() {}
36d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    CurvePoint(int index, int attenuationInMb) :
37d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        mIndex(index), mAttenuationInMb(attenuationInMb) {}
38d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    uint32_t mIndex;
39d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    int mAttenuationInMb;
40d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie};
41d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
42d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffieinline bool operator< (const CurvePoint &lhs, const CurvePoint &rhs)
43d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie{
44d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    return lhs.mIndex < rhs.mIndex;
45d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie}
46f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie
471fd372e40ef40643fa9d036a0c9db043475b1b02Eric Laurent// A volume curve for a given use case and device category
481fd372e40ef40643fa9d036a0c9db043475b1b02Eric Laurent// It contains of list of points of this curve expressing the attenuation in Millibels for
49d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie// a given volume index from 0 to 100
50f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffieclass VolumeCurve : public RefBase
51f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie{
52f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffiepublic:
53d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    VolumeCurve(device_category device, audio_stream_type_t stream) :
54d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        mDeviceCategory(device), mStreamType(stream) {}
55f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie
56f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie    device_category getDeviceCategory() const { return mDeviceCategory; }
57d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    audio_stream_type_t getStreamType() const { return mStreamType; }
58d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
59d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    void add(const CurvePoint &point) { mCurvePoints.add(point); }
60d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
61d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    float volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const;
62f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie
63d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    void dump(int fd) const;
64f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie
65f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffieprivate:
66d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    SortedVector<CurvePoint> mCurvePoints;
67f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie    device_category mDeviceCategory;
68f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie    audio_stream_type_t mStreamType;
69f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie};
70f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie
71d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie// Volume Curves for a given use case indexed by device category
72d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffieclass VolumeCurvesForStream : public KeyedVector<device_category, sp<VolumeCurve> >
73d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie{
74d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffiepublic:
75d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    VolumeCurvesForStream() : mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
76d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
775a2b62984c7cecd1761fe272c078dd814c167942Eric Laurent        mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, 0);
78d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
79d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
80d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    sp<VolumeCurve> getCurvesFor(device_category device) const
81d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
82d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        if (indexOfKey(device) < 0) {
83d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie            return 0;
84d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        }
85d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        return valueFor(device);
86d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
87d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
88d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    int getVolumeIndex(audio_devices_t device) const
89d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
90d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        device = Volume::getDeviceForVolume(device);
915a2b62984c7cecd1761fe272c078dd814c167942Eric Laurent        // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME
92d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        if (mIndexCur.indexOfKey(device) < 0) {
935a2b62984c7cecd1761fe272c078dd814c167942Eric Laurent            device = AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME;
94d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        }
95d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        return mIndexCur.valueFor(device);
96d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
97d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
98d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    bool canBeMuted() const { return mCanBeMuted; }
99d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    void clearCurrentVolumeIndex() { mIndexCur.clear(); }
100d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    void addCurrentVolumeIndex(audio_devices_t device, int index) { mIndexCur.add(device, index); }
101d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
102d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    void setVolumeIndexMin(int volIndexMin) { mIndexMin = volIndexMin; }
103d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    int getVolumeIndexMin() const { return mIndexMin; }
104d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
105d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    void setVolumeIndexMax(int volIndexMax) { mIndexMax = volIndexMax; }
106d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    int getVolumeIndexMax() const { return mIndexMax; }
107d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
1081fd372e40ef40643fa9d036a0c9db043475b1b02Eric Laurent    bool hasVolumeIndexForDevice(audio_devices_t device) const
1091fd372e40ef40643fa9d036a0c9db043475b1b02Eric Laurent    {
1101fd372e40ef40643fa9d036a0c9db043475b1b02Eric Laurent        device = Volume::getDeviceForVolume(device);
1111fd372e40ef40643fa9d036a0c9db043475b1b02Eric Laurent        return mIndexCur.indexOfKey(device) >= 0;
1121fd372e40ef40643fa9d036a0c9db043475b1b02Eric Laurent    }
1131fd372e40ef40643fa9d036a0c9db043475b1b02Eric Laurent
114d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    const sp<VolumeCurve> getOriginVolumeCurve(device_category deviceCategory) const
115d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
116d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        ALOG_ASSERT(mOriginVolumeCurves.indexOfKey(deviceCategory) >= 0, "Invalid device category");
117d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        return mOriginVolumeCurves.valueFor(deviceCategory);
118d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
119d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    void setVolumeCurve(device_category deviceCategory, const sp<VolumeCurve> &volumeCurve)
120d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
121d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        ALOG_ASSERT(indexOfKey(deviceCategory) >= 0, "Invalid device category for Volume Curve");
122d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        replaceValueFor(deviceCategory, volumeCurve);
123d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
124d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
125d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    ssize_t add(const sp<VolumeCurve> &volumeCurve)
126d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
127d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        device_category deviceCategory = volumeCurve->getDeviceCategory();
128d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        ssize_t index = indexOfKey(deviceCategory);
129d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        if (index < 0) {
130d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie            // Keep track of original Volume Curves per device category in order to switch curves.
131d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie            mOriginVolumeCurves.add(deviceCategory, volumeCurve);
132d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie            return KeyedVector::add(deviceCategory, volumeCurve);
133d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        }
134d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        return index;
135d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
136d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
137d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    float volIndexToDb(device_category deviceCat, int indexInUi) const
138d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
139d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        return getCurvesFor(deviceCat)->volIndexToDb(indexInUi, mIndexMin, mIndexMax);
140d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
141d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
142d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    void dump(int fd, int spaces, bool curvePoints = false) const;
143d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
144d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffieprivate:
145d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    KeyedVector<device_category, sp<VolumeCurve> > mOriginVolumeCurves;
146d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    KeyedVector<audio_devices_t, int> mIndexCur; /**< current volume index per device. */
147d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    int mIndexMin; /**< min volume index. */
148d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    int mIndexMax; /**< max volume index. */
149d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    bool mCanBeMuted; /**< true is the stream can be muted. */
150d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie};
151d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
152d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie// Collection of Volume Curves indexed by use case
153d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffieclass VolumeCurvesCollection : public KeyedVector<audio_stream_type_t, VolumeCurvesForStream>,
154d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie                               public IVolumeCurvesCollection
155d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie{
156d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffiepublic:
157d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    VolumeCurvesCollection()
158d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
15919219b44e05555b29e00ce56ce273d168fa83888François Gaffie        // Create an empty collection of curves
16019219b44e05555b29e00ce56ce273d168fa83888François Gaffie        for (ssize_t i = 0 ; i < AUDIO_STREAM_CNT; i++) {
161d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie            audio_stream_type_t stream = static_cast<audio_stream_type_t>(i);
162d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie            KeyedVector::add(stream, VolumeCurvesForStream());
163d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        }
164d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
165d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
166d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    // Once XML has been parsed, must be call first to sanity check table and initialize indexes
167d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax)
168d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
169d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        editValueAt(stream).setVolumeIndexMin(indexMin);
170d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        editValueAt(stream).setVolumeIndexMax(indexMax);
171d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        return NO_ERROR;
172d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
173d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    virtual void clearCurrentVolumeIndex(audio_stream_type_t stream)
174d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
175d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        editCurvesFor(stream).clearCurrentVolumeIndex();
176d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
177d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    virtual void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, int index)
178d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
179d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        editCurvesFor(stream).addCurrentVolumeIndex(device, index);
180d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
181d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    virtual bool canBeMuted(audio_stream_type_t stream) { return getCurvesFor(stream).canBeMuted(); }
182d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
183d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    virtual int getVolumeIndexMin(audio_stream_type_t stream) const
184d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
185d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        return getCurvesFor(stream).getVolumeIndexMin();
186d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
187d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    virtual int getVolumeIndexMax(audio_stream_type_t stream) const
188d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
189d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        return getCurvesFor(stream).getVolumeIndexMax();
190d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
191d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    virtual int getVolumeIndex(audio_stream_type_t stream, audio_devices_t device)
192d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
193d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        return getCurvesFor(stream).getVolumeIndex(device);
194d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
195d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    virtual void switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst)
196d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
197d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        const VolumeCurvesForStream &sourceCurves = getCurvesFor(streamSrc);
198d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        VolumeCurvesForStream &dstCurves = editCurvesFor(streamDst);
199d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        ALOG_ASSERT(sourceCurves.size() == dstCurves.size(), "device category not aligned");
200d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        for (size_t index = 0; index < sourceCurves.size(); index++) {
201d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie            device_category cat = sourceCurves.keyAt(index);
202d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie            dstCurves.setVolumeCurve(cat, sourceCurves.getOriginVolumeCurve(cat));
203d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        }
204d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
205d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    virtual float volIndexToDb(audio_stream_type_t stream, device_category cat, int indexInUi) const
206d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
207d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        return getCurvesFor(stream).volIndexToDb(cat, indexInUi);
208d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
2091fd372e40ef40643fa9d036a0c9db043475b1b02Eric Laurent    virtual bool hasVolumeIndexForDevice(audio_stream_type_t stream,
2101fd372e40ef40643fa9d036a0c9db043475b1b02Eric Laurent                                         audio_devices_t device) const
2111fd372e40ef40643fa9d036a0c9db043475b1b02Eric Laurent    {
2121fd372e40ef40643fa9d036a0c9db043475b1b02Eric Laurent        return getCurvesFor(stream).hasVolumeIndexForDevice(device);
2131fd372e40ef40643fa9d036a0c9db043475b1b02Eric Laurent    }
214d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
215d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    virtual status_t dump(int fd) const;
216d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie
217d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    ssize_t add(const sp<VolumeCurve> &volumeCurve)
218d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
219d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        audio_stream_type_t streamType = volumeCurve->getStreamType();
220d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        return editCurvesFor(streamType).add(volumeCurve);
221d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
222d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    VolumeCurvesForStream &editCurvesFor(audio_stream_type_t stream)
223d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
224d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        ALOG_ASSERT(indexOfKey(stream) >= 0, "Invalid stream type for Volume Curve");
225d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        return editValueAt(stream);
226d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
227d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    const VolumeCurvesForStream &getCurvesFor(audio_stream_type_t stream) const
228d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    {
229d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        ALOG_ASSERT(indexOfKey(stream) >= 0, "Invalid stream type for Volume Curve");
230d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie        return valueFor(stream);
231d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie    }
232d1ab2bd4f1ea166a7e9e81cfd7f3e5dd47135d4dFrançois Gaffie};
233f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie
234f4ad6e5637b6deccdac4b60615383f290b3806cfFrançois Gaffie}; // namespace android
235