VolumeShaper.h revision 39399b6b08b4e9fd7eae50e58e93b07216ad697f
19fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung/*
29fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * Copyright 2017 The Android Open Source Project
39fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung *
49fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * Licensed under the Apache License, Version 2.0 (the "License");
59fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * you may not use this file except in compliance with the License.
69fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * You may obtain a copy of the License at
79fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung *
89fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung *      http://www.apache.org/licenses/LICENSE-2.0
99fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung *
109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * Unless required by applicable law or agreed to in writing, software
119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * distributed under the License is distributed on an "AS IS" BASIS,
129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * See the License for the specific language governing permissions and
149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * limitations under the License.
159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung */
169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#ifndef ANDROID_VOLUME_SHAPER_H
189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#define ANDROID_VOLUME_SHAPER_H
199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
204ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung#include <cmath>
219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <list>
229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <math.h>
239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <sstream>
249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <binder/Parcel.h>
269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <media/Interpolator.h>
279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <utils/Mutex.h>
289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <utils/RefBase.h>
299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#pragma push_macro("LOG_TAG")
319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#undef LOG_TAG
329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#define LOG_TAG "VolumeShaper"
339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// turn on VolumeShaper logging
359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#if 0
369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#define VS_LOG ALOGD
379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#else
389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#define VS_LOG(...)
399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#endif
409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungnamespace android {
429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// The native VolumeShaper class mirrors the java VolumeShaper class;
449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// in addition, the native class contains implementation for actual operation.
459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung//
469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// VolumeShaper methods are not safe for multiple thread access.
479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// Use VolumeHandler for thread-safe encapsulation of multiple VolumeShapers.
489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung//
499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// Classes below written are to avoid naked pointers so there are no
509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// explicit destructors required.
519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungclass VolumeShaper {
539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungpublic:
549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    using S = float;
559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    using T = float;
569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    static const int kSystemIdMax = 16;
589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // VolumeShaper::Status is equivalent to status_t if negative
609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // but if non-negative represents the id operated on.
619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // It must be expressible as an int32_t for binder purposes.
629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    using Status = status_t;
639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    class Configuration : public Interpolator<S, T>, public RefBase {
659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    public:
669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        /* VolumeShaper.Configuration derives from the Interpolator class and adds
679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         * parameters relating to the volume shape.
689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         */
699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        // TODO document as per VolumeShaper.java flags.
719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        // must match with VolumeShaper.java in frameworks/base
739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        enum Type : int32_t {
749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            TYPE_ID,
759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            TYPE_SCALE,
769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        };
779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        // must match with VolumeShaper.java in frameworks/base
799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        enum OptionFlag : int32_t {
809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            OPTION_FLAG_NONE           = 0,
819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            OPTION_FLAG_VOLUME_IN_DBFS = (1 << 0),
829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            OPTION_FLAG_CLOCK_TIME     = (1 << 1),
839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            OPTION_FLAG_ALL            = (OPTION_FLAG_VOLUME_IN_DBFS | OPTION_FLAG_CLOCK_TIME),
859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        };
869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        // bring to derived class; must match with VolumeShaper.java in frameworks/base
889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        using InterpolatorType = Interpolator<S, T>::InterpolatorType;
899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Configuration()
919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : Interpolator<S, T>()
929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mType(TYPE_SCALE)
939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mOptionFlags(OPTION_FLAG_NONE)
949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mDurationMs(1000.)
959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mId(-1) {
969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
987d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung        explicit Configuration(const Configuration &configuration)
9910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            : Interpolator<S, T>(*static_cast<const Interpolator<S, T> *>(&configuration))
10010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            , mType(configuration.mType)
10110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            , mOptionFlags(configuration.mOptionFlags)
10210cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            , mDurationMs(configuration.mDurationMs)
10310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            , mId(configuration.mId) {
10410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        }
10510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung
1069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Type getType() const {
1079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mType;
1089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t setType(Type type) {
1119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            switch (type) {
1129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            case TYPE_ID:
1139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            case TYPE_SCALE:
1149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mType = type;
1159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return NO_ERROR;
1169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            default:
1179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGE("invalid Type: %d", type);
1189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return BAD_VALUE;
1199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        OptionFlag getOptionFlags() const {
1239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mOptionFlags;
1249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t setOptionFlags(OptionFlag optionFlags) {
1279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((optionFlags & ~OPTION_FLAG_ALL) != 0) {
1289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGE("optionFlags has invalid bits: %#x", optionFlags);
1299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return BAD_VALUE;
1309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mOptionFlags = optionFlags;
1329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return NO_ERROR;
1339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        double getDurationMs() const {
1369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mDurationMs;
1379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setDurationMs(double durationMs) {
1409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mDurationMs = durationMs;
1419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        int32_t getId() const {
1449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mId;
1459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setId(int32_t id) {
1489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mId = id;
1499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        T adjustVolume(T volume) const {
1529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
1539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const T out = powf(10.f, volume / 10.);
1549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                VS_LOG("in: %f  out: %f", volume, out);
1559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                volume = out;
1569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            // clamp
1589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (volume < 0.f) {
1599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                volume = 0.f;
1609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            } else if (volume > 1.f) {
1619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                volume = 1.f;
1629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return volume;
1649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t checkCurve() {
1679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (mType == TYPE_ID) return NO_ERROR;
1689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (this->size() < 2) {
1699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGE("curve must have at least 2 points");
1709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return BAD_VALUE;
1719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (first().first != 0.f || last().first != 1.f) {
1739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGE("curve must start at 0.f and end at 1.f");
1749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return BAD_VALUE;
1759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
1779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (const auto &pt : *this) {
1789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    if (!(pt.second <= 0.f) /* handle nan */) {
1799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        ALOGE("positive volume dbFS");
1809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        return BAD_VALUE;
1819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    }
1829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
1839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            } else {
1849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (const auto &pt : *this) {
1859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    if (!(pt.second >= 0.f) || !(pt.second <= 1.f) /* handle nan */) {
1869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        ALOGE("volume < 0.f or > 1.f");
1879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        return BAD_VALUE;
1889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    }
1899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
1909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return NO_ERROR;
1929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void clampVolume() {
1959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
1969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (auto it = this->begin(); it != this->end(); ++it) {
1979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    if (!(it->second <= 0.f) /* handle nan */) {
1989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        it->second = 0.f;
1999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    }
2009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
2019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            } else {
2029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (auto it = this->begin(); it != this->end(); ++it) {
2039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    if (!(it->second >= 0.f) /* handle nan */) {
2049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        it->second = 0.f;
2059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    } else if (!(it->second <= 1.f)) {
2069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        it->second = 1.f;
2079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    }
2089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
2099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
2109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        /* scaleToStartVolume() is used to set the start volume of a
2139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         * new VolumeShaper curve, when replacing one VolumeShaper
2149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         * with another using the "join" (volume match) option.
2159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         *
2169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         * It works best for monotonic volume ramps or ducks.
2179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         */
2189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void scaleToStartVolume(T volume) {
2199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (this->size() < 2) {
2209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return;
2219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
2229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const T startVolume = first().second;
2239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const T endVolume = last().second;
2249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (endVolume == startVolume) {
2259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                // match with linear ramp
2269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const T offset = volume - startVolume;
2279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (auto it = this->begin(); it != this->end(); ++it) {
2289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    it->second = it->second + offset * (1.f - it->first);
2299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
2309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            } else {
2319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const T  scale = (volume - endVolume) / (startVolume - endVolume);
2329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (auto it = this->begin(); it != this->end(); ++it) {
2339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    it->second = scale * (it->second - endVolume) + endVolume;
2349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
2359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
2369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            clampVolume();
2379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2397d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung        // The parcel layout must match VolumeShaper.java
2409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t writeToParcel(Parcel *parcel) const {
2419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (parcel == nullptr) return BAD_VALUE;
2429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel->writeInt32((int32_t)mType)
2439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: parcel->writeInt32(mId)
2449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: mType == TYPE_ID
2459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        ? NO_ERROR
2469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        : parcel->writeInt32((int32_t)mOptionFlags)
2479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: parcel->writeDouble(mDurationMs)
2489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: Interpolator<S, T>::writeToParcel(parcel);
2499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t readFromParcel(const Parcel &parcel) {
2529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            int32_t type, optionFlags;
2539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel.readInt32(&type)
2549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: setType((Type)type)
2559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: parcel.readInt32(&mId)
2569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: mType == TYPE_ID
2579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        ? NO_ERROR
2589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        : parcel.readInt32(&optionFlags)
2599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: setOptionFlags((OptionFlag)optionFlags)
2609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: parcel.readDouble(&mDurationMs)
2619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: Interpolator<S, T>::readFromParcel(parcel)
2629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: checkCurve();
2639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::string toString() const {
2669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            std::stringstream ss;
2679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mType: " << mType << std::endl;
2689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mId: " << mId << std::endl;
2699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (mType != TYPE_ID) {
2709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ss << "mOptionFlags: " << mOptionFlags << std::endl;
2719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ss << "mDurationMs: " << mDurationMs << std::endl;
2729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ss << Interpolator<S, T>::toString().c_str();
2739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
2749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return ss.str();
2759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    private:
2789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Type mType;
2799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        int32_t mId;
2809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        OptionFlag mOptionFlags;
2819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        double mDurationMs;
2829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }; // Configuration
2839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // must match with VolumeShaper.java in frameworks/base
2859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // TODO document per VolumeShaper.java flags.
2869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    class Operation : public RefBase {
2879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    public:
2889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        enum Flag : int32_t {
2899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_NONE      = 0,
2909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_REVERSE   = (1 << 0),
2919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_TERMINATE = (1 << 1),
2929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_JOIN      = (1 << 2),
2939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_DELAY     = (1 << 3),
2944ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            FLAG_CREATE_IF_NECESSARY = (1 << 4),
2959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2964ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            FLAG_ALL       = (FLAG_REVERSE | FLAG_TERMINATE | FLAG_JOIN | FLAG_DELAY
2974ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                            | FLAG_CREATE_IF_NECESSARY),
2989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        };
2999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Operation()
3014ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            : Operation(FLAG_NONE, -1 /* replaceId */) {
3029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3047d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung        Operation(Flag flags, int replaceId)
3054ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            : Operation(flags, replaceId, std::numeric_limits<S>::quiet_NaN() /* xOffset */) {
3064ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        }
3074ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung
3087d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung        explicit Operation(const Operation &operation)
3094ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            : Operation(operation.mFlags, operation.mReplaceId, operation.mXOffset) {
3104ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        }
3114ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung
3127d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung        explicit Operation(const sp<Operation> &operation)
3137d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung            : Operation(*operation.get()) {
3147d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung        }
3157d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung
3167d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung        Operation(Flag flags, int replaceId, S xOffset)
3179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : mFlags(flags)
3184ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            , mReplaceId(replaceId)
3194ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            , mXOffset(xOffset) {
3209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        int32_t getReplaceId() const {
3239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mReplaceId;
3249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setReplaceId(int32_t replaceId) {
3279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mReplaceId = replaceId;
3289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3304ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        S getXOffset() const {
3314ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            return mXOffset;
3324ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        }
3334ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung
3344ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        void setXOffset(S xOffset) {
3354ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            mXOffset = xOffset;
3364ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        }
3374ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung
3389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Flag getFlags() const {
3399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mFlags;
3409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t setFlags(Flag flags) {
3439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((flags & ~FLAG_ALL) != 0) {
3449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGE("flags has invalid bits: %#x", flags);
3459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return BAD_VALUE;
3469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
3479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mFlags = flags;
3489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return NO_ERROR;
3499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t writeToParcel(Parcel *parcel) const {
3529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (parcel == nullptr) return BAD_VALUE;
3539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel->writeInt32((int32_t)mFlags)
3544ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                    ?: parcel->writeInt32(mReplaceId)
3554ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                    ?: parcel->writeFloat(mXOffset);
3569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t readFromParcel(const Parcel &parcel) {
3599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            int32_t flags;
3609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel.readInt32(&flags)
3619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: parcel.readInt32(&mReplaceId)
3624ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                    ?: parcel.readFloat(&mXOffset)
3639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: setFlags((Flag)flags);
3649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::string toString() const {
3679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            std::stringstream ss;
3689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mFlags: " << mFlags << std::endl;
3699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mReplaceId: " << mReplaceId << std::endl;
3704ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            ss << "mXOffset: " << mXOffset << std::endl;
3719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return ss.str();
3729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    private:
3759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Flag mFlags;
3769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        int32_t mReplaceId;
3774ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        S mXOffset;
3789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }; // Operation
3799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // must match with VolumeShaper.java in frameworks/base
3819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    class State : public RefBase {
3829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    public:
3837d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung        State(T volume, S xOffset)
3849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : mVolume(volume)
3859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mXOffset(xOffset) {
3869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        State()
3899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : State(-1.f, -1.f) { }
3909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        T getVolume() const {
3929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mVolume;
3939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setVolume(T volume) {
3969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mVolume = volume;
3979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        S getXOffset() const {
4009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mXOffset;
4019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setXOffset(S xOffset) {
4049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mXOffset = xOffset;
4059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t writeToParcel(Parcel *parcel) const {
4089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (parcel == nullptr) return BAD_VALUE;
4099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel->writeFloat(mVolume)
4109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: parcel->writeFloat(mXOffset);
4119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t readFromParcel(const Parcel &parcel) {
4149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel.readFloat(&mVolume)
4159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                     ?: parcel.readFloat(&mXOffset);
4169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::string toString() const {
4199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            std::stringstream ss;
4209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mVolume: " << mVolume << std::endl;
4219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mXOffset: " << mXOffset << std::endl;
4229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return ss.str();
4239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    private:
4269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        T mVolume;
4279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        S mXOffset;
4289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }; // State
4299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    template <typename R>
4319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    class Translate {
4329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    public:
4339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Translate()
4349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : mOffset(0)
4359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mScale(1) {
4369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        R getOffset() const {
4399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mOffset;
4409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setOffset(R offset) {
4439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mOffset = offset;
4449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        R getScale() const {
4479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mScale;
4489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setScale(R scale) {
4519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mScale = scale;
4529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        R operator()(R in) const {
4559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mScale * (in - mOffset);
4569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::string toString() const {
4599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            std::stringstream ss;
4609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mOffset: " << mOffset << std::endl;
4619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mScale: " << mScale << std::endl;
4629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return ss.str();
4639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    private:
4669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        R mOffset;
4679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        R mScale;
4689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }; // Translate
4699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    static int64_t convertTimespecToUs(const struct timespec &tv)
4719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    {
4729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000;
4739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
4749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // current monotonic time in microseconds.
4769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    static int64_t getNowUs()
4779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    {
4789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        struct timespec tv;
4799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (clock_gettime(CLOCK_MONOTONIC, &tv) != 0) {
4809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return 0; // system is really sick, just return 0 for consistency.
4819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return convertTimespecToUs(tv);
4839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
4849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // TODO: Since we pass configuration and operation as shared pointers
4869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // there is a potential risk that the caller may modify these after
4879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // delivery.  Currently, we don't require copies made here.
4887d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung    VolumeShaper(
4899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const sp<VolumeShaper::Configuration> &configuration,
4909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const sp<VolumeShaper::Operation> &operation)
4919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        : mConfiguration(configuration) // we do not make a copy
4929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        , mOperation(operation)         // ditto
4939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        , mStartFrame(-1)
4949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        , mLastVolume(T(1))
4954ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        , mLastXOffset(0.f)
4964ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        , mDelayXOffset(std::numeric_limits<S>::quiet_NaN()) {
4979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (configuration.get() != nullptr
4989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                && (getFlags() & VolumeShaper::Operation::FLAG_DELAY) == 0) {
4999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mLastVolume = configuration->first().second;
5009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
5019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
5029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    void updatePosition(int64_t startFrame, double sampleRate) {
5049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        double scale = (mConfiguration->last().first - mConfiguration->first().first)
5059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        / (mConfiguration->getDurationMs() * 0.001 * sampleRate);
5069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const double minScale = 1. / INT64_MAX;
5079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        scale = std::max(scale, minScale);
5084ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        const S xOffset = std::isnan(mDelayXOffset) ? mConfiguration->first().first : mDelayXOffset;
5094ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        VS_LOG("update position: scale %lf  frameCount:%lld, sampleRate:%lf, xOffset:%f",
5104ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                scale, (long long) startFrame, sampleRate, xOffset);
5114ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung
5124ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        mXTranslate.setOffset(startFrame - xOffset / scale);
5139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        mXTranslate.setScale(scale);
5149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("translate: %s", mXTranslate.toString().c_str());
5159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
5169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // We allow a null operation here, though VolumeHandler always provides one.
5189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    VolumeShaper::Operation::Flag getFlags() const {
5199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return mOperation == nullptr
5209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ? VolumeShaper::Operation::FLAG_NONE :mOperation->getFlags();
5219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
5229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    sp<VolumeShaper::State> getState() const {
5244ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        return new VolumeShaper::State(mLastVolume, mLastXOffset);
5254ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    }
5264ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung
5274ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    void setDelayXOffset(S xOffset) {
5284ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        mDelayXOffset = xOffset;
5299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
5309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
53139399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung    bool isStarted() const {
53239399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung        return mStartFrame >= 0;
53339399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung    }
53439399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung
53510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung    std::pair<T /* volume */, bool /* active */> getVolume(
53610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            int64_t trackFrameCount, double trackSampleRate) {
5379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if ((getFlags() & VolumeShaper::Operation::FLAG_DELAY) != 0) {
5389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            VS_LOG("delayed VolumeShaper, ignoring");
5399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mLastVolume = T(1);
5404ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            mLastXOffset = 0.;
5419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return std::make_pair(T(1), false);
5429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
5439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const bool clockTime = (mConfiguration->getOptionFlags()
5449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) != 0;
5459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const int64_t frameCount = clockTime ? getNowUs() : trackFrameCount;
5469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const double sampleRate = clockTime ? 1000000 : trackSampleRate;
5479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (mStartFrame < 0) {
5499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            updatePosition(frameCount, sampleRate);
5509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mStartFrame = frameCount;
5519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
5529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("frameCount: %lld", (long long)frameCount);
5539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        S x = mXTranslate((T)frameCount);
5549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("translation: %f", x);
5559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        // handle reversal of position
5579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (getFlags() & VolumeShaper::Operation::FLAG_REVERSE) {
5589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            x = 1.f - x;
5599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            VS_LOG("reversing to %f", x);
5609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (x < mConfiguration->first().first) {
5614ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                mLastXOffset = 1.f;
5629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const T volume = mConfiguration->adjustVolume(
5639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        mConfiguration->first().second);  // persist last value
5649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                VS_LOG("persisting volume %f", volume);
5659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mLastVolume = volume;
5669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return std::make_pair(volume, false);
5679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
5689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (x > mConfiguration->last().first) {
5694ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                mLastXOffset = 0.f;
5709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mLastVolume = 1.f;
57110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                return std::make_pair(T(1), true); // too early
5729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
5739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        } else {
5749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (x < mConfiguration->first().first) {
5754ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                mLastXOffset = 0.f;
5769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mLastVolume = 1.f;
57710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                return std::make_pair(T(1), true); // too early
5789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
5799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (x > mConfiguration->last().first) {
5804ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                mLastXOffset = 1.f;
5819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const T volume = mConfiguration->adjustVolume(
5829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        mConfiguration->last().second);  // persist last value
5839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                VS_LOG("persisting volume %f", volume);
5849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mLastVolume = volume;
5859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return std::make_pair(volume, false);
5869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
5879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
5884ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        mLastXOffset = x;
5899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        // x contains the location on the volume curve to use.
5909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const T unscaledVolume = mConfiguration->findY(x);
5914ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        const T volume = mConfiguration->adjustVolume(unscaledVolume); // handle log scale
5929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("volume: %f  unscaled: %f", volume, unscaledVolume);
5939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        mLastVolume = volume;
59410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        return std::make_pair(volume, true);
5959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
5969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    std::string toString() const {
5989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::stringstream ss;
5999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        ss << "StartFrame: " << mStartFrame << std::endl;
6009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        ss << mXTranslate.toString().c_str();
6019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (mConfiguration.get() == nullptr) {
6029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "VolumeShaper::Configuration: nullptr" << std::endl;
6039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        } else {
6049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "VolumeShaper::Configuration:" << std::endl;
6059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << mConfiguration->toString().c_str();
6069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
6079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (mOperation.get() == nullptr) {
6089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "VolumeShaper::Operation: nullptr" << std::endl;
6099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        } else {
6109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "VolumeShaper::Operation:" << std::endl;
6119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << mOperation->toString().c_str();
6129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
6139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return ss.str();
6149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
6154ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung
6164ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    Translate<S> mXTranslate; // x axis translation from frames (in usec for clock time)
6174ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    sp<VolumeShaper::Configuration> mConfiguration;
6184ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    sp<VolumeShaper::Operation> mOperation;
6194ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    int64_t mStartFrame; // starting frame, non-negative when started (in usec for clock time)
6204ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    T mLastVolume;       // last computed interpolated volume (y-axis)
6214ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    S mLastXOffset;      // last computed interpolated xOffset/time (x-axis)
6224ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    S mDelayXOffset;     // delay xOffset on first volumeshaper start.
6239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung}; // VolumeShaper
6249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
6259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// VolumeHandler combines the volume factors of multiple VolumeShapers and handles
6269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// multiple thread access by synchronizing all public methods.
6279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungclass VolumeHandler : public RefBase {
6289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungpublic:
6299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    using S = float;
6309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    using T = float;
6319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
6324ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    // A volume handler which just keeps track of active VolumeShapers does not need sampleRate.
6334ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    VolumeHandler()
6344ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        : VolumeHandler(0 /* sampleRate */) {
6354ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    }
6364ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung
6379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    explicit VolumeHandler(uint32_t sampleRate)
6389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        : mSampleRate((double)sampleRate)
6394ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        , mLastFrame(0)
640da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung        , mVolumeShaperIdCounter(VolumeShaper::kSystemIdMax)
641da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung        , mLastVolume(1.f, false) {
6429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
6439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
6449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    VolumeShaper::Status applyVolumeShaper(
6459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const sp<VolumeShaper::Configuration> &configuration,
6469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const sp<VolumeShaper::Operation> &operation) {
64710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        VS_LOG("applyVolumeShaper:configuration: %s", configuration->toString().c_str());
64810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        VS_LOG("applyVolumeShaper:operation: %s", operation->toString().c_str());
6499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        AutoMutex _l(mLock);
6509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (configuration == nullptr) {
6519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ALOGE("null configuration");
6529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return VolumeShaper::Status(BAD_VALUE);
6539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
6549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (operation == nullptr) {
6559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ALOGE("null operation");
6569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return VolumeShaper::Status(BAD_VALUE);
6579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
6589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const int32_t id = configuration->getId();
6599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (id < 0) {
6609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ALOGE("negative id: %d", id);
6619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return VolumeShaper::Status(BAD_VALUE);
6629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
6639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("applyVolumeShaper id: %d", id);
6649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
6659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        switch (configuration->getType()) {
6669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        case VolumeShaper::Configuration::TYPE_SCALE: {
6679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const int replaceId = operation->getReplaceId();
6689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (replaceId >= 0) {
6699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                auto replaceIt = findId_l(replaceId);
6709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                if (replaceIt == mVolumeShapers.end()) {
6719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ALOGW("cannot find replace id: %d", replaceId);
6729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                } else {
6739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    if ((replaceIt->getFlags() & VolumeShaper::Operation::FLAG_JOIN) != 0) {
6749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        // For join, we scale the start volume of the current configuration
6759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        // to match the last-used volume of the replacing VolumeShaper.
6769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        auto state = replaceIt->getState();
6779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        if (state->getXOffset() >= 0) { // valid
6789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            const T volume = state->getVolume();
6799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ALOGD("join: scaling start volume to %f", volume);
6809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            configuration->scaleToStartVolume(volume);
6819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        }
6829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    }
6839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    (void)mVolumeShapers.erase(replaceIt);
6849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
6854ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                operation->setReplaceId(-1);
6869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
6879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            // check if we have another of the same id.
6889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            auto oldIt = findId_l(id);
6899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (oldIt != mVolumeShapers.end()) {
6904ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                if ((operation->getFlags()
6914ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                        & VolumeShaper::Operation::FLAG_CREATE_IF_NECESSARY) != 0) {
6924ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                    // TODO: move the case to a separate function.
6934ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                    goto HANDLE_TYPE_ID; // no need to create, take over existing id.
6944ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                }
6959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGW("duplicate id, removing old %d", id);
6969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                (void)mVolumeShapers.erase(oldIt);
6979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
6989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            // create new VolumeShaper
6999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mVolumeShapers.emplace_back(configuration, operation);
70010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        }
70110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        // fall through to handle the operation
7024ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        HANDLE_TYPE_ID:
70310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        case VolumeShaper::Configuration::TYPE_ID: {
70410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            VS_LOG("trying to find id: %d", id);
70510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            auto it = findId_l(id);
70610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            if (it == mVolumeShapers.end()) {
70710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                VS_LOG("couldn't find id: %d", id);
70810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                return VolumeShaper::Status(INVALID_OPERATION);
70910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            }
71010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            if ((it->getFlags() & VolumeShaper::Operation::FLAG_TERMINATE) != 0) {
71110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                VS_LOG("terminate id: %d", id);
71210cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                mVolumeShapers.erase(it);
71310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                break;
71410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            }
71510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            const bool clockTime = (it->mConfiguration->getOptionFlags()
71610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                    & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) != 0;
71710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            if ((it->getFlags() & VolumeShaper::Operation::FLAG_REVERSE) !=
71810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                    (operation->getFlags() & VolumeShaper::Operation::FLAG_REVERSE)) {
71910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                const int64_t frameCount = clockTime ? VolumeShaper::getNowUs() : mLastFrame;
72010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                const S x = it->mXTranslate((T)frameCount);
72110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                VS_LOG("reverse translation: %f", x);
72210cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                // reflect position
72310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                S target = 1.f - x;
72410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                if (target < it->mConfiguration->first().first) {
72510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                    VS_LOG("clamp to start - begin immediately");
72610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                    target = 0.;
72710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                }
72810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                VS_LOG("target reverse: %f", target);
72910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                it->mXTranslate.setOffset(it->mXTranslate.getOffset()
73010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                        + (x - target) / it->mXTranslate.getScale());
73110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            }
7324ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            const S xOffset = operation->getXOffset();
7334ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            if (!std::isnan(xOffset)) {
7344ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                const int64_t frameCount = clockTime ? VolumeShaper::getNowUs() : mLastFrame;
7354ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                const S x = it->mXTranslate((T)frameCount);
7364ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                VS_LOG("xOffset translation: %f", x);
7374ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                const S target = xOffset; // offset
7384ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                VS_LOG("xOffset target x offset: %f", target);
7394ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                it->mXTranslate.setOffset(it->mXTranslate.getOffset()
7404ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                        + (x - target) / it->mXTranslate.getScale());
7414ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                it->setDelayXOffset(xOffset);
7424ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            }
74310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            it->mOperation = operation; // replace the operation
7449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        } break;
7459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
7469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return VolumeShaper::Status(id);
7479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
7489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
7499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    sp<VolumeShaper::State> getVolumeShaperState(int id) {
7509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        AutoMutex _l(mLock);
7519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        auto it = findId_l(id);
7529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (it == mVolumeShapers.end()) {
7534ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            VS_LOG("cannot find state for id: %d", id);
7549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return nullptr;
7559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
7569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return it->getState();
7579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
7589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
75939399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung    // getVolume() is not const, as it updates internal state.
76039399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung    // Once called, any VolumeShapers not already started begin running.
76110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung    std::pair<T /* volume */, bool /* active */> getVolume(int64_t trackFrameCount) {
7629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        AutoMutex _l(mLock);
7639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        mLastFrame = trackFrameCount;
7649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        T volume(1);
76510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        size_t activeCount = 0;
7669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        for (auto it = mVolumeShapers.begin(); it != mVolumeShapers.end();) {
7679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            std::pair<T, bool> shaperVolume =
7689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    it->getVolume(trackFrameCount, mSampleRate);
7699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            volume *= shaperVolume.first;
77010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            activeCount += shaperVolume.second;
7719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ++it;
7729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
773da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung        mLastVolume = std::make_pair(volume, activeCount != 0);
774da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung        return mLastVolume;
775da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung    }
776da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung
77739399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung    // Used by a client side VolumeHandler to ensure all the VolumeShapers
77839399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung    // indicate that they have been started.  Upon a change in audioserver
77939399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung    // output sink, this information is used for restoration of the server side
78039399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung    // VolumeHandler.
78139399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung    void setStarted() {
78239399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung        (void)getVolume(mLastFrame);  // getVolume() will start the individual VolumeShapers.
78339399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung    }
78439399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung
785da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung    std::pair<T /* volume */, bool /* active */> getLastVolume() const {
786da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung        AutoMutex _l(mLock);
787da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung        return mLastVolume;
7889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
7899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
7909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    std::string toString() const {
7919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        AutoMutex _l(mLock);
7929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::stringstream ss;
7939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        ss << "mSampleRate: " << mSampleRate << std::endl;
7949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        ss << "mLastFrame: " << mLastFrame << std::endl;
7959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        for (const auto &shaper : mVolumeShapers) {
7969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << shaper.toString().c_str();
7979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
7989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return ss.str();
7999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
8009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
80139399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung    void forall(const std::function<VolumeShaper::Status (const VolumeShaper &)> &lambda) {
8024ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        AutoMutex _l(mLock);
803da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung        VS_LOG("forall: mVolumeShapers.size() %zu", mVolumeShapers.size());
8044ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        for (const auto &shaper : mVolumeShapers) {
80539399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung            VolumeShaper::Status status = lambda(shaper);
80639399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung            VS_LOG("forall applying lambda on shaper (%p): %d", &shaper, (int)status);
8074ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        }
8084ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    }
8094ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung
8104ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    void reset() {
8114ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        AutoMutex _l(mLock);
8124ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        mVolumeShapers.clear();
8137d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung        mLastFrame = 0;
8144ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        // keep mVolumeShaperIdCounter as is.
8154ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    }
8164ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung
8174ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    // Sets the configuration id if necessary - This is based on the counter
8184ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    // internal to the VolumeHandler.
8194ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    void setIdIfNecessary(const sp<VolumeShaper::Configuration> &configuration) {
8204ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        if (configuration->getType() == VolumeShaper::Configuration::TYPE_SCALE) {
8214ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            const int id = configuration->getId();
8224ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            if (id == -1) {
8234ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                // Reassign to a unique id, skipping system ids.
8244ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                AutoMutex _l(mLock);
8254ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                while (true) {
8264ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                    if (mVolumeShaperIdCounter == INT32_MAX) {
8274ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                        mVolumeShaperIdCounter = VolumeShaper::kSystemIdMax;
8284ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                    } else {
8294ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                        ++mVolumeShaperIdCounter;
8304ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                    }
8314ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                    if (findId_l(mVolumeShaperIdCounter) != mVolumeShapers.end()) {
8324ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                        continue; // collision with an existing id.
8334ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                    }
8344ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                    configuration->setId(mVolumeShaperIdCounter);
8354ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                    ALOGD("setting id to %d", mVolumeShaperIdCounter);
8364ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                    break;
8374ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung                }
8384ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung            }
8394ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung        }
8404ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    }
8414ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung
8429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungprivate:
8439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    std::list<VolumeShaper>::iterator findId_l(int32_t id) {
8449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::list<VolumeShaper>::iterator it = mVolumeShapers.begin();
8459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        for (; it != mVolumeShapers.end(); ++it) {
8469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (it->mConfiguration->getId() == id) {
8479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                break;
8489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
8499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
8509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return it;
8519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
8529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
8539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    mutable Mutex mLock;
8549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    double mSampleRate; // in samples (frames) per second
8557d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung    int64_t mLastFrame; // logging purpose only, 0 on start
8564ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung    int32_t mVolumeShaperIdCounter; // a counter to return a unique volume shaper id.
857da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung    std::pair<T /* volume */, bool /* active */> mLastVolume;
8589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    std::list<VolumeShaper> mVolumeShapers; // list provides stable iterators on erase
8599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung}; // VolumeHandler
8609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
8619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung} // namespace android
8629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
8639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#pragma pop_macro("LOG_TAG")
8649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
8659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#endif // ANDROID_VOLUME_SHAPER_H
866