VolumeShaper.h revision 10cbff139360f3f642e0e3b3ccf2d463dbed22cf
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
209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <list>
219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <math.h>
229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <sstream>
239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <binder/Parcel.h>
259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <media/Interpolator.h>
269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <utils/Mutex.h>
279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <utils/RefBase.h>
289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#pragma push_macro("LOG_TAG")
309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#undef LOG_TAG
319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#define LOG_TAG "VolumeShaper"
329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// turn on VolumeShaper logging
349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#if 0
359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#define VS_LOG ALOGD
369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#else
379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#define VS_LOG(...)
389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#endif
399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungnamespace android {
419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// The native VolumeShaper class mirrors the java VolumeShaper class;
439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// in addition, the native class contains implementation for actual operation.
449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung//
459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// VolumeShaper methods are not safe for multiple thread access.
469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// Use VolumeHandler for thread-safe encapsulation of multiple VolumeShapers.
479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung//
489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// Classes below written are to avoid naked pointers so there are no
499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// explicit destructors required.
509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungclass VolumeShaper {
529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungpublic:
539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    using S = float;
549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    using T = float;
559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    static const int kSystemIdMax = 16;
579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // VolumeShaper::Status is equivalent to status_t if negative
599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // but if non-negative represents the id operated on.
609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // It must be expressible as an int32_t for binder purposes.
619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    using Status = status_t;
629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    class Configuration : public Interpolator<S, T>, public RefBase {
649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    public:
659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        /* VolumeShaper.Configuration derives from the Interpolator class and adds
669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         * parameters relating to the volume shape.
679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         */
689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        // TODO document as per VolumeShaper.java flags.
709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        // must match with VolumeShaper.java in frameworks/base
729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        enum Type : int32_t {
739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            TYPE_ID,
749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            TYPE_SCALE,
759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        };
769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        // must match with VolumeShaper.java in frameworks/base
789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        enum OptionFlag : int32_t {
799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            OPTION_FLAG_NONE           = 0,
809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            OPTION_FLAG_VOLUME_IN_DBFS = (1 << 0),
819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            OPTION_FLAG_CLOCK_TIME     = (1 << 1),
829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            OPTION_FLAG_ALL            = (OPTION_FLAG_VOLUME_IN_DBFS | OPTION_FLAG_CLOCK_TIME),
849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        };
859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        // bring to derived class; must match with VolumeShaper.java in frameworks/base
879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        using InterpolatorType = Interpolator<S, T>::InterpolatorType;
889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Configuration()
909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : Interpolator<S, T>()
919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mType(TYPE_SCALE)
929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mOptionFlags(OPTION_FLAG_NONE)
939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mDurationMs(1000.)
949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mId(-1) {
959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
9710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        Configuration(const Configuration &configuration)
9810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            : Interpolator<S, T>(*static_cast<const Interpolator<S, T> *>(&configuration))
9910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            , mType(configuration.mType)
10010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            , mOptionFlags(configuration.mOptionFlags)
10110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            , mDurationMs(configuration.mDurationMs)
10210cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            , mId(configuration.mId) {
10310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        }
10410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung
1059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Type getType() const {
1069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mType;
1079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t setType(Type type) {
1109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            switch (type) {
1119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            case TYPE_ID:
1129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            case TYPE_SCALE:
1139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mType = type;
1149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return NO_ERROR;
1159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            default:
1169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGE("invalid Type: %d", type);
1179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return BAD_VALUE;
1189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        OptionFlag getOptionFlags() const {
1229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mOptionFlags;
1239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t setOptionFlags(OptionFlag optionFlags) {
1269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((optionFlags & ~OPTION_FLAG_ALL) != 0) {
1279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGE("optionFlags has invalid bits: %#x", optionFlags);
1289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return BAD_VALUE;
1299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mOptionFlags = optionFlags;
1319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return NO_ERROR;
1329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        double getDurationMs() const {
1359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mDurationMs;
1369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setDurationMs(double durationMs) {
1399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mDurationMs = durationMs;
1409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        int32_t getId() const {
1439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mId;
1449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setId(int32_t id) {
1479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mId = id;
1489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        T adjustVolume(T volume) const {
1519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
1529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const T out = powf(10.f, volume / 10.);
1539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                VS_LOG("in: %f  out: %f", volume, out);
1549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                volume = out;
1559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            // clamp
1579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (volume < 0.f) {
1589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                volume = 0.f;
1599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            } else if (volume > 1.f) {
1609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                volume = 1.f;
1619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return volume;
1639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t checkCurve() {
1669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (mType == TYPE_ID) return NO_ERROR;
1679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (this->size() < 2) {
1689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGE("curve must have at least 2 points");
1699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return BAD_VALUE;
1709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (first().first != 0.f || last().first != 1.f) {
1729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGE("curve must start at 0.f and end at 1.f");
1739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return BAD_VALUE;
1749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
1769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (const auto &pt : *this) {
1779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    if (!(pt.second <= 0.f) /* handle nan */) {
1789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        ALOGE("positive volume dbFS");
1799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        return BAD_VALUE;
1809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    }
1819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
1829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            } else {
1839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (const auto &pt : *this) {
1849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    if (!(pt.second >= 0.f) || !(pt.second <= 1.f) /* handle nan */) {
1859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        ALOGE("volume < 0.f or > 1.f");
1869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        return BAD_VALUE;
1879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    }
1889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
1899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return NO_ERROR;
1919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void clampVolume() {
1949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
1959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (auto it = this->begin(); it != this->end(); ++it) {
1969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    if (!(it->second <= 0.f) /* handle nan */) {
1979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        it->second = 0.f;
1989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    }
1999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
2009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            } else {
2019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (auto it = this->begin(); it != this->end(); ++it) {
2029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    if (!(it->second >= 0.f) /* handle nan */) {
2039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        it->second = 0.f;
2049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    } else if (!(it->second <= 1.f)) {
2059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        it->second = 1.f;
2069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    }
2079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
2089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
2099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        /* scaleToStartVolume() is used to set the start volume of a
2129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         * new VolumeShaper curve, when replacing one VolumeShaper
2139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         * with another using the "join" (volume match) option.
2149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         *
2159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         * It works best for monotonic volume ramps or ducks.
2169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         */
2179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void scaleToStartVolume(T volume) {
2189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (this->size() < 2) {
2199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return;
2209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
2219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const T startVolume = first().second;
2229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const T endVolume = last().second;
2239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (endVolume == startVolume) {
2249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                // match with linear ramp
2259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const T offset = volume - startVolume;
2269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (auto it = this->begin(); it != this->end(); ++it) {
2279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    it->second = it->second + offset * (1.f - it->first);
2289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
2299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            } else {
2309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const T  scale = (volume - endVolume) / (startVolume - endVolume);
2319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (auto it = this->begin(); it != this->end(); ++it) {
2329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    it->second = scale * (it->second - endVolume) + endVolume;
2339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
2349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
2359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            clampVolume();
2369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t writeToParcel(Parcel *parcel) const {
2399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (parcel == nullptr) return BAD_VALUE;
2409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel->writeInt32((int32_t)mType)
2419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: parcel->writeInt32(mId)
2429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: mType == TYPE_ID
2439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        ? NO_ERROR
2449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        : parcel->writeInt32((int32_t)mOptionFlags)
2459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: parcel->writeDouble(mDurationMs)
2469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: Interpolator<S, T>::writeToParcel(parcel);
2479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t readFromParcel(const Parcel &parcel) {
2509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            int32_t type, optionFlags;
2519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel.readInt32(&type)
2529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: setType((Type)type)
2539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: parcel.readInt32(&mId)
2549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: mType == TYPE_ID
2559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        ? NO_ERROR
2569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        : parcel.readInt32(&optionFlags)
2579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: setOptionFlags((OptionFlag)optionFlags)
2589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: parcel.readDouble(&mDurationMs)
2599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: Interpolator<S, T>::readFromParcel(parcel)
2609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: checkCurve();
2619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::string toString() const {
2649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            std::stringstream ss;
2659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mType: " << mType << std::endl;
2669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mId: " << mId << std::endl;
2679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (mType != TYPE_ID) {
2689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ss << "mOptionFlags: " << mOptionFlags << std::endl;
2699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ss << "mDurationMs: " << mDurationMs << std::endl;
2709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ss << Interpolator<S, T>::toString().c_str();
2719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
2729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return ss.str();
2739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    private:
2769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Type mType;
2779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        int32_t mId;
2789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        OptionFlag mOptionFlags;
2799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        double mDurationMs;
2809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }; // Configuration
2819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // must match with VolumeShaper.java in frameworks/base
2839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // TODO document per VolumeShaper.java flags.
2849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    class Operation : public RefBase {
2859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    public:
2869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        enum Flag : int32_t {
2879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_NONE      = 0,
2889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_REVERSE   = (1 << 0),
2899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_TERMINATE = (1 << 1),
2909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_JOIN      = (1 << 2),
2919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_DELAY     = (1 << 3),
2929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_ALL       = (FLAG_REVERSE | FLAG_TERMINATE | FLAG_JOIN | FLAG_DELAY),
2949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        };
2959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Operation()
2979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : mFlags(FLAG_NONE)
2989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mReplaceId(-1) {
2999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        explicit Operation(Flag flags, int replaceId)
3029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : mFlags(flags)
3039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mReplaceId(replaceId) {
3049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        int32_t getReplaceId() const {
3079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mReplaceId;
3089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setReplaceId(int32_t replaceId) {
3119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mReplaceId = replaceId;
3129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Flag getFlags() const {
3159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mFlags;
3169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t setFlags(Flag flags) {
3199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((flags & ~FLAG_ALL) != 0) {
3209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGE("flags has invalid bits: %#x", flags);
3219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return BAD_VALUE;
3229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
3239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mFlags = flags;
3249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return NO_ERROR;
3259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t writeToParcel(Parcel *parcel) const {
3289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (parcel == nullptr) return BAD_VALUE;
3299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel->writeInt32((int32_t)mFlags)
3309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: parcel->writeInt32(mReplaceId);
3319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t readFromParcel(const Parcel &parcel) {
3349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            int32_t flags;
3359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel.readInt32(&flags)
3369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: parcel.readInt32(&mReplaceId)
3379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: setFlags((Flag)flags);
3389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::string toString() const {
3419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            std::stringstream ss;
3429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mFlags: " << mFlags << std::endl;
3439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mReplaceId: " << mReplaceId << std::endl;
3449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return ss.str();
3459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    private:
3489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Flag mFlags;
3499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        int32_t mReplaceId;
3509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }; // Operation
3519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // must match with VolumeShaper.java in frameworks/base
3539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    class State : public RefBase {
3549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    public:
3559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        explicit State(T volume, S xOffset)
3569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : mVolume(volume)
3579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mXOffset(xOffset) {
3589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        State()
3619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : State(-1.f, -1.f) { }
3629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        T getVolume() const {
3649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mVolume;
3659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setVolume(T volume) {
3689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mVolume = volume;
3699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        S getXOffset() const {
3729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mXOffset;
3739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setXOffset(S xOffset) {
3769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mXOffset = xOffset;
3779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t writeToParcel(Parcel *parcel) const {
3809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (parcel == nullptr) return BAD_VALUE;
3819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel->writeFloat(mVolume)
3829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: parcel->writeFloat(mXOffset);
3839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t readFromParcel(const Parcel &parcel) {
3869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel.readFloat(&mVolume)
3879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                     ?: parcel.readFloat(&mXOffset);
3889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::string toString() const {
3919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            std::stringstream ss;
3929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mVolume: " << mVolume << std::endl;
3939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mXOffset: " << mXOffset << std::endl;
3949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return ss.str();
3959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    private:
3989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        T mVolume;
3999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        S mXOffset;
4009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }; // State
4019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    template <typename R>
4039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    class Translate {
4049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    public:
4059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Translate()
4069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : mOffset(0)
4079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mScale(1) {
4089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        R getOffset() const {
4119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mOffset;
4129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setOffset(R offset) {
4159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mOffset = offset;
4169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        R getScale() const {
4199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mScale;
4209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setScale(R scale) {
4239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mScale = scale;
4249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        R operator()(R in) const {
4279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mScale * (in - mOffset);
4289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::string toString() const {
4319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            std::stringstream ss;
4329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mOffset: " << mOffset << std::endl;
4339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mScale: " << mScale << std::endl;
4349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return ss.str();
4359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    private:
4389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        R mOffset;
4399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        R mScale;
4409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }; // Translate
4419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    static int64_t convertTimespecToUs(const struct timespec &tv)
4439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    {
4449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000;
4459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
4469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // current monotonic time in microseconds.
4489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    static int64_t getNowUs()
4499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    {
4509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        struct timespec tv;
4519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (clock_gettime(CLOCK_MONOTONIC, &tv) != 0) {
4529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return 0; // system is really sick, just return 0 for consistency.
4539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return convertTimespecToUs(tv);
4559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
4569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    Translate<S> mXTranslate;
4589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    Translate<T> mYTranslate;
4599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    sp<VolumeShaper::Configuration> mConfiguration;
4609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    sp<VolumeShaper::Operation> mOperation;
4619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    int64_t mStartFrame;
4629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    T mLastVolume;
4639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    S mXOffset;
4649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // TODO: Since we pass configuration and operation as shared pointers
4669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // there is a potential risk that the caller may modify these after
4679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // delivery.  Currently, we don't require copies made here.
4689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    explicit VolumeShaper(
4699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const sp<VolumeShaper::Configuration> &configuration,
4709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const sp<VolumeShaper::Operation> &operation)
4719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        : mConfiguration(configuration) // we do not make a copy
4729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        , mOperation(operation)         // ditto
4739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        , mStartFrame(-1)
4749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        , mLastVolume(T(1))
4759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        , mXOffset(0.f) {
4769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (configuration.get() != nullptr
4779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                && (getFlags() & VolumeShaper::Operation::FLAG_DELAY) == 0) {
4789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mLastVolume = configuration->first().second;
4799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
4819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    void updatePosition(int64_t startFrame, double sampleRate) {
4839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        double scale = (mConfiguration->last().first - mConfiguration->first().first)
4849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        / (mConfiguration->getDurationMs() * 0.001 * sampleRate);
4859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const double minScale = 1. / INT64_MAX;
4869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        scale = std::max(scale, minScale);
4879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("update position: scale %lf  frameCount:%lld, sampleRate:%lf",
4889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                scale, (long long) startFrame, sampleRate);
4899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        mXTranslate.setOffset(startFrame - mConfiguration->first().first / scale);
4909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        mXTranslate.setScale(scale);
4919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("translate: %s", mXTranslate.toString().c_str());
4929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
4939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // We allow a null operation here, though VolumeHandler always provides one.
4959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    VolumeShaper::Operation::Flag getFlags() const {
4969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return mOperation == nullptr
4979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ? VolumeShaper::Operation::FLAG_NONE :mOperation->getFlags();
4989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
4999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    sp<VolumeShaper::State> getState() const {
5019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return new VolumeShaper::State(mLastVolume, mXOffset);
5029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
5039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
50410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung    std::pair<T /* volume */, bool /* active */> getVolume(
50510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            int64_t trackFrameCount, double trackSampleRate) {
5069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if ((getFlags() & VolumeShaper::Operation::FLAG_DELAY) != 0) {
5079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            VS_LOG("delayed VolumeShaper, ignoring");
5089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mLastVolume = T(1);
5099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mXOffset = 0.;
5109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return std::make_pair(T(1), false);
5119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
5129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const bool clockTime = (mConfiguration->getOptionFlags()
5139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) != 0;
5149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const int64_t frameCount = clockTime ? getNowUs() : trackFrameCount;
5159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const double sampleRate = clockTime ? 1000000 : trackSampleRate;
5169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (mStartFrame < 0) {
5189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            updatePosition(frameCount, sampleRate);
5199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mStartFrame = frameCount;
5209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
5219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("frameCount: %lld", (long long)frameCount);
5229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        S x = mXTranslate((T)frameCount);
5239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("translation: %f", x);
5249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        // handle reversal of position
5269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (getFlags() & VolumeShaper::Operation::FLAG_REVERSE) {
5279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            x = 1.f - x;
5289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            VS_LOG("reversing to %f", x);
5299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (x < mConfiguration->first().first) {
5309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mXOffset = 1.f;
5319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const T volume = mConfiguration->adjustVolume(
5329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        mConfiguration->first().second);  // persist last value
5339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                VS_LOG("persisting volume %f", volume);
5349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mLastVolume = volume;
5359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return std::make_pair(volume, false);
5369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
5379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (x > mConfiguration->last().first) {
5389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mXOffset = 0.f;
5399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mLastVolume = 1.f;
54010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                return std::make_pair(T(1), true); // too early
5419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
5429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        } else {
5439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (x < mConfiguration->first().first) {
5449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mXOffset = 0.f;
5459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mLastVolume = 1.f;
54610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                return std::make_pair(T(1), true); // too early
5479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
5489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (x > mConfiguration->last().first) {
5499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mXOffset = 1.f;
5509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const T volume = mConfiguration->adjustVolume(
5519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        mConfiguration->last().second);  // persist last value
5529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                VS_LOG("persisting volume %f", volume);
5539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mLastVolume = volume;
5549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return std::make_pair(volume, false);
5559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
5569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
5579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        mXOffset = x;
5589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        // x contains the location on the volume curve to use.
5599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const T unscaledVolume = mConfiguration->findY(x);
5609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const T volumeChange = mYTranslate(unscaledVolume);
5619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const T volume = mConfiguration->adjustVolume(volumeChange);
5629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("volume: %f  unscaled: %f", volume, unscaledVolume);
5639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        mLastVolume = volume;
56410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        return std::make_pair(volume, true);
5659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
5669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    std::string toString() const {
5689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::stringstream ss;
5699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        ss << "StartFrame: " << mStartFrame << std::endl;
5709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        ss << mXTranslate.toString().c_str();
5719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        ss << mYTranslate.toString().c_str();
5729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (mConfiguration.get() == nullptr) {
5739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "VolumeShaper::Configuration: nullptr" << std::endl;
5749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        } else {
5759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "VolumeShaper::Configuration:" << std::endl;
5769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << mConfiguration->toString().c_str();
5779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
5789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (mOperation.get() == nullptr) {
5799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "VolumeShaper::Operation: nullptr" << std::endl;
5809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        } else {
5819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "VolumeShaper::Operation:" << std::endl;
5829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << mOperation->toString().c_str();
5839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
5849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return ss.str();
5859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
5869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung}; // VolumeShaper
5879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// VolumeHandler combines the volume factors of multiple VolumeShapers and handles
5899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// multiple thread access by synchronizing all public methods.
5909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungclass VolumeHandler : public RefBase {
5919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungpublic:
5929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    using S = float;
5939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    using T = float;
5949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    explicit VolumeHandler(uint32_t sampleRate)
5969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        : mSampleRate((double)sampleRate)
5979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        , mLastFrame(0) {
5989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
5999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
6009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    VolumeShaper::Status applyVolumeShaper(
6019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const sp<VolumeShaper::Configuration> &configuration,
6029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const sp<VolumeShaper::Operation> &operation) {
60310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        VS_LOG("applyVolumeShaper:configuration: %s", configuration->toString().c_str());
60410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        VS_LOG("applyVolumeShaper:operation: %s", operation->toString().c_str());
6059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        AutoMutex _l(mLock);
6069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (configuration == nullptr) {
6079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ALOGE("null configuration");
6089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return VolumeShaper::Status(BAD_VALUE);
6099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
6109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (operation == nullptr) {
6119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ALOGE("null operation");
6129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return VolumeShaper::Status(BAD_VALUE);
6139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
6149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const int32_t id = configuration->getId();
6159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (id < 0) {
6169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ALOGE("negative id: %d", id);
6179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return VolumeShaper::Status(BAD_VALUE);
6189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
6199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("applyVolumeShaper id: %d", id);
6209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
6219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        switch (configuration->getType()) {
6229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        case VolumeShaper::Configuration::TYPE_SCALE: {
6239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const int replaceId = operation->getReplaceId();
6249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (replaceId >= 0) {
6259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                auto replaceIt = findId_l(replaceId);
6269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                if (replaceIt == mVolumeShapers.end()) {
6279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ALOGW("cannot find replace id: %d", replaceId);
6289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                } else {
6299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    if ((replaceIt->getFlags() & VolumeShaper::Operation::FLAG_JOIN) != 0) {
6309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        // For join, we scale the start volume of the current configuration
6319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        // to match the last-used volume of the replacing VolumeShaper.
6329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        auto state = replaceIt->getState();
6339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        if (state->getXOffset() >= 0) { // valid
6349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            const T volume = state->getVolume();
6359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ALOGD("join: scaling start volume to %f", volume);
6369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            configuration->scaleToStartVolume(volume);
6379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        }
6389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    }
6399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    (void)mVolumeShapers.erase(replaceIt);
6409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
6419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
6429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            // check if we have another of the same id.
6439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            auto oldIt = findId_l(id);
6449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (oldIt != mVolumeShapers.end()) {
6459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGW("duplicate id, removing old %d", id);
6469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                (void)mVolumeShapers.erase(oldIt);
6479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
6489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            // create new VolumeShaper
6499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mVolumeShapers.emplace_back(configuration, operation);
65010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        }
65110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        // fall through to handle the operation
65210cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        case VolumeShaper::Configuration::TYPE_ID: {
65310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            VS_LOG("trying to find id: %d", id);
65410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            auto it = findId_l(id);
65510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            if (it == mVolumeShapers.end()) {
65610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                VS_LOG("couldn't find id: %d", id);
65710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                return VolumeShaper::Status(INVALID_OPERATION);
65810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            }
65910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            if ((it->getFlags() & VolumeShaper::Operation::FLAG_TERMINATE) != 0) {
66010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                VS_LOG("terminate id: %d", id);
66110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                mVolumeShapers.erase(it);
66210cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                break;
66310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            }
66410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            const bool clockTime = (it->mConfiguration->getOptionFlags()
66510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                    & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) != 0;
66610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            if ((it->getFlags() & VolumeShaper::Operation::FLAG_REVERSE) !=
66710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                    (operation->getFlags() & VolumeShaper::Operation::FLAG_REVERSE)) {
66810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                const int64_t frameCount = clockTime ? VolumeShaper::getNowUs() : mLastFrame;
66910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                const S x = it->mXTranslate((T)frameCount);
67010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                VS_LOG("reverse translation: %f", x);
67110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                // reflect position
67210cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                S target = 1.f - x;
67310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                if (target < it->mConfiguration->first().first) {
67410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                    VS_LOG("clamp to start - begin immediately");
67510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                    target = 0.;
67610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                }
67710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                VS_LOG("target reverse: %f", target);
67810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                it->mXTranslate.setOffset(it->mXTranslate.getOffset()
67910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung                        + (x - target) / it->mXTranslate.getScale());
68010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            }
68110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            it->mOperation = operation; // replace the operation
6829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        } break;
6839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
6849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return VolumeShaper::Status(id);
6859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
6869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
6879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    sp<VolumeShaper::State> getVolumeShaperState(int id) {
6889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        AutoMutex _l(mLock);
6899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        auto it = findId_l(id);
6909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (it == mVolumeShapers.end()) {
6919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return nullptr;
6929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
6939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return it->getState();
6949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
6959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
69610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung    std::pair<T /* volume */, bool /* active */> getVolume(int64_t trackFrameCount) {
6979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        AutoMutex _l(mLock);
6989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        mLastFrame = trackFrameCount;
6999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        T volume(1);
70010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        size_t activeCount = 0;
7019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        for (auto it = mVolumeShapers.begin(); it != mVolumeShapers.end();) {
7029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            std::pair<T, bool> shaperVolume =
7039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    it->getVolume(trackFrameCount, mSampleRate);
7049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            volume *= shaperVolume.first;
70510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung            activeCount += shaperVolume.second;
7069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ++it;
7079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
70810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung        return std::make_pair(volume, activeCount != 0);
7099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
7109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
7119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    std::string toString() const {
7129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        AutoMutex _l(mLock);
7139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::stringstream ss;
7149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        ss << "mSampleRate: " << mSampleRate << std::endl;
7159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        ss << "mLastFrame: " << mLastFrame << std::endl;
7169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        for (const auto &shaper : mVolumeShapers) {
7179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << shaper.toString().c_str();
7189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
7199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return ss.str();
7209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
7219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
7229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungprivate:
7239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    std::list<VolumeShaper>::iterator findId_l(int32_t id) {
7249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::list<VolumeShaper>::iterator it = mVolumeShapers.begin();
7259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        for (; it != mVolumeShapers.end(); ++it) {
7269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (it->mConfiguration->getId() == id) {
7279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                break;
7289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
7299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
7309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return it;
7319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
7329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
7339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    mutable Mutex mLock;
7349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    double mSampleRate; // in samples (frames) per second
7359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    int64_t mLastFrame; // logging purpose only
7369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    std::list<VolumeShaper> mVolumeShapers; // list provides stable iterators on erase
7379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung}; // VolumeHandler
7389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
7399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung} // namespace android
7409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
7419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#pragma pop_macro("LOG_TAG")
7429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
7439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#endif // ANDROID_VOLUME_SHAPER_H
744