Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef ANDROID_VOLUME_SHAPER_H
     18 #define ANDROID_VOLUME_SHAPER_H
     19 
     20 #include <cmath>
     21 #include <list>
     22 #include <math.h>
     23 #include <sstream>
     24 
     25 #include <binder/Parcel.h>
     26 #include <media/Interpolator.h>
     27 #include <utils/Mutex.h>
     28 #include <utils/RefBase.h>
     29 
     30 #pragma push_macro("LOG_TAG")
     31 #undef LOG_TAG
     32 #define LOG_TAG "VolumeShaper"
     33 
     34 // turn on VolumeShaper logging
     35 #define VS_LOGGING 0
     36 #define VS_LOG(...) ALOGD_IF(VS_LOGGING, __VA_ARGS__)
     37 
     38 namespace android {
     39 
     40 namespace media {
     41 
     42 // The native VolumeShaper class mirrors the java VolumeShaper class;
     43 // in addition, the native class contains implementation for actual operation.
     44 //
     45 // VolumeShaper methods are not safe for multiple thread access.
     46 // Use VolumeHandler for thread-safe encapsulation of multiple VolumeShapers.
     47 //
     48 // Classes below written are to avoid naked pointers so there are no
     49 // explicit destructors required.
     50 
     51 class VolumeShaper {
     52 public:
     53     // S and T are like template typenames (matching the Interpolator<S, T>)
     54     using S = float; // time type
     55     using T = float; // volume type
     56 
     57 // Curve and dimension information
     58 // TODO: member static const or constexpr float initialization not permitted in C++11
     59 #define MIN_CURVE_TIME    0.f  // type S: start of VolumeShaper curve (normalized)
     60 #define MAX_CURVE_TIME    1.f  // type S: end of VolumeShaper curve (normalized)
     61 #define MIN_LINEAR_VOLUME 0.f  // type T: silence / mute audio
     62 #define MAX_LINEAR_VOLUME 1.f  // type T: max volume, unity gain
     63 #define MAX_LOG_VOLUME    0.f  // type T: max volume, unity gain in dBFS
     64 
     65     /* kSystemVolumeShapersMax is the maximum number of system VolumeShapers.
     66      * Each system VolumeShapers has a predefined Id, which ranges from 0
     67      * to kSystemVolumeShapersMax - 1 and is unique for its usage.
     68      *
     69      * "1" is reserved for system ducking.
     70      */
     71     static const int kSystemVolumeShapersMax = 16;
     72 
     73     /* kUserVolumeShapersMax is the maximum number of application
     74      * VolumeShapers for a player/track.  Application VolumeShapers are
     75      * assigned on creation by the client, and have Ids ranging
     76      * from kSystemVolumeShapersMax to INT32_MAX.
     77      *
     78      * The number of user/application volume shapers is independent to the
     79      * system volume shapers. If an application tries to create more than
     80      * kUserVolumeShapersMax to a player, then the apply() will fail.
     81      * This prevents exhausting server side resources by a potentially malicious
     82      * application.
     83      */
     84     static const int kUserVolumeShapersMax = 16;
     85 
     86     /* VolumeShaper::Status is equivalent to status_t if negative
     87      * but if non-negative represents the id operated on.
     88      * It must be expressible as an int32_t for binder purposes.
     89      */
     90     using Status = status_t;
     91 
     92     // Local definition for clamp as std::clamp is included in C++17 only.
     93     // TODO: use the std::clamp version when Android build uses C++17.
     94     template<typename R>
     95     static constexpr const R &clamp(const R &v, const R &lo, const R &hi) {
     96         return (v < lo) ? lo : (hi < v) ? hi : v;
     97     }
     98 
     99     /* VolumeShaper.Configuration derives from the Interpolator class and adds
    100      * parameters relating to the volume shape.
    101      *
    102      * This parallels the Java implementation and the enums must match.
    103      * See "frameworks/base/media/java/android/media/VolumeShaper.java" for
    104      * details on the Java implementation.
    105      */
    106     class Configuration : public Interpolator<S, T>, public RefBase, public Parcelable {
    107     public:
    108         // Must match with VolumeShaper.java in frameworks/base.
    109         enum Type : int32_t {
    110             TYPE_ID,
    111             TYPE_SCALE,
    112         };
    113 
    114         // Must match with VolumeShaper.java in frameworks/base.
    115         enum OptionFlag : int32_t {
    116             OPTION_FLAG_NONE           = 0,
    117             OPTION_FLAG_VOLUME_IN_DBFS = (1 << 0),
    118             OPTION_FLAG_CLOCK_TIME     = (1 << 1),
    119 
    120             OPTION_FLAG_ALL            = (OPTION_FLAG_VOLUME_IN_DBFS | OPTION_FLAG_CLOCK_TIME),
    121         };
    122 
    123         // Bring from base class; must match with VolumeShaper.java in frameworks/base.
    124         using InterpolatorType = Interpolator<S, T>::InterpolatorType;
    125 
    126         Configuration()
    127             : Interpolator<S, T>()
    128             , RefBase()
    129             , mType(TYPE_SCALE)
    130             , mId(-1)
    131             , mOptionFlags(OPTION_FLAG_NONE)
    132             , mDurationMs(1000.) {
    133         }
    134 
    135         explicit Configuration(const Configuration &configuration)
    136             : Interpolator<S, T>(*static_cast<const Interpolator<S, T> *>(&configuration))
    137             , RefBase()
    138             , mType(configuration.mType)
    139             , mId(configuration.mId)
    140             , mOptionFlags(configuration.mOptionFlags)
    141             , mDurationMs(configuration.mDurationMs) {
    142         }
    143 
    144         Type getType() const {
    145             return mType;
    146         }
    147 
    148         status_t setType(Type type) {
    149             switch (type) {
    150             case TYPE_ID:
    151             case TYPE_SCALE:
    152                 mType = type;
    153                 return NO_ERROR;
    154             default:
    155                 ALOGE("invalid Type: %d", type);
    156                 return BAD_VALUE;
    157             }
    158         }
    159 
    160         OptionFlag getOptionFlags() const {
    161             return mOptionFlags;
    162         }
    163 
    164         status_t setOptionFlags(OptionFlag optionFlags) {
    165             if ((optionFlags & ~OPTION_FLAG_ALL) != 0) {
    166                 ALOGE("optionFlags has invalid bits: %#x", optionFlags);
    167                 return BAD_VALUE;
    168             }
    169             mOptionFlags = optionFlags;
    170             return NO_ERROR;
    171         }
    172 
    173         double getDurationMs() const {
    174             return mDurationMs;
    175         }
    176 
    177         status_t setDurationMs(double durationMs) {
    178             if (durationMs > 0.) {
    179                 mDurationMs = durationMs;
    180                 return NO_ERROR;
    181             }
    182             // zero, negative, or nan. These values not possible from Java.
    183             return BAD_VALUE;
    184         }
    185 
    186         int32_t getId() const {
    187             return mId;
    188         }
    189 
    190         void setId(int32_t id) {
    191             // We permit a negative id here (representing invalid).
    192             mId = id;
    193         }
    194 
    195         /* Adjust the volume to be in linear range from MIN_LINEAR_VOLUME to MAX_LINEAR_VOLUME
    196          * and compensate for log dbFS volume as needed.
    197          */
    198         T adjustVolume(T volume) const {
    199             if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
    200                 const T out = powf(10.f, volume / 10.f);
    201                 VS_LOG("in: %f  out: %f", volume, out);
    202                 volume = out;
    203             }
    204             return clamp(volume, MIN_LINEAR_VOLUME /* lo */, MAX_LINEAR_VOLUME /* hi */);
    205         }
    206 
    207         /* Check if the existing curve is valid.
    208          */
    209         status_t checkCurve() const {
    210             if (mType == TYPE_ID) return NO_ERROR;
    211             if (this->size() < 2) {
    212                 ALOGE("curve must have at least 2 points");
    213                 return BAD_VALUE;
    214             }
    215             if (first().first != MIN_CURVE_TIME || last().first != MAX_CURVE_TIME) {
    216                 ALOGE("curve must start at MIN_CURVE_TIME and end at MAX_CURVE_TIME");
    217                 return BAD_VALUE;
    218             }
    219             if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
    220                 for (const auto &pt : *this) {
    221                     if (!(pt.second <= MAX_LOG_VOLUME) /* handle nan */) {
    222                         ALOGE("positive volume dbFS");
    223                         return BAD_VALUE;
    224                     }
    225                 }
    226             } else {
    227                 for (const auto &pt : *this) {
    228                     if (!(pt.second >= MIN_LINEAR_VOLUME)
    229                             || !(pt.second <= MAX_LINEAR_VOLUME) /* handle nan */) {
    230                         ALOGE("volume < MIN_LINEAR_VOLUME or > MAX_LINEAR_VOLUME");
    231                         return BAD_VALUE;
    232                     }
    233                 }
    234             }
    235             return NO_ERROR;
    236         }
    237 
    238         /* Clamps the volume curve in the configuration to
    239          * the valid range for log or linear scale.
    240          */
    241         void clampVolume() {
    242             if ((mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
    243                 for (auto it = this->begin(); it != this->end(); ++it) {
    244                     if (!(it->second <= MAX_LOG_VOLUME) /* handle nan */) {
    245                         it->second = MAX_LOG_VOLUME;
    246                     }
    247                 }
    248             } else {
    249                 for (auto it = this->begin(); it != this->end(); ++it) {
    250                     if (!(it->second >= MIN_LINEAR_VOLUME) /* handle nan */) {
    251                         it->second = MIN_LINEAR_VOLUME;
    252                     } else if (!(it->second <= MAX_LINEAR_VOLUME)) {
    253                         it->second = MAX_LINEAR_VOLUME;
    254                     }
    255                 }
    256             }
    257         }
    258 
    259         /* scaleToStartVolume() is used to set the start volume of a
    260          * new VolumeShaper curve, when replacing one VolumeShaper
    261          * with another using the "join" (volume match) option.
    262          *
    263          * It works best for monotonic volume ramps or ducks.
    264          */
    265         void scaleToStartVolume(T volume) {
    266             if (this->size() < 2) {
    267                 return;
    268             }
    269             const T startVolume = first().second;
    270             const T endVolume = last().second;
    271             if (endVolume == startVolume) {
    272                 // match with linear ramp
    273                 const T offset = volume - startVolume;
    274                 static const T scale =  1.f / (MAX_CURVE_TIME - MIN_CURVE_TIME); // nominally 1.f
    275                 for (auto it = this->begin(); it != this->end(); ++it) {
    276                     it->second = it->second + offset * (MAX_CURVE_TIME - it->first) * scale;
    277                 }
    278             } else {
    279                 const T  scale = (volume - endVolume) / (startVolume - endVolume);
    280                 for (auto it = this->begin(); it != this->end(); ++it) {
    281                     it->second = scale * (it->second - endVolume) + endVolume;
    282                 }
    283             }
    284             clampVolume();
    285         }
    286 
    287         // The parcel layout must match VolumeShaper.java
    288         status_t writeToParcel(Parcel *parcel) const override {
    289             if (parcel == nullptr) return BAD_VALUE;
    290             return parcel->writeInt32((int32_t)mType)
    291                     ?: parcel->writeInt32(mId)
    292                     ?: mType == TYPE_ID
    293                         ? NO_ERROR
    294                         : parcel->writeInt32((int32_t)mOptionFlags)
    295                             ?: parcel->writeDouble(mDurationMs)
    296                             ?: Interpolator<S, T>::writeToParcel(parcel);
    297         }
    298 
    299         status_t readFromParcel(const Parcel *parcel) override {
    300             int32_t type, optionFlags;
    301             return parcel->readInt32(&type)
    302                     ?: setType((Type)type)
    303                     ?: parcel->readInt32(&mId)
    304                     ?: mType == TYPE_ID
    305                         ? NO_ERROR
    306                         : parcel->readInt32(&optionFlags)
    307                             ?: setOptionFlags((OptionFlag)optionFlags)
    308                             ?: parcel->readDouble(&mDurationMs)
    309                             ?: Interpolator<S, T>::readFromParcel(*parcel)
    310                             ?: checkCurve();
    311         }
    312 
    313         // Returns a string for debug printing.
    314         std::string toString() const {
    315             std::stringstream ss;
    316             ss << "VolumeShaper::Configuration{mType=" << static_cast<int32_t>(mType);
    317             ss << ", mId=" << mId;
    318             if (mType != TYPE_ID) {
    319                 ss << ", mOptionFlags=" << static_cast<int32_t>(mOptionFlags);
    320                 ss << ", mDurationMs=" << mDurationMs;
    321                 ss << ", " << Interpolator<S, T>::toString().c_str();
    322             }
    323             ss << "}";
    324             return ss.str();
    325         }
    326 
    327     private:
    328         Type mType;              // type of configuration
    329         int32_t mId;             // A valid id is >= 0.
    330         OptionFlag mOptionFlags; // option flags for the configuration.
    331         double mDurationMs;      // duration, must be > 0; default is 1000 ms.
    332     }; // Configuration
    333 
    334     /* VolumeShaper::Operation expresses an operation to perform on the
    335      * configuration (either explicitly specified or an id).
    336      *
    337      * This parallels the Java implementation and the enums must match.
    338      * See "frameworks/base/media/java/android/media/VolumeShaper.java" for
    339      * details on the Java implementation.
    340      */
    341     class Operation : public RefBase, public Parcelable {
    342     public:
    343         // Must match with VolumeShaper.java.
    344         enum Flag : int32_t {
    345             FLAG_NONE      = 0,
    346             FLAG_REVERSE   = (1 << 0), // the absence of this indicates "play"
    347             FLAG_TERMINATE = (1 << 1),
    348             FLAG_JOIN      = (1 << 2),
    349             FLAG_DELAY     = (1 << 3),
    350             FLAG_CREATE_IF_NECESSARY = (1 << 4),
    351 
    352             FLAG_ALL       = (FLAG_REVERSE | FLAG_TERMINATE | FLAG_JOIN | FLAG_DELAY
    353                             | FLAG_CREATE_IF_NECESSARY),
    354         };
    355 
    356         Operation()
    357             : Operation(FLAG_NONE, -1 /* replaceId */) {
    358         }
    359 
    360         Operation(Flag flags, int replaceId)
    361             : Operation(flags, replaceId, std::numeric_limits<S>::quiet_NaN() /* xOffset */) {
    362         }
    363 
    364         explicit Operation(const Operation &operation)
    365             : Operation(operation.mFlags, operation.mReplaceId, operation.mXOffset) {
    366         }
    367 
    368         explicit Operation(const sp<Operation> &operation)
    369             : Operation(*operation.get()) {
    370         }
    371 
    372         Operation(Flag flags, int replaceId, S xOffset)
    373             : mFlags(flags)
    374             , mReplaceId(replaceId)
    375             , mXOffset(xOffset) {
    376         }
    377 
    378         int32_t getReplaceId() const {
    379             return mReplaceId;
    380         }
    381 
    382         void setReplaceId(int32_t replaceId) {
    383             mReplaceId = replaceId;
    384         }
    385 
    386         S getXOffset() const {
    387             return mXOffset;
    388         }
    389 
    390         void setXOffset(S xOffset) {
    391             mXOffset = clamp(xOffset, MIN_CURVE_TIME /* lo */, MAX_CURVE_TIME /* hi */);
    392         }
    393 
    394         Flag getFlags() const {
    395             return mFlags;
    396         }
    397 
    398         /* xOffset is the position on the volume curve and may go backwards
    399          * if you are in reverse mode. This must be in the range from
    400          * [MIN_CURVE_TIME, MAX_CURVE_TIME].
    401          *
    402          * normalizedTime always increases as time or framecount increases.
    403          * normalizedTime is nominally from MIN_CURVE_TIME to MAX_CURVE_TIME when
    404          * running through the curve, but could be outside this range afterwards.
    405          * If you are reversing, this means the position on the curve, or xOffset,
    406          * is computed as MAX_CURVE_TIME - normalizedTime, clamped to
    407          * [MIN_CURVE_TIME, MAX_CURVE_TIME].
    408          */
    409         void setNormalizedTime(S normalizedTime) {
    410             setXOffset((mFlags & FLAG_REVERSE) != 0
    411                     ? MAX_CURVE_TIME - normalizedTime : normalizedTime);
    412         }
    413 
    414         status_t setFlags(Flag flags) {
    415             if ((flags & ~FLAG_ALL) != 0) {
    416                 ALOGE("flags has invalid bits: %#x", flags);
    417                 return BAD_VALUE;
    418             }
    419             mFlags = flags;
    420             return NO_ERROR;
    421         }
    422 
    423         status_t writeToParcel(Parcel *parcel) const override {
    424             if (parcel == nullptr) return BAD_VALUE;
    425             return parcel->writeInt32((int32_t)mFlags)
    426                     ?: parcel->writeInt32(mReplaceId)
    427                     ?: parcel->writeFloat(mXOffset);
    428         }
    429 
    430         status_t readFromParcel(const Parcel *parcel) override {
    431             int32_t flags;
    432             return parcel->readInt32(&flags)
    433                     ?: parcel->readInt32(&mReplaceId)
    434                     ?: parcel->readFloat(&mXOffset)
    435                     ?: setFlags((Flag)flags);
    436         }
    437 
    438         std::string toString() const {
    439             std::stringstream ss;
    440             ss << "VolumeShaper::Operation{mFlags=" << static_cast<int32_t>(mFlags) ;
    441             ss << ", mReplaceId=" << mReplaceId;
    442             ss << ", mXOffset=" << mXOffset;
    443             ss << "}";
    444             return ss.str();
    445         }
    446 
    447     private:
    448         Flag mFlags;        // operation to do
    449         int32_t mReplaceId; // if >= 0 the id to remove in a replace operation.
    450         S mXOffset;         // position in the curve to set if a valid number (not nan)
    451     }; // Operation
    452 
    453     /* VolumeShaper.State is returned when requesting the last
    454      * state of the VolumeShaper.
    455      *
    456      * This parallels the Java implementation.
    457      * See "frameworks/base/media/java/android/media/VolumeShaper.java" for
    458      * details on the Java implementation.
    459      */
    460     class State : public RefBase, public Parcelable {
    461     public:
    462         State(T volume, S xOffset)
    463             : mVolume(volume)
    464             , mXOffset(xOffset) {
    465         }
    466 
    467         State()
    468             : State(NAN, NAN) { }
    469 
    470         T getVolume() const {
    471             return mVolume;
    472         }
    473 
    474         void setVolume(T volume) {
    475             mVolume = volume;
    476         }
    477 
    478         S getXOffset() const {
    479             return mXOffset;
    480         }
    481 
    482         void setXOffset(S xOffset) {
    483             mXOffset = xOffset;
    484         }
    485 
    486         status_t writeToParcel(Parcel *parcel) const override {
    487             if (parcel == nullptr) return BAD_VALUE;
    488             return parcel->writeFloat(mVolume)
    489                     ?: parcel->writeFloat(mXOffset);
    490         }
    491 
    492         status_t readFromParcel(const Parcel *parcel) override {
    493             return parcel->readFloat(&mVolume)
    494                      ?: parcel->readFloat(&mXOffset);
    495         }
    496 
    497         std::string toString() const {
    498             std::stringstream ss;
    499             ss << "VolumeShaper::State{mVolume=" << mVolume;
    500             ss << ", mXOffset=" << mXOffset;
    501             ss << "}";
    502             return ss.str();
    503         }
    504 
    505     private:
    506         T mVolume;   // linear volume in the range MIN_LINEAR_VOLUME to MAX_LINEAR_VOLUME
    507         S mXOffset;  // position on curve expressed from MIN_CURVE_TIME to MAX_CURVE_TIME
    508     }; // State
    509 
    510     // Internal helper class to do an affine transform for time and amplitude scaling.
    511     template <typename R>
    512     class Translate {
    513     public:
    514         Translate()
    515             : mOffset(0)
    516             , mScale(1) {
    517         }
    518 
    519         R getOffset() const {
    520             return mOffset;
    521         }
    522 
    523         void setOffset(R offset) {
    524             mOffset = offset;
    525         }
    526 
    527         R getScale() const {
    528             return mScale;
    529         }
    530 
    531         void setScale(R scale) {
    532             mScale = scale;
    533         }
    534 
    535         R operator()(R in) const {
    536             return mScale * (in - mOffset);
    537         }
    538 
    539         std::string toString() const {
    540             std::stringstream ss;
    541             ss << "VolumeShaper::Translate{mOffset=" << mOffset;
    542             ss << ", mScale=" << mScale;
    543             ss << "}";
    544             return ss.str();
    545         }
    546 
    547     private:
    548         R mOffset;
    549         R mScale;
    550     }; // Translate
    551 
    552     static int64_t convertTimespecToUs(const struct timespec &tv)
    553     {
    554         return tv.tv_sec * 1000000LL + tv.tv_nsec / 1000;
    555     }
    556 
    557     // current monotonic time in microseconds.
    558     static int64_t getNowUs()
    559     {
    560         struct timespec tv;
    561         if (clock_gettime(CLOCK_MONOTONIC, &tv) != 0) {
    562             return 0; // system is really sick, just return 0 for consistency.
    563         }
    564         return convertTimespecToUs(tv);
    565     }
    566 
    567     /* Native implementation of VolumeShaper.  This is NOT mirrored
    568      * on the Java side, so we don't need to mimic Java side layout
    569      * and data; furthermore, this isn't refcounted as a "RefBase" object.
    570      *
    571      * Since we pass configuration and operation as shared pointers (like
    572      * Java) there is a potential risk that the caller may modify
    573      * these after delivery.
    574      */
    575     VolumeShaper(
    576             const sp<VolumeShaper::Configuration> &configuration,
    577             const sp<VolumeShaper::Operation> &operation)
    578         : mConfiguration(configuration) // we do not make a copy
    579         , mOperation(operation)         // ditto
    580         , mStartFrame(-1)
    581         , mLastVolume(T(1))
    582         , mLastXOffset(MIN_CURVE_TIME)
    583         , mDelayXOffset(MIN_CURVE_TIME) {
    584         if (configuration.get() != nullptr
    585                 && (getFlags() & VolumeShaper::Operation::FLAG_DELAY) == 0) {
    586             mLastVolume = configuration->first().second;
    587         }
    588     }
    589 
    590     // We allow a null operation here, though VolumeHandler always provides one.
    591     VolumeShaper::Operation::Flag getFlags() const {
    592         return mOperation == nullptr
    593                 ? VolumeShaper::Operation::FLAG_NONE : mOperation->getFlags();
    594     }
    595 
    596     /* Returns the last volume and xoffset reported to the AudioFlinger.
    597      * If the VolumeShaper has not been started, compute what the volume
    598      * should be based on the initial offset specified.
    599      */
    600     sp<VolumeShaper::State> getState() const {
    601         if (!isStarted()) {
    602             const T volume = computeVolumeFromXOffset(mDelayXOffset);
    603             VS_LOG("delayed VolumeShaper, using cached offset:%f for volume:%f",
    604                     mDelayXOffset, volume);
    605             return new VolumeShaper::State(volume, mDelayXOffset);
    606         } else {
    607             return new VolumeShaper::State(mLastVolume, mLastXOffset);
    608         }
    609     }
    610 
    611     S getDelayXOffset() const {
    612         return mDelayXOffset;
    613     }
    614 
    615     void setDelayXOffset(S xOffset) {
    616         mDelayXOffset = clamp(xOffset, MIN_CURVE_TIME /* lo */, MAX_CURVE_TIME /* hi */);
    617     }
    618 
    619     bool isStarted() const {
    620         return mStartFrame >= 0;
    621     }
    622 
    623     /* getVolume() updates the last volume/xoffset state so it is not
    624      * const, even though logically it may be viewed as const.
    625      */
    626     std::pair<T /* volume */, bool /* active */> getVolume(
    627             int64_t trackFrameCount, double trackSampleRate) {
    628         if ((getFlags() & VolumeShaper::Operation::FLAG_DELAY) != 0) {
    629             // We haven't had PLAY called yet, so just return the value
    630             // as if PLAY were called just now.
    631             VS_LOG("delayed VolumeShaper, using cached offset %f", mDelayXOffset);
    632             const T volume = computeVolumeFromXOffset(mDelayXOffset);
    633             return std::make_pair(volume, false);
    634         }
    635         const bool clockTime = (mConfiguration->getOptionFlags()
    636                 & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) != 0;
    637         const int64_t frameCount = clockTime ? getNowUs() : trackFrameCount;
    638         const double sampleRate = clockTime ? 1000000 : trackSampleRate;
    639 
    640         if (mStartFrame < 0) {
    641             updatePosition(frameCount, sampleRate, mDelayXOffset);
    642             mStartFrame = frameCount;
    643         }
    644         VS_LOG("frameCount: %lld", (long long)frameCount);
    645         const S x = mXTranslate((T)frameCount);
    646         VS_LOG("translation to normalized time: %f", x);
    647 
    648         std::tuple<T /* volume */, S /* position */, bool /* active */> vt =
    649                 computeStateFromNormalizedTime(x);
    650 
    651         mLastVolume = std::get<0>(vt);
    652         mLastXOffset = std::get<1>(vt);
    653         const bool active = std::get<2>(vt);
    654         VS_LOG("rescaled time:%f  volume:%f  xOffset:%f  active:%s",
    655                 x, mLastVolume, mLastXOffset, active ? "true" : "false");
    656         return std::make_pair(mLastVolume, active);
    657     }
    658 
    659     std::string toString() const {
    660         std::stringstream ss;
    661         ss << "VolumeShaper{mStartFrame=" << mStartFrame;
    662         ss << ", mXTranslate=" << mXTranslate.toString().c_str();
    663         ss << ", mConfiguration=" <<
    664                 (mConfiguration.get() == nullptr
    665                         ? "nullptr" : mConfiguration->toString().c_str());
    666         ss << ", mOperation=" <<
    667                 (mOperation.get() == nullptr
    668                         ? "nullptr" :  mOperation->toString().c_str());
    669         ss << "}";
    670         return ss.str();
    671     }
    672 
    673     Translate<S> mXTranslate; // translation from frames (usec for clock time) to normalized time.
    674     sp<VolumeShaper::Configuration> mConfiguration;
    675     sp<VolumeShaper::Operation> mOperation;
    676 
    677 private:
    678     int64_t mStartFrame; // starting frame, non-negative when started (in usec for clock time)
    679     T mLastVolume;       // last computed interpolated volume (y-axis)
    680     S mLastXOffset;      // last computed interpolated xOffset/time (x-axis)
    681     S mDelayXOffset;     // xOffset to use for first invocation of VolumeShaper.
    682 
    683     // Called internally to adjust mXTranslate for first time start.
    684     void updatePosition(int64_t startFrame, double sampleRate, S xOffset) {
    685         double scale = (mConfiguration->last().first - mConfiguration->first().first)
    686                         / (mConfiguration->getDurationMs() * 0.001 * sampleRate);
    687         const double minScale = 1. / static_cast<double>(INT64_MAX);
    688         scale = std::max(scale, minScale);
    689         VS_LOG("update position: scale %lf  frameCount:%lld, sampleRate:%lf, xOffset:%f",
    690                 scale, (long long) startFrame, sampleRate, xOffset);
    691 
    692         S normalizedTime = (getFlags() & VolumeShaper::Operation::FLAG_REVERSE) != 0 ?
    693                 MAX_CURVE_TIME - xOffset : xOffset;
    694         mXTranslate.setOffset(static_cast<float>(static_cast<double>(startFrame)
    695                                                  - static_cast<double>(normalizedTime) / scale));
    696         mXTranslate.setScale(static_cast<float>(scale));
    697         VS_LOG("translate: %s", mXTranslate.toString().c_str());
    698     }
    699 
    700     T computeVolumeFromXOffset(S xOffset) const {
    701         const T unscaledVolume = mConfiguration->findY(xOffset);
    702         const T volume = mConfiguration->adjustVolume(unscaledVolume); // handle log scale
    703         VS_LOG("computeVolumeFromXOffset %f -> %f -> %f", xOffset, unscaledVolume, volume);
    704         return volume;
    705     }
    706 
    707     std::tuple<T /* volume */, S /* position */, bool /* active */>
    708     computeStateFromNormalizedTime(S x) const {
    709         bool active = true;
    710         // handle reversal of position
    711         if (getFlags() & VolumeShaper::Operation::FLAG_REVERSE) {
    712             x = MAX_CURVE_TIME - x;
    713             VS_LOG("reversing to %f", x);
    714             if (x < MIN_CURVE_TIME) {
    715                 x = MIN_CURVE_TIME;
    716                 active = false; // at the end
    717             } else if (x > MAX_CURVE_TIME) {
    718                 x = MAX_CURVE_TIME; //early
    719             }
    720         } else {
    721             if (x < MIN_CURVE_TIME) {
    722                 x = MIN_CURVE_TIME; // early
    723             } else if (x > MAX_CURVE_TIME) {
    724                 x = MAX_CURVE_TIME;
    725                 active = false; // at end
    726             }
    727         }
    728         const S xOffset = x;
    729         const T volume = computeVolumeFromXOffset(xOffset);
    730         return std::make_tuple(volume, xOffset, active);
    731     }
    732 }; // VolumeShaper
    733 
    734 /* VolumeHandler combines the volume factors of multiple VolumeShapers associated
    735  * with a player.  It is thread safe by synchronizing all public methods.
    736  *
    737  * This is a native-only implementation.
    738  *
    739  * The server side VolumeHandler is used to maintain a list of volume handlers,
    740  * keep state, and obtain volume.
    741  *
    742  * The client side VolumeHandler is used to maintain a list of volume handlers,
    743  * keep some partial state, and restore if the server dies.
    744  */
    745 class VolumeHandler : public RefBase {
    746 public:
    747     using S = float;
    748     using T = float;
    749 
    750     // A volume handler which just keeps track of active VolumeShapers does not need sampleRate.
    751     VolumeHandler()
    752         : VolumeHandler(0 /* sampleRate */) {
    753     }
    754 
    755     explicit VolumeHandler(uint32_t sampleRate)
    756         : mSampleRate((double)sampleRate)
    757         , mLastFrame(0)
    758         , mVolumeShaperIdCounter(VolumeShaper::kSystemVolumeShapersMax)
    759         , mLastVolume(1.f, false) {
    760     }
    761 
    762     VolumeShaper::Status applyVolumeShaper(
    763             const sp<VolumeShaper::Configuration> &configuration,
    764             const sp<VolumeShaper::Operation> &operation_in) {
    765         // make a local copy of operation, as we modify it.
    766         sp<VolumeShaper::Operation> operation(new VolumeShaper::Operation(operation_in));
    767         VS_LOG("applyVolumeShaper:configuration: %s", configuration->toString().c_str());
    768         VS_LOG("applyVolumeShaper:operation: %s", operation->toString().c_str());
    769         AutoMutex _l(mLock);
    770         if (configuration == nullptr) {
    771             ALOGE("null configuration");
    772             return VolumeShaper::Status(BAD_VALUE);
    773         }
    774         if (operation == nullptr) {
    775             ALOGE("null operation");
    776             return VolumeShaper::Status(BAD_VALUE);
    777         }
    778         const int32_t id = configuration->getId();
    779         if (id < 0) {
    780             ALOGE("negative id: %d", id);
    781             return VolumeShaper::Status(BAD_VALUE);
    782         }
    783         VS_LOG("applyVolumeShaper id: %d", id);
    784 
    785         switch (configuration->getType()) {
    786         case VolumeShaper::Configuration::TYPE_SCALE: {
    787             const int replaceId = operation->getReplaceId();
    788             if (replaceId >= 0) {
    789                 VS_LOG("replacing %d", replaceId);
    790                 auto replaceIt = findId_l(replaceId);
    791                 if (replaceIt == mVolumeShapers.end()) {
    792                     ALOGW("cannot find replace id: %d", replaceId);
    793                 } else {
    794                     if ((operation->getFlags() & VolumeShaper::Operation::FLAG_JOIN) != 0) {
    795                         // For join, we scale the start volume of the current configuration
    796                         // to match the last-used volume of the replacing VolumeShaper.
    797                         auto state = replaceIt->getState();
    798                         ALOGD("join: state:%s", state->toString().c_str());
    799                         if (state->getXOffset() >= 0) { // valid
    800                             const T volume = state->getVolume();
    801                             ALOGD("join: scaling start volume to %f", volume);
    802                             configuration->scaleToStartVolume(volume);
    803                         }
    804                     }
    805                     (void)mVolumeShapers.erase(replaceIt);
    806                 }
    807                 operation->setReplaceId(-1);
    808             }
    809             // check if we have another of the same id.
    810             auto oldIt = findId_l(id);
    811             if (oldIt != mVolumeShapers.end()) {
    812                 if ((operation->getFlags()
    813                         & VolumeShaper::Operation::FLAG_CREATE_IF_NECESSARY) != 0) {
    814                     // TODO: move the case to a separate function.
    815                     goto HANDLE_TYPE_ID; // no need to create, take over existing id.
    816                 }
    817                 ALOGW("duplicate id, removing old %d", id);
    818                 (void)mVolumeShapers.erase(oldIt);
    819             }
    820 
    821             /* Check if too many application VolumeShapers (with id >= kSystemVolumeShapersMax).
    822              * We check on the server side to ensure synchronization and robustness.
    823              *
    824              * This shouldn't fail on a replace command unless the replaced id is
    825              * already invalid (which *should* be checked in the Java layer).
    826              */
    827             if (id >= VolumeShaper::kSystemVolumeShapersMax
    828                     && numberOfUserVolumeShapers_l() >= VolumeShaper::kUserVolumeShapersMax) {
    829                 ALOGW("Too many app VolumeShapers, cannot add to VolumeHandler");
    830                 return VolumeShaper::Status(INVALID_OPERATION);
    831             }
    832 
    833             // create new VolumeShaper with default behavior.
    834             mVolumeShapers.emplace_back(configuration, new VolumeShaper::Operation());
    835             VS_LOG("after adding, number of volumeShapers:%zu", mVolumeShapers.size());
    836         }
    837         // fall through to handle the operation
    838         HANDLE_TYPE_ID:
    839         case VolumeShaper::Configuration::TYPE_ID: {
    840             VS_LOG("trying to find id: %d", id);
    841             auto it = findId_l(id);
    842             if (it == mVolumeShapers.end()) {
    843                 VS_LOG("couldn't find id: %d", id);
    844                 return VolumeShaper::Status(INVALID_OPERATION);
    845             }
    846             if ((operation->getFlags() & VolumeShaper::Operation::FLAG_TERMINATE) != 0) {
    847                 VS_LOG("terminate id: %d", id);
    848                 mVolumeShapers.erase(it);
    849                 break;
    850             }
    851             const bool clockTime = (it->mConfiguration->getOptionFlags()
    852                     & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) != 0;
    853             if ((it->getFlags() & VolumeShaper::Operation::FLAG_REVERSE) !=
    854                     (operation->getFlags() & VolumeShaper::Operation::FLAG_REVERSE)) {
    855                 if (it->isStarted()) {
    856                     const int64_t frameCount = clockTime ? VolumeShaper::getNowUs() : mLastFrame;
    857                     const S x = it->mXTranslate((T)frameCount);
    858                     VS_LOG("reverse normalizedTime: %f", x);
    859                     // reflect position
    860                     S target = MAX_CURVE_TIME - x;
    861                     if (target < MIN_CURVE_TIME) {
    862                         VS_LOG("clamp to start - begin immediately");
    863                         target = MIN_CURVE_TIME;
    864                     }
    865                     VS_LOG("reverse normalizedTime target: %f", target);
    866                     it->mXTranslate.setOffset(it->mXTranslate.getOffset()
    867                             + (x - target) / it->mXTranslate.getScale());
    868                 }
    869                 // if not started, the delay offset doesn't change.
    870             }
    871             const S xOffset = operation->getXOffset();
    872             if (!std::isnan(xOffset)) {
    873                 if (it->isStarted()) {
    874                     const int64_t frameCount = clockTime ? VolumeShaper::getNowUs() : mLastFrame;
    875                     const S x = it->mXTranslate((T)frameCount);
    876                     VS_LOG("normalizedTime translation: %f", x);
    877                     const S target =
    878                             (operation->getFlags() & VolumeShaper::Operation::FLAG_REVERSE) != 0 ?
    879                                     MAX_CURVE_TIME - xOffset : xOffset;
    880                     VS_LOG("normalizedTime target x offset: %f", target);
    881                     it->mXTranslate.setOffset(it->mXTranslate.getOffset()
    882                             + (x - target) / it->mXTranslate.getScale());
    883                 } else {
    884                     it->setDelayXOffset(xOffset);
    885                 }
    886             }
    887             it->mOperation = operation; // replace the operation
    888         } break;
    889         }
    890         return VolumeShaper::Status(id);
    891     }
    892 
    893     sp<VolumeShaper::State> getVolumeShaperState(int id) {
    894         AutoMutex _l(mLock);
    895         auto it = findId_l(id);
    896         if (it == mVolumeShapers.end()) {
    897             VS_LOG("cannot find state for id: %d", id);
    898             return nullptr;
    899         }
    900         return it->getState();
    901     }
    902 
    903     /* getVolume() is not const, as it updates internal state.
    904      * Once called, any VolumeShapers not already started begin running.
    905      */
    906     std::pair<T /* volume */, bool /* active */> getVolume(int64_t trackFrameCount) {
    907         AutoMutex _l(mLock);
    908         mLastFrame = trackFrameCount;
    909         T volume(1);
    910         size_t activeCount = 0;
    911         for (auto it = mVolumeShapers.begin(); it != mVolumeShapers.end();) {
    912             const std::pair<T, bool> shaperVolume =
    913                     it->getVolume(trackFrameCount, mSampleRate);
    914             volume *= shaperVolume.first;
    915             activeCount += shaperVolume.second;
    916             ++it;
    917         }
    918         mLastVolume = std::make_pair(volume, activeCount != 0);
    919         VS_LOG("getVolume: <%f, %s>", mLastVolume.first, mLastVolume.second ? "true" : "false");
    920         return mLastVolume;
    921     }
    922 
    923     /* Used by a client side VolumeHandler to ensure all the VolumeShapers
    924      * indicate that they have been started.  Upon a change in audioserver
    925      * output sink, this information is used for restoration of the server side
    926      * VolumeHandler.
    927      */
    928     void setStarted() {
    929         (void)getVolume(mLastFrame);  // getVolume() will start the individual VolumeShapers.
    930     }
    931 
    932     std::pair<T /* volume */, bool /* active */> getLastVolume() const {
    933         AutoMutex _l(mLock);
    934         return mLastVolume;
    935     }
    936 
    937     std::string toString() const {
    938         AutoMutex _l(mLock);
    939         std::stringstream ss;
    940         ss << "VolumeHandler{mSampleRate=" << mSampleRate;
    941         ss << ", mLastFrame=" << mLastFrame;
    942         ss << ", mVolumeShapers={";
    943         bool first = true;
    944         for (const auto &shaper : mVolumeShapers) {
    945             if (first) {
    946                 first = false;
    947             } else {
    948                 ss << ", ";
    949             }
    950             ss << shaper.toString().c_str();
    951         }
    952         ss << "}}";
    953         return ss.str();
    954     }
    955 
    956     void forall(const std::function<VolumeShaper::Status (const VolumeShaper &)> &lambda) {
    957         AutoMutex _l(mLock);
    958         VS_LOG("forall: mVolumeShapers.size() %zu", mVolumeShapers.size());
    959         for (const auto &shaper : mVolumeShapers) {
    960             VolumeShaper::Status status = lambda(shaper);
    961             VS_LOG("forall applying lambda on shaper (%p): %d", &shaper, (int)status);
    962         }
    963     }
    964 
    965     void reset() {
    966         AutoMutex _l(mLock);
    967         mVolumeShapers.clear();
    968         mLastFrame = 0;
    969         // keep mVolumeShaperIdCounter as is.
    970     }
    971 
    972     /* Sets the configuration id if necessary - This is based on the counter
    973      * internal to the VolumeHandler.
    974      */
    975     void setIdIfNecessary(const sp<VolumeShaper::Configuration> &configuration) {
    976         if (configuration->getType() == VolumeShaper::Configuration::TYPE_SCALE) {
    977             const int id = configuration->getId();
    978             if (id == -1) {
    979                 // Reassign to a unique id, skipping system ids.
    980                 AutoMutex _l(mLock);
    981                 while (true) {
    982                     if (mVolumeShaperIdCounter == INT32_MAX) {
    983                         mVolumeShaperIdCounter = VolumeShaper::kSystemVolumeShapersMax;
    984                     } else {
    985                         ++mVolumeShaperIdCounter;
    986                     }
    987                     if (findId_l(mVolumeShaperIdCounter) != mVolumeShapers.end()) {
    988                         continue; // collision with an existing id.
    989                     }
    990                     configuration->setId(mVolumeShaperIdCounter);
    991                     ALOGD("setting id to %d", mVolumeShaperIdCounter);
    992                     break;
    993                 }
    994             }
    995         }
    996     }
    997 
    998 private:
    999     std::list<VolumeShaper>::iterator findId_l(int32_t id) {
   1000         std::list<VolumeShaper>::iterator it = mVolumeShapers.begin();
   1001         for (; it != mVolumeShapers.end(); ++it) {
   1002             if (it->mConfiguration->getId() == id) {
   1003                 break;
   1004             }
   1005         }
   1006         return it;
   1007     }
   1008 
   1009     size_t numberOfUserVolumeShapers_l() const {
   1010         size_t count = 0;
   1011         for (const auto &shaper : mVolumeShapers) {
   1012             count += (shaper.mConfiguration->getId() >= VolumeShaper::kSystemVolumeShapersMax);
   1013         }
   1014         return count;
   1015     }
   1016 
   1017     mutable Mutex mLock;
   1018     double mSampleRate; // in samples (frames) per second
   1019     int64_t mLastFrame; // logging purpose only, 0 on start
   1020     int32_t mVolumeShaperIdCounter; // a counter to return a unique volume shaper id.
   1021     std::pair<T /* volume */, bool /* active */> mLastVolume;
   1022     std::list<VolumeShaper> mVolumeShapers; // list provides stable iterators on erase
   1023 }; // VolumeHandler
   1024 
   1025 } // namespace media
   1026 
   1027 } // namespace android
   1028 
   1029 #pragma pop_macro("LOG_TAG")
   1030 
   1031 #endif // ANDROID_VOLUME_SHAPER_H
   1032