VolumeShaper.h revision 9fc8b5cd4a64ef07e84c69112461324d5c13a0b0
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
979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Type getType() const {
989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mType;
999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t setType(Type type) {
1029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            switch (type) {
1039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            case TYPE_ID:
1049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            case TYPE_SCALE:
1059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mType = type;
1069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return NO_ERROR;
1079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            default:
1089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGE("invalid Type: %d", type);
1099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return BAD_VALUE;
1109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        OptionFlag getOptionFlags() const {
1149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mOptionFlags;
1159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t setOptionFlags(OptionFlag optionFlags) {
1189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((optionFlags & ~OPTION_FLAG_ALL) != 0) {
1199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGE("optionFlags has invalid bits: %#x", optionFlags);
1209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return BAD_VALUE;
1219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mOptionFlags = optionFlags;
1239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return NO_ERROR;
1249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        double getDurationMs() const {
1279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mDurationMs;
1289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setDurationMs(double durationMs) {
1319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mDurationMs = durationMs;
1329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        int32_t getId() const {
1359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mId;
1369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setId(int32_t id) {
1399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mId = id;
1409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        T adjustVolume(T volume) const {
1439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
1449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const T out = powf(10.f, volume / 10.);
1459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                VS_LOG("in: %f  out: %f", volume, out);
1469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                volume = out;
1479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            // clamp
1499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (volume < 0.f) {
1509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                volume = 0.f;
1519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            } else if (volume > 1.f) {
1529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                volume = 1.f;
1539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return volume;
1559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t checkCurve() {
1589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (mType == TYPE_ID) return NO_ERROR;
1599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (this->size() < 2) {
1609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGE("curve must have at least 2 points");
1619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return BAD_VALUE;
1629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (first().first != 0.f || last().first != 1.f) {
1649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGE("curve must start at 0.f and end at 1.f");
1659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return BAD_VALUE;
1669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
1689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (const auto &pt : *this) {
1699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    if (!(pt.second <= 0.f) /* handle nan */) {
1709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        ALOGE("positive volume dbFS");
1719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        return BAD_VALUE;
1729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    }
1739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
1749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            } else {
1759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (const auto &pt : *this) {
1769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    if (!(pt.second >= 0.f) || !(pt.second <= 1.f) /* handle nan */) {
1779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        ALOGE("volume < 0.f or > 1.f");
1789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        return BAD_VALUE;
1799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    }
1809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
1819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
1829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return NO_ERROR;
1839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
1849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
1859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void clampVolume() {
1869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
1879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (auto it = this->begin(); it != this->end(); ++it) {
1889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    if (!(it->second <= 0.f) /* handle nan */) {
1899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        it->second = 0.f;
1909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    }
1919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
1929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            } else {
1939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (auto it = this->begin(); it != this->end(); ++it) {
1949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    if (!(it->second >= 0.f) /* handle nan */) {
1959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        it->second = 0.f;
1969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    } else if (!(it->second <= 1.f)) {
1979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        it->second = 1.f;
1989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    }
1999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
2009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
2019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        /* scaleToStartVolume() is used to set the start volume of a
2049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         * new VolumeShaper curve, when replacing one VolumeShaper
2059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         * with another using the "join" (volume match) option.
2069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         *
2079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         * It works best for monotonic volume ramps or ducks.
2089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung         */
2099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void scaleToStartVolume(T volume) {
2109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (this->size() < 2) {
2119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return;
2129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
2139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const T startVolume = first().second;
2149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const T endVolume = last().second;
2159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (endVolume == startVolume) {
2169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                // match with linear ramp
2179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const T offset = volume - startVolume;
2189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (auto it = this->begin(); it != this->end(); ++it) {
2199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    it->second = it->second + offset * (1.f - it->first);
2209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
2219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            } else {
2229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const T  scale = (volume - endVolume) / (startVolume - endVolume);
2239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                for (auto it = this->begin(); it != this->end(); ++it) {
2249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    it->second = scale * (it->second - endVolume) + endVolume;
2259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
2269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
2279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            clampVolume();
2289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t writeToParcel(Parcel *parcel) const {
2319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (parcel == nullptr) return BAD_VALUE;
2329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel->writeInt32((int32_t)mType)
2339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: parcel->writeInt32(mId)
2349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: mType == TYPE_ID
2359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        ? NO_ERROR
2369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        : parcel->writeInt32((int32_t)mOptionFlags)
2379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: parcel->writeDouble(mDurationMs)
2389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: Interpolator<S, T>::writeToParcel(parcel);
2399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t readFromParcel(const Parcel &parcel) {
2429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            int32_t type, optionFlags;
2439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel.readInt32(&type)
2449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: setType((Type)type)
2459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: parcel.readInt32(&mId)
2469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: mType == TYPE_ID
2479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        ? NO_ERROR
2489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        : parcel.readInt32(&optionFlags)
2499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: setOptionFlags((OptionFlag)optionFlags)
2509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: parcel.readDouble(&mDurationMs)
2519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: Interpolator<S, T>::readFromParcel(parcel)
2529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ?: checkCurve();
2539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::string toString() const {
2569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            std::stringstream ss;
2579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mType: " << mType << std::endl;
2589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mId: " << mId << std::endl;
2599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (mType != TYPE_ID) {
2609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ss << "mOptionFlags: " << mOptionFlags << std::endl;
2619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ss << "mDurationMs: " << mDurationMs << std::endl;
2629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ss << Interpolator<S, T>::toString().c_str();
2639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
2649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return ss.str();
2659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    private:
2689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Type mType;
2699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        int32_t mId;
2709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        OptionFlag mOptionFlags;
2719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        double mDurationMs;
2729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }; // Configuration
2739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // must match with VolumeShaper.java in frameworks/base
2759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // TODO document per VolumeShaper.java flags.
2769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    class Operation : public RefBase {
2779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    public:
2789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        enum Flag : int32_t {
2799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_NONE      = 0,
2809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_REVERSE   = (1 << 0),
2819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_TERMINATE = (1 << 1),
2829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_JOIN      = (1 << 2),
2839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_DELAY     = (1 << 3),
2849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            FLAG_ALL       = (FLAG_REVERSE | FLAG_TERMINATE | FLAG_JOIN | FLAG_DELAY),
2869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        };
2879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Operation()
2899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : mFlags(FLAG_NONE)
2909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mReplaceId(-1) {
2919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        explicit Operation(Flag flags, int replaceId)
2949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : mFlags(flags)
2959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mReplaceId(replaceId) {
2969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
2979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
2989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        int32_t getReplaceId() const {
2999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mReplaceId;
3009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setReplaceId(int32_t replaceId) {
3039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mReplaceId = replaceId;
3049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Flag getFlags() const {
3079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mFlags;
3089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t setFlags(Flag flags) {
3119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((flags & ~FLAG_ALL) != 0) {
3129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGE("flags has invalid bits: %#x", flags);
3139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return BAD_VALUE;
3149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
3159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mFlags = flags;
3169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return NO_ERROR;
3179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t writeToParcel(Parcel *parcel) const {
3209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (parcel == nullptr) return BAD_VALUE;
3219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel->writeInt32((int32_t)mFlags)
3229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: parcel->writeInt32(mReplaceId);
3239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t readFromParcel(const Parcel &parcel) {
3269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            int32_t flags;
3279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel.readInt32(&flags)
3289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: parcel.readInt32(&mReplaceId)
3299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: setFlags((Flag)flags);
3309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::string toString() const {
3339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            std::stringstream ss;
3349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mFlags: " << mFlags << std::endl;
3359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mReplaceId: " << mReplaceId << std::endl;
3369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return ss.str();
3379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    private:
3409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Flag mFlags;
3419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        int32_t mReplaceId;
3429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }; // Operation
3439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // must match with VolumeShaper.java in frameworks/base
3459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    class State : public RefBase {
3469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    public:
3479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        explicit State(T volume, S xOffset)
3489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : mVolume(volume)
3499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mXOffset(xOffset) {
3509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        State()
3539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : State(-1.f, -1.f) { }
3549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        T getVolume() const {
3569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mVolume;
3579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setVolume(T volume) {
3609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mVolume = volume;
3619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        S getXOffset() const {
3649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mXOffset;
3659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setXOffset(S xOffset) {
3689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mXOffset = xOffset;
3699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t writeToParcel(Parcel *parcel) const {
3729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (parcel == nullptr) return BAD_VALUE;
3739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel->writeFloat(mVolume)
3749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ?: parcel->writeFloat(mXOffset);
3759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        status_t readFromParcel(const Parcel &parcel) {
3789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return parcel.readFloat(&mVolume)
3799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                     ?: parcel.readFloat(&mXOffset);
3809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::string toString() const {
3839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            std::stringstream ss;
3849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mVolume: " << mVolume << std::endl;
3859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mXOffset: " << mXOffset << std::endl;
3869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return ss.str();
3879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
3889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    private:
3909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        T mVolume;
3919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        S mXOffset;
3929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }; // State
3939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
3949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    template <typename R>
3959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    class Translate {
3969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    public:
3979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        Translate()
3989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            : mOffset(0)
3999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            , mScale(1) {
4009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        R getOffset() const {
4039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mOffset;
4049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setOffset(R offset) {
4079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mOffset = offset;
4089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        R getScale() const {
4119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mScale;
4129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        void setScale(R scale) {
4159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mScale = scale;
4169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        R operator()(R in) const {
4199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return mScale * (in - mOffset);
4209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::string toString() const {
4239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            std::stringstream ss;
4249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mOffset: " << mOffset << std::endl;
4259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "mScale: " << mScale << std::endl;
4269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return ss.str();
4279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    private:
4309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        R mOffset;
4319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        R mScale;
4329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }; // Translate
4339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    static int64_t convertTimespecToUs(const struct timespec &tv)
4359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    {
4369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000;
4379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
4389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // current monotonic time in microseconds.
4409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    static int64_t getNowUs()
4419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    {
4429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        struct timespec tv;
4439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (clock_gettime(CLOCK_MONOTONIC, &tv) != 0) {
4449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return 0; // system is really sick, just return 0 for consistency.
4459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return convertTimespecToUs(tv);
4479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
4489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    Translate<S> mXTranslate;
4509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    Translate<T> mYTranslate;
4519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    sp<VolumeShaper::Configuration> mConfiguration;
4529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    sp<VolumeShaper::Operation> mOperation;
4539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    int64_t mStartFrame;
4549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    T mLastVolume;
4559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    S mXOffset;
4569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // TODO: Since we pass configuration and operation as shared pointers
4589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // there is a potential risk that the caller may modify these after
4599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // delivery.  Currently, we don't require copies made here.
4609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    explicit VolumeShaper(
4619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const sp<VolumeShaper::Configuration> &configuration,
4629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const sp<VolumeShaper::Operation> &operation)
4639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        : mConfiguration(configuration) // we do not make a copy
4649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        , mOperation(operation)         // ditto
4659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        , mStartFrame(-1)
4669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        , mLastVolume(T(1))
4679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        , mXOffset(0.f) {
4689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (configuration.get() != nullptr
4699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                && (getFlags() & VolumeShaper::Operation::FLAG_DELAY) == 0) {
4709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mLastVolume = configuration->first().second;
4719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
4729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
4739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    void updatePosition(int64_t startFrame, double sampleRate) {
4759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        double scale = (mConfiguration->last().first - mConfiguration->first().first)
4769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        / (mConfiguration->getDurationMs() * 0.001 * sampleRate);
4779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const double minScale = 1. / INT64_MAX;
4789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        scale = std::max(scale, minScale);
4799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("update position: scale %lf  frameCount:%lld, sampleRate:%lf",
4809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                scale, (long long) startFrame, sampleRate);
4819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        mXTranslate.setOffset(startFrame - mConfiguration->first().first / scale);
4829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        mXTranslate.setScale(scale);
4839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("translate: %s", mXTranslate.toString().c_str());
4849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
4859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    // We allow a null operation here, though VolumeHandler always provides one.
4879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    VolumeShaper::Operation::Flag getFlags() const {
4889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return mOperation == nullptr
4899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ? VolumeShaper::Operation::FLAG_NONE :mOperation->getFlags();
4909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
4919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    sp<VolumeShaper::State> getState() const {
4939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return new VolumeShaper::State(mLastVolume, mXOffset);
4949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
4959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
4969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    std::pair<T, bool> getVolume(int64_t trackFrameCount, double trackSampleRate) {
4979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (mConfiguration.get() == nullptr || mConfiguration->empty()) {
4989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ALOGE("nonexistent VolumeShaper, removing");
4999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mLastVolume = T(1);
5009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mXOffset = 0.f;
5019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return std::make_pair(T(1), true);
5029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
5039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if ((getFlags() & VolumeShaper::Operation::FLAG_DELAY) != 0) {
5049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            VS_LOG("delayed VolumeShaper, ignoring");
5059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mLastVolume = T(1);
5069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mXOffset = 0.;
5079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return std::make_pair(T(1), false);
5089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
5099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const bool clockTime = (mConfiguration->getOptionFlags()
5109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) != 0;
5119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const int64_t frameCount = clockTime ? getNowUs() : trackFrameCount;
5129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const double sampleRate = clockTime ? 1000000 : trackSampleRate;
5139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (mStartFrame < 0) {
5159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            updatePosition(frameCount, sampleRate);
5169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mStartFrame = frameCount;
5179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
5189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("frameCount: %lld", (long long)frameCount);
5199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        S x = mXTranslate((T)frameCount);
5209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("translation: %f", x);
5219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        // handle reversal of position
5239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (getFlags() & VolumeShaper::Operation::FLAG_REVERSE) {
5249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            x = 1.f - x;
5259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            VS_LOG("reversing to %f", x);
5269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (x < mConfiguration->first().first) {
5279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mXOffset = 1.f;
5289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const T volume = mConfiguration->adjustVolume(
5299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        mConfiguration->first().second);  // persist last value
5309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                VS_LOG("persisting volume %f", volume);
5319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mLastVolume = volume;
5329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return std::make_pair(volume, false);
5339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
5349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (x > mConfiguration->last().first) {
5359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mXOffset = 0.f;
5369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mLastVolume = 1.f;
5379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return std::make_pair(T(1), false); // too early
5389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
5399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        } else {
5409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (x < mConfiguration->first().first) {
5419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mXOffset = 0.f;
5429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mLastVolume = 1.f;
5439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return std::make_pair(T(1), false); // too early
5449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
5459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (x > mConfiguration->last().first) {
5469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mXOffset = 1.f;
5479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const T volume = mConfiguration->adjustVolume(
5489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        mConfiguration->last().second);  // persist last value
5499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                VS_LOG("persisting volume %f", volume);
5509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mLastVolume = volume;
5519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return std::make_pair(volume, false);
5529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
5539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
5549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        mXOffset = x;
5559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        // x contains the location on the volume curve to use.
5569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const T unscaledVolume = mConfiguration->findY(x);
5579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const T volumeChange = mYTranslate(unscaledVolume);
5589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const T volume = mConfiguration->adjustVolume(volumeChange);
5599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("volume: %f  unscaled: %f", volume, unscaledVolume);
5609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        mLastVolume = volume;
5619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return std::make_pair(volume, false);
5629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
5639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    std::string toString() const {
5659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::stringstream ss;
5669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        ss << "StartFrame: " << mStartFrame << std::endl;
5679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        ss << mXTranslate.toString().c_str();
5689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        ss << mYTranslate.toString().c_str();
5699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (mConfiguration.get() == nullptr) {
5709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "VolumeShaper::Configuration: nullptr" << std::endl;
5719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        } else {
5729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "VolumeShaper::Configuration:" << std::endl;
5739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << mConfiguration->toString().c_str();
5749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
5759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (mOperation.get() == nullptr) {
5769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "VolumeShaper::Operation: nullptr" << std::endl;
5779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        } else {
5789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << "VolumeShaper::Operation:" << std::endl;
5799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << mOperation->toString().c_str();
5809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
5819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return ss.str();
5829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
5839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung}; // VolumeShaper
5849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// VolumeHandler combines the volume factors of multiple VolumeShapers and handles
5869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// multiple thread access by synchronizing all public methods.
5879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungclass VolumeHandler : public RefBase {
5889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungpublic:
5899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    using S = float;
5909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    using T = float;
5919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    explicit VolumeHandler(uint32_t sampleRate)
5939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        : mSampleRate((double)sampleRate)
5949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        , mLastFrame(0) {
5959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
5969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
5979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    VolumeShaper::Status applyVolumeShaper(
5989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const sp<VolumeShaper::Configuration> &configuration,
5999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const sp<VolumeShaper::Operation> &operation) {
6009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        AutoMutex _l(mLock);
6019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (configuration == nullptr) {
6029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ALOGE("null configuration");
6039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return VolumeShaper::Status(BAD_VALUE);
6049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
6059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (operation == nullptr) {
6069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ALOGE("null operation");
6079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return VolumeShaper::Status(BAD_VALUE);
6089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
6099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        const int32_t id = configuration->getId();
6109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (id < 0) {
6119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ALOGE("negative id: %d", id);
6129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return VolumeShaper::Status(BAD_VALUE);
6139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
6149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        VS_LOG("applyVolumeShaper id: %d", id);
6159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
6169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        switch (configuration->getType()) {
6179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        case VolumeShaper::Configuration::TYPE_ID: {
6189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            VS_LOG("trying to find id: %d", id);
6199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            auto it = findId_l(id);
6209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (it == mVolumeShapers.end()) {
6219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                VS_LOG("couldn't find id: %d\n%s", id, this->toString().c_str());
6229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                return VolumeShaper::Status(INVALID_OPERATION);
6239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
6249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((it->getFlags() & VolumeShaper::Operation::FLAG_TERMINATE) != 0) {
6259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                VS_LOG("terminate id: %d", id);
6269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                mVolumeShapers.erase(it);
6279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                break;
6289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
6299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if ((it->getFlags() & VolumeShaper::Operation::FLAG_REVERSE) !=
6309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    (operation->getFlags() & VolumeShaper::Operation::FLAG_REVERSE)) {
6319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                const S x = it->mXTranslate((T)mLastFrame);
6329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                VS_LOG("translation: %f", x);
6339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                // reflect position
6349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                S target = 1.f - x;
6359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                if (target < it->mConfiguration->first().first) {
6369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    VS_LOG("clamp to start - begin immediately");
6379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    target = 0.;
6389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
6399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                VS_LOG("target: %f", target);
6409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                it->mXTranslate.setOffset(it->mXTranslate.getOffset()
6419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        + (x - target) / it->mXTranslate.getScale());
6429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
6439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            it->mOperation = operation; // replace the operation
6449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        } break;
6459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        case VolumeShaper::Configuration::TYPE_SCALE: {
6469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            const int replaceId = operation->getReplaceId();
6479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (replaceId >= 0) {
6489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                auto replaceIt = findId_l(replaceId);
6499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                if (replaceIt == mVolumeShapers.end()) {
6509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    ALOGW("cannot find replace id: %d", replaceId);
6519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                } else {
6529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    if ((replaceIt->getFlags() & VolumeShaper::Operation::FLAG_JOIN) != 0) {
6539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        // For join, we scale the start volume of the current configuration
6549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        // to match the last-used volume of the replacing VolumeShaper.
6559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        auto state = replaceIt->getState();
6569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        if (state->getXOffset() >= 0) { // valid
6579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            const T volume = state->getVolume();
6589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            ALOGD("join: scaling start volume to %f", volume);
6599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                            configuration->scaleToStartVolume(volume);
6609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                        }
6619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    }
6629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    (void)mVolumeShapers.erase(replaceIt);
6639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                }
6649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
6659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            // check if we have another of the same id.
6669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            auto oldIt = findId_l(id);
6679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (oldIt != mVolumeShapers.end()) {
6689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                ALOGW("duplicate id, removing old %d", id);
6699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                (void)mVolumeShapers.erase(oldIt);
6709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
6719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            // create new VolumeShaper
6729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            mVolumeShapers.emplace_back(configuration, operation);
6739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        } break;
6749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
6759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return VolumeShaper::Status(id);
6769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
6779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
6789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    sp<VolumeShaper::State> getVolumeShaperState(int id) {
6799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        AutoMutex _l(mLock);
6809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        auto it = findId_l(id);
6819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        if (it == mVolumeShapers.end()) {
6829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            return nullptr;
6839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
6849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return it->getState();
6859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
6869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
6879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    T getVolume(int64_t trackFrameCount) {
6889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        AutoMutex _l(mLock);
6899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        mLastFrame = trackFrameCount;
6909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        T volume(1);
6919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        for (auto it = mVolumeShapers.begin(); it != mVolumeShapers.end();) {
6929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            std::pair<T, bool> shaperVolume =
6939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                    it->getVolume(trackFrameCount, mSampleRate);
6949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            volume *= shaperVolume.first;
6959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (shaperVolume.second) {
6969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                it = mVolumeShapers.erase(it);
6979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                continue;
6989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
6999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ++it;
7009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
7019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return volume;
7029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
7039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
7049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    std::string toString() const {
7059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        AutoMutex _l(mLock);
7069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::stringstream ss;
7079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        ss << "mSampleRate: " << mSampleRate << std::endl;
7089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        ss << "mLastFrame: " << mLastFrame << std::endl;
7099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        for (const auto &shaper : mVolumeShapers) {
7109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            ss << shaper.toString().c_str();
7119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
7129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return ss.str();
7139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
7149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
7159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungprivate:
7169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    std::list<VolumeShaper>::iterator findId_l(int32_t id) {
7179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        std::list<VolumeShaper>::iterator it = mVolumeShapers.begin();
7189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        for (; it != mVolumeShapers.end(); ++it) {
7199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            if (it->mConfiguration->getId() == id) {
7209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung                break;
7219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung            }
7229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        }
7239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung        return it;
7249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    }
7259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
7269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    mutable Mutex mLock;
7279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    double mSampleRate; // in samples (frames) per second
7289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    int64_t mLastFrame; // logging purpose only
7299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung    std::list<VolumeShaper> mVolumeShapers; // list provides stable iterators on erase
7309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung}; // VolumeHandler
7319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
7329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung} // namespace android
7339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
7349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#pragma pop_macro("LOG_TAG")
7359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung
7369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#endif // ANDROID_VOLUME_SHAPER_H
737