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