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