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